用于ATmega128的软件UART范例程序
一般教科书上提供的UART收发的程序往往是一段采用轮循(Polling)方式完成收发的简单代码。但对于高速的AVR来讲,采用这种方式大大降低了 MUC的效率。在使用AVR时,应根据芯片本身的特点(片内大容量数据存储器RAM,更适合采用高级语言编写系统程序),编写高效可靠的UART收发接口(低层)程序。下面是一个典型的ATmega128的软件USART的接口程序。
#include
#define RXB8 1
#define TXB8 0
#define UPE 2
#define OVR 3
#define FE 4
#define UDRE 5
#define RXC 7
#define FRAMING_ERROR (1
#define PARITY_ERROR (1
#define DATA_OVERRUN (1
#define DATA_REGISTER_EMPTY (1
#define RX_COMPLEte (1
// USART0 Receiver buffer
#define RX_BUFFER_SIZE0 8
char rx_buffer0[RX_BUFFER_SIZE0];
unsigned char rx_wr_index0,rx_rd_index0,rx_counter0;
// This flag is set ON USART0 Receiver buffer overflow
bit rx_buffer_overflow0;
// USART0 Receiver interrupt service routine
#pragma savereg-
interrupt [USART0_RXC] void uart0_rx_isr(void)
{
char status,data;
#asm
push r26
push r27
push r30
push r31
in r26,sreg
push r26
#endasm
status=UCSR0A;
data=UDR0;
if ((status (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
{
rx_buffer0[rx_wr_index0]=data;
if (++rx_wr_index0 == RX_BUFFER_SIZE0) rx_wr_index0=0;
if (++rx_counter0 == RX_BUFFER_SIZE0)
{
rx_counter0=0;
rx_buffer_overflow0=1;
};
};
#asm
pop r26
out sreg,r26
pop r31
pop r30
pop r27
pop r26
#endasm
}
#pragma savereg+
#ifndef _DEBUG_TERMINAL_IO_
// Get a character from the USART0 Receiver buffer
#define _ALTERNATE_GETCHAR_
#pragma used+
char getchar(void)
{
char data;
while (rx_counter0==0);
data=rx_buffer0[rx_rd_index0];
if (++rx_rd_index0 == RX_BUFFER_SIZE0) rx_rd_index0=0;
#asm(cli)
--rx_counter0;
#asm(sei)
return data;
}
#pragma used-
#endif
// USART0 Transmitter buffer
#define TX_BUFFER_SIZE0 8
char tx_buffer0[TX_BUFFER_SIZE0];
unsigned char tx_wr_index0,tx_rd_index0,tx_counter0;
// USART0 Transmitter interrupt service routine
#pragma savereg-
interrupt [USART0_TXC] void uart0_tx_isr(void)
{
#asm
push r26
push r27
push r30
push r31
in r26,sreg
push r26
#edasm
if (tx_counter0)
{
--tx_counter0;
UDR0=tx_buffer0[tx_rd_index0];
if (++tx_rd_index0 == TX_BUFFER_SIZE0) tx_rd_index0=0;
};
#asm
pop r26
out sreg,r26
pop r31
pop r30
pop r27
pop r26
#endasm
}
#pragma savereg+
#ifndef _DEBUG_TERMINAL_IO_
// Write a character to the USART0 Transmitter buffer
#define _ALTERNATE_PUTCHAR_
#pragma used+
void putchar(char c)
{
while (tx_counter0 == TX_BUFFER_SIZE0);
#asm(cli)
if (tx_counter0 || ((UCSR0A DATA_REGISTER_EMPTY)==0))
{
tx_buffer0[tx_wr_index0]=c;
if (++tx_wr_index0 == TX_BUFFER_SIZE0) tx_wr_index0=0;
++tx_counter0;
}
else
UDR0=c;
#asm(sei)
}
#pragma used-
#endif
// Standard Input/Output functions
#include
// Declare your global variables here
void main(void)
{
// USART0 initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART0 Receiver: On
// USART0 Transmitter: On
// USART0 Mode: Asynchronous
// USART0 Baud rate: 9600
UCSR0A=0x00;
UCSR0B=0xD8;
UCSR0C=0x06;
UBRR0H=0x00;
UBRR0L=0x67;
// Global enable interrupts
#asm(sei)
while (1)
{
// Place your code here
};
}
这段由CVAVR程序生成器产生的UART接口代码是一个非常好的、高效可靠,并且值得认真学习和体会的。其特点如下:
l. 它采用两个8字节的接收和发送缓冲器来提高MCU的效率,如当主程序调用Putchar()发送数据时,如果UART口不空闲,就将数据放入发送缓冲器中,MCU不必等待,可以继续执行其它的工作。而UART的硬件发送完一个数据后,产生中断,由中断服务程序负责将发送缓冲器中数据依次送出。
2.数据缓冲器结构是一个线性的循环队列,由读、写和队列计数器3个指针控制,用于判断队列是否空、溢出,以及当前数据在队列中的位置。
3. 用编译控制命令#pragma savereg-和#pragma savereg+,使得由CVAVR在生成的中断服务程序中不进行中断保护(CVAVR生成中断保护会将比较多的寄存器压入堆栈中),而在中断中嵌入汇编,只将5个在本中断中必须要保护的寄存器压栈。这样提高了UART中断处理的速度
范例 程序 UART 软件 ATmega128 用于 相关文章:
- STC-ISP烧写软件-范例功能(11-27)
- AVR使用范例--AVR外部中断范例(11-11)
- AVR内部EEPROM读写范例(12-12)
- AVR看门狗使用范例 avr wdt看门狗详解(08-16)
- AVR使用范例--AVR软件延时精确计算指导(05-06)
- VxWorks实时操作系统下MPC8260ATM驱动的实现(11-11)