基于stm32的多功能时钟10——数据采集与蓝牙控制

        嘿,我的小可爱们!

        在《蓝牙串口通信》这一章中,小编带着大家编写了蓝牙串口通信程序,测试了蓝牙通信正常。由于我后来又找到了《蓝牙调试器》软件,功能强大,可自定义控件,所以下面将编写通信协议,通过这款软件,来实现数据采集和蓝牙控制。而我们在上一章中,完成了蓝牙监控界面的设计,所以这一章中,我们开始讲解程序的编写。


        首先,我们要将数据包设置成结构体的形式,便于后面的操作和管理,同时定义接收数据堆栈和发送数据堆栈。之所以这样做,是因为通信协议规定,数据包必须包括起始字节、数据字节、校验字节和结束字节,这样做的目的就是确保数据传输的正确性和稳定性。关于通信方面的知识,我以后用到的话,还会介绍的,例如ESP8266等模块。

/*定义串口发送数据堆栈*/

typedef struct

{

    u8 head;//定义起始字节

    u8 getdata[8];//定义采集数据,包括温度(1字节)、湿度(1字节)、是否报警(1字节)、电机运行状态(1字节)、空气质量(2字节)和测量距离(2字节)

    u8 verify;//定义校验字节

    u8 tail;//定义结束字节

}TX_STACK;//定义串口发送数据堆栈

/*定义串口接收数据堆栈*/

typedef struct

{

    u8 head;//定义起始字节

    u8 control[10];//定义阈值存放区,温湿度上下限(4字节),空气质量、安全距离(4字节),取消报警和启停电机(2字节)

    u8 verify;//定义校验字节

    u8 tail;//定义结束字节

    u8 ptr;//定义接收数据指针

    u8 lock_flag;//定义数据接收完毕标志位

}RX_STACK;//定义串口接收数据堆栈

TX_STACK tx_stack;//定义发送数据缓存区

RX_STACK rx_stack;//定义接收数据缓存区

关于蓝牙串口的配置代码,在前面已经讲述过。下面,我们分为两个模块来讲解。

(1)数据采集,实时显示

这一部分,是单片机发送数据,通过蓝牙传输给手机,在手机界面上显示单片机采集到的数据。

/*发送堆栈初始化*/

void tx_init(void)

{

    u8 i;

    tx_stack.head = 0xa5;//起始字节

    for(i=0; i<8; i++)

    {

        tx_stack.getdata[i] = 0x00;//采集数据

    }

    tx_stack.verify = 0x00;

    tx_stack.tail = 0x5a;//结束字节

}

我们先将发送堆栈初始化,然后通过下面的发送程序发送出去。

/*发送采集数据*/

void send_collected_data(void)

{

    u8 i;

    //发送起始字节

    USART_SendData(USART2,tx_stack.head);

    while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);

    //发送采集数据

    for(i=0; i<8; i++)

    {

        USART_SendData(USART2, tx_stack.getdata[i]);

        while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);

        tx_stack.verify += tx_stack.getdata[i];

    }

    //发送校验字节

    USART_SendData(USART2,tx_stack.verify);

    while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);

    //发送结束字节

    USART_SendData(USART2,tx_stack.tail);

    while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);

    tx_init();

}

        在发送采集数据函数里,我们根据协议,依次发送起始字节、采集数据字节、校验字节和结束字节。这样,在蓝牙软件里,就会对单片机发送过来的数据进行分析处理。首先,判断数据包是否符合通信协议,如果符合(起始字节、结束字节等正确,数据结构正确)。再对接收的数据进行校验,如果校验成功,则数据有效,蓝牙软件就会显示对应的数据,包括文本、图表等形式。如果校验不成功,则数据失效,不予处理。(注意:这里只要单片机依次发数据即可,判断数据包是否符合协议以及数据校验等操作是上位机软件程序完成的)

        temp = distance/100;

        tx_stack.getdata[0] = temperature;

        tx_stack.getdata[1] = humidity;

        tx_stack.getdata[2] = cancel;

        tx_stack.getdata[3] = state;

        tx_stack.getdata[4] = value%256;

        tx_stack.getdata[5] = value/256;

        tx_stack.getdata[6] = temp%256;

        tx_stack.getdata[7] = temp/256;

        send_collected_data();

在主程序里,对发送数据包的每个元素采集到的数值,再调用该发送程序即可。

(2)蓝牙控制,参数调整

        这一部分,是单片机接收程序,单片机接收手机发出的指令,并做相关的处理。

        我们先要在串口中断函数里编写数据包接收语句,相较于发送(此项目采集数据,实时性强),接收不是每时每刻都进行的,用中断的方式可能会更好些。在接收中断函数里,我们只要依次接收数据,将数据存放在相应的接收数据结构体里即可。

