;********************************************************************** ; at328-2s.S - Demonstrate simple I/O functions of ATmega328 ; ; This program will cause a 7-segment display to either count up in ; hexadecimal (0,1,2,...,E,F,0,1,...) or count down in decimal ; (9,8,...,1,0,9,8,..) depending on whether or not a switch is pressed. ; ; Port C, bit 1 - input from switch (0 = pressed, 1 = not pressed) ; When the switch is not pressed, the 7-segment display counts ; up in hexadecimal. When the switch is pressed, the 7-segment ; display counts down in decimal. ; Port B, bits 0-1 and Port D, bits 2-6 - Outputs to data inputs of ; the 74LS374 register. ; Bit 6 -> segment A, 5->B, ... , 1->F, 0->G ; A low output bit will cause the LED segment to light up. ; Port C, bit 2 - Output to positive edge-triggered clock input ; of 74LS374 register. ; ; Revision History ; Date Author Description ; 08/18/07 A. Weber Updated for JL16 ; 02/26/08 A. Weber Modified for CodeWarrior assembler ; 06/11/13 A. Weber Translated to AVR assembler (avr-gcc) ; 11/18/13 A. Weber Renamed for ATmega328P ;********************************************************************** #include #define SWITCH PC1 #define SEG_DATA_B 0x03 // Bits in Port B for LED display #define SEG_DATA_D 0x7c // Bits in Port D for LED display #define SEG_CLOCK PC2 count = 19 ; Current count value delay2 = 20 ; Delay counts delay1 = 21 delay0 = 22 zero = 1 ; R1 is zero .section .text .global main main: sbi _SFR_IO_ADDR(PORTC), PC1 ; Enable pull-up resistor on switch sbi _SFR_IO_ADDR(DDRC), SEG_CLOCK ; Set register clock for output in r16, _SFR_IO_ADDR(DDRB) ; Segment bits 0-1 are output on ori r16, SEG_DATA_B ; PORTB bits 0-1 out _SFR_IO_ADDR(DDRB), r16 in r16, _SFR_IO_ADDR(DDRD) ; Segment bits 2-6 are output on ori r16, SEG_DATA_D ; PORTD bits 2-6 out _SFR_IO_ADDR(DDRD), r16 clr count ; Set initial count value to zero loop: rcall display_digit ; Output count digit to display rcall delay ; Delay for a bit sbic _SFR_IO_ADDR(PINC), PC1 ; Check the button rjmp up ; if PC1 = 0, count down down: dec count ; Decrement count cpi count,10 ; Is it over 9? If number was zero, ; decrementing it will make it 255 brlo d1 ; If lower or same, it's OK ldi count,9 ; Otherwise, set it to nine d1: rjmp done up: inc count ; Increment it cpi count,16 ; Is it over 15? brlo done ; If lower or same, it's OK clr count ; Otherwise, reset it to zero done: rjmp loop display_digit: ldi r30,lo8(segtbl) ; Put segment table address in Z ldi r31,hi8(segtbl) add r30,count ; Add the offset adc r31,zero lpm r18,Z ; Get segment bit from program memory com r18 ; Invert bits since low output lights LED in r17, _SFR_IO_ADDR(PORTB) ; Get PORTB to R17 andi r17, ~SEG_DATA_B ; Mask off the segment bits mov r16, r18 ; Copy segment bits to R16 andi r16, SEG_DATA_B ; Mask off the other bits or r17, r16 ; OR them together out _SFR_IO_ADDR(PORTB), r17 ; Put R17 back to PORTB in r17, _SFR_IO_ADDR(PORTD) ; Get PORTD to R17 andi r17, ~SEG_DATA_D ; Mask of the segment bits mov r16, r18 ; Copy segment bits to R16 andi r16, SEG_DATA_D ; Mask off the other bits or r17, r16 ; OR them together out _SFR_IO_ADDR(PORTD), r17 ; Put R17 back to PORTB sbi _SFR_IO_ADDR(PORTC), SEG_CLOCK ; Toggle the clock bit to 1 cbi _SFR_IO_ADDR(PORTC), SEG_CLOCK ; Toggle the clock bit to 0 ret ; ; Delay 0.5 seconds ; delay: ldi delay2, 50 ; Run the 0.01 delay loop 50 times ; The following code delays 0.01 second by looping. The inner loop goes ; 256 times each time the outer loop goes once. The outer loop runs ; 127 times. x2: ldi delay1, 127 ; 1 cycles x1: clr delay0 ; 1 cycle x0: dec delay0 ; 1 cycle brne x0 ; 2 cycles dec delay1 ; 1 cycles brne x1 ; 2 cycles ; Total time is 1 + 127 * (1 + 256 * (1 + 2) + 1 + 2) = 98,045 cycles ; A 9.8304MHz external clock gives a cycle time of (101ns/cycle). ; Delay is then .00997 seconds. Close enough. dec delay2 brne x2 ret ; Table of seven-segment bits, from Wakerly, Table 5-21 ; ; 6 ; 1 5 ; 0 ; 2 4 ; 3 ; segtbl: .byte 0x7e ; 0 .byte 0x30 ; 1 .byte 0x6d ; 2 .byte 0x79 ; 3 .byte 0x33 ; 4 .byte 0x5b ; 5 .byte 0x5f ; 6 .byte 0x70 ; 7 .byte 0x7f ; 8 .byte 0x73 ; 9 .byte 0x77 ; A .byte 0x1f ; b .byte 0x4e ; C .byte 0x3d ; d .byte 0x4f ; E .byte 0x47 ; F