完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
使用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; //显示发送区数据量 } } 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586 (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的数据量,观察现象。 |
|
|
|
只有小组成员才能发言,加入小组>>
695 浏览 0 评论
1106 浏览 1 评论
2473 浏览 5 评论
2808 浏览 9 评论
移植了freeRTOS到STMf103之后显示没有定义的原因?
2646 浏览 6 评论
使用eim外接fpga可是端口一点反应都没有有没有大哥指点一下啊
655浏览 9评论
651浏览 7评论
请教大神怎样去解决iMX6Q在linux3.0.35内核上做AP失败的问题呢
783浏览 6评论
630浏览 5评论
670浏览 5评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 18:46 , Processed in 1.114895 second(s), Total 80, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号