; ; Whippleway Experiment 10 for the ATmega328 ; ; Created: 3/28/2017 8:06:37 PM ; Author : Dick Whipple ; ; Baud Rate ; .equ ubrrval = 103 ;See section 24.11 Table 24-7 fosc = 16 Mhz U2Xn = 0 column ; .macro addi subi @0, -@1 ;subtract the negative of an immediate value .endmacro ; ; Load Register Immediate Word Macro ; .macro ldiw ldi @0, high(@2) ldi @1, low(@2) ;subtract the negative of an immediate value .endmacro ; start: ; ; Enable Rcx and Trx ; ldi r16, 0b00011000 ;0buuuvwxyz uuu = 000 disable all USART interrupts ; v = 1 enable Rx (receive) (Search "Bit 4 – RXEN0") ; w = 1 enable Tx (transmit) Search "Bit 3 - TXEN0") ; x = 0 selects number of character bits less than nine. Associated with UCSZ00 and UCSZ01 in I/O register UCSR0C (Search "Bit 2 - UCSZ02") ; y = 0 ninth received bit if x = 1. (Search "Bit 1 - RXB80") ; z = 0 ninth transmit bit if x = 1 (Search "Bit 1 - TXB80")  sts ucsr0b,r16 ; ; Baud Rate 9600 ; ldi r17,HIGH(ubrrval) ;UBRR High ldi r16,LOW(ubrrval) ;UBBR Low sts ubrr0h,r17 sts ubrr0l,r16 ; ; Frame Format: 8 data, 2 stop ; ldi r16, 0b000001110 ;0buuvvwxxy uu = 00 select asynchronous USART mode (Ses Table 24-8) ; vv = 00 disable parity (See Table 24-9) ; w = 1 select 2 stop bits (Search "Bit 3 - USBS0") ; xx = 11 selects 8 data bit. Associated with UCSZ02 in I/O register UCSR0B (Search "Bit 2 - UCSZ01") ; y = 0 for asynchronous mode. (Search "Bit 0 - UCPOL0") sts ucsr0c,r16 ; ; Target Jump - Change target jump to start of program to test ; jmp exmp5_1a ;Target Jump ; ; Experiment 5 Example 1a Terminal Echo Code using mask and ANDI ; exmp5_1a: ; chrina: lds r17, ucsr0a ;get USART receive status byte andi r17, 0b10000000 ;mask bit 7 (RXC0=7) of UCSR0A (USART receive complete), a one indicating character available (Search "Bit 7 – RXC0") breq chrina ;if zero, loop and wait lds r16, udr0 ;otherwise, get character into r16 ; chrouta: lds r17, ucsr0a ;get USART transmit status byte andi r17, 0b00100000 ;mask bit 5 (UDRE0=5) of UCSR0A (USART transmit buffer empty), a one indicating transmit buffer empty (Search "Bit 5 – UDRE0") breq chrouta ;loop and wait sts udr0, r16 ;otherwise, output character in r16 ; rjmp chrina ; ; Experiment 5 Example 1b Terminal Echo Code using ATmega328 bit-wise testing ; exmp5_1b: ; chrinb: lds r17, ucsr0a ;get USART receive status byte sbrs r17, rxc0 ;skip next instruction if bit 7 (RXC0=7) of UCSR0A (USART receive complete) is one indicating character available (Search "Bit 7 – RXC0") rjmp chrinb ;otherwise, loop and wait lds r16, udr0 ;get character into r16 ; chroutb: lds r17, ucsr0a ;get USART transmit status byte sbrs r17,udre0 ;skip next instruction if bit 5 (UDRE0=5) of UCSR0A (USART transmit buffer empty) is one indicating transmit buffer empty (Search "Bit 5 – UDRE0") rjmp chroutb ;otherwise, loop and wait sts udr0, r16 ;output character in r16 ; rjmp chrinb ;repeat ; ; Experiment 5 Example 2a Sum Integers Using DO-WHILE (with error trap) ; ; Sum integers from 0 to sum limit and display result ; exmp5_2a: call crlf ;display new line ldi r18,5 ;set sum limit (test value = 5 Result = 15) clr r16 ;clear sum clr r2 ;clear counter exmp5_2a_again: cp r18,r2 ;if counter equals sum limit, then branch to done breq exmp5_2a_done inc r2 ;increment counter add r16,r2 ;add counter to sum brcs exmp5_2a_error ;if overflow, trap error rjmp exmp5_2a_again ;otherwise, do again ; exmp5_2a_done: set ;inhibit leading zeros call decout ;display decimal value jmp halt ;jump to endless loop ; ; Error Trap ; exmp5_2a_error: ldi r16,'E' ;display letter E for error call chrout jmp halt ;branch to endless loop ; ; Experiment 5 Example 2b Sum Integers Using DO-WHILE (with error trap) ; ; Elimination of consecutive branches ; ; Sum integers from 0 to sum limit and display result ; ; Also, test 22 then 23. The latter should produce an error. ; exmp5_2b: call crlf ;display new line ldi r18,5 ;set sum limit clr r16 ;clear sum clr r2 ;clear counter exmp5_2b_again: cp r18,r2 ;does counter equals sum limit? breq exmp5_2b_done ;if so, branch to done inc r2 ;increment counter add r16,r2 ;add counter to sum brcc exmp5_2b_again ;if no overflow, do again ; ; Error Trap ; ldi r16,'E' ;display letter E for error call chrout jmp halt ;branch to endless loop ; exmp5_2b_done: set ;inhibit leading zeros call decout ;display decimal value jmp halt ;jump to endless loop ; ; Experiment 5 Example 2c Sum Integers Using DO-WHILE (with error trap) ; ; Elimination of consecutive branches AND separate counter ; ; Sum integers from 0 to sum limit and display result ; ; Test 22 then 23. The latter should produce an error. ; exmp5_2c: call crlf ;display new line ldi r18,5 ;set sum limit/counter inc r18 ;pre-increment sum limit/counter clr r16 ;clear sum exmp5_2c_again: dec r18 ;does combined sum limit/counter equal zero? breq exmp5_2c_done ;if so, branch to done add r16,r18 ;add sum limit/counter to sum brcc exmp5_2c_again ;if no overflow, do again ; ; Error Trap ; ldi r16,'E' ;display letter E for error call chrout jmp halt ;branch to endless loop ; exmp5_2c_done: set ;inhibit leading zeros call decout ;display decimal value jmp halt ;jump to endless loop ; ; Endless Loop ; halt: rjmp halt ; ; Experiment 5 Example 3a Chasing Bit Display - Right to Left ; ; Displayed one bit moves from right to left ; exmp5_3a: ldi r20,0b00000001 ;load r20 with 1 in right most bit (bit 0) exmp5_3a_again: call crlf ;display new line mov r16,r20 ;display r20 call binout call delay_2s ;wait 2 seconds clc ;clear carry rol r20 ;rotate r20 left through carry brcc exmp5_3a_again ;until bit reaches carry, do again rjmp exmp5_3a ;start over ; ; Experiment 5 Example 3b Chasing Bit Display - Left to Right ; ; Displayed one bit moves from left to right ; exmp5_3b: ldi r20,0b10000000 ;load r20 with 1 in left most bit (bit 7) exmp5_3b_again: call crlf ;display new line call delay_2s ;wait 2 seconds mov r16,r20 ;display r20 call binout clc ;clear carry ror r20 ;rotate r20 right through carry brcc exmp5_3b_again ;until bit reaches carry, do again rjmp exmp5_3b ;start over ; ; Experiment 6 Example 1a Terminal Echo Code using mask, ANDI, and temporary storage in SRAM ; exmp6_1: ; ; Note: Since this is the first data segment (.dseg) byte reserved, it will get the address 0x0100. The next ; reserved byte will get the address 0x0101 and so on. The assembler keeps up with data bytes ; are reserved. ; exmp6_1_chrina: lds r17, ucsr0a ;get USART receive status byte andi r17, (1<= 'z'+1 brcc exmp6_6_cont0 ;if so, branch to continue 0 andi r16,0b11011111 ;make upper case exmp6_6_cont0: st x+,r16 ;store in SRAM rjmp exmp6_6_loop0 ;do again exmp6_6_cont1: st x,r16 ;store sentinel value call crlf ;display new line ; ; output original message ; ldiw zh,zl,(exmp6_6_msg<<1) ;point z register to start of message call msgout ;display original message ; ; output translated message ; call crlf ;display new line ldiw zh,zl,(exmp6_6_ucmsg<<1) ;point z register to converted messagr in SRAM exmp6_6_loop1: ld r16,z+ ;load character into r16 and post increment z or r16,r16 ;was sentinel character reached? breq exmp6_6_done ;if so, branch to halt call chrout ;display character rjmp exmp6_6_loop1 ;do again ; exmp6_6_done: jmp halt ;jump to endless loop ; exmp6_6_msg: .db "Upper case test program: AB...Z = ab...z",'a'-1,'z'+1,0,0 ; .dseg exmp6_6_ucmsg: .byte 50 ; .cseg ; ; Experiment 6 Example 7 Demonstrate Table Look-Up Using Indirect Addressing - Part 1 ; ; Display a numeric value from a table based on keyboard entry of numbers 0 to 9. ; ; Note: Table length limited to 10 items. ; exmp6_7: ldiw zh,zl,(exmp6_7_tbl<<1) ;point z register to first entry in table call crlf ;display new line call chrin ;get character into r16 cpi r16,'0' ;is character less than ASCII zero? brcs exmp6_7_error ;if so, branch to error cpi r16,'9'+1 ;greater than ASCII nine plus 1 brcc exmp6_7_error ;if so, branch to error andi r16,0x0f ;mask off upper nibble to get table offset add zl,r16 ;calculate low byte of table plus offset clr r16 ;clear r16 adc zh,r16 ;calculate high byte of table entry address lpm r16,z ;load character into r16 set ;inhibit leading zeros call decout rjmp exmp6_7 ;do again ; ; ; Error Trap ; exmp6_7_error: ldi r16,'E' ;display letter E for error call chrout jmp exmp6_7 ;do again ; exmp6_7_tbl: .db 0,12,23,35,44,55,68,77,86,102 ; ; Experiment 6 Example 8 Demonstrate Table Look-Up Using Indirect Addressing - Part 2 ; ; Display the word representing keyboard entry of numbers 0 to 9. ; ; Note: Table length limited to 10 items. ; exmp6_8: ldiw zh,zl,(exmp6_8_tbl_p<<1) ;point z register to first entry in table call crlf ;display new line call chrin ;get character into r16 cpi r16,'0' ;is character less than ASCII zero? brcs exmp6_8_error ;if so, branch to error cpi r16,'9'+1 ;is character greater than ASCII nine plus 1 brcc exmp6_8_error ;if so, branch to error andi r16,0x0f ;mask off upper nibble to get table offset lsl r16 ;quadruple table offset (recall that addresses are times 2 and double byte) lsl r16 add zl,r16 ;calculate low byte of table entry address clr r16 ;clear r16 adc zh,r16 ;calculate high byte of table entry address lpm r16,z+ ;get address of first character in message lpm zh,z mov zl,r16 lpm r16,z ;load first character of message into r16 set ;inhibit leading zeros call msgout ;display message rjmp exmp6_8 ;do again ; ; ; Error Trap ; exmp6_8_error: ldi r16,'E' ;display letter E for error call chrout jmp exmp6_8 ;do again ; exmp6_8_tbl_p: .dd (word_0<<1),(word_1<<1),(word_2<<1),(word_3<<1),(word_4<<1),(word_5<<1),(word_6<<1),(word_7<<1),(word_8<<1),(word_9<<1) ; word_0: .db "Zero",0,0 word_1: .db "One",0 word_2: .db "Two",0 word_3: .db "Three",0 word_4: .db "Four",0,0 word_5: .db "Five",0,0 word_6: .db "Six",0 word_7: .db "Seven",0 word_8: .db "Eight",0 word_9: .db "Nine",0,0 ; ; ****** Utility Subroutines ****** ; ; 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 ; ; ; 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 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: r16,r17,r18,sreg ; decout: 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 rjmp chrout ;output ASCII numneral and return ; 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 ; ; Delay 10 Milliseconds ; ; Parameters: None ; ; Returns: Nothing ; ; Registers Used: x,y,SREG ; delay_10ms: ldiw xh,xl,10 ;delay 10 milliseconds rjmp delay_ms ; ; Delay One Second ; ; Parameters: None ; ; Returns: Nothing ; ; Registers Used: x,y,SREG ; delay_1s: ldiw xh,xl,1000 ;delay 1 second rjmp delay_ms ; ; 2 Second Delay ; ; Parameters: None ; ; Returns: Nothing ; ; Registers Used: x,y,SREG ; delay_2s: ldiw xh,xl,2000 ;delay 2000 milliseconds rjmp delay_ms ; ; 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