×
单片机 > 单片机程序设计 > 详情

uart 中断 缓冲区

发布时间:2020-05-23 发布时间:
|
在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的话就不调用了。 
或改为: 
  signed int getchar(void)  
   
    signed int data;  
    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")      // 开中断 
    
    return data;  


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

#define RXB8 
#define TXB8 
#define UPE 
#define OVR 
#define FE 
#define UDRE 
#define RXC 

#define FRAMING_ERROR (1<
#define PARITY_ERROR (1<
#define DATA_OVERRUN (1<
#define DATA_REGISTER_EMPTY (1<
#define RX_COMPLETE (1<

// USART Transmitter buffer 
#define TX_BUFFER_SIZE 
char tx_buffer[TX_BUFFER_SIZE]; 

#if TX_BUFFER_SIZE<256 
unsigned char tx_wr_index,tx_rd_index,tx_counter; 
#else 
unsigned int tx_wr_index,tx_rd_index,tx_counter; 
#endif 

// USART Transmitter interrupt service routine 
interrupt [USART_TXC] void usart_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_ 
// Write character to the USART Transmitter buffer 
#define _ALTERNATE_PUTCHAR_ 
#pragma used+ 
void putchar(char c) 

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") 

#pragma used- 
#endif 

// Standard Input/Output functions 
#include  

// Declare your global variables here 

void main(void) 

// Declare your local variables here 

// Input/Output Ports initialization 
// Port initialization 
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In  
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T  
PORTA=0x00; 
DDRA=0x00; 

// Port initialization 
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In  
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T  
PORTB=0x00; 
DDRB=0x00; 

// Port initialization 
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In  
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T  
PORTC=0x00; 
DDRC=0x00; 

// Port initialization 
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In  
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T  
PORTD=0x00; 
DDRD=0x00; 

// Timer/Counter initialization 
// Clock source: System Clock 
// Clock value: Timer Stopped 
// Mode: Normal top=FFh 
// OC0 output: Disconnected 
TCCR0=0x00; 
TCNT0=0x00; 
OCR0=0x00; 

// Timer/Counter initialization 
// Clock source: System Clock 
// Clock value: Timer Stopped 
// Mode: Normal top=FFFFh 
// OC1A output: Discon. 
// OC1B output: Discon. 
// Noise Canceler: Off 
// Input Capture on Falling Edge 
// Timer Overflow Interrupt: Off 
// Input Capture Interrupt: Off 
// Compare Match Interrupt: Off 
// Compare Match Interrupt: Off 
TCCR1A=0x00; 
TCCR1B=0x00; 
TCNT1H=0x00; 
TCNT1L=0x00; 
ICR1H=0x00; 
ICR1L=0x00; 
OCR1AH=0x00; 
OCR1AL=0x00; 
OCR1BH=0x00; 
OCR1BL=0x00; 

// Timer/Counter initialization 
// Clock source: System Clock 
// Clock value: Timer Stopped 
// Mode: Normal top=FFh 
// OC2 output: Disconnected 
ASSR=0x00; 
TCCR2=0x00; 
TCNT2=0x00; 
OCR2=0x00; 

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

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

// USART initialization 
// Communication Parameters: Data, Stop, No Parity 
// USART Receiver: Off 
// USART Transmitter: On 
// USART Mode: Asynchronous 
// USART Baud rate: 9600 
UCSRA=0x00; 
UCSRB=0x48; 
UCSRC=0x86; 
UBRRH=0x00; 
UBRRL=0x19; 

// Analog Comparator initialization 
// Analog Comparator: Off 
// Analog Comparator Input Capture by Timer/Counter 1: Off 
ACSR=0x80; 
SFIOR=0x00; 

// Global enable interrupts 
#asm("sei") 

while (1) 
      
      // Place your code here 
      putchar(0x55); 
      }; 


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

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
Keil(MDK-ARM)系列教程(七)_菜单