打印
[范例教程]

如何将下位机采集的浮点型数据发送给上位机

[复制链接]
2376|51
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
kmzuaz|  楼主 | 2023-10-27 22:32 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
  • #include "REG52.H"
  • #define const_voice_short  40 //蜂鸣器短叫的持续时间
  • #define const_rc_size  10     //接收串口中断数据的缓冲区数组大小
  • #define const_receive_time  5 //如果超过这个时间没有串口数据过来,就认为一串数据已经全部接收完,这个时间根据实际情况来调整大小
  • unsigned char xdata array[10];//缓存数组
  • float value = -5.625;                  //模拟下位机采集经过计算后的数据
  • /*
  • -5.625 = C 0 B 4 0 0 0 0
  • C    0     B   4     0   0    0    0
  • 1100 0000 1011 0100 0000 0000 0000 0000
  • 按照浮点数格式切割成相应的域 1 1000 0001 01101 000000000000000000
  • 经分析:符号域1 意味着负数;指数域为129 意味着实际的指数为2 (减去偏差值127);
  • 尾数域为01101 意味着实际的二进制尾数为1.01101 (加上隐含的小数点前面的1)。
  • 所以,实际的实数为:
  • = -1.01101 × 2^2 =- ( 1*2^0 + 1*2^(-2) + 1*2^(-3) + 1*2^(-5) ) × 2^2
  • = -(1+0.25+0.125+0.03125)*4
  • = -1.40625*4
  • = -5.625
  • */
  • void initial_myself(void);
  • void initial_peripheral(void);
  • void delay_long(unsigned int uiDelaylong);
  • void T0_time(void);       //定时中断函数
  • void usart_receive(void); //串口接收中断函数
  • void usart_service(void); //串口服务程序,在main函数里
  • sbit beep_dr=P3^6; //蜂鸣器的驱动IO口
  • unsigned int  uiSendCnt=0;     //用来识别串口是否接收完一串数据的计时器
  • unsigned char ucSendLock=1;    //串口服务程序的自锁变量,每次接收完一串数据只处理一次
  • unsigned int  uiRcregTotal=0;  //代表当前缓冲区已经接收了多少个数据
  • unsigned char ucRcregBuf[const_rc_size]; //接收串口中断数据的缓冲区数组
  • unsigned int  uiRcMoveIndex=0;  //用来解析数据协议的中间变量
  • unsigned int  uiVoiceCnt=0;  //蜂鸣器鸣叫的持续时间计数器
  • void usart_send();                //串口发送程序
  • void  Change();                        //将浮点弄转换成字符弄
  • void main()
  • {
  •         initial_myself();
  •         delay_long(100);
  •         initial_peripheral();
  •         while(1)
  •         {
  •            usart_service();  //串口服务程序
  •         }
  • }
  • union                            //联合体定义
  • {
  •     char a[4];
  •         float b;
  • }temp;
  • void usart_service(void)  //串口服务程序,在main函数里
  • {
  • /* 注释一:
  • * 识别一串数据是否已经全部接收完了的原理:
  • * 在规定的时间里,如果没有接收到任何一个字节数据,那么就认为一串数据被接收完了,然后就进入数据协议
  • * 解析和处理的阶段。这个功能的实现要配合定时中断,串口中断的程序一起阅读,要理解他们之间的关系。
  • */
  •      if(uiSendCnt>=const_receive_time&&ucSendLock==1) //说明超过了一定的时间内,再也没有新数据从串口来
  •      {
  •             ucSendLock=0;    //处理一次就锁起来,不用每次都进来,除非有新接收的数据
  •                     //下面的代码进入数据协议解析和数据处理的阶段
  •                uiRcMoveIndex=uiRcregTotal; //由于是判断数据尾,所以下标移动变量从数组的最尾端开始向0移动
  •             while(uiRcMoveIndex>=5)   //如果处理的数据量大于等于5(2个有效数据,3个数据头)说明还没有把缓冲区的数据处理完
  •             {
  •                if(ucRcregBuf[uiRcMoveIndex-3]==0xeb&&ucRcregBuf[uiRcMoveIndex-2]==0x00&&ucRcregBuf[uiRcMoveIndex-1]==0x55)  //数据尾eb 00 55的判断
  •                {
  •                                         if(ucRcregBuf[uiRcMoveIndex-5]==0x01&&ucRcregBuf[uiRcMoveIndex-4]==0x02)  //有效数据01 02的判断
  •                                         {
  •                                                 usart_send();        //收到正确的数据后,开发发送采集到的数据
  •                                                 uiVoiceCnt=const_voice_short; //蜂鸣器发出声音,说明数据发送完毕
  •                                         }
  •                   break;   //退出循环
  •                }
  •                uiRcMoveIndex--; //因为是判断数据尾,下标向着0的方向移动
  •            }
  •            uiRcregTotal=0;  //清空缓冲的下标,方便下次重新从0下标开始接受新数据
  •      }
  • }
  • void usart_send()           //串口发送
  • {
  •     static unsigned int ucSendCnt = 0;
  •         ES = 0; //关串口中断
  •         TI = 0; //清零串口发送完成中断请求标志
  •         Change();
  •         for(ucSendCnt = 0;ucSendCnt<4;ucSendCnt++)//发送四个字节,表示一个浮点数
  •         {
  •              SBUF = array[ucSendCnt];                        //将数据装入缓冲区
  •              delay_long(50);                                        //延时一会儿
  •         }
  •         TI = 0; //清零串口发送完成中断请求标志
  •         ES = 1; //允许串口中断
  • }
  • /*
  • 联合休:
  • 当多个数据需要共享内存或者多个数据每次只取其一时,可以利用联合体(union)。
  •      在C Programming Language 一书中对于联合体是这么描述的:
  •      1)联合体是一个结构;
  •      2)它的所有成员相对于基地址的偏移量都为0;
  •      3)此结构空间要大到足够容纳最"宽"的成员;
  •      4)其对齐方式要适合其中所有的成员;
  • 下面解释这四条描述:
  •      由于联合体中的所有成员是共享一段内存的,因此每个成员的存放首地址相对于于联合体变量
  •          的基地址的偏移量为0,即所有成员的首地址都是一样的。为了使得所有成员能够共享一段内存,
  •          因此该空间必须足够容纳这些成员中最宽的成员。对于这句“对齐方式要适合其中所有的成员”是
  •          指其必须符合所有成员的自身对齐方式。
  • */
  • void  Change()
  • {
  •      temp.b   = value;                //将数据存入联合休中
  •      array[0] = temp.a[0];        //一个字节一个字节的取出来
  •      array[1] = temp.a[1];
  •      array[2] = temp.a[2];
  •      array[3] = temp.a[3];
  • }
  • void T0_time(void) interrupt 1    //定时中断
  • {
  •         TF0=0;  //清除中断标志
  •         TR0=0; //关中断
  •          uiSendCnt++;    //表面上这个数据不断累加,但是在串口中断里,每接收一个字节它都会被清零,除非这个中间没有串口数据过来
  •         if(uiSendCnt>=const_receive_time)   //如果超过这个时间没有串口数据过来,就认为一串数据已经全部接收完
  •         {
  •             ucSendLock=1;     //开自锁标志
  •         }
  •         if(uiVoiceCnt!=0)
  •         {
  •             uiVoiceCnt--; //每次进入定时中断都自减1,直到等于零为止。才停止鸣叫
  •             beep_dr=0;  //蜂鸣器是PNP三极管控制,低电平就开始鸣叫。
  •         }
  •         else
  •         {
  •             ; //此处多加一个空指令,想维持跟if括号语句的数量对称,都是两条指令。不加也可以。
  •             beep_dr=1;  //蜂鸣器是PNP三极管控制,高电平就停止鸣叫。
  •         }
  •         TH0=0xfe;   //重装初始值(65535-500)=65035=0xfe0b
  •         TL0=0x0b;
  •         TR0=1;  //开中断
  • }
  • void usart_receive(void) interrupt 4                 //串口接收数据中断
  • {
  •         if(RI==1)
  •         {
  •                 RI = 0;
  •                 ++uiRcregTotal;
  •                 if(uiRcregTotal>=const_rc_size)  //超过缓冲区
  •                 {
  •                     uiRcregTotal=const_rc_size;
  •                 }
  •                 ucRcregBuf[uiRcregTotal-1]=SBUF;   //将串口接收到的数据缓存到接收缓冲区里
  •                 uiSendCnt=0;  //及时喂狗,虽然main函数那边不断在累加,但是只要串口的数据还没发送完毕,那么它***也长不大,因为每个中断都被清零。
  •         }
  •         else  //我在其它单片机上都不用else这段代码的,可能在51单片机上多增加" TI = 0;"稳定性会更好吧。
  •         {
  •                 TI = 0;
  •         }
  • }
  • void delay_long(unsigned int uiDelayLong)
  • {
  •    unsigned int i;
  •    unsigned int j;
  •    for(i=0;i<uiDelayLong;i++)
  •    {
  •       for(j=0;j<50;j++)  //内嵌循环的空指令数量
  •           {
  •              ; //一个分号相当于执行一条空语句
  •           }
  •    }
  • }
  • void initial_myself(void)  //第一区 初始化单片机
  • {
  •           beep_dr=1; //用PNP三极管控制蜂鸣器,输出高电平时不叫。
  •           //配置定时器
  •           TMOD=0x01;  //设置定时器0为工作方式1
  •           TH0=0xfe;   //重装初始值(65535-500)=65035=0xfe0b
  •           TL0=0x0b;
  •           //配置串口
  •           SCON=0x50;
  •           TMOD=0X21;
  •           TH1=TL1=-(11059200L/12/32/9600);  //这段配置代码具体是什么意思,我也不太清楚,反正是跟串口波特率有关。
  •           TR1=1;
  • }
  • void initial_peripheral(void) //第二区 初始化外围
  • {
  •            EA=1;     //开总中断
  •            ES=1;     //允许串口中断
  •            ET0=1;    //允许定时中断
  •            TR0=1;    //启动定时中断
  • }

使用特权

评论回复
沙发
juliestephen| | 2023-11-5 10:39 | 只看该作者
单片机可以通过串口或其他通信方式将下位机采集的浮点型数据发送给上位机。

使用特权

评论回复
板凳
ulystronglll| | 2023-11-5 10:45 | 只看该作者
将浮点型数据转换为整形或字符型数据。可以使用数学库中的函数,如ceil()、floor()、round()等,将浮点型数据四舍五入到指定的小数位数,然后再转换为整形或字符型数据。

使用特权

评论回复
地板
sesefadou| | 2023-11-5 11:19 | 只看该作者
保证通信链路的稳定性和可靠性,对于无线通信尤为重要。

使用特权

评论回复
5
tabmone| | 2023-11-5 11:53 | 只看该作者
对于浮点型数据,需要约定数据的位数、小数点位置等细节。

使用特权

评论回复
6
pentruman| | 2023-11-5 14:59 | 只看该作者
需要将浮点型数据转换为字符串形式,然后通过串口发送。在上位机端,接收到的字符串需要再转换回浮点型数据。

使用特权

评论回复
7
minzisc| | 2023-11-5 15:57 | 只看该作者
单片机将接收到的数据通过串口或者网络发送给上位机

使用特权

评论回复
8
burgessmaggie| | 2023-11-5 16:48 | 只看该作者
在发送数据时,需要先将数据加载到发送寄存器中,然后发送数据给上位机。在接收数据时,需要从寄存器中读取数据,然后进行数据处理。

