terom@9: .nolist terom@9: .include "m168def.inc" ; Same family as 328P terom@9: .list terom@9: terom@18: .include "macros.inc" terom@9: terom@9: ;; Load a 16-bit *word* address into the given register a a byte address terom@9: .macro loadp_16_i terom@9: ldi @0, high(2 * @2) terom@9: ldi @1, low(2 * @2) terom@9: .endm terom@9: terom@9: .macro load_16_i terom@9: ldi @0, high(@2) terom@9: ldi @1, low(@2) terom@9: .endm terom@9: terom@14: ;; Data terom@14: .dseg terom@14: buffer: .byte 0 terom@14: terom@9: ;; Interrupt Vector terom@14: .cseg terom@13: .org 0x0000 terom@9: rjmp Main terom@9: terom@13: ;; Libraries terom@13: .include "div.inc" ; Division routines terom@13: terom@9: ;; Serial terom@9: .set SERIAL_BAUD = 103 ; 9.6k @ 16Mhz terom@9: terom@9: ;; Initialize the UART for terom@9: Serial_Init: terom@9: ; Set up control registers terom@9: ; Single-speed terom@9: poke [UCSR0A, r16, (0 << U2X0)] terom@9: terom@9: ; Async terom@9: ; n parity terom@9: ; 1 stop terom@9: ; 8 bits terom@9: poke [UCSR0C, r16, (0b00 << UMSEL00) | (0b00 << UPM00) | (0 << USBS0) | (0b11 << UCSZ00)] terom@9: terom@9: ; Baud rate terom@9: poke [UBRR0L, r16:r17, SERIAL_BAUD] terom@9: terom@9: ; Enable RX terom@9: ; Enable TX terom@9: ; 8 bits terom@11: poke [UCSR0B, r16, (1 << RXEN0) | (1 << TXEN0) | (0 << UCSZ02)] terom@9: terom@9: ; Done terom@9: ret terom@9: terom@9: ;; Send a single byte on serial port terom@9: ; Input byte in r16 terom@9: Serial_Send: terom@9: ; Wait for idle terom@9: lds r0, UCSR0A terom@9: sbrs r0, UDRE0 terom@9: rjmp Serial_Send terom@9: terom@9: ; Copy byte to buffer terom@9: sts UDR0, r16 terom@9: terom@9: ; Done terom@9: ret terom@9: terom@11: ;; Read a single byte from serial port terom@11: ; Output byte in r16 terom@11: Serial_Recv: terom@11: ; Wait for recv terom@11: lds r0, UCSR0A terom@11: sbrs r0, RXC0 terom@11: rjmp Serial_Recv terom@11: terom@11: ; Copy byte from buffer terom@11: lds r16, UDR0 terom@11: terom@11: ; Done terom@11: ret terom@11: terom@14: ;; Write nul-terminated string from program mem to serial port terom@9: ; Input string in Z terom@14: Serial_pprint: terom@9: ; Load byte to r16 terom@9: lpm r16, Z+ terom@9: terom@9: ; Quit if nul terom@9: tst r16 terom@14: breq _serial_pprint_end terom@9: terom@9: ; Write it terom@9: rcall Serial_Send terom@9: terom@9: ; Continue terom@14: rjmp Serial_pprint terom@9: terom@14: _serial_pprint_end: terom@14: ret terom@14: terom@14: ;; Write nul-terminated string from sram and \r\n to serial port terom@14: ; Input string in Z terom@14: Serial_sprintln: terom@14: ; Load byte to r16 terom@14: ld r16, Z+ terom@14: terom@14: ; Quit if nul terom@14: tst r16 terom@14: breq _serial_sprintln_end terom@14: terom@14: ; Write it terom@14: rcall Serial_Send terom@14: terom@14: ; Continue terom@14: rjmp Serial_sprintln terom@14: terom@14: _serial_sprintln_end: terom@14: ; \r\n terom@14: ldi r16, 13 terom@14: rcall Serial_Send terom@14: ldi r16, 10 terom@14: rcall Serial_Send terom@14: terom@14: ; Done terom@9: ret terom@9: terom@13: ;; Write char to serial port terom@13: ; Input byte in r16 terom@14: Serial_bprint: terom@13: ; ASCII offset for '0' terom@13: ldi r17, 48 terom@13: mov r4, r17 terom@13: terom@13: ; Convert terom@13: ldi r17, 100 terom@13: call div8u terom@13: add r16, r4 terom@13: rcall Serial_Send terom@13: mov r16, r15 terom@13: terom@13: ldi r17, 10 terom@13: call div8u terom@13: add r16, r4 terom@13: rcall Serial_Send terom@13: mov r16, r15 terom@13: terom@13: add r16, r4 terom@13: rcall Serial_Send terom@13: terom@13: ret terom@13: terom@9: ;; Program terom@9: message: .db "Hello World", 13, 10, 0 terom@9: terom@9: Main: terom@9: ; Initialization terom@9: ; Stack terom@9: poke [SPL, r16:r17, RAMEND] terom@9: terom@9: ; Enable interrupts terom@9: sei terom@9: terom@9: ; Init terom@9: rcall Serial_Init terom@9: terom@9: ; Main program terom@9: ldi ZH, high(message * 2) terom@9: ldi ZL, low(message * 2) terom@9: terom@14: rcall Serial_pprint terom@11: terom@11: ; Echo out terom@11: sbi DDRB, PORTB5 terom@11: ldi r20, 0 terom@13: ldi r21, 0 terom@14: ldi r22, 0 terom@14: terom@14: ; pointer to memory buffer terom@14: ldi XH, high(buffer) terom@14: ldi XL, low(buffer) terom@14: terom@14: st X, r22 ; '\0' terom@11: terom@11: Main_Echo: terom@13: ; blink LED terom@11: out PORTB, r20 terom@13: terom@13: ; read terom@11: rcall Serial_Recv terom@13: push r16 terom@13: terom@14: ; display terom@14: rcall Serial_bprint terom@14: ldi r16, 32 terom@14: rcall Serial_Send terom@14: terom@14: pop r16 terom@14: terom@14: ; test for control chars terom@14: cpi r16, 127 ; DEL terom@14: breq backspace terom@14: terom@14: cpi r16, 13 ; '\r' terom@14: breq cr terom@14: terom@14: cpi r16, 10 ; '\n' terom@14: breq Main_Echo ; ignore terom@14: terom@14: rjmp char ; buffer char terom@14: terom@14: ; Erase last char terom@14: backspace: terom@14: ; ignore if already at zero terom@14: cpi XL, low(buffer) terom@14: ldi r23, high(buffer) terom@14: cpc XH, r23 terom@14: breq echo terom@14: terom@14: ; use pre-decrement to store nul terom@14: st -X, r22 ; '\0' terom@14: terom@14: rjmp echo terom@14: terom@14: ; Erase line terom@14: cr: terom@14: ; seek to start terom@14: ldi XH, high(buffer) terom@14: ldi XL, low(buffer) terom@14: terom@14: ; store nul terom@14: st X, r22 ; '\0' terom@14: terom@14: rjmp echo terom@14: terom@14: char: terom@14: ; buffer char terom@14: st X+, r16 terom@14: st X, r22 ; '\0' terom@14: terom@14: echo: terom@13: ; running counter terom@13: inc r21 terom@13: mov r16, r21 terom@14: rcall Serial_bprint terom@13: terom@13: ; ' ' terom@13: ldi r16, 32 terom@11: rcall Serial_Send terom@14: terom@14: ; length terom@14: mov r16, XL terom@14: rcall Serial_bprint terom@14: terom@14: ; ' ' terom@14: ldi r16, 32 terom@13: rcall Serial_Send terom@13: terom@14: ; output buffer terom@14: ldi ZH, high(buffer) terom@14: ldi ZL, low(buffer) terom@14: rcall Serial_sprintln terom@13: terom@13: ; toggle terom@11: com r20 terom@13: terom@13: ; continue terom@11: rjmp Main_Echo terom@11: