;**** A P P L I C A T I O N N O T E A V R 3 0 5-85 ************************ ;* ;* Title : Half Duplex Interrupt Driven Software UART ;* Version : 1.00 ;* Last update : 98.11.12 ;* Update Author : Stelios Koroneos ;* Target : 90s8515 ;* ;* Support email : avr@atmel.com ;* Author's e-mail : skoron@netor.gr ;* ;* Code Size : 57 Words ;* Low Register Usage : 0 ;* High Register Usage : 4 ;* Interrupt Usage : None ;* ;* This is a modification of the original application note 305. ;* By minor modifications it can work on all AVR's with RAM ;* Modification were made from the original AVR305 so it will ;* run on 90s8515 ;* By modyfing the Interrupt jump table it can be used on all ;* the AVR family except 90s1200 ;* ;* DESCRIPTION ;* This Application note contains a very code efficient software UART. ;* The example program receives one character and echoes it back. ;*************************************************************************** .include "8515def.inc" ;***** Pin definitions .equ RxD =0 ;Receive pin is PD0 .equ TxD =1 ;Transmit pin is PD1 ;***** Global register variables .def bitcnt =R16 ;bit counter .def temp =R17 ;temporary storage register .def Txbyte =R18 ;Data to be transmitted .def RXbyte =R19 ;Received data .cseg .org 0 ;*INTERRUPT JUMP TABLE ;*Modify for other AVR's rjmp reset reti ;IRQ0 handle reti ;IRQ1 handle reti ;Timer1 capture handle reti ;Timer1 compA reti ;Timer1 compB reti ;Timer1 overflow reti ;Timer0 overflow reti ;SPI reti ;UART RX complete reti ;UART UDR Empty reti ;UART TX complete reti ;Analog comp reset: ;We need to init the stack pointer for all parts except 90s1200 ;Without SP we can not jump or call a subroutine ;Manual 5-24 ldi TEMP,low(RamEnd) ; out SPL,TEMP ;init Stack Pointer Low ldi temp,high(RamEnd) ; out SPL+1,TEMP ;init Stack Pointer High ;********************************************************************* ;***** Program Execution Starts Here ;***** Test program sbi PORTD,TxD ;Init port pins sbi DDRD,TxD ldi Txbyte,12 ;Clear terminal rcall putchar forever: rcall getchar mov Txbyte,Rxbyte rcall putchar ;Echo received char rjmp forever ;*************************************************************************** ;* ;* "putchar" ;* ;* This subroutine transmits the byte stored in the "Txbyte" register ;* The number of stop bits used is set with the sb constant ;* ;* Number of words :14 including return ;* Number of cycles :Depens on bit rate ;* Low registers used :None ;* High registers used :2 (bitcnt,Txbyte) ;* Pointers used :None ;* ;*************************************************************************** .equ sb =1 ;Number of stop bits (1, 2, ...) putchar: ldi bitcnt,9+sb ;1+8+sb (sb is # of stop bits) com Txbyte ;Inverte everything sec ;Start bit putchar0: brcc putchar1 ;If carry set cbi PORTD,TxD ; send a '0' rjmp putchar2 ;else putchar1: sbi PORTD,TxD ; send a '1' nop putchar2: rcall UART_delay ;One bit delay rcall UART_delay lsr Txbyte ;Get next bit dec bitcnt ;If not all bit sent brne putchar0 ; send next ;else ret ; return ;*************************************************************************** ;* ;* "getchar" ;* ;* This subroutine receives one byte and returns it in the "Rxbyte" register ;* ;* Number of words :14 including return ;* Number of cycles :Depens on when data arrives ;* Low registers used :None ;* High registers used :2 (bitcnt,Rxbyte) ;* Pointers used :None ;* ;*************************************************************************** getchar: ldi bitcnt,9 ;8 data bit + 1 stop bit getchar1: sbic PIND,RxD ;Wait for start bit rjmp getchar1 rcall UART_delay ;0.5 bit delay getchar2: rcall UART_delay ;1 bit delay rcall UART_delay clc ;clear carry sbic PIND,RxD ;if RX pin high sec ; dec bitcnt ;If bit is stop bit breq getchar3 ; return ;else ror Rxbyte ; shift bit into Rxbyte rjmp getchar2 ; go get next getchar3: ret ;*************************************************************************** ;* ;* "UART_delay" ;* ;* This delay subroutine generates the required delay between the bits when ;* transmitting and receiving bytes. The total execution time is set by the ;* constant "b": ;* ;* 3·b + 7 cycles (including rcall and ret) ;* ;* Number of words :4 including return ;* Low registers used :None ;* High registers used :1 (temp) ;* Pointers used :None ;* ;*************************************************************************** ; Some b values: (See also table in Appnote documentation) ; ; 1 MHz crystal: ; 9600 bps - b=14 ; 19200 bps - b=5 ; 28800 bps - b=2 ; ; 2 MHz crystal: ; 19200 bps - b=14 ; 28800 bps - b=8 ; 57600 bps - b=2 ; 4 MHz crystal: ; 19200 bps - b=31 ; 28800 bps - b=19 ; 57600 bps - b=8 ; 115200 bps - b=2 .equ b =135 ;4800 bps @ 4 MHz crystal UART_delay: ldi temp,b UART_delay1: dec temp brne UART_delay1 ret