使用特权

评论回复
9
louliana| | 2023-11-5 17:58 | 只看该作者
需要将浮点型数据转换为适合传输的格式。常用的方法是将浮点型数据转换为字符串

使用特权

评论回复
10
minzisc| | 2023-11-5 20:15 | 只看该作者
单片机将采集到的浮点型数据编码为可以通过串行通信协议发送的数据格式。常见的编码方式包括二进制、十六进制等。

使用特权

评论回复
11
lzbf| | 2023-11-5 21:18 | 只看该作者
如果单片机和上位机之间需要无线通信,可以采用蓝牙、Wi-Fi等无线通信技术。

使用特权

评论回复
12
lihuami| | 2023-11-5 21:43 | 只看该作者
在实际应用中需要按照特定单片机的规范进行设计和编写程序。

使用特权

评论回复
13
janewood| | 2023-11-5 22:24 | 只看该作者
在下位机和上位机之间建立通信协议,例如使用串口通信、网络通信等。然后,你就可以按照通信协议将编码后的数据发送到上位机。

使用特权

评论回复
14
claretttt| | 2023-11-8 16:13 | 只看该作者
单片机将浮点型数据转换为字节流,通过无线信号发送给上位机

使用特权

评论回复
15
jonas222| | 2023-11-8 18:54 | 只看该作者
单片机将浮点型数据转换为字节流,通过网络发送给上位机。上位机端接收数据后,再将字节流转换回浮点型数据。

使用特权

评论回复
16
elsaflower| | 2023-11-8 19:27 | 只看该作者
上位机通过串行通信接口接收单片机发送的数据,并将其解码为所需的浮点型数字。

使用特权

评论回复
17
i1mcu| | 2023-11-8 19:53 | 只看该作者
考虑到单片机的处理能力和功耗,选择合适的通信速率和工作模式。

使用特权

评论回复
18
febgxu| | 2023-11-8 20:34 | 只看该作者
在上位机端处理数据时,注意数据的有效范围和精度,避免数据溢出或精度损失

使用特权

评论回复
19
ingramward| | 2023-11-8 20:58 | 只看该作者
单片机通过串行通信接口(如UART、SPI等)将编码后的数据发送给上位机。在发送数据之前,需要设置通信接口的波特率、数据位、校验位等参数,以确保数据传输的正确性。

使用特权

评论回复
20
olivem55arlowe| | 2023-11-8 21:26 | 只看该作者
单片机和上位机之间的串行通信接口需要匹配。例如,如果使用UART通信,上位机需要使用相同的UART接口进行接收。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

6

主题

2904

帖子

0

粉丝