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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 24799|回復: 7
收起左側

如何將下位機采集的浮點型數據發送給上位機

[復制鏈接]
ID:69862 發表于 2015-1-29 22:15 | 顯示全部樓層 |閱讀模式
本帖最后由 xiao_yp2014 于 2016-1-21 14:21 編輯

大家好!我叫肖亞平,從小熱愛上了電子技術,讀書時陰差陽錯的選擇了電子這方面的專業,學習電子技術、一直到今年畢業。對于我的理解來說,學校里面學到的技術不是全部實用,但是必須有用,所以一直奮斗在前線。我對學習總結出一句話“壓力不是有人努力,而是比你牛X N倍的人依然在努力

在有些項目中,需要單片機把數據處理完后,返回給上位機,數據處理離不成計算,有計算就會涉及到小數,那么,如何將小數轉換成十六進制數據呢,下面請看簡便算法。

上位機發送命令:01 02 EB 00 55   
下位機返回-5.625 的十六進制數據 C0 B4 00 00

捕獲.PNG
  1. #include "REG52.H"

  2. #define const_voice_short  40 //蜂鳴器短叫的持續時間
  3. #define const_rc_size  10     //接收串口中斷數據的緩沖區數組大小

  4. #define const_receive_time  5 //如果超過這個時間沒有串口數據過來,就認為一串數據已經全部接收完,這個時間根據實際情況來調整大小

  5. unsigned char xdata array[10];//緩存數組

  6. float value = -5.625;                  //模擬下位機采集經過計算后的數據
  7. /*
  8. -5.625 = C 0 B 4 0 0 0 0

  9. C    0     B   4     0   0    0    0
  10. 1100 0000 1011 0100 0000 0000 0000 0000
  11. 按照浮點數格式切割成相應的域 1 1000 0001 01101 000000000000000000
  12. 經分析:符號域1 意味著負數;指數域為129 意味著實際的指數為2 (減去偏差值127);
  13. 尾數域為01101 意味著實際的二進制尾數為1.01101 (加上隱含的小數點前面的1)。
  14. 所以,實際的實數為:
  15. = -1.01101 × 2^2 =- ( 1*2^0 + 1*2^(-2) + 1*2^(-3) + 1*2^(-5) ) × 2^2
  16. = -(1+0.25+0.125+0.03125)*4
  17. = -1.40625*4
  18. = -5.625
  19. */

  20. void initial_myself(void);   
  21. void initial_peripheral(void);
  22. void delay_long(unsigned int uiDelaylong);



  23. void T0_time(void);       //定時中斷函數
  24. void usart_receive(void); //串口接收中斷函數
  25. void usart_service(void); //串口服務程序,在main函數里

  26. sbit beep_dr=P3^6; //蜂鳴器的驅動IO口

  27. unsigned int  uiSendCnt=0;     //用來識別串口是否接收完一串數據的計時器
  28. unsigned char ucSendLock=1;    //串口服務程序的自鎖變量,每次接收完一串數據只處理一次
  29. unsigned int  uiRcregTotal=0;  //代表當前緩沖區已經接收了多少個數據
  30. unsigned char ucRcregBuf[const_rc_size]; //接收串口中斷數據的緩沖區數組
  31. unsigned int  uiRcMoveIndex=0;  //用來解析數據協議的中間變量


  32. unsigned int  uiVoiceCnt=0;  //蜂鳴器鳴叫的持續時間計數器

  33. void usart_send();                //串口發送程序
  34. void  Change();                        //將浮點弄轉換成字符弄

  35. void main()
  36. {
  37.         initial_myself();  
  38.         delay_long(100);   
  39.         initial_peripheral();

  40.         while(1)  
  41.         {
  42.            usart_service();  //串口服務程序
  43.         }
  44. }

  45. union                            //聯合體定義
  46. {
  47.     char a[4];
  48.         float b;
  49. }temp;

  50. void usart_service(void)  //串口服務程序,在main函數里
  51. {
  52. /* 注釋一:
  53. * 識別一串數據是否已經全部接收完了的原理:
  54. * 在規定的時間里,如果沒有接收到任何一個字節數據,那么就認為一串數據被接收完了,然后就進入數據協議
  55. * 解析和處理的階段。這個功能的實現要配合定時中斷,串口中斷的程序一起閱讀,要理解他們之間的關系。
  56. */
  57.      if(uiSendCnt>=const_receive_time&&ucSendLock==1) //說明超過了一定的時間內,再也沒有新數據從串口來
  58.      {

  59.             ucSendLock=0;    //處理一次就鎖起來,不用每次都進來,除非有新接收的數據

  60.                     //下面的代碼進入數據協議解析和數據處理的階段
  61.                uiRcMoveIndex=uiRcregTotal; //由于是判斷數據尾,所以下標移動變量從數組的最尾端開始向0移動

  62.             while(uiRcMoveIndex>=5)   //如果處理的數據量大于等于5(2個有效數據,3個數據頭)說明還沒有把緩沖區的數據處理完
  63.             {
  64.                if(ucRcregBuf[uiRcMoveIndex-3]==0xeb&&ucRcregBuf[uiRcMoveIndex-2]==0x00&&ucRcregBuf[uiRcMoveIndex-1]==0x55)  //數據尾eb 00 55的判斷
  65.                {
  66.                                         if(ucRcregBuf[uiRcMoveIndex-5]==0x01&&ucRcregBuf[uiRcMoveIndex-4]==0x02)  //有效數據01 02的判斷
  67.                                         {
  68.                                                 usart_send();        //收到正確的數據后,開發發送采集到的數據
  69.                                                 uiVoiceCnt=const_voice_short; //蜂鳴器發出聲音,說明數據發送完畢
  70.                                                 
  71.                                         }
  72.                   break;   //退出循環
  73.                }
  74.                uiRcMoveIndex--; //因為是判斷數據尾,下標向著0的方向移動
  75.            }

  76.            uiRcregTotal=0;  //清空緩沖的下標,方便下次重新從0下標開始接受新數據
  77.      }

  78. }

  79. void usart_send()           //串口發送
  80. {
  81.     static unsigned int ucSendCnt = 0;

  82.         ES = 0; //關串口中斷
  83.         TI = 0; //清零串口發送完成中斷請求標志
  84.         Change();
  85.         
  86.         for(ucSendCnt = 0;ucSendCnt<4;ucSendCnt++)//發送四個字節,表示一個浮點數
  87.         {
  88.              SBUF = array[ucSendCnt];                        //將數據裝入緩沖區
  89.              delay_long(50);                                        //延時一會兒
  90.         }
  91.         
  92.         TI = 0; //清零串口發送完成中斷請求標志
  93.         ES = 1; //允許串口中斷
  94. }

  95. /*
  96. 聯合休:
  97. 當多個數據需要共享內存或者多個數據每次只取其一時,可以利用聯合體(union)。
  98.      在C Programming Language 一書中對于聯合體是這么描述的:
  99.      1)聯合體是一個結構;
  100.      2)它的所有成員相對于基地址的偏移量都為0;
  101.      3)此結構空間要大到足夠容納最"寬"的成員;
  102.      4)其對齊方式要適合其中所有的成員;

  103. 下面解釋這四條描述:
  104.      由于聯合體中的所有成員是共享一段內存的,因此每個成員的存放首地址相對于于聯合體變量
  105.          的基地址的偏移量為0,即所有成員的首地址都是一樣的。為了使得所有成員能夠共享一段內存,
  106.          因此該空間必須足夠容納這些成員中最寬的成員。對于這句“對齊方式要適合其中所有的成員”是
  107.          指其必須符合所有成員的自身對齊方式。
  108. */
  109. void  Change()
  110. {
  111.      temp.b   = value;                //將數據存入聯合休中
  112.      array[0] = temp.a[0];        //一個字節一個字節的取出來
  113.      array[1] = temp.a[1];
  114.      array[2] = temp.a[2];
  115.      array[3] = temp.a[3];
  116. }

  117. void T0_time(void) interrupt 1    //定時中斷
  118. {
  119.         TF0=0;  //清除中斷標志
  120.         TR0=0; //關中斷
  121.         
  122.          uiSendCnt++;    //表面上這個數據不斷累加,但是在串口中斷里,每接收一個字節它都會被清零,除非這個中間沒有串口數據過來

  123.         if(uiSendCnt>=const_receive_time)   //如果超過這個時間沒有串口數據過來,就認為一串數據已經全部接收完
  124.         {
  125.             ucSendLock=1;     //開自鎖標志
  126.         }
  127.         
  128.         if(uiVoiceCnt!=0)
  129.         {
  130.             uiVoiceCnt--; //每次進入定時中斷都自減1,直到等于零為止。才停止鳴叫
  131.             beep_dr=0;  //蜂鳴器是PNP三極管控制,低電平就開始鳴叫。
  132.         }
  133.         else
  134.         {
  135.             ; //此處多加一個空指令,想維持跟if括號語句的數量對稱,都是兩條指令。不加也可以。
  136.             beep_dr=1;  //蜂鳴器是PNP三極管控制,高電平就停止鳴叫。
  137.         }
  138.         
  139.         
  140.         TH0=0xfe;   //重裝初始值(65535-500)=65035=0xfe0b
  141.         TL0=0x0b;
  142.         TR0=1;  //開中斷
  143. }


  144. void usart_receive(void) interrupt 4                 //串口接收數據中斷        
  145. {        

  146.         if(RI==1)  
  147.         {
  148.                 RI = 0;
  149.                 ++uiRcregTotal;

  150.                 if(uiRcregTotal>=const_rc_size)  //超過緩沖區
  151.                 {
  152.                     uiRcregTotal=const_rc_size;
  153.                 }
  154.                 ucRcregBuf[uiRcregTotal-1]=SBUF;   //將串口接收到的數據緩存到接收緩沖區里
  155.                 uiSendCnt=0;  //及時喂狗,雖然main函數那邊不斷在累加,但是只要串口的數據還沒發送完畢,那么它永遠也長不大,因為每個中斷都被清零。
  156.         }
  157.         else  //我在其它單片機上都不用else這段代碼的,可能在51單片機上多增加" TI = 0;"穩定性會更好吧。
  158.         {
  159.                 TI = 0;
  160.         }

  161. }                                


  162. void delay_long(unsigned int uiDelayLong)
  163. {
  164.    unsigned int i;
  165.    unsigned int j;
  166.    for(i=0;i<uiDelayLong;i++)
  167.    {
  168.       for(j=0;j<50;j++)  //內嵌循環的空指令數量
  169.           {
  170.              ; //一個分號相當于執行一條空語句
  171.           }
  172.    }
  173. }


  174. void initial_myself(void)  //第一區 初始化單片機
  175. {

  176.           beep_dr=1; //用PNP三極管控制蜂鳴器,輸出高電平時不叫。
  177.         
  178.           //配置定時器
  179.           TMOD=0x01;  //設置定時器0為工作方式1
  180.           TH0=0xfe;   //重裝初始值(65535-500)=65035=0xfe0b
  181.           TL0=0x0b;
  182.         
  183.         
  184.           //配置串口
  185.           SCON=0x50;
  186.           TMOD=0X21;
  187.           TH1=TL1=-(11059200L/12/32/9600);  //這段配置代碼具體是什么意思,我也不太清楚,反正是跟串口波特率有關。
  188.           TR1=1;        
  189. }

  190. void initial_peripheral(void) //第二區 初始化外圍
  191. {

  192.            EA=1;     //開總中斷
  193.            ES=1;     //允許串口中斷
  194.            ET0=1;    //允許定時中斷
  195.            TR0=1;    //啟動定時中斷
  196. }
