|  | 
          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端接收到的內容不亂碼");(沒有換行符),串口大師接收到的內容都會亂碼。。。 |