久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 13208|回復: 5
打印 上一主題 下一主題
收起左側

51單片機printf函數的說明及使用以及串口接收字符處理

  [復制鏈接]
跳轉到指定樓層
樓主
51單片機串口通信中需要發送數據,而一般都會使用printf這個外部函數,printf函數在<stdio.h>這個頭文件中,所以要使用這個函數必須要有stdio.h這個頭文件。printf函數不需要我們去定義其內部實現,可以直接使用,當然也可以自己去構造一個相似功能的函數。

在stdio.h中可以看到printf函數的第一個參數為一個字符指針其用法與c語言中的的是一樣的,而printf函數的內部實現是依靠putchar這個函數來實現的,putchar這個函數在c51的庫文件下有定義

源碼如下
  1. #include <reg51.h>

  2. #define XON  0x11             /*串口流控制符  啟動*/
  3. #define XOFF 0x13            /*串口流控制符  中斷*/


  4. /*
  5. * putchar (full version):  expands '\n' into CR LF and handles     /*完整版 每次發送數據都要檢查sbuf是否有中斷信號 */
  6. *                          XON/XOFF (Ctrl+S/Ctrl+Q) protocol             /* XON啟動 XOFF中斷      通信協議*/                                                         
  7. */
  8. char putchar (char c)  {

  9.   if (c == '\n')  {          /*判斷是否是換行符的原因,是因為字符串的標準格式是末尾為\r(回車符)\n(換行符)這兩個字符*/
  10.     if (RI)  {                          /*判斷接收標識符是否為1,若為1則說明SBUF接受到了信息*/
  11.       if (SBUF == XOFF)  {       /*判斷SBUF中的信息是否為中斷信號  是則執行以下程序*/
  12.         do  {
  13.           RI = 0;                          /*將接收標識符置1 可以繼續接收信息*/
  14.           while (!RI);                    /*判斷是否接收到了信息,是則往下循環*/
  15.         }
  16.         while (SBUF != XON);     /*判斷接收的信息是否為啟動信息,是則退出循環,不是繼續循環*/
  17.         RI = 0;                          /*將接受標識符置1 可以繼續接收信息*/
  18.       }
  19.   }</div><div>/*只要c是換行符,最終都要執行這里   判斷發送標識符是否為1,只有為1才往下執行,這點非常重要調用printf函數時,必須將TI置1*/</div><div>while (!TI);</div><div>  TI = 0;                                         /*將TI置0 準備發送數據*/
  20.   SBUF = 0x0d;                         /* output CR  */          /*  發送回車符*/
  21.   }
  22.   if (RI)  {                           /*下面的if函數又是判斷SBUF中是否接收了中斷信號與上面的一樣*/
  23.     if (SBUF == XOFF)  {
  24.       do  {
  25.         RI = 0;
  26.         while (!RI);
  27.       }
  28.       while (SBUF != XON);
  29.       RI = 0;
  30. <div>    }</div><div>while (!TI);      /*判斷發送標識符是否為1*/
  31. TI = 0; /*將TI置0 準備發送數據*/
  32.   return (SBUF = c);                                /*發送字符c*/
  33. }



  34. #if 0         // comment out versions below

  35. /*
  36. * putchar (basic version): expands '\n' into CR LF                  /*精簡版*/
  37. */
  38. char putchar (char c)  {              
  39.   if (c == '\n')  {             /*還是判斷字符c是不是換行符*/
  40.     while (!TI);                  /*判斷TI是否置1     為1向下執行*/
  41.     TI = 0;
  42.     SBUF = 0x0d;                         /* output CR  */       /* c是換行符先發送回車符*/
  43.   }
  44.   while (!TI);                                /*又是判斷TI是否為1   為1向下執行*/
  45.   TI = 0;                                     /*將TI置0 準備發送數據*/
  46.   return (SBUF = c);                    /*發送字符c*/
  47. }


  48. /*
  49. * putchar (mini version): outputs charcter only                    /*迷離版   少了判斷字符c是否為換行符的步驟 */
  50. */
  51. char putchar (char c)  {
  52.   while (!TI);                                           /*判斷TI是否置1     為1向下執行*/                     
  53.   TI = 0;                                                  /*將TI置0 準備發送數據*/
  54.   return (SBUF = c);/*發送字符c*/
  55. }                                                         

  56. #endif
復制代碼
對于上面putchar函數的實現過程以及細節我已經注釋的非常清楚了,但上面的串口流控制符可能有些人有疑惑,我這里解釋一下。
XON/XOFF  這兩個字符就是串口流控制字符,所謂的流就是數據流,當兩個串口之間進行通信時,鑒于兩個設備的硬件不一樣,一個設備發送的信息讓另一個設備處理不過來時,接收方設備就向發送方發送一個XOFF(0X13)字符,發送方接收到這個字符以后就會中斷發送,直到接收方處理完數據后又向發送方發送一個XON(0x11)字符,當發送方接收到這個字符時又開始向接收方發送數據。

接下來我們可以用printf函數來發送數據了,但發送數據前要將TI置1
  1. #include<reg52.h>
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #include<intrins.h>
  5. void af(int a){
  6. int b,c;
  7. for(b=0;b<a;b++)
  8. for(c=0;c<110;c++);
  9. }
  10. void main(){
  11. TMOD=0X20;
  12. TH1=0Xfd;
  13. TL1=0xfd;
  14. SCON=0X50;
  15. SM0=0;
  16. SM1=1;
  17. TR1=1;
  18. EA=1;
  19. ES=0;
  20. REN=1;
  21. TI=1;                /*初始化將TI置1*/

  22. while(1){
  23. af(1000);          /*延遲1秒*/

  24. printf("ghjkl;lkjhgffghjklkjhgfghjk");       /*調用printf函數*/
  25.           TI=1;                                                 /*又將TI置1 方便下車調用printf函數*/
  26. }
  27. }
復制代碼
以上就是printf函數的使用方法,如果覺得這個函數不好使用,可以對putchar函數的源代碼進行改動,構造出自己的輸出函數這里就不做介紹了。


發送數據可以使用printf函數但如果我們想接收字符串時就需要自己構造函數,下面的接收字符串函數僅供參考
  1. #include<reg52.h>
  2. #include<stdio.h>
  3. char a=0;                            /*定義全局字符變量a并且賦值為'0'    a用于接收字符函數判斷串口中斷是否產生  */
  4. char c[30]="0";                    /*定義全局字符數值c初始為'0'            c用于存放接收的字符串               */
  5. int b=0;                              /*定義全局整型變量b  初始b為0     b用于字符串的賦值串口每中斷一次b加1 */
  6. void yc(int a){                     /*構造延遲函數yc*/
  7. int b,c;
  8. for(b=0;b<a;b++)
  9. for(c=0;c<110;c++);
  10. }
  11. int  scan(){                         /*構造接收字符串函數scan*、/
  12. int af;                                 /*定義一個整型變量af 用于返回值*/
  13. int ef=0;                            /*定義一個整型變量ef 賦值為0  用于判斷*/
  14. if(a==1){                            /*通過判斷a的值來判斷串口中斷是否產生*/
  15. af=b;                                  /*將全局變量b的值賦值給變量af*/
  16. yc(1);                                  /*延遲1秒*/
  17. while(b!=af){                       /*判斷b與af是否相等     不等進入循環     否則退出循環 */
  18. af=b;                                  /*又將b的值賦值給af*/
  19.   yc(1);  /*延遲1秒*/
  20. }
  21. a=0;                                     /*將a復原為0以便下次處理*/
  22. c[b]='\0';                              /*將第b個地址位賦值為空字符*/
  23. b=0;                                     /*將b清零*/
  24. ef=1;                                    /*ef賦值1 以便返回*/
  25. }
  26. return ef;
  27. }
  28. void main(){
  29. TMOD=0X20;
  30. TH1=0Xfd;
  31. TL1=0Xfd;
  32. SM0=0;
  33. SM1=1;
  34. REN=1;
  35. TR1=1;
  36. EA=1;
  37. ES=1;
  38. while(1){
  39. while(!scan());             /*接收到字符串就退出循環*/
  40. TI=1;                           /*TI置1 下面調用printf函數*/
  41. ES=0;                          /*串口中斷置不置0其實沒有多大的影響*/
  42. printf(c);                    /*用printf函數將接收到的字符串發送出去*/
  43. ES=1  ;     
  44. }

  45. }

  46. void zd()interrupt 4
  47. {
  48. RI=0;                  /*RI置0 以便下次中斷*/
  49. a=1;                   /*有中斷a就為1*/
  50. c[b]=SBUF;       /*將每次接受的字符存入c中*/
  51. b++;               /*中斷產生則b加1*/

  52. }
復制代碼

出自 51黑電子論壇

捕獲3.PNG (22.02 KB, 下載次數: 66)

捕獲3.PNG

捕獲2.PNG (5.7 KB, 下載次數: 85)

捕獲2.PNG

捕獲1.PNG (5.49 KB, 下載次數: 64)

捕獲1.PNG

捕獲.PNG (1.35 KB, 下載次數: 66)

捕獲.PNG

捕獲3.PNG (22.02 KB, 下載次數: 85)

捕獲3.PNG

捕獲2.PNG (5.7 KB, 下載次數: 84)

捕獲2.PNG

捕獲2.PNG (5.7 KB, 下載次數: 80)

捕獲2.PNG

捕獲1.PNG (5.49 KB, 下載次數: 78)

捕獲1.PNG

捕獲.PNG (1.35 KB, 下載次數: 70)

捕獲.PNG

評分

參與人數 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏6 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:653902 發表于 2019-12-15 18:51 | 只看該作者
看了您對putchar函數的中文注釋,感覺非常有用。
有個小問題請教,在17和21行,程序是寫的RI=0,注釋中為將RI置1,有點不理解,不是應該注釋為將RI清零嗎?謝謝
回復

使用道具 舉報

板凳
ID:535176 發表于 2020-4-9 08:00 | 只看該作者
我用兩個串口這個putchar函數名怎么起啊
回復

使用道具 舉報

地板
ID:527981 發表于 2020-12-31 22:53 | 只看該作者
rotga 發表于 2019-12-15 18:51
看了您對putchar函數的中文注釋,感覺非常有用。
有個小問題請教,在17和21行,程序是寫的RI=0,注釋中為 ...

確實是你說的那樣,我寫的有問題
回復

使用道具 舉報

5#
ID:527981 發表于 2020-12-31 23:11 | 只看該作者
冷月楓 發表于 2020-4-9 08:00
我用兩個串口這個putchar函數名怎么起啊

這個是庫函數里面的,你可以按照它的結構來自己寫相似功能的函數
回復

使用道具 舉報

6#
ID:390416 發表于 2021-1-1 10:02 | 只看該作者
那么問題來了,函數里面有while(TI)或者while(RI)這樣的死等。要是以1200波特率通信,那就不好玩了。
看《人人學會單片機》學串口多字節高效率發送代碼。直接中斷里面發送。不需要執行while 死等循環。
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 欧美精品在线一区二区三区 | 91夜色在线观看 | 久久久亚洲综合 | 国产一区亚洲 | 一区视频在线免费观看 | 国产视频亚洲视频 | 91极品视频 | 日日噜噜噜夜夜爽爽狠狠视频97 | 国产精品高清一区二区 | 国产成人在线一区 | 华人黄网站大全 | 日韩中文字幕在线观看 | sese视频在线观看 | 亚洲 欧美 日韩在线 | 国产欧美日韩久久久 | 欧美性生活免费 | 久久久久久久av | 亚洲在线免费观看 | 国产视频亚洲视频 | 香蕉视频久久久 | 欧美www在线 | 欧美日韩视频在线播放 | 日韩精品成人免费观看视频 | 国产精品久久久久久久久久久新郎 | 久久蜜桃资源一区二区老牛 | 91福利网 | 在线观看三级av | 浴室洗澡偷拍一区二区 | 国产精品久久av | 日韩成人免费视频 | 国产精品亚洲综合 | 天堂精品| 在线一区视频 | 91亚洲欧美| 毛片入口 | 国产精品黄色 | 人成精品 | 免费毛片网| 久久久久无码国产精品一区 | 九九天堂网| 成人一区av偷拍 |