; ; Whippleway Experiment 11 for the ATmega328 ; ; Created: 3/28/2017 8:06:37 PM ; Author : Dick Whipple ; ; Add Immediate Macro ; ; ; Define Macros ; ; Add Immediate Macro ; ; addi r,k ; ; r register 0 to 31 ; k single byte constant ; .macro addi subi @0, -@1 ;subtract the negative of an immediate value .endmacro ; ; Load Immediate Word Macro ; ; ldiw r0,r1,k ; ; r0 register loads with high byte of k ; r1 register loads with low byte of k ; k double byte constant (0 to 65,535) ; .macro ldiw ldi @0,high(@2) ldi @1,low(@2) .endmacro; ; Baud Rate ; .equ ubrrval = 103 ;See section 24.11 Table 24-7 fosc = 16 Mhz U2Xn = 0 column ; ; Pin Assignments ; .equ pin0 = 0 ;Port d Bit 0 .equ pin1 = 1 ;Port d Bit 1 .equ pin2 = 2 ;Port d Bit 2 .equ pin3 = 3 ;Port d Bit 3 .equ pin4 = 4 ;Port d Bit 4 .equ pin5 = 5 ;Port d Bit 5 .equ pin6 = 6 ;Port d Bit 6 .equ pin7 = 7 ;Port d Bit 7 .equ pin8 = 0 ;Port b Bit 0 .equ pin9 = 1 ;Port b Bit 1 .equ pin10 = 2 ;Port b Bit 2 .equ pin11 = 3 ;Port b Bit 3 .equ pin12 = 4 ;Port b Bit 4 .equ pin13 = 5 ;Port b Bit 5 .equ pina0 = 0 ;Port c Bit 0 .equ pina1 = 1 ;Port c Bit 1 .equ pina2 = 2 ;Port c Bit 2 .equ pina3 = 3 ;Port c Bit 3 .equ pina4 = 4 ;Port c Bit 4 .equ pina5 = 5 ;Port c Bit 5 ; ; Define LED/Button Labels ; .equ red_pin = pin9 .equ green_pin = pin10 .equ blue_pin = pin11 .equ button_1 = pin2 jmp RESET ; Reset jmp null_int ; IRQ0 jmp null_int ; IRQ1 jmp null_int ; PCINT0 jmp null_int ; PCINT1 jmp null_int ; PCINT2 jmp null_int ; Watchdog Timeout jmp null_int ; Timer2 CompareA jmp null_int ; Timer2 CompareB jmp null_int ; Timer2 Overflow jmp null_int ; Timer1 Capture jmp TIM1_COMPA ; Timer1 CompareA jmp null_int ; Timer1 CompareB jmp null_int ; Timer1 Overflow jmp null_int ; Timer0 CompareA jmp null_int ; Timer0 CompareB jmp null_int ; Timer0 Overflow jmp null_int ; SPI Transfer Complete jmp null_int ; USART RX Complete jmp null_int ; USART UDR Empty jmp null_int ; USART TX Complete jmp null_int ; ADC Conversion Complete jmp null_int ; eeprom Ready jmp null_int ; Analog Comparator jmp null_int ; 2-wire Serial jmp null_int ; SPM Ready ; null_int: reti ; ; Digital I/O Initialization Code ; reset: ; clr r16 out ddrb,r16 ;set all ports to input out ddrc,r16 out ddrd,r16 ldi r16,0xff ;enable all pull-up resistors out portb,r16 out portc,r16 out portd,r16 ; ; Serial Communication Initialization Code ; ; Enable Rcx (pin 1) and Trx (pin 2) ; ldi r16, (1< r17 ldi r16,LOW(ubrrval) ;lsb of UBBR -> r16 sts ubrr0h,r17 sts ubrr0l,r16 ; ; eeprome Format: 8 data, 2 stop ; ldi r16, (1< r16 clr r17 ;setup to wait for all zeros first time debounce_wait_loop: ldiw xh,xl,5 ;delay 5 milliseconds call delay_ms in r18,pind ;check button 1 clc ;pre-clear carry sbrc r18,button_1 ;if button pressed, skip setting carry sec ;if button not pressed, set carry rol r16 ;rotate carry to r16 bit0 cp r16,r17 ;wait until r16 filled with all zeros first time or all ones second time brne debounce_wait_loop or r17,r17 ;if first time, setup to wait for all ones second time ser r17 breq debounce_wait_loop ;after second time, return done ret ; ; Example Circuit 3 - Rotate through LEDs with with potentiometer based delay (Analog Input) ; ; Set Up Digital I/O ; circuit_3: sbi ddrb,pin9 ;set pin 9 Red LED as output (port b bit 1) sbi ddrb,pin10 ;set pin 10 Green LED as output (port b bit 2) sbi ddrb,pin11 ;set pin 11 Blue LED as output (port b bit 3) ; ; Set Up Analog-to-Digital Converter ; ; See Section 28.9 for register information ; ldi r16,0b01000000 ;0bxxy0zzzz xx = 01 use internal AVcc for reference (See Table 28-3) ; y = 0 right adjust result (Search "Bit 5 ADLAR") ; zzzz = 0000 A/D channel 0 (See Table 28-4) sts admux,r16 ; ; Main Program ; circuit_3_again: ldi zl,(1< r1 ; circuit_6_self: ; call crlf ;display new line mov r16,r1 call decout ;display r16 in ASCII inc r1 ;increment r16 call delay_1s ;delay 1 second rjmp circuit_6_self ;do nothing and wait for interrupts ; ; Timer 1 Interrupt Processing Routine ; TIM1_COMPA: ; push r16 ;save r16 in r16, SREG ;save SREG sbic portd,3 ;turn blue LED on if off rjmp TIM1_COMPA_cont0 sbi portd,3 out SREG, r16 ;restore SREG pop r16 ;resotre r16 reti ;set gloabal interrupt and return ; TIM1_COMPA_cont0: ; cbi portd,3 ;turn blue LED off if on out SREG, r16 ;restore SREG pop r16 ;resotre r16 reti ;set gloabal interrupt and return ; ; Example Circuit 7 - Rotate through variably bright LEDs (Analog Input) ; circuit_7: ; ; Set Up Timer 1 to output on pins 9 and 10 with prescaler /64 (490 Hz) ; sbi ddrb,pin9 ;set port b bit 1 output for timer 1 compare register "a" sbi ddrb,pin10 ;set port b bit 2 output for timer 1 compare register "b" ; ldi r16,0b00000011 ;Prescaler timer 1 N=64 490 Hz sts TCCR1B,r16 ; ; Set Up Timer 2 to output on pin 11 with prescaler /64 (490 Hz) ; sbi ddrb,pin11 ;set port b bit 3 output for timer 2 compare register "a" ldi r16,0b00000100 ;Prescaler timer 2 N=64 490 Hz sts TCCR2B,r16 ; ; Enable PWM Timer 1 ; ldi r16,0b10100001 ;enable green and red PWM: for timer 1, clear on compare match, and PWM phase correct ;0bxxyy00zz xx = 10 enable to clear timer 1 compare register "a" on compare match when up-counting ; and set timer 1 compare register "a" on compare match when down-counting. (pin 9) ; yy = 10 enable to clear timer 1 compare register "b" on compare match when up-counting ; and set timer 1 compare register "b" on compare match when down-counting. (pin 10) ; zz = 01 phase correct 8-bit mode sts TCCR1A,r16 ; ; Enable PWM Timer 2 ; ldi r16,0b10000001 ;enable blue PWM: for timer 2, clear on compare match, and PWM phase correct ;0bxxyy00zz xx = 10 enable to clear timer 1 compare register "a" on compare match when up-counting ; and set timer 2 compare register "a" on compare match when down-counting. (pin 11) ; yy = 00 disable timer 2 compare register "b" ; zz = 01 phase correct 8-bit mode sts TCCR2A,r16 ; ; Main Program ; circuit_7_again: ; clr r16 sts ocr1al,r16 ;preset green (pin 9) duty cycle = 0% (0 out of 255) sts ocr1ah,r16 sts ocr1bl,r16 ;preset red (pin 10) duty cycle = 0% (0 out of 255) sts ocr1bh,r16 sts ocr2a,r16 ;preset blue (pin 11) duty cycle = 0% (0 out of 255) ; ldiw zh,zl,0 ;preset z counter to 0 ; circuit_7_loop: ; rcall showRGB ;showRGB(z) call delay_10ms adiw zh:zl,1 ;Z + 1 -> Z ldiw xh,xl,768 ;768 -> x sub xl,zl ;X - Z -> X sbc xh,zh ; brne circuit_7_loop ;if z <> 768, then continue looping rjmp circuit_7_again ;else do again from start ; ; Show RGB ; showRGB: push zh ;save z push zl ; ldiw xh,xl,255 ;255 -> x sub xl,zl sbc xh,zh brcs showRGB_cont0 ;if z>255, branch to cont0 mov r16,zl ;red = zl clr r17 ;green = 0 clr r18 ;blue = 0 rjmp showRGB_show ;go show it ; showRGB_cont0: ldiw xh,xl,511 ;511 -> x sub xl,zl sbc xh,zh brcs showRGB_cont1 ;if z>511, branch to cont1 clr r16 ;red = 0 ldi r17,255 sub r17,xl ;green=255-x clr r18 ;blue = 0 rjmp showRGB_show ; showRGB_cont1: ldiw xh,xl,512 sub zl,xl sbc zh,xh ;zl = z - 512 clr r16 ;red = 0 clr r17 ;green = 0 mov r18,zl ;blue = zl ; showRGB_show: sts ocr1al,r16 ;set red compare register sts ocr1bl,r17 ;set green compare register sts ocr2a,r18 ;set blue compare register ; pop zl ;restore z pop zh ret ; ; Example Circuit 8 - Demonstrate Temperature Sensor ; circuit_8: ; ; Set Up Analog-to-Digital Converter ; ldi r16,0b01000000 ;0bxxy0zzzz xx = 01 use internal AVcc for reference (search "Table 28-3") ; y = 0 right adjust result (search "Bit 5 ADLAR") ; zzzz = 0000 A/D channel 0 (search "Table 28-4") sts admux,r16 ;ADC Multiplexer Selection Register (search "28.9.1) ; ; Main Program ; circuit_8_loop: ; ldi r16,0b11000111 ;0bxy000zzz x = 1 enable A/D (search "Bit 7 ADEN") ; y = 1 start conversion (search "Bit 6 ADSC") ; zzz = 111 prescale = 128 (search "Table 28-5") sts adcsra,r16 ;ADC Control and Status Register A (search "28.9.2") ; circuit_8_wait: ; lds r16,adcsra ;check if a-d conversion complete? sbrc r16,adsc ;adsc cleared? rjmp circuit_8_wait ;if not, wait lds r20,adcl ;a-d result rawA/D in r21:r20 lds r21,adch push r20 ;save rawA/D push r21 ldiw r19,r18,102 ;(rawA/D - 102) * 500 / 1023 -> r21:r20 temperature to nearest deg C call sub16 ldiw r19,r18,500 call mul16 ldiw r19,r18,1023 call div16 set call dec16out ;display temperature pop r21 ;restore rawA/D pop r20 ldiw r19,r18,102 ;(rawA/D - 102) * 500 / 33 * 10 / 31 -> r21:r20 temperature nearest 0.1 deg C call sub16 ldiw r19,r18,500 call mul16 ldiw r19,r18,33 call div16 ldiw r19,r18,10 call mul16 ldiw r19,r18,31 call div16 set call dec16out ;display temperature call crlf ;new line ldiw xh,xl,500 ;delay 500 ms call delay_ms rjmp circuit_8 ; ; Example Circuit 9 - Demonstrate SPI Communication ; ; 25lc1024 eeprom instruction set ; .equ eeprom_READ = 0b00000011 .equ eeprom_WRITE = 0b00000010 .equ eeprom_WREN = 0b00000110 .equ eeprom_WRDI = 0b00000100 .equ eeprom_RDSR = 0b00000101 .equ eeprom_WRSR = 0b00000001 .equ eeprom_PE = 0b01000010 .equ eeprom_SE = 0b11011000 .equ eeprom_CE = 0b11000111 .equ eeprom_RDID = 0b10101011 .equ eeprom_DPD = 0b10111001 ; circuit_9: ; ; Set Up SPI ; ldi r16,0b00101100 ;port b bits 2 (CE), 3 (MOSI), and 5 (SCK) as output ; out ddrb,r16 ;update data direction register B sbi portb,2 ;deselect eeprom ldi r16,0b01010001 ;0btuvwxyzz t = 0 disable SPI interrupt (See section 23.5.1) ; u = 1 enable SPI ; v = 1 least significant bit (LSB) first ; w = 1 select ATmega328 as master ; xx = 00 SPI mode 0 ; zz = 01 prescale = 16 for SPI clock = 1 Mhz (search "Table 23-5") out spcr,r16 ;configure SPI control register ; ; Set Up Analog-to-Digital Converter ; ldi r16,0b01000000 ;0bxxy0zzzz xx = 01 use internal AVcc for reference (search "Table 28-3") ; y = 0 right adjust result (search "Bit 5 ADLAR") ; zzzz = 0000 A/D channel 0 (search "Table 28-4") sts admux,r16 ; ; Main ; rcall crlf ;display new line rcall circuit_9_esig ;get esig cpi r16, 41 ; 41? breq circuit_9_cont0 ;if so, continue ldiw zh,zl,(spi_error_esig<<1) ;point z register to start of error message rcall msgout ;display error message call crlf rjmp circuit_9_self ; ; Write Raw A/D Data to EEPROM ; circuit_9_cont0: ; push r16 ;save r16 ldiw zh,zl,(spi_msg_0<<1) ;point z register to start of message 0 rcall msgout ;display esig message pop r16 ;restore r16 set rcall decout ;display electronic signature rcall crlf ;display new line ; ldiw zh,zl,(spi_msg_1<<1) ;point z register to start of message 0 rcall msgout ;display Raw A/D write message rcall crlf ;display new line ldi r16,10 ;set max iterations to 10 mov r3,r16 clr r4 ;set count to 0 ; ldiw r26,r25,0 ;set page of 24-bit starting address ldi r24,0 ;set location of 24-bit starting address ; circuit_9_loop0: ; ldi r16,0b11000111 ;0bxy000zzz x = 1 enable A/D (search "Bit 7 ADEN") ; y = 1 start conversion (search "Bit 6 ADSC") ; zzz = 111 prescale = 128 (search "Table 28-5") sts adcsra,r16 ;ADC Control and Status Register A (search "28.9.2") ; circuit_9_wait: ; lds r16,adcsra ;check if a-d conversion complete? sbrc r16,adsc ;adsc cleared? rjmp circuit_9_wait ;if not, wait lds r20,adcl ;a-d result rawA/D in r21:r20 lds r21,adch rcall circuit_9_write_word ;write raw A/D to eeprom mov r16,r4 ;display count clt rcall decout inc r4 ;increment count set call dec16out ;display raw A/D call crlf ;display new line rcall delay_5s ;5 second delay addi r24,2 ;bump to next address in eeprom dec r3 ;done? brne circuit_9_loop0 ;if not, loop ; rcall crlf ;display new line ; ; Read Data Back from EEPROM ; ldiw zh,zl,(spi_msg_2<<1) ;point z register to start of message 0 rcall msgout ;display Raw A/D read message rcall crlf ;display new line ldi r16,10 ;set max iterations to 10 mov r3,r16 clr r4 ;set count to 0 ldiw r26,r25,0 ;set page of 24-bit starting address ldi r24,0 ;set location of 24-bit starting address ; circuit_9_loop1: ; mov r16,r4 ;display count clt call decout inc r4 ;increment count rcall circuit_9_read_word ;read raw A/D from eeprom set ;display it rcall dec16out rcall crlf ;display new line addi r24,2 ;bump to next address in eeprom dec r3 ;done: brne circuit_9_loop1 ;if not, loop ; circuit_9_self: ; jmp circuit_9_self ; ; SPI Read Electronic Signature ; circuit_9_esig: ; cbi portb,2 ;select eeprom ldi r16,eeprom_RDID ;send esig request rcall spi_write ; ldi r17,3 ;send 3 dummy 24-byte address ; circuit_9_esig_loop: ; ldi r16,0 rcall spi_write dec r17 ;done? brne circuit_9_esig_loop ;if not, loop ; rcall spi_read ;read esig sbi portb,2 ;deselect eeprom ret ; ; SPI Write Word (Double Byte) ; ; r21:r20 contains the word to written ; r26:r25:R24 contain the 24-bit address ; circuit_9_write_word: ; cbi portb,2 ;select eeprom ldi r16,eeprom_WREN ;send write enable request rcall spi_write sbi portb,2 ;deselect eeprom cbi portb,2 ;select eeprom ldi r16,eeprom_WRITE ;send write request rcall spi_write mov r16,r26 ;send 24-bit address rcall spi_write mov r16,r25 rcall spi_write mov r16,r24 rcall spi_write mov r16,r21 ;send most significant byte to be written rcall spi_write mov r16,r20 ;send least significant byte to be written rcall spi_write sbi portb,2 ;deselect eeprom and start write cycle ; circuit_write_word_wait: ; rcall spi_read_SDSR ;read status register sbrc r16,0 ;wait while WIP bit 0 set (write in progress) rjmp circuit_write_word_wait ret ; ; SPI Read Word (Double Byte) ; ; r21:r20 contains the byte read ; r26:r25:R24 contain the 24-bit address ; circuit_9_read_word: ; cbi portb,2 ;select eeprom ldi r16,eeprom_READ ;send read request rcall spi_write mov r16,r26 ;send 24-bit address rcall spi_write mov r16,r25 rcall spi_write mov r16,r24 rcall spi_write rcall spi_read ;read most significant byte mov r21,r16 rcall spi_read ;read least significant byte mov r20,r16 sbi portb,2 ;deselect eeprom ret ; ; SPI Read Status Register into r16 ; spi_read_SDSR: ; cbi portb,2 ;select eeprom ldi r16,eeprom_RDSR ;send status register read request rcall spi_write rcall spi_read ;read status register sbi portb,2 ;deselect eeprom and start write cycle ret ; ; SPI Write r16 ; spi_write: ; out spdr,r16 ;send byte to SPI ; spi_write_wait: ; in r16,spsr ;write completed? sbrs r16,spif ;if not, wait rjmp spi_write_wait ret ; ; SPI Read into r16 ; spi_read: ; ldi r16,0 ;send dummy byte to spi out spdr,r16 ; spi_read_wait: ; in r16,spsr ;write completed? sbrs r16,spif ;if not, wait rjmp spi_read_wait in r16,spdr ;get return byte ret ; spi_msg_0: .db "25LC1024 EEPROM Electronic Signature: ", 0, 0 spi_msg_1: .db "Raw A/D Data Written to EEPROM: ", 0, 0 spi_msg_2: .db "Data Read Back from EEPROM: ", 0, 0 spi_error_esig: .db "SPI Error: Wrong electronic signature",0 spi_error_wel: .db "SPI Error: Write enable latch not set",0 ; ; Utility Subroutines ; ; Delay 10 Milliseconds ; ; Parameters: None ; ; Returns: Nothing ; ; Registers Used: x,y,SREG ; delay_10ms: ldiw xh,xl,10 ;delay 10 milliseconds call delay_ms ret ; ; Delay One Second ; ; Parameters: None ; ; Returns: Nothing ; ; Registers Used: x,y,SREG ; delay_1s: ldiw xh,xl,1000 ;delay 1 second call delay_ms ret ; ; Delay Five Seconds ; ; Parameters: None ; ; Returns: Nothing ; ; Registers Used: x,y,SREG ; delay_5s: ldiw xh,xl,5000 ;delay 5 seconds call delay_ms ret ; ; Millisecond Delay ; ; Delays x register milliseconds ; ; Parameters: x milliseconds (minimum 1 ms) ; ; Returns: Nothing ; ; Registers Used: x,y,SREG ; delay_ms: ldi yh,0x0f ;load initial x register count ldi yl,0x9e cpi xh,0 ;x = 0 not allowed brne delay_ms_loop ;if not 0, skip incrementing xl cpi xl,0 brne delay_ms_loop ;if not 0, skip incrementing x inc xl ;make x = 1 delay_ms_loop: sbiw yh:yl,1 ;decrement x register until zero brne delay_ms_loop ;if not zero, repeat count down sbiw xh:xl,1 ;decrement r29 until zero brne delay_ms ;if not zero, count down r30:r31 again.: ret ;done and return ; ; ; Binary Output ; ; Displays in ASCII 1's and 0's an unsigned 8-bit binary value ; ; Parameters: Binary value in r16 ; ; Returns: Nothing ; ; Registers Used: r16,r18,r19,sreg ; binout: ldi r19,8 ;number of interation for an 8-bit byte mov r18,r16 ;make r18 byte to display ldi r16,' ' ;output space rcall chrout binout_loop: ldi r16,'0' ;preload r19 with ASCII 0 sbrc r18,7 ;if bit 7 zero, skip next instruction inc r16 ;make an ASCII one rcall chrout ;output the ASCII value lsl r18 ;move next lower bit to bit 7 position dec r19 ;if not done, do next bit brne binout_loop ret ; ; ; Hex Output ; ; Displays the ASCII Hex of an unsigned 8-bit binary value ; ; Parameters: Binary value in r16 ; ; Returns: Nothing ; ; Registers Used: r16,sreg ; hexout: push r16 ror r16 ror r16 ror r16 ror r16 rcall hexdig pop r16 hexdig: andi r16,0x0f cpi r16,10 brcc hexdig_cont addi r16,48 jmp chrout hexdig_cont: addi r16,55 jmp chrout ; ; Decimal Output (unsigned 16-bit binary to decimal ASCII conversion) ; ; Displays in ASCII decimal format an unsigned 8-bit binary value ; ; Input: Binary value in r21:r20, T flag set to inhibit leading zeros ; ; Returns: Nothing ; ; Registers Used: r16,r17,r18,sreg ; dec16out: push r21 ;save r21:r20 push r20 ldi r16,' ' ;output space rcall chrout ldi r16,'0'-1 ; ASCII 0 less 1 -> r16 ldi r22,low(10000) ldi r23,high(10000) d16loop10000: inc r16 ;next ACSCII numeral sub r20,r22 ;subtract 10000 sbc r21,r23 brcc d16loop10000 ;if r21:r20 > 0 then do again add r20,r22 ;otherwise, add back 10000 adc r21,r23 call inhzero ;output ASCII numneral ldi r16,'0'-1 ; ASCII 0 less 1 -> r16 ldi r22,low(1000) ldi r23,high(1000) d16loop1000: inc r16 ;next ACSCII numeral sub r20,r22 ;subtract 1000 sbc r21,r23 brcc d16loop1000 ;if r21:r20 > 0 then do again add r20,r22 ;otherwise, add back 1000 adc r21,r23 call inhzero ;output ASCII numneral ldi r16,'0'-1 ; ASCII 0 less 1 -> r16 ldi r22,low(100) ldi r23,high(100) d16loop100: inc r16 ;next ACSCII numeral sub r20,r22 ;subtract 100 sbc r21,r23 brcc d16loop100 ;if r21:r20 > 0 then do again add r20,r22 ;otherwise, add back 100 adc r21,r23 call inhzero ;output ASCII numneral ldi r16,'0'-1 ; ASCII 0 less 1 -> r16 ldi r22,low(10) ldi r23,high(10) d16loop10: inc r16 ;next ACSCII numeral sub r20,r22 ;subtract 10 sbc r21,r23 brcc d16loop10 ;if r21:r20 > 0 then do again add r20,r22 ;otherwise, add back 10 adc r21,r23 call inhzero ;output ASCII numneral ldi r16,'0'-1 ; ASCII 0 less 1 -> r16 ldi r22,low(1) ldi r23,high(1) d16loop1: inc r16 ;next ACSCII numeral sub r20,r22 ;subtract 1 sbc r21,r23 brcc d16loop1 ;if r18 > 0 then do again add r20,r22 ;otherwise, add back 1 add r21,r23 rcall chrout ;output ASCII numneral and return pop r20 ;restore r21:r20 pop r21 ret ; ; Decimal Output (unsigned 8-bit binary to decimal ASCII conversion) ; ; Displays in ASCII decimal format an unsigned 8-bit binary value ; ; Input: Binary value in r16, T flag set to inhibit leading zeros ; ; Returns: Nothing ; ; Registers Used: r17,r18,sreg ; decout: push r16 ;save r16 mov r18,r16 ;r16 -> r18 ldi r16,' ' ;output space rcall chrout ldi r16,'0'-1 ; ASCII 0 less 1 -> r16 dloop100: inc r16 ;next ACSCII numeral subi r18,100 ;subtract 100 brcc dloop100 ;if r18 > 0 then do again addi r18,100 ;otherwise, add back 100 rcall inhzero ;output ASCII numneral ; ldi r16,'0'-1 ; ASCII 0 less 1 -> r16 dloop10: inc r16 ;next ACSCII numeral subi r18,10 ;subtract 10 brcc dloop10 ;if r18 > 0 then do again addi r18,10 ;otherwise, add back 10 rcall inhzero ;output ASCII numneral ldi r16,'0'-1 ; ASCII 0 less 1 -> r16 dloop1: inc r16 ;next ACSCII numeral subi r18,1 ;subtract 1 brcc dloop1 ;if r18 > 0 then do again addi r18,1 ;otherwise, add back 1 rcall chrout ;output ASCII numneral and return pop r16 ;restore r16 ret ; inhzero: brtc chrout ;if T flag cleared, output the ASCII numeral cpi r16,'0' ;if ASCII numeral is zero and T set, return without outputting ASCII numeral (inhibit lead zero) brne inhzero_cont ret ; ; inhzero_cont: clt rjmp chrout ; ; Carriage Return & Linefeed ; ; Displays carriage return then linefeed ; ; Parameters: None ; ; Returns: Nothing ; ; Registers Used: r16,r17,sreg ; crlf: ldi r16, 13 ;display carriage return rcall chrout ldi r16,10 ;display linefeed rjmp chrout ; ; Character Input ; ; Input: None ; ; Output: Character from keyboard in r16 ; ; Registers Used: r16,r17,sreg ; chrin: lds r17, ucsr0a ;get USART receive status byte sbrs r17, rxc0 ;skip next instruction if rxc0 bit is one (character available) rjmp chrin ;loop and wait (instruction skipped if character available) lds r16, udr0 ;get character into r16 ret ; ; Character Output ; ; Input: Character to be output in r16 ; ; Output: To monitor ; ; Registers Used: r16,r17,sreg ; chrout: lds r17, ucsr0a ;get USART transmit status byte sbrs r17,udre0 ;skip next instruction if udre0 bit is one (not busy outputting character) rjmp chrout ;loop and wait (instruction skipped if not busy outputting character) sts udr0, r16 ;output character in r16 ret ; ; Message Output ; ; Displays message in program memory pointed to by z register. Sentinel value is numeric zero ; ; Parameters: z register address at start of message ; ; Returns: Nothing ; ; Registers Used: r16,r17, z (r31:r30),sreg ; msgout: lpm r16,z+ ;load character into r16 and post increment z or r16,r16 ;sentinel character reached? breq msgout_done ;if so, branch to halt call chrout rjmp msgout ;do again ; msgout_done: ret ;jump to endless loop ; ; MATH Subroutines (16 bit) ; ; Operators supported ; ; - negation: call twoComp16 with operand in r21:21; result in r21:r20 ; + addition: call add16 with operands r21:21 + r19:r19; result in r21:r20 ; - subtraction: call sub16 with operands r21:21 - r19:r19; result in r21:r20 ; * multiplication: call mul16 with operands in r21:21 * r19:r19; result in r21:r20 ; / division: call div16 with operands in r21:21 * r19:r19; result in r21:r20 ; ; Negation ; ; Parameters: r21:r20 ; ; Returns: r21:r20 ; ; Registers Used: r20,r21,r22,sreg ; twosComp16: ; ldi r22, 0xff eor r20, r22 eor r21, r22 subi r20, low(-1) sbci r21, high(-1) ret ; ; Addition (21:r20 + r19:r18 -> r21:r20) ; ; Parameters: r21:r20, r19:r18 ; ; Returns: r21:r20 ; ; Registers Used: r20,r21,r22,sreg ; add16: ; add r20, r18 adc r21, r19 ret ; ; Subtraction (21:r20 - r19:r18 -> r21:r20) ; ; Parameters: r21:r20, r19:r18 ; ; Returns: r21:r20 ; ; Registers Used: r20,r21,r22,sreg ; sub16: ; clc sub r20, r18 sbc r21, r19 ret ; ; Multiplication (21:r20 * r19:r18 -> r21:r20) ; ; Parameters: r21:r20, r19:r18 ; ; Returns: r21:r20 ; ; Registers Used: r20,r21,r22,sreg ; mul16: ; mul r20, r18 ; al * bl movw r17:r16,r1:r0 mul r21, r18 ; ah * bl add r17, r0 mul r19, r20 ; bh * al add r17, r0 mov r20, r16 mov r21, r17 ret ; ; Division (21:r20 / r19:r18 -> r21:r20) ; ; Parameters: r21:r20, r19:r18 ; ; Returns: r21:r20 ; ; Registers Used: r20,r21,r22,sreg ; div16: ; clr r16 ;clear remainder Low byte sub r17,r17 ;clear remainder High byte and carry ldi r22,17 ;init loop counter ; div16_1: ; rol r20 ;shift left dividend rol r21 dec r22 ;decrement counter brne div16_2 ;if done ret ; return ; div16_2: ; rol r16 ;shift dividend into remainder rol r17 sub r16,r18 ;remainder = remainder - divisor sbc r17,r19 ; brcc div16_3 ;if result negative add r16,r18 ; restore remainder adc r17,r19 clc ; clear carry to be shifted into result rjmp div16_1 ;else ; div16_3: ; sec ;set carry to be shifted into result rjmp div16_1