本文正在参与「金石计划 . 分割6万现金大奖」

ESP32-C3 蓝牙部分咱们学习了GATT,本文尝试运用蓝牙做一个简略的小运用。

前言

前面文章说过,蓝牙协议博主了解不是很深化,只进行一些根底的了解,示例的测验,和初学者相同,基本上蓝牙专栏系列博文都是一步一步摸索过来的,功夫不负有心人,到目前为止,多多少少对蓝牙 GATT 有了必定的知道。

那么咱们今日就要学以致用,运用 ESP32-C3 的蓝牙 GATT,做一个数据通信的运用实例。

我是矜辰所造成的,全网同名,尽量用心写好每一系列文章,不浮夸,不迁就,认真对待学常识的咱们,矜辰所造成的,金石为开!


一、整体框架

整个实例功用仍是比较简略的,毕竟咱们也刚触摸 ESP32-C3 的蓝牙,直接用下图表明:

ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板

安卓手机 APP 我得考虑一下 ,由于博主是 java 小白,尽管自己写过简略的APP, 有时刻当然搞起来没问题,可是得花些时刻,而博主最近时刻不太够用…… 所以这个,再看把 = =!

废话不多说,咱们直接开端……

二、数据传输部分

先完结把传感器数据上传至手机的部分功用。

2.1 增加温湿度驱动组件

咱们按照步骤先把需求的组件增加(鄙人一篇文章我会运用一篇文章来介绍 ESP-IDF 的工程结构,现已阐明怎样调整一个工程以及怎样增加自己的组件代码)。

组件的增加,咱们假如熟悉工程架构,能够直接把文件夹仿制到工程中,那咱们温湿度驱动组件,咱们先用一下规范的组件增加办法,如下图:

ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板

当然,这儿仅仅搭建了一个规范的组件框架,咱们得把以前的 sht21 驱动代码仿制到这两个文件中。

2.2 传感器数据传输程序

驱动代码移植好了,咱们要运用起来,这个当地首要便是在于怎样把数据传输出去,在上一篇蓝牙系列的文章ESP-IDF 蓝牙开发 之GATT 数据通信 — 发送自定义数据中咱们做过剖析,咱们怎样传输自定义数据。

所以在那个根底之上我做了如下处理:

case ESP_GATTS_READ_EVT:
            ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_READ_EVT, conn_id %d, trans_id %d, handle %d\n", 
                                    param->read.conn_id, param->read.trans_id, param->read.handle);
            // ESP_LOGI(GATTS_TABLE_TAG, "VAL_B %d\n", heart_rate_handle_table[IDX_CHAR_VAL_B]);
            if(heart_rate_handle_table[IDX_CHAR_VAL_B] == param->read.handle){
                int thread;
                float T = 0;
                float H = 0;
                char th_data[20];
                thread = SHT2X_THMeasure(I2C_MASTER_NUM);
                if(thread == ESP_ERR_TIMEOUT){}
                else{
                    T = (getTemperature()/100.0);
                    H = (getHumidity()/100.0);
                }
                sprintf(th_data,"tem:%.2f , hum:%.2f",T,H);
              esp_ble_gatts_set_attr_value(param->read.handle,sizeof(th_data),(uint8_t*)th_data);
            }
            break;

温湿度的逻辑不是必定得写在这儿,程序任何当地都能够。需求接连读取2才才能正确的读到实时数据。

请看下面详细阐明。

再次阐明: ESP_GATTS_READ_EVT 事情

这儿要先再次阐明一个问题,便是回调函数中断的事情,咱们这个 ESP_GATTS_READ_EVT 事情。

ESP_GATTS_READ_EVT 事情,回调函数的事情,是在事情产生之后。回调函数中的事情都是在事情产生了,才会触发的!

READ 读取的数据不是靠回调函数里边写逻辑给的数据,而是一向存在的 characteristic 的 value 值。 事情仅仅告知你有读事情产生!

改动 characteristic 的 value 值的逻辑,能够在程序中恣意当地修正,手机读取时分只取其时的 characteristic 的 value 值。

对于上一篇文章,有粉丝提过的问题,我这儿放出我的答复:

ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板
.

回到咱们上面给出的代码要留意的当地:

1、 是用上面的办法,需求鄙人一次读取的时分才能读到上一次温湿度的值,假如需求实时数据,能够采取接连读取2次的办法(下文有优化代码);

这个是一个逻辑问题,便是怎样传输实时数据,比如能够另外创立一个使命,不停的周期性读取温湿度数据,放入characteristic 的 value 中。 那么每次 READ 就能够直接读取到最新的 温湿度数据。

2、仍是需求留意示例中 value 的长度不能操作 20 字节(咱们上一篇文章测验的成果);

在上面程序中运用了组合字符串的 sprintf 函数,留意长度不能过长。

2.3 功用测验

咱们完结上述代码,测验一下。

记住增加了新的组件,最好是make clean 一下,这儿便是清除一下编译,重新编译。

