| 
          
            
            
             
			  #include <avr/io.h> #include <avr/sfr_defs.h> #include <stdio.h>
  // 芯片型号: ATMega16A // 晶振: 外部11.0592MHz // 熔丝位配置: CKSEL3~0=1110, CKOPT=0 // 只有使用外部晶振才能保证PC端接收到的内容不乱码
  int fputc(int ch, FILE *fp) {     if (fp == stdout)     {         if (ch == '\n')         {             // 自动添加\r             UDR = '\r';             while ((UCSRA & _BV(UDRE)) == 0);         }         UDR = ch;         while ((UCSRA & _BV(UDRE)) == 0);     }     return ch; }
  int fgetc(FILE *fp) {     if (fp == stdout)     {         while ((UCSRA & _BV(RXC)) == 0);         return UDR;     }     return 0; }
  void USART_WriteString(const char *s) {     while (*s)     {         UDR = *s++;         while ((UCSRA & _BV(UDRE)) == 0);     } }
  int main(void) {     char str[50];     //UBRRL = 71; // 波特率: 9600     UBRRL = 5; // 波特率: 115200     UCSRB = _BV(RXEN) | _BV(TXEN);
      USART_WriteString("This is a string.\r\n");     fdevopen((int (*)(char, FILE*))fputc, fgetc); // 进行类型转换的目的是为了避免警告     printf("Hello World!\nUBRRL=%d\n", UBRRL);     while (1)     {         gets(str);         puts(str);     } }              
                       | 
        
                
          
                        | 
          
            
            
            
			  这个程序有一个问题,就是如果连续发送多行,那么接收到的内容从第二行开始就会不完整。例如,发送: This is a long string. This is another paragraph.
  接收到的却是: This is a long string. Thph.
  
 
 这是因为串行通信是收发同时进行的,而在上面的程序中却是先接收(gets)后发送(puts),这样当gets获取完第一行内容后,puts才开始发送,并且发送需要一定的时间。等puts发送完了gets才开始接收,此时单片机端早已发送了很多字符了,中间的内容都没有收到而溢出(Overrun)了。所以第二行的内容就不完整。
               
                       | 
        
                
          
                        | 
          
            
            
             
			  上述问题的解决办法是,创建一个FIFO缓冲区(队列),并打开串口接收中断。每接收到一个字符就放入该缓冲区中,而scanf, gets, fgetc等函数则是从缓冲区中读取字符,如果没有字符可读取就一直阻塞。这样就能做到收发同时进行,且可以正常使用标准输入函数。 【改进后的程序】 #include <avr/interrupt.h> #include <avr/io.h> #include <avr/sfr_defs.h> #include <stdio.h>
  // 芯片型号: ATMega16A // 晶振: 外部11.0592MHz // 熔丝位配置: CKSEL3~0=1110, CKOPT=0 // 只有使用外部晶振才能保证PC端接收到的内容不乱码
  // 队列结构体 struct fifo {     unsigned char buf[128];     unsigned char front;     unsigned char rear; } usartbuf;
  #define fifo_init(f) ((f)->front = (f)->rear = 0) // 初始化队列 #define fifo_empty(f) ((f)->front == (f)->rear) // 队空判定 #define fifo_full(f) ((f)->front == ((f)->rear + 1) % sizeof((f)->buf)) // 队满判定
  // 入队 unsigned char fifo_in(struct fifo *f, unsigned char data) {     if (fifo_full(f))         return 0;     f->buf[f->rear] = data;     f->rear = (f->rear + 1) % sizeof(f->buf);     return 1; }
  // 出队 unsigned char fifo_out(struct fifo *f, unsigned char *data) {     if (fifo_empty(f))         return 0;     *data = f->buf[f->front];     f->front = (f->front + 1) % sizeof(f->buf);     return 1; }
  int fputc(int ch, FILE *fp) {     if (fp == stdout)     {         if (ch == '\n')         {             // 自动添加\r             UDR = '\r';             while ((UCSRA & _BV(UDRE)) == 0);         }         UDR = ch;         while ((UCSRA & _BV(UDRE)) == 0);     }     return ch; }
  int fgetc(FILE *fp) {     unsigned char value = 0;     if (fp == stdout)         while (!fifo_out(&usartbuf, &value));     return value; }
  int main(void) {     char str[101]; // 假定每一行最长不超过100个字符     //UBRRL = 71; // 波特率: 9600     UBRRL = 5; // 波特率: 115200     UCSRB = _BV(RXEN) | _BV(TXEN) | _BV(RXCIE); // 开接收中断     sei(); // 开总中断
      fdevopen((int (*)(char, FILE*))fputc, fgetc);     while (1)     {         gets(str);         puts(str);     } }
  // 串口接收中断 ISR(USARTRXC_vect) {     fifo_in(&usartbuf, UDR); }              
                       | 
        
                
          
                        | 
          
            
            
             
			  在main函数中最好先将front和rear的值清零: int main(void) {     char str[101]; // 假定每一行最长不超过100个字符     //UBRRL = 71; // 波特率: 9600     UBRRL = 5; // 波特率: 115200     UCSRB = _BV(RXEN) | _BV(TXEN) | _BV(RXCIE); // 开接收中断     sei(); // 开总中断
      fifo_init(&usartbuf); // 将front和rear清零     fdevopen((int (*)(char, FILE*))fputc, fgetc);     while (1)     {         gets(str);         puts(str);     } }              
                       | 
        
                
          
                        | 
          
            
            
            
			   如果接收到的内容出现乱码或字符丢失的现象,说明FIFO缓冲区的大小不够,扩大缓冲区就行了: struct fifo {     unsigned char buf[512]; // 缓冲区的大小     unsigned int front, rear; // 这两个变量要改用int类型 } usartbuf;              
                       | 
        
                
          
                        | 
          
            
            
            
			  串口大师这个软件本身可能有问题,发送同样的内容,另一个串口调试工具就没有出现乱码。
                
                       | 
        
                
          
                        | 
          
            
            
            
			                如果接收到的内容出现乱码或字符丢失的现象,说明FIFO缓冲区的大小不够,扩大缓冲区就行了: struct fifo {     unsigned...  
			  同时还应该注意扩大main函数中str数组的大小。              
                       | 
        
                
          
                        | 
          
            
            
             
			  在C程序里直接执行printf("// 只有使用外部晶振才能保证PC端接收到的内容不乱码");(没有换行符),串口大师接收到的内容都会乱码。。。             
                       |