AVR USART(UART)发送中断程序 使用缓冲器

使用USART发送数据,需要一定时间,若是用传统方法,等发送完再处理其它任务(如语句 while(!(UCSRA&0x40));),那么,将大大降低了高速的AVR的执行效率!

  那么怎样处理才可以解决低速串口与高速AVR之间的矛盾呢?可以采用开辟发送缓冲区的做法:
  当AVR需要发送数据时,如果USART口不空闲或者发送缓冲区还有待发送的数据,就将数据放入发送缓冲器中(如果缓冲器未满),AVR不必等待,可以转去执行其它任务。而后,等USART的硬件发送完一个数据后产生中断,由中断服务程序负责将发送缓冲器中数据依次送出。
  发送缓冲器数据结构的设计:循环队列,由读、写2个指针及一个队列计数器控制,用于判断当前写入数据、读出数据在队列中的位置,并判断队列是否为空,是否已满。
  程序设计时需注意,为了防止处理冲突,在对数据缓冲器的读、写过程中,要将中断关闭,避免错误产生,从而提高程序的可靠性。

#include <iom16v.h>
#define DISP_PORT PORTB
#define DISP_DDR  DDRB

#define TX_BUFFER_SIZE 255
#define UDR_EMPTY (1<<UDRE) 
//UDRE:USART数据寄存器空标志,该标志位可以产生中断
// Bit 5 – UDRE: USART  数据寄存器空
//UDRE标志指出发送缓冲器(UDR)是否准备好接收新数据。
//UDRE为1说明缓冲器为空,已准备好进行数据接收。
uint8 x_buffer[TX_BUFFER_SIZE],tx_wr_index=0,tx_rd_index=0,tx_counter=0; 
/*---------------------------------------------------------
程序名称:UART初始化程序
程序功能:初始化UART为:8位,9.6K,接收中断
注意事项:基于7.3728M晶振 */
void uart0_init(void)
{
    UCSRB = 0x00;   //disable while setting baud rate
    UCSRA = 0x00;   //U2X = 0,不加倍数率
    UCSRC = 0x86;   //8位
    //固定的
    /*  设置帧格式 : 8 个数据位 , 2 个停止位 */
    //UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
    UBRRL = 47;     //set baud rate lo,波特率为9.6K
    UBRRH = 0x00;   //set baud rate hi
    UCSRB = 0x58;   //发送中断允许,接收缓冲自动清空,接收允许
}
/*---------------------------------------------------------
程序名称:UART发送中断服务程序*/
#pragma interrupt_handler uart0_tx_isr:14
void uart0_tx_isr(void)
{
    if (tx_counter) //如果缓冲区有数据则进入发送程序
    {
        tx_counter--;
        UDR=tx_buffer[tx_rd_index]; 
        if (++tx_rd_index == TX_BUFFER_SIZE) //如果缓冲区读指针满
            tx_rd_index=0;    //读指针置0
    }
}
/*---------------------------------------------------------
程序功能:UART发送程序*/
void uart0_putchar(uint8 c) 
{ 
    while (tx_counter == TX_BUFFER_SIZE); //如果缓冲区满则等待
    CLI(); 
    if (tx_counter || ((UCSRA & UDR_EMPTY)==0))  //如果缓冲区有数据或者UDR不空闲
    {
        tx_buffer[tx_wr_index]=c;   //将数据写入缓冲
        if (++tx_wr_index == TX_BUFFER_SIZE)  //如果已经写满
            tx_wr_index=0;    //写指针置0
        tx_counter++;
    } 
    else     //如果缓冲区没有数据且UDR空闲
        UDR=c;      //没什么事就发了吧
//USART发送数据缓冲寄存器和USART接收数据缓冲寄存器共享相同的I/O地址,
//称为USART 数据寄存器或UDR。
//将数据写入UDR时实际操作的是发送数据缓冲器存器(TXB),
//读UDR时实际返回的是接收数据缓冲寄存器 (RXB) 的内容。
    SEI();
} 
void mcu_init(void)
{
    CLI();
    uart0_init();
    MCUCR = 0x00;
    GICR  = 0x00;
    TIMSK = 0x00;   //timer interrupt sources
    SEI();          //re-enable interrupts
}

void main()
{
    uint8 sendChar=0;

    mcu_init();
    DISP_DDR=0xFF;

    while(1)
    {
        uart0_putchar(sendChar); //发送数据,数据为变量sendChar
        delay50us(20);
        DISP_PORT=tx_counter;  //显示发送区数据量
    }
}

(1)缓冲区数据量tx_counter的值取决于AVR的发送频率及UART的波特率。假定UART的波特率一定,若是AVR的发送频率过高,低速的UART的发送速度将跟不上,导致缓冲区数据量tx_counter不断增加。用LED指示tx_counter,将可以观察到向上加的现象。

(2)改变UART初始化语句:UBRRL = 47; 将“47”改为“40”、“60”、“80”,从而改变UART的波特率。可以看到波特率越高,数据量tx_counter向上加的速度越低;当波特率高到一定程度,发送时间将小于延时时间,UART空闲,程序不将待发送的数据放入缓冲,即缓冲区没有数据,数据量tx_counter一直为“0”;波特率越低,数据量tx_ounter向上加的速度越高。用LED指示tx_counter的数据量,观察现象。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值