新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > uart 中斷 緩沖區(qū)

uart 中斷 緩沖區(qū)

作者: 時間:2016-11-28 來源:網(wǎng)絡 收藏
在CVAVR系統(tǒng)提供的標準庫函數(shù)stdio.h中,提供了getchar()函數(shù),該函數(shù)是采用輪詢方式從USART接收數(shù)據(jù)的,輪詢方式不僅效率低,而且會丟失數(shù)據(jù),不能實現(xiàn)多任務的并行處理。

CVAVR程序向?qū)е薪o出的采用中斷+緩沖的方式接受數(shù)據(jù),同PC的串口接受數(shù)據(jù)的方法一樣,充分利用了AVR的高速和RAM多的優(yōu)點,體現(xiàn)出了如何才能充分發(fā)揮AVR的特點的程序設計思想,這種思路在32位系統(tǒng)中也是這樣的。

使用AVR的話,對軟件的設計能力要求更高了,否則根本不能發(fā)揮和體現(xiàn)AVR的特點。許多人有了一點C的基礎,就認為采用C編寫單片機程序沒問題,很快就會掌握AVR了,對此我只能一笑了之??纯幢菊旧媳姸嗟拇a,再看看本貼的遭遇,能說什么呢?

回到本題:
注1:
如果在程序的開頭部分加上語句
#define_DEBUG_TERMINAL_IO_
那么程序在編譯時仍使用系統(tǒng)自己的getchar()函數(shù),這樣在軟件模擬仿真時,可以從模擬的終端讀取數(shù)據(jù),便于在軟件模擬環(huán)境中調(diào)試整個系統(tǒng),而需要正式運行時,則把該句注釋掉。
注2:
此處在正式應用中應根據(jù)實際情況做適當?shù)男薷?。否則當主程序調(diào)用getchar()時,如果緩沖隊列中沒有數(shù)據(jù),同時對方也沒有發(fā)數(shù)據(jù)的情況時,程序會在此死循環(huán)。
比較簡單的辦法是將這句刪掉,而在調(diào)用getchar()函數(shù)前先判斷rx_counter的值,為0的話就不調(diào)用了。
或改為:
signedintgetchar(void)
{
signedintdata;
if(rx_counter==0)
{
data=-1;
}
else
{
data=rx_buffer[rx_rd_index];//讀取緩沖隊列中的數(shù)據(jù)
if(++rx_rd_index==RX_BUFFER_SIZE)rx_rd_index=0;//讀取指針指向下一個未讀的數(shù)據(jù),如果指到了隊列尾部,則指回到隊列頭步
#asm("cli")//關中斷!非常重要
--rx_counter;//隊列中未讀數(shù)據(jù)個數(shù)減1。因為該變量在接收中斷中要改變的,為了防止沖突,所以改動前臨時關閉中斷。程序相當可靠了。
#asm("sei")//開中斷
}
returndata;
}

注3:
有興趣希望深入實在學習的網(wǎng)友,可將CVAVR生成的USART發(fā)送代碼仔細分析以下。它的發(fā)送代碼非常完美,可以馬上使用。
#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);
};
}

思考分析:
我在主程序的循環(huán)里僅有一句不停的發(fā)0X55,問題是AVR的運行速度非??欤鳸SART串出的速度肯定明顯的慢(按9600bps計算,需要1秒多時間才能送出1000個字符),那么,假定主程序循環(huán)了1000次,發(fā)送1000個0x55,請判斷在UASRT口上能否正確的發(fā)出1000個0x55,有沒有丟失或溢出現(xiàn)象存在?


關鍵詞: uart中斷緩沖

評論


技術專區(qū)

關閉