用AVR单片机模拟的串口程序
在一些应用中,经常要用到双串口,但是一般单片机只提供一个串口,其实完全可以用普通I/O口模拟一个串口。以下的程序是我编写的模拟串口程序,程序中使用了单片机的定时器0,和INT0中断。数据的发送和接收由中断程序自动进行。程序已经过AVR仿真器仿真和实际烧片使用,证明可靠。有一点需要说明的是,此模拟的串口为半双工方式。 主程序中,单片机将标准串口设置为115200bps,将模拟串口设置为19200bps。单片机将标准串口收到的数据从模拟串口发送出去,将模拟串口接收到的数据从标准串口发送回来。
;************************************************************************************************** ;* title: half duplex uart simulaton program ;* version: 1.0 ;* program time: 2001/11/05 ;* target: AT90S8515 ;* design: zsmbj@beijing ;************************************************************************************************** .include "c:\program files\atmel\avr studio\appnotes\8515def.inc" ;BPS=19200 ;F=11059200
.equ N=72
.equ txd0 =3 ;uart0 txd .equ rxd0 =2 ;uart0 rxd ;**************************************************************** .equ stack=0x0ff ;**************************************************************** ;bit define .equ rdr=0 .equ fe0=1 .equ td=6 .equ busy=7 ;register define .def temp=r16 .def sbuf0=r17 .def status=r18 .def bit_cnt=r19 ;************************************************************************************************** .org 0x00 rjmp reset .org 0x01 rjmp int00 .org 0x07 rjmp timer0_int ;********************************************************** .cseg ;********************************************************** ;****initial ;********************************************************** .org 0x0010 ;reset at90s8515 reset: ldi temp,0b00001000 out ddrb,temp
ldi temp,high(stack) ;stack out sph,temp ldi temp,low(stack) out spl,temp
ldi temp,5 ;baud 115200bps at 11.0592M fosc out ubrr,temp ldi temp,0b00011000 ;enable rx and tx out ucr,temp ;timer0 set ldi temp,0x02 ;ck/8 0.72338us out tccr0,temp
ldi temp,0x0a ;disable outside sram,int0 fall edge make a interrupt out mcucr,temp ldi temp,0x40 out gimsk,temp ;enable int0 and int1 interrupt
ldi temp,0 mov status,temp sbi portb,txd0 ;txd0 bit=1
sei ;globle interrupt enable rjmp main ;****************************************** timer0_int: push temp in temp,sreg push temp
ldi temp,(256-N) out TCNT0,temp inc bit_cnt
sbrs status,td rjmp timer0_receive ;>>>>>>>>>>>>>>>>>>>>>>>>>> ;send data 8 data bit and 1 stop bit timer0_send: sbrc bit_cnt,3 ;if bit_cnt=8 then stop bit rjmp timer0_send_stop timer0_send_data: sbrc sbuf0,0 ;txd=0 sbi portb,txd0 sbrs sbuf0,0 ;txd=1 cbi portb,txd0 lsr sbuf0 rjmp timer0_end timer0_send_stop: sbi portb,txd0 ;stop bit=1 sbrc bit_cnt,0 rjmp timer0_complete ;if bit_cnt=9 then complete ;;;;;;;;;;;;;;;;;;; in temp,gifr sbr temp,(1<<intf0) out gifr,temp ;clr int0 flag
in temp,gimsk sbr temp,(1<<int0) out gimsk,temp ;enable gimsk/int0
rjmp timer0_end ;>>>>>>>>>>>>>>>>>>>>>>>>>> ;receive start 1bit data 8 bit stop 1bit timer0_receive: cpi bit_cnt,1 ;if bit_cnt=1 then start bit breq timer0_receive_start cpi bit_cnt,10 ;if bit_cnt=10 then stop bit breq timer0_receive_stop
rjmp timer0_receive_data timer0_receive_start: sbis pind,rxd0 rjmp timer0_end
cbr status,(1<<rdr) ;start bit wrong then rdr=0 exit rjmp timer0_complete timer0_receive_data: sec sbis pind,rxd0 ;get rxd0 data clc ror sbuf0 rjmp timer0_end timer0_receive_stop: cbr status,(1<<fe0) ;if stop bit=0 then fe0=0 sbis pind,rxd0 rjmp timer0_complete sbr status,(1<<fe0) sbr status,(1<<rdr) ;rdr=1 ;>>>>>>>>>>>>>>>>>>>>>>>>>> timer0_complete: in temp,timsk cbr temp,(1<<toie0) out timsk,temp ;disable timsk/toie0 ;;;;;;;;;;;;;;;;;;; in temp,gifr sbr temp,(1<<intf0) out gifr,temp ;clr int0 flag
in temp,gimsk sbr temp,(1<<int0) out gimsk,temp ;enable gimsk/int0
cbr status,(1<<busy)|(1<<td) ;busy=0,td=0 timer0_end: pop temp out sreg,temp pop temp
reti ;****************************************** int00: push temp in temp,sreg push temp
ldi temp,(256-N/2) ;skip 0.5bit out TCNT0,temp
ldi status,(1<<busy) ;busy=1,rdr=0,td=0,fe0=0 clr bit_cnt
in temp,tifr sbr temp,(1<<tov0) out tifr,temp ;clr tifr/tov0
in temp,timsk sbr temp,(1<<toie0) out timsk,temp ;enable timsk/toie0
in temp,gimsk cbr temp,(1<<int0) out gimsk,temp ;disable gimsk/int0
pop temp out sreg,temp pop temp reti ;**********************************************************rxd0_data: txd0_data: ldi status,(1<<busy)|(1<<td) ;busy=1,td=1,rdr=0
push temp in temp,gimsk cbr temp,(1<<int0) out gimsk,temp ;disable gimsk/int0 pop temp
ser bit_cnt ;bit_cnt=0xff mov sbuf0,temp ;send data
ldi temp,(256-N) out TCNT0,temp ;wait 1 bit timer0 interrupt
in temp,tifr sbr temp,(1<<tov0) out tifr,temp ;clr tifr/tov0
in temp,timsk sbr temp,(1<<toie0) out timsk,temp ;enable timsk/toie0
cbi portb,txd0 ;uart start
ret ;****************************************** rxd0_data: sbrs status,fe0 ;if fe0=0 then exit rjmp rxd0_data_end cbr status,(1<<rdr) ;rdr=0 mov temp,sbuf0 rxd0_data_end: ret ;******************************************
;uart received a byts from uart and then return it from uart0: ;uart received a byts from uart0 and then return it from uart : main: sbic usr,rxc rjmp send_115200
sbrs status,rdr rjmp uart_end send_19200: rcall rxd0_data ;get uart data from 19200bps uart0
wait2: sbis usr,udrie rjmp wait2 out udr,temp ;send data to 115200bps uart rjmp uart_end
send_115200: in temp,udr ;get uart data from 115200bps uart sbic usr,fe rjmp uart_end ;if fe err then end
wait3: sbrc status,td ;wait send flag rjmp wait3 rcall txd0_data ;send data to 19200bps uart0 uart_end: rjmp main ;********************************************************** .exit ;**********************************************************
|