復制代碼




回復

使用道具 舉報

ID:67796 發表于 2015-1-29 22:35 | 顯示全部樓層
標題是不是寫錯了?
帖子內容講的是聯合體字節流。
這個方法比效率比sprintf高,但是代碼較多,適合于大量源數據采集/傳輸。
回復

使用道具 舉報

ID:69862 發表于 2015-1-29 23:01 | 顯示全部樓層
exv 發表于 2015-1-29 22:35
標題是不是寫錯了?
帖子內容講的是聯合體字節流。
這個方法比效率比sprintf高,但是代碼較多,適合于大 ...

標題沒有錯,我的主導思想是聯合體共用內存首地址一個優點,也可以叫做是缺點來為我辦事,你也可以曬曬你的方法。
回復

使用道具 舉報

ID:67796 發表于 2015-1-29 23:24 | 顯示全部樓層
本帖最后由 exv 于 2015-1-29 23:27 編輯
xiao_yp2014 發表于 2015-1-29 23:01
標題沒有錯,我的主導思想是聯合體共用內存首地址一個優點,也可以叫做是缺點來為我辦事,你也可以曬曬你 ...

聯合休==>聯合體

這個別字太顯眼了,看標題感覺很奇怪,點進來才知講的聯合體。

聯合體的這個特點也不好說是缺點,就像一個可自由存取可分隔的盒子,在執行效率上有優勢。

