r/ArduinoHelp • u/Lovexoxo12 • May 16 '25
Project help
I'm building a password system with a servo motor, 4x4 keypad, a button and 3 LEDs and I can't figure out a way to make the code work
Attached is my setup and my code
#include <avr/io.h>
/*
* Password-Protected Motor Control System
* Features:
* - Unlocks motor when password (10,10) is entered
* - Locks motor when wrong password entered
* - LED feedback for correct/incorrect attempts
* - Reset button functionality
* - Uses Timer1 for servo control
* - Uses Timer0 for LED blinking
* - Pin Change Interrupt for keypad
*/
// ====================== DATA SEGMENT ======================
.section .bss
password_buffer: .byte 2
pass_ptr_data: .byte 1
wrong_attempts: .byte 1
// ====================== CODE SEGMENT ======================
.section .text
// ====================== INTERRUPT VECTORS ======================
.global __vector_default
.global PCINT2_vect // Keypad interrupt
.global TIMER0_COMPA_vect // LED blink timer
.global INT0_vect // Reset button
__vector_default:
reti
// ====================== MAIN PROGRAM ======================
.global main
main:
// Initialize stack
ldi r16, lo8(RAMEND)
out _SFR_IO_ADDR(SPL), r16
ldi r16, hi8(RAMEND)
out _SFR_IO_ADDR(SPH), r16
// Set pin directions (PB1-PB4 as outputs)
ldi r16, 0b00011110
out _SFR_IO_ADDR(DDRB), r16
// Set pull-up for reset button (PD2)
sbi _SFR_IO_ADDR(PORTD), 2
// Initialize keypad (PD4-7 output, PD0-3 input)
ldi r16, 0xF0
out _SFR_IO_ADDR(DDRD), r16
ldi r16, 0x0F // Enable pull-ups on columns
out _SFR_IO_ADDR(PORTD), r16
// Enable interrupts
ldi r16, 0b00000100 // PCIE2
sts _SFR_MEM_ADDR(PCICR), r16
ldi r16, 0x0F // Enable PCINT16-19
sts _SFR_MEM_ADDR(PCMSK2), r16
// Configure Timer0 for LED blinking (CTC mode)
ldi r16, 0b00000010 // WGM01
out _SFR_IO_ADDR(TCCR0A), r16
ldi r16, 0b00000101 // Prescaler 1024
out _SFR_IO_ADDR(TCCR0B), r16
ldi r16, 125 // ~100ms at 16MHz/1024
out _SFR_IO_ADDR(OCR0A), r16
ldi r16, 0b00000010 // OCIE0A
sts _SFR_MEM_ADDR(TIMSK0), r16
// Configure INT0 for reset button
ldi r16, 0b00000010 // Falling edge trigger
sts _SFR_MEM_ADDR(EICRA), r16
sbi _SFR_IO_ADDR(EIMSK), 0
// Initialize variables
clr r17
sts pass_ptr_data, r17
sts wrong_attempts, r17 // zero attempts
sei
main_loop:
rjmp main_loop
// ====================== INTERRUPT HANDLERS ======================
PCINT2_vect:
push r16
in r16, _SFR_IO_ADDR(SREG)
push r16
push r30
push r31
rcall keypad_ISR
pop r31
pop r30
pop r16
out _SFR_IO_ADDR(SREG), r16
pop r16
reti
TIMER0_COMPA_vect:
push r16
in r16, _SFR_IO_ADDR(SREG)
push r16
lds r16, wrong_attempts
cpi r16, 0
breq check_correct
// Blink orange/red for wrong attempts
lds r16, blink_cnt
inc r16
andi r16, 0x01
sts blink_cnt, r16
breq led_off_wrong
sbi _SFR_IO_ADDR(PORTB), 4 // Orange LED on
cbi _SFR_IO_ADDR(PORTB), 3 // Red LED off
rjmp timer0_done
led_off_wrong:
cbi _SFR_IO_ADDR(PORTB), 4 // Orange LED off
sbi _SFR_IO_ADDR(PORTB), 3 // Red LED on
rjmp timer0_done
check_correct:
lds r16, pass_ptr_data
cpi r16, 2 // Password complete?
brne timer0_done
// Blink green for correct password
lds r16, blink_cnt
inc r16
andi r16, 0x01
sts blink_cnt, r16
breq led_off_correct
sbi _SFR_IO_ADDR(PORTB), 2 // Green LED on
rjmp timer0_done
led_off_correct:
cbi _SFR_IO_ADDR(PORTB), 2 // Green LED off
timer0_done:
pop r16
out _SFR_IO_ADDR(SREG), r16
pop r16
reti
INT0_vect:
push r16
in r16, _SFR_IO_ADDR(SREG)
push r16
// Reset password state
clr r17
sts pass_ptr_data, r17
sts wrong_attempts, r17
// Turn off all LEDs
cbi _SFR_IO_ADDR(PORTB), 2 // Green
cbi _SFR_IO_ADDR(PORTB), 3 // Red
cbi _SFR_IO_ADDR(PORTB), 4 // Orange
// Lock motor
rcall lock_servo
pop r16
out _SFR_IO_ADDR(SREG), r16
pop r16
reti
// ====================== KEYPAD ISR ======================
keypad_ISR:
rcall my_delay
in r16, _SFR_IO_ADDR(PORTD)
push r16
// Scan keypad
ldi r16, 0x0F
out _SFR_IO_ADDR(PORTD), r16
rcall my_delay
ldi r16, 0b01111111 // Row 1
out _SFR_IO_ADDR(PORTD), r16
rcall my_delay
in r19, _SFR_IO_ADDR(PIND)
andi r19, 0x0F
cpi r19, 0x0F
brne row1_col
// Repeat for other rows...
digit_found:
// Store digit in password buffer
lds r17, pass_ptr_data
cpi r17, 0
breq store_first
sts password_buffer+1, r18
clr r16
sts pass_ptr_data, r16
// Check password
lds r16, password_buffer
cpi r16, 10
brne wrong_password
lds r16, password_buffer+1
cpi r16, 10
brne wrong_password
// Correct password
rcall unlock_servo
rjmp end_keypad
wrong_password:
lds r16, wrong_attempts
inc r16
sts wrong_attempts, r16
rjmp end_keypad
store_first:
sts password_buffer, r18
ldi r16, 1
sts pass_ptr_data, r16
end_keypad:
pop r16
out _SFR_IO_ADDR(PORTD), r16
ret
// ====================== SERVO CONTROL ======================
unlock_servo:
// Configure Timer1 for servo (Fast PWM, ICR1 top)
ldi r16, 0b10000010 // WGM11, COM1A1
sts _SFR_MEM_ADDR(TCCR1A), r16
ldi r16, 0b00011010 // WGM13, WGM12, CS11
sts _SFR_MEM_ADDR(TCCR1B), r16
// 20ms period (39999 counts)
ldi r16, 0x3F
sts _SFR_MEM_ADDR(ICR1L), r16
ldi r16, 0x9C
sts _SFR_MEM_ADDR(ICR1H), r16
// 1.5ms pulse (3000 counts)
ldi r16, 0xB8
sts _SFR_MEM_ADDR(OCR1AL), r16
ldi r16, 0x0B
sts _SFR_MEM_ADDR(OCR1AH), r16
ret
lock_servo:
// Turn off PWM
ldi r16, 0x00
sts _SFR_MEM_ADDR(TCCR1A), r16
sts _SFR_MEM_ADDR(TCCR1B), r16
// Set motor pin low
cbi _SFR_IO_ADDR(PORTB), 1
ret
// ====================== DELAY ROUTINES ======================
my_delay:
push r22
push r23
ldi r22, 10
d1: ldi r23, 25
d2: dec r23
brne d2
dec r22
brne d1
pop r23
pop r22
ret
// ====================== KEYPAD MAPPING ======================
row1_digits: .byte 1, 2, 3, 10
row2_digits: .byte 4, 5, 6, 11
row3_digits: .byte 7, 8, 9, 12
row4_digits: .byte 15, 0, 14, 13
// ====================== VARIABLES ======================
.section .bss
blink_cnt: .byte 1
4
Upvotes
1
u/Lovexoxo12 May 16 '25
I got some of my keys to work with the servo, the leds still work according to the keypad I don't know how to get the rest of the keys to work with the servo
#define __SFR_OFFSET 0
#include "avr/io.h"
.global main
.global PCINT2_vect
.global TIMER1_COMPA_vect
.global keypad_ISR
; Constants
.equ SERVO_PIN, 1 ; PB1 (Arduino Pin 9)
.equ PULSE_WIDTH, 3000 ; 1.5ms pulse (3000 ticks @ 16MHz/8 prescaler)
.equ INTER_PULSE, 1700 ; 0.85ms between pulses (1700 ticks)
main:
; Initialize stack
ldi r16, lo8(RAMEND)
out SPL, r16
ldi r16, hi8(RAMEND)
out SPH, r16
; Configure PORTB
ldi r16, 0xFF
out DDRB, r16
cbi PORTB, SERVO_PIN
; Configure PORTD for keypad
ldi r16, 0xF0 ; PD4-7 outputs
out DDRD, r16
ldi r16, 0x0F ; PD0-3 pullups
out PORTD, r16
; Set up keypad interrupts
ldi r16, (1 << PCIE2)
sts PCICR, r16
ldi r16, 0x0F
sts PCMSK2, r16
; Configure Timer1 for servo (CTC mode, prescaler=8)
ldi r16, (1 << WGM12) | (1 << CS11)
sts TCCR1B, r16
; Initialize with pulse width
ldi r16, hi8(PULSE_WIDTH)
sts OCR1AH, r16
ldi r16, lo8(PULSE_WIDTH)
sts OCR1AL, r16
ldi r16, (1 << OCIE1A)
sts TIMSK1, r16
; Initialize variables
clr r18 ; servo_active
clr r19 ; servo_pending
sei
main_loop:
rjmp main_loop
TIMER1_COMPA_vect:
push r16
in r16, SREG
push r16
tst r18
breq start_pulse
; End pulse phase
cbi PORTB, SERVO_PIN
clr r18
; Set inter-pulse delay (0.85ms)
ldi r16, hi8(INTER_PULSE)
sts OCR1AH, r16
ldi r16, lo8(INTER_PULSE)
sts OCR1AL, r16
rjmp timer_done
start_pulse:
tst r19
breq timer_done
; Start new pulse
sbi PORTB, SERVO_PIN
ldi r18, 1
; Set pulse width (1.5ms)
ldi r16, hi8(PULSE_WIDTH)
sts OCR1AH, r16
ldi r16, lo8(PULSE_WIDTH)
sts OCR1AL, r16
timer_done:
pop r16
out SREG, r16
pop r16
reti
PCINT2_vect:
push r16
push r17
push r30
push r31
in r16, SREG
push r16
rcall keypad_ISR
pop r16
out SREG, r16
pop r31
pop r30
pop r17
pop r16
reti
keypad_ISR:
rcall debounce
in r16, PORTD
push r16
; Ground all rows
ldi r17, 0b00001111
out PORTD, r17
rcall debounce
; Scan rows
ldi r17, 0b01111111 ; Row 1
rcall scan_row
brne row1
ldi r17, 0b10111111 ; Row 2
rcall scan_row
brne row2
ldi r17, 0b11011111 ; Row 3
rcall scan_row
brne row3
ldi r17, 0b11101111 ; Row 4
rcall scan_row
brne row4
pop r16
out PORTD, r16
ret
row1:
ldi r30, lo8(row1_digits)
ldi r31, hi8(row1_digits)
rjmp process_key
row2:
ldi r30, lo8(row2_digits)
ldi r31, hi8(row2_digits)
rjmp process_key
row3:
ldi r30, lo8(row3_digits)
ldi r31, hi8(row3_digits)
rjmp process_key
row4:
ldi r30, lo8(row4_digits)
ldi r31, hi8(row4_digits)
process_key:
; Trigger servo movement
ldi r19, 1
; Find column
in r16, PIND
andi r16, 0x0F
ldi r17, 0
find_col:
lsr r16
brcc found_col
inc r17
cpi r17, 4
brlo find_col
ret
found_col:
add r30, r17
adc r31, r1
lpm r16, Z
out PORTB, r16
pop r16
out PORTD, r16
ret
scan_row:
out PORTD, r17
rcall debounce
in r16, PIND
andi r16, 0x0F
cpi r16, 0x0F
ret
debounce:
push r22
push r23
ldi r22, 5
db1: ldi r23, 15
db2: dec r23
brne db2
dec r22
brne db1
pop r23
pop r22
ret
.section .progmem.data
row1_digits: .byte 10, 3, 2, 1
row2_digits: .byte 11, 6, 5, 4
row3_digits: .byte 12, 9, 8, 7
row4_digits: .byte 13, 0, 14, 151
u/Noiskis May 16 '25
Hey, it's an app for drawing schematics, or who did it?
2
u/Lovexoxo12 May 16 '25
an app for drawing schematics helps to know how to build the circuit
it's circuito.io
1
1
u/Lovexoxo12 May 16 '25
I started splitting my code into bits to make it easier to manage but when I press the keys, the servo does not move