|  | 
          1楼
          巨大八爪鱼
          2017-3-22 10:11
          
          
            #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);
 }
 }
 
 | 
    
      |  | 
          2楼
          巨大八爪鱼
          2017-3-23 09:30
          
          
            这个程序有一个问题,就是如果连续发送多行,那么接收到的内容从第二行开始就会不完整。例如,发送:This is a long string.
 This is another paragraph.
 
 接收到的却是:
 This is a long string.
 Thph.
 
 
 这是因为串行通信是收发同时进行的,而在上面的程序中却是先接收(gets)后发送(puts),这样当gets获取完第一行内容后,puts才开始发送,并且发送需要一定的时间。等puts发送完了gets才开始接收,此时单片机端早已发送了很多字符了,中间的内容都没有收到而溢出(Overrun)了。所以第二行的内容就不完整。
 | 
    
      |  | 
          3楼
          巨大八爪鱼
          2017-3-23 09:55
          
          
            上述问题的解决办法是,创建一个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);
 }
 
 | 
    
      |  | 
          4楼
          巨大八爪鱼
          2017-3-23 09:58
          
          
            在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);
 }
 }
 
 | 
    
      |  | 
          6楼
          巨大八爪鱼
          2017-3-23 18:02
          
          
             如果接收到的内容出现乱码或字符丢失的现象,说明FIFO缓冲区的大小不够,扩大缓冲区就行了: struct fifo {     unsigned char buf[512]; // 缓冲区的大小     unsigned int front, rear; // 这两个变量要改用int类型 } usartbuf; | 
    
      |  | 
          7楼
          巨大八爪鱼
          2017-3-23 18:06
          
          
            串口大师这个软件本身可能有问题,发送同样的内容,另一个串口调试工具就没有出现乱码。
  | 
    
      |  | 
          8楼
          巨大八爪鱼
          2017-3-23 18:22
          
          
            
          
          如果接收到的内容出现乱码或字符丢失的现象,说明FIFO缓冲区的大小不够,扩大缓冲区就行了: struct fifo {     unsigned...  同时还应该注意扩大main函数中str数组的大小。 | 
    
      |  | 
          9楼
          巨大八爪鱼
          2017-3-23 18:24
          
          
            在C程序里直接执行printf("// 只有使用外部晶振才能保证PC端接收到的内容不乱码");(没有换行符),串口大师接收到的内容都会乱码。。。 |