void USART2_IRQHandler(void)

{

    static u8 i = 0;

    if(USART_GetITStatus(USART2, USART_IT_RXNE)!=RESET)

    {

        rev_data = USART_ReceiveData(USART2);            //接收数据

        if(rx_stack.lock_flag == UNLOCK)

        {

            switch(i)

            {

                case 0:rx_stack.head = rev_data;i++;break;

                case 1:rx_stack.control[rx_stack.ptr++] = rev_data;i++;break;

                case 2:rx_stack.control[rx_stack.ptr++] = rev_data;i++;break;

                case 3:rx_stack.control[rx_stack.ptr++] = rev_data;i++;break;

                case 4:rx_stack.control[rx_stack.ptr++] = rev_data;i++;break;

                case 5:rx_stack.control[rx_stack.ptr++] = rev_data;i++;break;

                case 6:rx_stack.control[rx_stack.ptr++] = rev_data;i++;break;

                case 7:rx_stack.control[rx_stack.ptr++] = rev_data;i++;break;

                case 8:rx_stack.control[rx_stack.ptr++] = rev_data;i++;break;

                case 9:rx_stack.control[rx_stack.ptr++] = rev_data;i++;break;

                case 10:rx_stack.control[rx_stack.ptr++] = rev_data;i++;break;

                case 11:rx_stack.verify = rev_data;i++;break;

                case 12:rx_stack.tail = rev_data;i++;break;

                default:rx_stack.lock_flag = LOCKED;i=0;break;

            }

        }

    }

    USART_ClearITPendingBit(USART2, USART_IT_RXNE);      //清除接收中断标志

}

        接收手机发送的数据包后,我们要对数据包进行解析。当然在解析之前,先要判断数据能不能校验成功,如果校验成功,则接收的数据正确,做相关的处理;否则,接收的数据错误,不做任何处理。这里,我们需要判断起始字节、结束字节(固定值0xa5和0x5a)是否符合协议,以及校验字节是否和数据字节之和低8位是否相等。这里,由于采用软件里的自定义控件进行数据命令的发送,所以起始字节和结束字节可不必校验(肯定是固定值0xa5和0x5a)。如果是通过文本框发送数据,那么就要校验这两个字节(手动输入,不能确保)。

/*发送蓝牙控制数据*/

void send_control_data(void)

{

    u8 sum = 0,i;

    if(rx_stack.lock_flag == LOCKED)

    {

        for(i=0; i<10; i++)

        {

            sum += rx_stack.control[i];

        }

        /*检验成功*/

        if(rx_stack.verify==sum)

        {

            temper_H = rx_stack.control[0];

            temper_L = rx_stack.control[1];

            humid_H = rx_stack.control[2];

            humid_L = rx_stack.control[3];

            cancel = rx_stack.control[4];

            motor_flag = rx_stack.control[5];

            air_upperlimit = rx_stack.control[6]+rx_stack.control[7]*256;

            length = rx_stack.control[8]+rx_stack.control[9]*256;

        }

        else

        {

            ;//校验失败,不操作

        }

        rx_stack.lock_flag = UNLOCK;

        rx_init();

    }

}

当然,我们在此之前需要对接收数据堆栈进行初始化,然后再主函数中调用解析函数即可。

/*接收堆栈初始化*/

void rx_init(void)

{

    rx_stack.head = 0x00;//起始字节

    rx_stack.control[0] = temper_H;//数据接收控制4字节

    rx_stack.control[1] = temper_L;

    rx_stack.control[2] = humid_H;

    rx_stack.control[3] = humid_L;

    rx_stack.control[4] = cancel;

    rx_stack.control[5] = motor_flag;

    rx_stack.control[6] = air_upperlimit%256;

    rx_stack.control[7] = air_upperlimit/256;

    rx_stack.control[8] = length%256;

    rx_stack.control[9] = length/256;

    rx_stack.verify = 0x00;//数据校验字节

    rx_stack.tail = 0x00;//结束字节

    rx_stack.lock_flag = UNLOCK;

    rx_stack.ptr = 0x00;

}

通信确认
蓝牙通信正常
蓝牙界面1


蓝牙界面2

        到这里,我们的蓝牙串口通信协议就编写完成了,当然过程肯定没有这么简单,不信你也可以试试。此时,我们连接好蓝牙,打开之前的多功能时钟工程,就可以在工程界面里看到实时采集的数据,并且不断的更新。同时,你也可以设置相关的参数,UI界面也会随着你的操作而会发生变化,单片机也会做相关的处理,是不是很神奇,是不是很有趣,那就一起来开发多功能时钟吧。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容