回復

使用道具 舉報

ID:69862 發表于 2015-1-30 00:57 | 顯示全部樓層
exv 發表于 2015-1-29 23:24
聯合休==>聯合體

這個別字太顯眼了,看標題感覺很奇怪,點進來才知講的聯合體。

回復

使用道具 舉報

ID:57234 發表于 2015-1-30 02:10 來自手機 | 顯示全部樓層
現在正在回家的火車上面閱讀樓主的帖子。剛剛從一個隧道里面出來。一看就知道樓主一定是一個代碼高手,這個程序非常精辟,果斷收藏了。我以前也是實現過類似的功能,也是需要把浮點數上傳到上為機上位機里面。為了這個功能我頭疼了很多天。后面還是在51hei論壇里面找到了一個函數先把浮點數轉化為字符串,然后再把字符串到上位機。然后上位機程序再把字符串轉化為浮點數據。勉為其難地解決了這個問題。樓主這個程序改天回去試一下。
回復

使用道具 舉報

ID:69862 發表于 2015-1-30 18:44 | 顯示全部樓層
xiaoou 發表于 2015-1-30 02:10
現在正在回家的火車上面閱讀樓主的帖子。剛剛從一個隧道里面出來。一看就知道樓主一定是一個代碼高手,這個 ...

希望對你有所幫助,帶著回家喜悅的心情,閱讀如此精彩的程序,相信你會滿載而歸的。
回復

