0
问答首页 最新问题 热门问题 等待回答标签广场
我要提问

单片机

电脑(PC)通过串口向单片机发送浮点数(float、double)的方法

电脑(PC)通过串口向单片机发送浮点数(float、double)的方法version1.0maswellxiao         在实际应用中我们可能会遇到这样一个问题,PC机要向单片机发送一个浮点数,float类型、double类型也好。maswell我曾经做过AD转换并发送数据到MATLAB中做FFT、滤波器等数字信号处理。处理完毕以后maswell我遇到一个非常棘手的问题……MATLAB数据处理完毕以后得到的数据类型是小数类型,就算忽略后几位精度,最起码也是一个float数据类型的数,怎么把这个数发送到单片机呢?         经过几天的折腾。maswell我一不小心就实现PC通过串口向单片机发送浮点小数。下面把这种方法分享给大家。         首先我们需要一个预备知识。也就是float数据类型在单片机中的存储方式。         float数据类型总共占据32个位bit,其中第一个位为数据符号(Symbol,在下面简称为S)该位表示数据的正负性。接下来8个位是阶码(Expoent,下面简称为E),这8个位表示浮点数的小数点的位置。最后有23位的尾数(mantissa,M),这23个位表示数据。下面做个示意图  1位S  8个位E23个位M         例如:十进制的数据Nfile:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image002.png将之换成二进制表示file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image004.pngfile:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image006.pngfile:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image008.pngfile:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image010.png因此file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image012.png并由公式file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image014.png得file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image016.png组合起来就是  S  EM0file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image018.pngfile:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image020.png4bit一格隔开  0100  001011110110111010010111100142F6E979因此十进制浮点小数N = 123.456在单片机里存储的数据为0x42F6E979         

提问者:gvjhvbc 地点:- 浏览次数:2878 提问时间:10-19 17:43
我有更好的答案
提 交
2条回答
semiaxis 07-29 02:12

至此,我们的思路有了一点了。PC机向单片机发送十六进制代码0x42F6E979就意味着向单片机发送浮点小数123.456了。

下面是MATLAB向单片机发送数据的一段代码

function pushbutton7_Callback(hObject, eventdata, handles)

% hObject    handle to pushbutton7 (see GCBO)

% eventdata  reserved - to be defined in a future version of MATLAB

% handles    structure with handles and user data (see GUIDATA)

global s;

global TxDataToMSP430;

TxDataHex = num2hex(single(TxDataToMSP430));

fwrite(s,'dcba','uchar');%协议密码

t1 =clock;

while 1

    if fread(s,1) == hex2dec('af');

        break;

    end

    if etime(clock , t1) > 1%1秒钟内未收到数据则放弃

        break ;

    end

end

TxDataHexTemp(1) = TxDataHex(1);

TxDataHexTemp(2) = TxDataHex(2);

fwrite(s,base2dec(TxDataHexTemp,16),'uchar');%协议数据

         我当初做的是一个GUI界面,函数名是MATLAB自动生成的,我的下位机用的是MSP430G2553单片机。编译环境CCS5.2

volatile float DisplayData1,DisplayData2,DisplayData3,DisplayData4;

volatile long DisplayData;//接收到的数据转换前数据

unsigned char TXVolFlag = 0;

static char FrameHeaderFlag = 1;//识别帧头标志位

static char StopTxFlag = 0;//上位机发送停止发送标志

unsigned char ReadDataClassFlag = 0x00;//读数据包格式

         以上为全局变量。注意DisplayData为long数据类型

#pragma vector=USCIAB0RX_VECTOR

__interrupt void USCI0RX_ISR(void)

{

    static char k = 0;

    if(FrameHeaderFlag)

    {

        ReadDataClassFlag = IdentifyHeader();

        if(ReadDataClassFlag != 0x00)//识别帧头

            FrameHeaderFlag = 0;

    }

    else//上一次读到的temp不是0,说明握手成功

    {

        switch(ReadDataClassFlag)

        {

        case 0xaf:

        case 0xbe:

        case 0xcc:

        case 0xdb:

            switch(k)

            {

            case 0:

                DisplayData = UCA0RXBUF;

                DisplayData <<= 8;

                k = 1;

                break;

            case 1:

                DisplayData += UCA0RXBUF;

                DisplayData <<= 8;

                k = 2;

                break;

            case 2:

                DisplayData += UCA0RXBUF;

                DisplayData <<= 8;

                k = 3;

                break;

            case 3:

                DisplayData += UCA0RXBUF;

                k = 0;

                switch(ReadDataClassFlag)

                {

                ///////////////////////////////////接收数据,以下是接收数据的控制字

                case 0xaf:DisplayData1 = *((float *)&DisplayData);break;

                case 0xbe:DisplayData2 = *((float *)&DisplayData);break;

                case 0xcc:DisplayData3 = *((float *)&DisplayData);break;

                case 0xdb:DisplayData4 = *((float *)&DisplayData);break;

                default:;

                }

                FrameHeaderFlag = 1;//帧数据接收完毕,32个bit数据为一帧

                break;

            default:;

            }

            break;

        case 0xfa://停止发送的密码

            IdentifyHeader();

            break;

        default:;

        }

    }

}

我这个函数是MSP430G2553单片机的接受中断函数,单片机串口接收到数据后进入中断,首先判断是不是协议的帧头(我这里自行定义了一个协议)如果不是帧头,则是数据,进入数据的判断,由于PC机发送的是32位的数据,而UART只支持接收8位的数据,故此用了四个case语句判断。接收完32位的数据以后,问题又来了,我们用来存储接收来的数据是long类型(volatile long DisplayData;)的。而我们需要接收的数据是float数据类型的。故此还需要一个转换。其实这个转换很简单。一个语句就可以了。

DisplayData1 = *((float *)&DisplayData);

首先将DisplayData的地址强制转换为float数据类型的地址,然后再对地址取值就可以了。至此,就可以完整地将long数据类型转换为float数据类型。

         那么一整个过程就可以完整地实现,从PC机发送1、0代码到MSP430单片机接收为long数据类型,再由long数据类型强制转换为float数据类型。

         那么同样道理,我们可以用同样的方法将long long数据类型转换为double数据类型。

pmet 08-01 09:04

我们每次接受一个float数据,只需把这个数据从long转换成float就行了,为什么这里要分四种情况         

                case 0xafisplayData1 = *((float *)&DisplayData);break;

                case 0xbeisplayData2 = *((float *)&DisplayData);break;

                case 0xccisplayData3 = *((float *)&DisplayData);break;

                case 0xdbisplayData4 = *((float *)&DisplayData);break;

            

撰写答案
提 交
1 / 3
1 / 3
相关单片机
具有音调控制的单片机立体声前置放大器
用于单片机与电子装置中的开关电源
单片机软硬件复位的条件都有啥
电动机的单片机控制
单片机应用系统开发实例导航