烧录测验:

ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板

数据传输成功!

再次阐明这个数据逻辑问题,能够自行处理,我这儿计划读取实时数据时分接连读取2次,取第2次的数据。

2.4 代码优化

本来想着让咱们自己测验的,后来想想这种接连读取2次的确不太稳当,爽性自己改个,横竖简略:

便是新建一个使命,如下图:

ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板

READ 事情中能够声明都不用做:

ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板

本以为没问题,没想到= =!

衔接的时分就出问题了,的确不太了解:

ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板

后来考虑了一下,我直接在手机与设备衔接上了以后再创立使命,断开了之后再删除使命不是挺好的?

所以改了一下使命创立的方位:

在 GATT 回调函数,找到设备衔接上的事情,进行对应的修正(图中有点问题,下文有修正阐明):

ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板

感觉能够,测验一下:

ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板

OK! 第一次便是读到现已更新过的值!

可是上面的代码 仍是有个问题,便是断开链接删除使命的时分会出错,上面犯了一个过错,vTaskDelete() 的参数应该是使命句柄,我在创立使命的时分没有给使命句柄。

详细原因能够检查我的FreeRTOS 博文:

FreeRTOS记载(二、FreeRTOS使命API知道和源码简析)

所以代码仍是得修正一下,如下图:

ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板

ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板
.

到这儿,咱们成功完结了手机经过蓝牙实时读取开发板的温湿度数据!

额定阐明:

这个当地仍是得说一下,我经过创立使命的的办法能够读取实时数据,可是我多次测验下来,有时分仍是会出问题,在衔接的时分有可能重启,可是由于会立即重启康复,所以到不影响运用测验。

还有一个便是设置的 THread 使命栈太小了,后来把使命放到 2048 ,就没有栈溢出的问题。

出问题的情况便是 THread 使命,假如使命时正常创立,然后手动断开,都没有问题,只有在衔接往后,也没有手动断开,过了很长一段时刻可能会呈现。

猜想原因:估量便是在没有正常衔接的时分不应该对 characteristic 的 value 进行修正操作。

三、操控部分

操控部分咱们的方针是经过手机操控板载的 SK6812全彩RGB 灯。

3.1 增加LED驱动组件

首先仍是LED驱动的组件增加,上面咱们延时了经过规范架构办法增加组件,在熟悉组件的根底之上,咱们能够直接把文件仿制过来。

ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板

仿制过来,咱们得做个根底的测验:

详细的运用办法能够检查专栏中的博文《ESP32-C3入门教程 根底篇(五、RMT运用 — 操控 SK6812全彩RGB 灯)》,在这个工程中:

ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板

做个简略的测验,在咱们上面的温湿度读取使命中,切换一下灯的状态:

ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板

上面给出的代码:

1、 一旦手机与开发板建立蓝牙衔接,LED灯红绿蓝三色切换;

这儿其实常识为了测验一下驱动是否正常,可是这儿让我想到,也能够运用一个单独的LED来表明蓝牙衔接状态,无蓝牙衔接一种状态,有蓝牙衔接另一种状态;

2、在 ESP-IDF 中运用 FreeRTOS 的延时函数vTaskDelay,需求得到精准延时,需求加上pdMS_TO_TICKS

习惯了 stm32 中 FreeRTOS 的vTaskDelay 的运用简略在这儿出问题,在上面vTaskDelay(pdMS_TO_TICKS(2000));才是延时2s,假如不加时刻不准确。

3、在上面创立 THread 使命的时分,给的使命栈是 1024 ,可是仍是会有栈溢出,所以这儿根据需求能够适当加大。

测验正常,SK6812 灯驱动增加成功。

3.2 操控 SK6812 程序

驱动增加成功,现在来考虑一下怎样运用蓝牙操控开发板的 SK6812 。

咱们运用了一个 characteristic 来做传感器数据传输,咱们同样能够用一个 characteristic 来做数据接纳,这次咱们运用一个只写的 characteristic :

ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板

经过咱们以前可知,Service 中的 C characteristic 为只写的,并且咱们知道他的句柄为 47。

并且咱们对会回调函数的了解,这个灯的操作咱们能够直接在回调函数中完结,本次首要是为了表达这种办法,所以咱们运用比较简略的操控指令,看代码就知道:

(下图代码有问题,粗枝大叶!)

ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板

上面代码直接运用3字节的指令操控 0xA5 0x03 0x01 打开红灯,其他相似,记住把上面使命中 SK6812 测验代码去掉。

编译烧录测验…… 有问题……:

ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板

这个是由于上面代码粗枝大叶!! 判断符写成了赋值,== 写成了= ,除了这个还有色彩赤色和绿色搞反了,最终修正代码:

case ESP_GATTS_WRITE_EVT:
            if (!param->write.is_prep){
                // the data length of gattc write  must be less than GATTS_DEMO_CHAR_VAL_LEN_MAX.
                ESP_LOGI(GATTS_TABLE_TAG, "GATT_WRITE_EVT, handle = %d, value len = %d, value :", param->write.handle, param->write.len);
                esp_log_buffer_hex(GATTS_TABLE_TAG, param->write.value, param->write.len);
                if(heart_rate_handle_table[IDX_CHAR_VAL_C] == param->write.handle && param->write.len == 3){
                    if((param->write.value[0] == 0xA5)&&(param->write.value[1] == 0x03)&&(param->write.value[2] == 0x01)){
                        ESP_LOGI(GATTS_TABLE_TAG, "SK6812 turn green!!");
                        strip->set_pixel(strip, 0, 255, 0, 0);
                        strip->refresh(strip, 100);
                    }
                    else if((param->write.value[0] == 0xA5)&&(param->write.value[1] == 0x03)&&(param->write.value[2] == 0x02)){
                        ESP_LOGI(GATTS_TABLE_TAG, "SK6812 turn red!!");
                        strip->set_pixel(strip, 0, 0, 255, 0);
                        strip->refresh(strip, 100);
                    }
                    else if((param->write.value[0] == 0xA5)&&(param->write.value[1] == 0x03)&&(param->write.value[2] == 0x03)){
                        ESP_LOGI(GATTS_TABLE_TAG, "SK6812 turn blue!!");
                        strip->set_pixel(strip, 0, 0, 0, 255);
                        strip->refresh(strip, 100);
                    }                 
                }
                // 后边省掉

阐明,上文中的 RGB 对应的方位有点问题,赤色 和 绿色 的值对应方位好像反了,是由于ESP-IDF 驱动中的色彩处理驱动函数是反过来的:

ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板
能够自行改正过来!

实际测验,作用一切正常:

ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板

到这儿,咱们成功完结了手机经过蓝牙操控开发板的 SK6812 LED!

额定阐明:

当然示例仅仅提供了最基本简略的思路,SK6812 是能够多个串联,然后还能支撑调光的,运用蓝牙当然也能够完结。

尽管咱们在示例中,直接在事情中经过判断写入的值来进行操作,可是也要了解,这个写入的值最终是直接写入了这个 characteristic 的 value 中,咱们运用这个 characteristic 的值来改动 SK6812 LED的色彩也是能够的。

3.3 代码优化

本来要结尾了,糟糕完结以后回家路上想了想,我能够发送3个字节,那么我能够直接发送 RGB 的色彩值啊? 这不是正好3个字节代表色彩吗?仍是傻乎乎的自定义指令……

咱们在代码中增加一个分支做操控,由于色彩组成为3个字节,咱们把上面测验用到的操控代码,变成2个字节好做区别,完结代码很简略:

if(heart_rate_handle_table[IDX_CHAR_VAL_C] == param->write.handle ){
         if(param->write.len == 3){
             ESP_LOGI(GATTS_TABLE_TAG, "SK6812 set color!");
             strip->set_pixel(strip, 0, param->write.value[0], param->write.value[1], param->write.value[2]);
             strip->refresh(strip, 100);
         }
         else if(param->write.len == 2){
             if((param->write.value[0] == 0xA5)&&(param->write.value[1] == 0x01)){
                 ESP_LOGI(GATTS_TABLE_TAG, "SK6812 turn green!!");
                 strip->set_pixel(strip, 0, 255, 0, 0);
                 strip->refresh(strip, 100);
             }
             else if((param->write.value[0] == 0xA5)&&(param->write.value[1] == 0x02)){
                 ESP_LOGI(GATTS_TABLE_TAG, "SK6812 turn red!!");
                 strip->set_pixel(strip, 0, 0, 255, 0);
                 strip->refresh(strip, 100);
             }
             else if((param->write.value[0] == 0xA5)&&(param->write.value[1] == 0x03)){
                 ESP_LOGI(GATTS_TABLE_TAG, "SK6812 turn blue!!");
                 strip->set_pixel(strip, 0, 0, 0, 255);
                 strip->refresh(strip, 100);
             }  
         }               
     }

测验下来,好用许多!开发板图就算了,放一下LOG图,想要什么色彩,对着色彩表输入 RGB 值即可:

ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板

四、APP 部分

APP部分,假如要做,至少我想完结的是全色调光,实时的改动 LED 的色彩。这个市面上现已有许多成型的产品和 APP 了。

我这个… java 真实一言难尽,先暂时放置,容我好好想想先 … …

ESP-IDF 蓝牙开发实战 — 传感器数据上传及手机控制开发板

结语(附源码)

本文运用 ESP32-C3 的蓝牙,完结了数据的上传和下行的操控,也算完结咱们最初的小方针了。

本运用一切的代码,只需看过我的博文,各个部分都是有剖析阐明的。

本来想把 app_main.c 源码放出来给咱们仿制,可是一放文章直接显现3W多字,这儿直接给出源码地址吧:

工程源码: 本运用实例代码

从最开端的面对蓝牙的迷茫,到现在完结了一个简略的运用。

披荆斩棘会有时 ,直挂云帆济长海 !