独闷闷网

 找回密码
 立即注册
搜索
查看: 12883|回复: 5
打印 上一主题 下一主题
收起左侧

[原创] 联合体应用——如何将下位机采集的浮点型数据发送给上位机

[复制链接]
跳转到指定楼层
楼主
发表于 2015-1-29 22:11:47 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
本帖最后由 xiao_yp2014 于 2016-1-21 14:41 编辑

在有些项目中,需要单片机把数据处理完后,返回给上位机,数据处理离不成计算,有计算就会涉及到小数,那么,如何将小数转换成十六进制数据呢,下面请看简便算法。

上位机发送命令:01 02 EB 00 55    (串口接收就用鸿哥的,不改动了)
下位机返回-5.625 的十六进制数据 C0 B4 00 00




  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.         for(ucSendCnt = 0;ucSendCnt<4;ucSendCnt++)//发送四个字节,表示一个浮点数
  86.         {
  87.                     SBUF = array[ucSendCnt];                        //将数据装入缓冲区
  88.                 delay_long(50);                                        //延时一会儿
  89.         }
  90.         TI = 0; //清零串口发送完成中断请求标志
  91.         ES = 1; //允许串口中断
  92. }

  93. /*
  94. 联合休:
  95. 当多个数据需要共享内存或者多个数据每次只取其一时,可以利用联合体(union)。
  96.      在C Programming Language 一书中对于联合体是这么描述的:
  97.      1)联合体是一个结构;
  98.      2)它的所有成员相对于基地址的偏移量都为0;
  99.      3)此结构空间要大到足够容纳最"宽"的成员;
  100.      4)其对齐方式要适合其中所有的成员;

  101. 下面解释这四条描述:
  102.          由于联合体中的所有成员是共享一段内存的,因此每个成员的存放首地址相对于于联合体变量
  103.          的基地址的偏移量为0,即所有成员的首地址都是一样的。为了使得所有成员能够共享一段内存,
  104.          因此该空间必须足够容纳这些成员中最宽的成员。对于这句“对齐方式要适合其中所有的成员”是
  105.          指其必须符合所有成员的自身对齐方式。
  106. */
  107. void  Change()
  108. {
  109.            temp.b        = value;                //将数据存入联合休中

  110.          array[0] = temp.a[0];        //一个字节一个字节的取出来
  111.          array[1] = temp.a[1];
  112.          array[2] = temp.a[2];
  113.          array[3] = temp.a[3];
  114. }

  115. void T0_time(void) interrupt 1    //定时中断
  116. {
  117.         TF0=0;  //清除中断标志
  118.         TR0=0; //关中断
  119.         
  120.          uiSendCnt++;    //表面上这个数据不断累加,但是在串口中断里,每接收一个字节它都会被清零,除非这个中间没有串口数据过来

  121.         if(uiSendCnt>=const_receive_time)   //如果超过这个时间没有串口数据过来,就认为一串数据已经全部接收完
  122.         {
  123.                   ucSendLock=1;     //开自锁标志
  124.         }
  125.         
  126.         if(uiVoiceCnt!=0)
  127.         {
  128.                  uiVoiceCnt--; //每次进入定时中断都自减1,直到等于零为止。才停止鸣叫
  129.                  beep_dr=0;  //蜂鸣器是PNP三极管控制,低电平就开始鸣叫。
  130.         }
  131.         else
  132.         {
  133.                  ; //此处多加一个空指令,想维持跟if括号语句的数量对称,都是两条指令。不加也可以。
  134.                  beep_dr=1;  //蜂鸣器是PNP三极管控制,高电平就停止鸣叫。
  135.         }
  136.         
  137.         
  138.         TH0=0xfe;   //重装初始值(65535-500)=65035=0xfe0b
  139.         TL0=0x0b;
  140.         TR0=1;  //开中断
  141. }


  142. void usart_receive(void) interrupt 4                 //串口接收数据中断        
  143. {        

  144.         if(RI==1)  
  145.         {
  146.                 RI = 0;
  147.                 ++uiRcregTotal;

  148.                 if(uiRcregTotal>=const_rc_size)  //超过缓冲区
  149.                 {
  150.                         uiRcregTotal=const_rc_size;
  151.                 }
  152.                 ucRcregBuf[uiRcregTotal-1]=SBUF;   //将串口接收到的数据缓存到接收缓冲区里
  153.                 uiSendCnt=0;  //及时喂狗,虽然main函数那边不断在累加,但是只要串口的数据还没发送完毕,那么它永远也长不大,因为每个中断都被清零。
  154.         }
  155.         else  //我在其它单片机上都不用else这段代码的,可能在51单片机上多增加" TI = 0;"稳定性会更好吧。
  156.         {
  157.                 TI = 0;
  158.         }

  159. }                                

  160. void delay_long(unsigned int uiDelayLong)
  161. {
  162.    unsigned int i;
  163.    unsigned int j;
  164.    for(i=0;i<uiDelayLong;i++)
  165.    {
  166.       for(j=0;j<50;j++)  //内嵌循环的空指令数量
  167.           {
  168.              ; //一个分号相当于执行一条空语句
  169.           }
  170.    }
  171. }


  172. void initial_myself(void)  //第一区 初始化单片机
  173. {

  174.           beep_dr=1; //用PNP三极管控制蜂鸣器,输出高电平时不叫。
  175.         
  176.           //配置定时器
  177.           TMOD=0x01;  //设置定时器0为工作方式1
  178.           TH0=0xfe;   //重装初始值(65535-500)=65035=0xfe0b
  179.           TL0=0x0b;
  180.         
  181.         
  182.           //配置串口
  183.           SCON=0x50;
  184.           TMOD=0X21;
  185.           TH1=TL1=-(11059200L/12/32/9600);  //这段配置代码具体是什么意思,我也不太清楚,反正是跟串口波特率有关。
  186.           TR1=1;
  187.         
  188. }

  189. void initial_peripheral(void) //第二区 初始化外围
  190. {

  191.            EA=1;     //开总中断
  192.            ES=1;     //允许串口中断
  193.            ET0=1;    //允许定时中断
  194.            TR0=1;    //启动定时中断

  195. }
复制代码






乐于分享,勇于质疑!
沙发
发表于 2015-1-30 01:33:50 | 只看该作者
辛苦了。感谢分享。
乐于分享,勇于质疑!
板凳
 楼主| 发表于 2015-1-30 09:33:37 | 只看该作者
jianhong_wu 发表于 2015-1-30 01:33
辛苦了。感谢分享。

应该的。。。
乐于分享,勇于质疑!
地板
发表于 2015-1-30 10:14:27 | 只看该作者
学习了 ,多谢
乐于分享,勇于质疑!
5#
发表于 2015-1-30 17:15:13 | 只看该作者
学习了。。感谢楼主的分享,辛苦了
乐于分享,勇于质疑!
6#
发表于 2015-2-7 11:52:11 | 只看该作者
union                            //联合体定义
{
    char a[4];
        float b;
}temp;

//////////////////原来float在51里面是4个字节
乐于分享,勇于质疑!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|独闷闷网 ( 粤ICP备12007667号-2 )

GMT+8, 2024-11-29 16:42 , Processed in 0.194500 second(s), 20 queries .

快速回复 返回顶部 返回列表