微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > uart 中断 缓冲区

uart 中断 缓冲区

时间:11-28 来源:互联网 点击:
在CVAVR系统提供的标准库函数stdio.h中,提供了getchar()函数,该函数是采用轮询方式从USART接收数据的,轮询方式不仅效率低,而且会丢失数据,不能实现多任务的并行处理。

CVAVR程序向导中给出的采用中断+缓冲的方式接受数据,同PC的串口接受数据的方法一样,充分利用了AVR的高速和RAM多的优点,体现出了如何才能充分发挥AVR的特点的程序设计思想,这种思路在32位系统中也是这样的。

使用AVR的话,对软件的设计能力要求更高了,否则根本不能发挥和体现AVR的特点。许多人有了一点C的基础,就认为采用C编写单片机程序没问题,很快就会掌握AVR了,对此我只能一笑了之。看看本站上众多的代码,再看看本贴的遭遇,能说什么呢?

回到本题:
注1:
如果在程序的开头部分加上语句
#define_DEBUG_TERMINAL_IO_
那么程序在编译时仍使用系统自己的getchar()函数,这样在软件模拟仿真时,可以从模拟的终端读取数据,便于在软件模拟环境中调试整个系统,而需要正式运行时,则把该句注释掉。
注2:
此处在正式应用中应根据实际情况做适当的修改。否则当主程序调用getchar()时,如果缓冲队列中没有数据,同时对方也没有发数据的情况时,程序会在此死循环。
比较简单的办法是将这句删掉,而在调用getchar()函数前先判断rx_counter的值,为0的话就不调用了。
或改为:
signedintgetchar(void)
{
signedintdata;
if(rx_counter==0)
{
data=-1;
}
else
{
data=rx_buffer[rx_rd_index];//读取缓冲队列中的数据
if(++rx_rd_index==RX_BUFFER_SIZE)rx_rd_index=0;//读取指针指向下一个未读的数据,如果指到了队列尾部,则指回到队列头步
#asm("cli")//关中断!非常重要
--rx_counter;//队列中未读数据个数减1。因为该变量在接收中断中要改变的,为了防止冲突,所以改动前临时关闭中断。程序相当可靠了。
#asm("sei")//开中断
}
returndata;
}

注3:
有兴趣希望深入实在学习的网友,可将CVAVR生成的USART发送代码仔细分析以下。它的发送代码非常完美,可以马上使用。
#include

#defineRXB81
#defineTXB80
#defineUPE2
#defineOVR3
#defineFE4
#defineUDRE5
#defineRXC7

#defineFRAMING_ERROR(1
#definePARITY_ERROR(1
#defineDATA_OVERRUN(1
#defineDATA_REGISTER_EMPTY(1
#defineRX_COMPLETE(1

//USARTTransmitterbuffer
#defineTX_BUFFER_SIZE8
chartx_buffer[TX_BUFFER_SIZE];

#ifTX_BUFFER_SIZE<256
unsignedchartx_wr_index,tx_rd_index,tx_counter;
#else
unsignedinttx_wr_index,tx_rd_index,tx_counter;
#endif

//USARTTransmitterinterruptserviceroutine
interrupt[USART_TXC]voidusart_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;
};
}

#ifndef_DEBUG_TERMINAL_IO_
//WriteacharactertotheUSARTTransmitterbuffer
#define_ALTERNATE_PUTCHAR_
#pragmaused+
voidputchar(charc)
{
while(tx_counter==TX_BUFFER_SIZE);
#asm("cli")
if(tx_counter||((UCSRA&DATA_REGISTER_EMPTY)==0))
{
tx_buffer[tx_wr_index]=c;
if(++tx_wr_index==TX_BUFFER_SIZE)tx_wr_index=0;
++tx_counter;
}
else
UDR=c;
#asm("sei")
}
#pragmaused-
#endif

//StandardInput/Outputfunctions
#include

//Declareyourglobalvariableshere

voidmain(void)
{
//Declareyourlocalvariableshere

//Input/OutputPortsinitialization
//PortAinitialization
//Func7=InFunc6=InFunc5=InFunc4=InFunc3=InFunc2=InFunc1=InFunc0=In
//State7=TState6=TState5=TState4=TState3=TState2=TState1=TState0=T
PORTA=0x00;
DDRA=0x00;

//PortBinitialization
//Func7=InFunc6=InFunc5=InFunc4=InFunc3=InFunc2=InFunc1=InFunc0=In
//State7=TState6=TState5=TState4=TState3=TState2=TState1=TState0=T
PORTB=0x00;
DDRB=0x00;

//PortCinitialization
//Func7=InFunc6=InFunc5=InFunc4=InFunc3=InFunc2=InFunc1=InFunc0=In
//State7=TState6=TState5=TState4=TState3=TState2=TState1=TState0=T
PORTC=0x00;
DDRC=0x00;

//PortDinitialization
//Func7=InFunc6=InFunc5=InFunc4=InFunc3=InFunc2=InFunc1=InFunc0=In
//State7=TState6=TState5=TState4=TState3=TState2=TState1=TState0=T
PORTD=0x00;
DDRD=0x00;

//Timer/Counter0initialization
//Clocksource:SystemClock
//Clockvalue:Timer0Stopped
//Mode:Normaltop=FFh
//OC0output:Disconnected
TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;

//Timer/Counter1initialization
//Clocksource:SystemClock
//Clockvalue:Timer1Stopped
//Mode:Normaltop=FFFFh
//OC1Aoutput:Discon.
//OC1Boutput:Discon.
//NoiseCanceler:Off
//InputCaptureonFallingEdge
//Timer1OverflowInterrupt:Off
//InputCaptureInterrupt:Off
//CompareAMatchInterrupt:Off
//CompareBMatchInterrupt:Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

//Timer/Counter2initialization
//Clocksource:SystemClock
//Clockvalue:Timer2Stopped
//Mode:Normaltop=FFh
//OC2output:Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

//ExternalInterrupt(s)initialization
//INT0:Off
//INT1:Off
//INT2:Off
MCUCR=0x00;
MCUCSR=0x00;

//Timer(s)/Counter(s)Interrupt(s)initialization
TIMSK=0x00;

//USARTinitialization
//CommunicationParameters:8Data,1Stop,NoParity
//USARTReceiver:Off
//USARTTransmitter:On
//USARTMode:Asynchronous
//USARTBaudrate:9600
UCSRA=0x00;
UCSRB=0x48;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x19;

//AnalogComparatorinitialization
//AnalogComparator:Off
//AnalogComparatorInputCapturebyTimer/Counter1:Off
ACSR=0x80;
SFIOR=0x00;

//Globalenableinterrupts
#asm("sei")

while(1)
{
//Placeyourcodehere
putchar(0x55);
};
}

思考分析:
我在主程序的循环里仅有一句不停的发0X55,问题是AVR的运行速度非常快,而USART串出的速度肯定明显的慢(按9600bps计算,需要1秒多时间才能送出1000个字符),那么,假定主程序循环了1000次,发送1000个0x55,请判断在UASRT口上能否正确的发出1000个0x55,有没有丢失或溢出现象存在?

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top