1 .nolist |
|
2 .include "m168def.inc" ; Same family as 328P |
|
3 .list |
|
4 |
|
5 .include "macros.inc" |
|
6 |
|
7 ;; Load a 16-bit *word* address into the given register a a byte address |
|
8 .macro loadp_16_i |
|
9 ldi @0, high(2 * @2) |
|
10 ldi @1, low(2 * @2) |
|
11 .endm |
|
12 |
|
13 .macro load_16_i |
|
14 ldi @0, high(@2) |
|
15 ldi @1, low(@2) |
|
16 .endm |
|
17 |
|
18 ;; Data |
|
19 .dseg |
|
20 buffer: .byte 0 |
|
21 |
|
22 ;; Interrupt Vector |
|
23 .cseg |
|
24 .org 0x0000 |
|
25 rjmp Main |
|
26 |
|
27 ;; Libraries |
|
28 .include "div.inc" ; Division routines |
|
29 |
|
30 ;; Serial |
|
31 .set SERIAL_BAUD = 103 ; 9.6k @ 16Mhz |
|
32 |
|
33 ;; Initialize the UART for |
|
34 Serial_Init: |
|
35 ; Set up control registers |
|
36 ; Single-speed |
|
37 poke [UCSR0A, r16, (0 << U2X0)] |
|
38 |
|
39 ; Async |
|
40 ; n parity |
|
41 ; 1 stop |
|
42 ; 8 bits |
|
43 poke [UCSR0C, r16, (0b00 << UMSEL00) | (0b00 << UPM00) | (0 << USBS0) | (0b11 << UCSZ00)] |
|
44 |
|
45 ; Baud rate |
|
46 poke [UBRR0L, r16:r17, SERIAL_BAUD] |
|
47 |
|
48 ; Enable RX |
|
49 ; Enable TX |
|
50 ; 8 bits |
|
51 poke [UCSR0B, r16, (1 << RXEN0) | (1 << TXEN0) | (0 << UCSZ02)] |
|
52 |
|
53 ; Done |
|
54 ret |
|
55 |
|
56 ;; Send a single byte on serial port |
|
57 ; Input byte in r16 |
|
58 Serial_Send: |
|
59 ; Wait for idle |
|
60 lds r0, UCSR0A |
|
61 sbrs r0, UDRE0 |
|
62 rjmp Serial_Send |
|
63 |
|
64 ; Copy byte to buffer |
|
65 sts UDR0, r16 |
|
66 |
|
67 ; Done |
|
68 ret |
|
69 |
|
70 ;; Read a single byte from serial port |
|
71 ; Output byte in r16 |
|
72 Serial_Recv: |
|
73 ; Wait for recv |
|
74 lds r0, UCSR0A |
|
75 sbrs r0, RXC0 |
|
76 rjmp Serial_Recv |
|
77 |
|
78 ; Copy byte from buffer |
|
79 lds r16, UDR0 |
|
80 |
|
81 ; Done |
|
82 ret |
|
83 |
|
84 ;; Write nul-terminated string from program mem to serial port |
|
85 ; Input string in Z |
|
86 Serial_pprint: |
|
87 ; Load byte to r16 |
|
88 lpm r16, Z+ |
|
89 |
|
90 ; Quit if nul |
|
91 tst r16 |
|
92 breq _serial_pprint_end |
|
93 |
|
94 ; Write it |
|
95 rcall Serial_Send |
|
96 |
|
97 ; Continue |
|
98 rjmp Serial_pprint |
|
99 |
|
100 _serial_pprint_end: |
|
101 ret |
|
102 |
|
103 ;; Write nul-terminated string from sram and \r\n to serial port |
|
104 ; Input string in Z |
|
105 Serial_sprintln: |
|
106 ; Load byte to r16 |
|
107 ld r16, Z+ |
|
108 |
|
109 ; Quit if nul |
|
110 tst r16 |
|
111 breq _serial_sprintln_end |
|
112 |
|
113 ; Write it |
|
114 rcall Serial_Send |
|
115 |
|
116 ; Continue |
|
117 rjmp Serial_sprintln |
|
118 |
|
119 _serial_sprintln_end: |
|
120 ; \r\n |
|
121 ldi r16, 13 |
|
122 rcall Serial_Send |
|
123 ldi r16, 10 |
|
124 rcall Serial_Send |
|
125 |
|
126 ; Done |
|
127 ret |
|
128 |
|
129 ;; Write char to serial port |
|
130 ; Input byte in r16 |
|
131 Serial_bprint: |
|
132 ; ASCII offset for '0' |
|
133 ldi r17, 48 |
|
134 mov r4, r17 |
|
135 |
|
136 ; Convert |
|
137 ldi r17, 100 |
|
138 call div8u |
|
139 add r16, r4 |
|
140 rcall Serial_Send |
|
141 mov r16, r15 |
|
142 |
|
143 ldi r17, 10 |
|
144 call div8u |
|
145 add r16, r4 |
|
146 rcall Serial_Send |
|
147 mov r16, r15 |
|
148 |
|
149 add r16, r4 |
|
150 rcall Serial_Send |
|
151 |
|
152 ret |
|
153 |
|
154 ;; Program |
|
155 message: .db "Hello World", 13, 10, 0 |
|
156 |
|
157 Main: |
|
158 ; Initialization |
|
159 ; Stack |
|
160 poke [SPL, r16:r17, RAMEND] |
|
161 |
|
162 ; Enable interrupts |
|
163 sei |
|
164 |
|
165 ; Init |
|
166 rcall Serial_Init |
|
167 |
|
168 ; Main program |
|
169 ldi ZH, high(message * 2) |
|
170 ldi ZL, low(message * 2) |
|
171 |
|
172 rcall Serial_pprint |
|
173 |
|
174 ; Echo out |
|
175 sbi DDRB, PORTB5 |
|
176 ldi r20, 0 |
|
177 ldi r21, 0 |
|
178 ldi r22, 0 |
|
179 |
|
180 ; pointer to memory buffer |
|
181 ldi XH, high(buffer) |
|
182 ldi XL, low(buffer) |
|
183 |
|
184 st X, r22 ; '\0' |
|
185 |
|
186 Main_Echo: |
|
187 ; blink LED |
|
188 out PORTB, r20 |
|
189 |
|
190 ; read |
|
191 rcall Serial_Recv |
|
192 push r16 |
|
193 |
|
194 ; display |
|
195 rcall Serial_bprint |
|
196 ldi r16, 32 |
|
197 rcall Serial_Send |
|
198 |
|
199 pop r16 |
|
200 |
|
201 ; test for control chars |
|
202 cpi r16, 127 ; DEL |
|
203 breq backspace |
|
204 |
|
205 cpi r16, 13 ; '\r' |
|
206 breq cr |
|
207 |
|
208 cpi r16, 10 ; '\n' |
|
209 breq Main_Echo ; ignore |
|
210 |
|
211 rjmp char ; buffer char |
|
212 |
|
213 ; Erase last char |
|
214 backspace: |
|
215 ; ignore if already at zero |
|
216 cpi XL, low(buffer) |
|
217 ldi r23, high(buffer) |
|
218 cpc XH, r23 |
|
219 breq echo |
|
220 |
|
221 ; use pre-decrement to store nul |
|
222 st -X, r22 ; '\0' |
|
223 |
|
224 rjmp echo |
|
225 |
|
226 ; Erase line |
|
227 cr: |
|
228 ; seek to start |
|
229 ldi XH, high(buffer) |
|
230 ldi XL, low(buffer) |
|
231 |
|
232 ; store nul |
|
233 st X, r22 ; '\0' |
|
234 |
|
235 rjmp echo |
|
236 |
|
237 char: |
|
238 ; buffer char |
|
239 st X+, r16 |
|
240 st X, r22 ; '\0' |
|
241 |
|
242 echo: |
|
243 ; running counter |
|
244 inc r21 |
|
245 mov r16, r21 |
|
246 rcall Serial_bprint |
|
247 |
|
248 ; ' ' |
|
249 ldi r16, 32 |
|
250 rcall Serial_Send |
|
251 |
|
252 ; length |
|
253 mov r16, XL |
|
254 rcall Serial_bprint |
|
255 |
|
256 ; ' ' |
|
257 ldi r16, 32 |
|
258 rcall Serial_Send |
|
259 |
|
260 ; output buffer |
|
261 ldi ZH, high(buffer) |
|
262 ldi ZL, low(buffer) |
|
263 rcall Serial_sprintln |
|
264 |
|
265 ; toggle |
|
266 com r20 |
|
267 |
|
268 ; continue |
|
269 rjmp Main_Echo |
|
270 |
|