使用道具 舉報

ID:249808 發表于 2023-8-24 19:13 | 顯示全部樓層
xiaoou 發表于 2015-1-30 02:10
現在正在回家的火車上面閱讀樓主的帖子。剛剛從一個隧道里面出來。一看就知道樓主一定是一個代碼高手,這個 ...

我也是這么操作的……
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 人人澡视频 | 国产一区二区三区四区区 | 午夜免费福利影院 | 最新黄色毛片 | 日韩成人中文字幕 | 中文天堂在线一区 | 日韩午夜场| 国产成人精品久久 | 精品国产一区二区三区久久久蜜月 | 一级一级毛片免费看 | 国产免费播放视频 | 精品欧美一区二区在线观看欧美熟 | 久久久久久亚洲 | 日韩精品一区二区在线观看 | 欧美日韩不卡 | 成人国产精品久久久 | 美女一级黄| 国产999精品久久久 日本视频一区二区三区 | 久久久免费毛片 | 欧美激情欧美激情在线五月 | 一级毛片在线看 | 91社区在线高清 | 国产精品久久久久久久免费大片 | 欧美操操操 | 久久精品视频12 | 亚洲日韩中文字幕一区 | 久久久久久久久国产成人免费 | 久久国产激情视频 | 久久久精品一区 | 永久网站| 精精国产视频 | 日本久久久一区二区三区 | 日韩av.com | 精品乱码一区二区三四区 | yiren22综合网成人 | 97超碰站 | 精品久久久久久久久久 | 国产高清一区二区三区 | 国产精品一区在线观看 | 国产精品午夜电影 | 精品国产一区二区三区久久久蜜月 |