Looping Example
Design Objective
When the user presses the button, read first 3 switches (least significant), if the number is less than or equal to 5 then calculate factorial. If greater than 5 turn on decimal point. Display the least significant 4 bits of the answer.
My Design Steps
Step 1: Initialized Ports
; Disable interrupts and configure stack pointer for 328Pcli; Initialize Switches with Pull-up resistors and Test LEDsin r16,DDRC // input Port C Data Direction Register (0x07) for switches 5 to 0cbr r16,0b00111111 // define bits 5 to 0 as input (clear bit register)out DDRC,r16 // output
in r16,PORTC // input Port C Register (0x08) for switches 5 to 0
sbr r16,0b00111111 // add pull-up resistors (PUR)
out PORTC,r16 // output
in r16,DDRD // input Port D Data Direction Register (0x0A) for switches 7 to 6
cbr r16,0b11000000 // define bits 7 to 6 as input (clear)
out DDRD,r16 // output
in r16,PORTD // input Port D Register (0x0B) for switches 7 to 6
sbr r16,0b11000000 // add pull-up resistors (PUR)
out PORTD,r16 // output
; Initialize SPI Port and Test LEDsin r16,DDRB // Input from Port B Data Direction Register (DDRB) at i/o address 0x04sbr r16,0b00101111 // Set PB5, PB3, PB2 (SCK, MOSI, SS) and PB1, PB0 (TEST LEDs) as outputsout DDRB,r16 // Output to Port B Data Direction Register (DDRB) at i/o address 0x04in r16,PORTB // input Port B Register (0x05) bit 2 (SS) at i/o address 0x05cbr r16,0b00000111 // bit 1 (TEST LED1), bit 0 (TEST LED0)out PORTB,r16 // outputldi r16,0b01010001 // Set SPCR Enable (SPE) bit 6, Master (MSTR) bit 4, // clock rate fck/16 (SPR1 = 0,SPR0 = 1)out SPCR,r16 // Output to SPI Control Register (SPCR) at i/o address 0x2cStep 2: Turned on LED 0 to indicate initialization complete
sbi PORTB, 0 // Turn on LED 0Step 3: Wrote code to pulse the clock
start: cbi PORTD, 5 sbi PORTD, 5Step 4: Read in pin waiting for the button to be pressed (Loop Example 1)
// check button
sbic PIND, 2 rjmp startStep 5: Need to filter out Bounce (Loop Example 2)
delay_50: ldi r16, 0 // 256wait: dec r16 // 1 clock cycle brne wait // + 2 cycle if true, 1 cycles if false // 3 cycles x 256 - 1 = 599 x 1/16 MHz = 48 usecMaximum delay that could be generated was only 48 usec
Step 6: Added a NOP instruction, max delay was now 64 usec
Set delay for nice even number of 50 usec
delay_50: ldi r16, 200 // 200 = 0xC8wait: nop // 1 clock cycle dec r16 // 1 clock cycle brne wait // + 2 cycle if true, 1 cycles if true // 4 cycles x 200 - 1 = 799 x 1/16 MHz = 50 usecStep 7: Made an outside loop of 10 (Loop Example 3)
delay_500: ldi r17, 10delay_50: ldi r16, 200 // 200 = 0xC8wait: nop // 1 clock cycle dec r16 // 1 clock cycle brne wait // + 2 cycle if true, 1 cycles if true // 4 cycles x 200 - 1 = 799 x 1/16 MHz = 50 usec dec r17 brne delay_50 // 10 x 50 usec = 500 us (approx)Step 8: Converted loop to a subroutine so I could change condition to button release.
; --------------------------Delay500: push r16 push r17 ldi r17, 10 // was 10delay_50: ldi r16, 200 // 200 = 0xC8wait: nop // 1 clock cycle dec r16 // 1 clock cycle brne wait // + 2 cycle if true, 1 cycles if true // 4 cycles x 200 - 1 = 799 x 1/16 MHz = 50 usec dec r17 brne delay_50 // 10 x 50 usec = 500 us (approx) dec r18 brne delay_500 // 10 x 50 usec = 500 us (approx) pop r17 pop r16retStep 9: Check for button pressed and then released
start: cbi PORTD, 5 sbi PORTD, 5// check button down sbic PIND, 2 rjmp start rcall Delay500 // remove bouncecheck_button: cbi PORTD, 5 sbi PORTD, 5// check button up sbis PIND, 2 rjmp check_button rcall Delay500 // remove bounceStep 10: Read Switch and check if less than or equal to 5
in r16, PINC cbr r16, 0b11110000 // clear undefined bits cpi r16, 6 // no unsigned less than or equal to 5 brlo factorial// error condition ldi r16, 0x80 // decimal point mov r8, r16 rcall writeDisplay rjmp startStep 11: Calculate Factorial (Loop Example 4)
factorial: ldi r17, 1 mov r0, r17calculate: mul r0, r16 // r1:r0 = r0 x r16 dec r16 brne calculateStep 12: Convert least significant nibble to 7-segment display (Flash Program Indirect Addressing Mode)
display_answer: ldi r16, 0b00001111 // limit to least significant nibble and r0, r16 ldi ZL,low(table<<1) // load address of look-up ldi ZH,high(table<<1) clr r1 add ZL, r0 adc ZH, r1 lpm spi7SEG, Z rcall writeDisplay rjmp start// gfedcba gfedcba gfedcba gfedcba gfedcba gfedcbatable: .DB 0b00111111, 0b00000110, 0b01011011, 0b01001111, 0b01100110, 0b01101101// 0 1 2 3 4 5 .DB 0b01111101, 0b00000111, 0b01111111, 0b01100111, 0b01110111, 0b01111100// 6 7 8 9 A B .DB 0b00111001, 0b01011110, 0b01111001, 0b01110001// C D E F