ESP32-C3 蓝牙部分我们学习了GATT,本文尝试使用蓝牙做一个简单的小应用。
目录
前面文章说过,蓝牙协议博主了解不是很深入,只进行一些基础的了解,示例的测试,和初学者一样,基本上蓝牙专栏系列博文都是一步一步摸索过来的,功夫不负有心人,到目前为止,多多少少对蓝牙 GATT 有了一定的认识。
那么我们今天就要学以致用,使用 ESP32-C3 的蓝牙 GATT,做一个数据通信的应用实例。
与本实例相关的 ESP32-C3 专栏系列博文如下:
ESP32-C3 入门专栏目录:【导航】ESP32-C3 入门教程目录 【快速跳转】
❤️
ESP32-C3学习 蓝牙 篇系列博文连接:❤️
测试使用的开发板:
自己画一块ESP32-C3 的开发板(第一次使用立创EDA)(PCB到手)❤️
测试使用的开发环境:
ESP32-C3 VScode开发环境搭建(基于乐鑫官方ESP-IDF——Windows和Ubuntu双环境)
❤️
蓝牙篇系列相关博文:
ESP32-C3 学习测试 蓝牙 篇(一、认识 ESP-IDF 的蓝牙框架、简单的了解蓝牙协议栈)
ESP32-C3 学习测试 蓝牙 篇(二、蓝牙调试APP、开发板手机连接初体验)
ESP32-C3 学习测试 蓝牙 篇(三、认识蓝牙 GATT 协议)
ESP32-C3 学习测试 蓝牙 篇(四、GATT Server 示例解析)
ESP32-C3 学习测试 蓝牙 篇(五、添加 characteristic)
ESP32-C3 学习测试 蓝牙 篇(六、添加 Service)
ESP32-C3 学习测试 蓝牙 篇(七、GATT 数据通信 — 发送自定义数据)
❤️
本应用涉及的博文除了上面之外还有:
ESP-IDF工程结构说明:
认识 ESP-IDF-v4.3+工程结构(ESP32-C3应用调整示例)
设备和传感器驱动:
ESP32-C3入门教程 基础篇(四、I2C总线 — 与SHT21温湿度传感器通讯)
ESP32-C3入门教程 基础篇(五、RMT应用 — 控制 SK6812全彩RGB 灯)
整个实例功能还是比较简单的,毕竟我们也刚接触 ESP32-C3 的蓝牙,直接用下图表示:

.
安卓手机 APP 我得考虑一下 ,因为我是 java 小白,虽然照猫画虎做过APP, 有时间当然搞起来没问题,但是得花些时间,而博主最近时间不太够用…… 所以这个,再看把 = =!
废话不多说,我们直接开始……
先实现把传感器数据上传至手机的部分功能。
在我的博文 认识 ESP-IDF-v4.3+工程结构(ESP32-C3应用调整示例)中提到过,如何调整一个工程以及如何添加自己的组件代码,我们按照步骤先把需要的组件添加。
组件的添加,我们如果熟悉工程架构,可以直接把文件夹复制到工程中,那我们温湿度驱动组件,我们先用一下标准的组件添加方式,如下图:

当然,这里只是搭建了一个标准的组件框架,我们得把以前的 sht21 驱动代码复制到这两个文件中。
驱动代码移植好了,我们要使用起来,这个地方主要就是在于怎么把数据传输出去,在蓝牙系列的文章ESP32-C3 学习测试 蓝牙 篇(七、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 事件,回调函数的事件,是在事件发生之后。回调函数中的事件都是在事件发生了,才会触发的!
READ 读取的数据不是靠回调函数里面写逻辑给的数据,而是一直存在的 characteristic 的 value 值。 事件只是告诉你有读事件发生!
改变 characteristic 的 value 值的逻辑,可以在程序中任意地方修改,手机读取时候只取当时的 characteristic 的 value 值。
在上一篇博文

.
回到我们上面给出的代码要注意的地方:
1、 是用上面的方式,需要在下一次读取的时候才能读到上一次温湿度的值,如果需要实时数据,可以采取连续读取2次的方式(下文有优化代码);
这个是一个逻辑问题,就是如何传输实时数据,比如可以另外创建一个任务,不停的周期性读取温湿度数据,放入characteristic 的 value 中。 那么每次 READ 就可以直接读取到最新的 温湿度数据。
2、还是需要注意示例中 value 的长度不能操作 20 字节(我们上一篇文章测试的结果);
在上面程序中使用了组合字符串的 sprintf 函数,注意长度不能过长。
我们完成上述代码,测试一下。
记得添加了新的组件,最好是make clean 一下,这里就是清除一下编译,重新编译。
烧录测试:

数据传输成功!
再次说明这个数据逻辑问题,可以自行处理,我这里计划读取实时数据时候连续读取2次,取第2次的数据。
本来想着让大家自己测试的,后来想想这种连续读取2次确实不太妥当,干脆自己改个,反正简单:
就是新建一个任务,如下图:

READ 事件中可以声明都不用做:

本以为没问题,没想到= =!
连接的时候就出问题了,确实不太明白:

后来考虑了一下,我直接在手机与设备连接上了以后再创建任务,断开了之后再删除任务不是挺好的?
于是改了一下任务创建的位置:
在 GATT 回调函数,找到设备连接上的事件,进行对应的修改(图中有点问题,下文有修改说明):

感觉可以,测试一下:

OK! 第一次就是读到已经更新过的值!
但是上面的代码 还是有个问题,就是断开链接删除任务的时候会出错,上面犯了一个错误,vTaskDelete() 的参数应该是任务句柄,我在创建任务的时候没有给任务句柄。
具体原因可以查看我的FreeRTOS 博文:
FreeRTOS记录(二、FreeRTOS任务API认识和源码简析)
所以代码还是得修改一下,如下图:


.
❤️ 到这里,我们成功实现了手机通过蓝牙实时读取开发板的温湿度数据!
额外说明:
这个地方还是得说一下,我通过创建任务的的方式可以读取实时数据,但是我多次测试下来,有时候还是会出问题,在连接的时候有可能重启,但是因为会立即重启恢复,所以到不影响使用测试。
还有一个就是设置的 THread 任务栈太小了,后来把任务放到 2048 ,就没有栈溢出的问题。
出问题的情况就是 THread 任务,如果任务时正常创建,然后手动断开,都没有问题,只有在连接过后,也没有手动断开,过了很长一段时间可能会出现。
猜测原因:估计就是在没有正常连接的时候不应该对 characteristic 的 value 进行修改操作(后面知道原因再来更新说明)。
控制部分我们的目标是通过手机控制板载的 SK6812全彩RGB 灯。
首先还是LED驱动的组件添加,上面我们延时了通过标准架构方式添加组件,在熟悉组件的基础之上,我们可以直接把文件复制过来。

复制过来,我们得做个基础的测试:
具体的使用方式可以查看专栏中的博文《ESP32-C3入门教程 基础篇(五、RMT应用 — 控制 SK6812全彩RGB 灯)》,在这个工程中:

做个简单的测试,在我们上面的温湿度读取任务中,切换一下灯的状态:

上面给出的代码:
1、 一旦手机与开发板建立蓝牙连接,LED灯红绿蓝三色切换;
这里其实知识为了测试一下驱动是否正常,但是这里让我想到,也可以使用一个单独的LED来表示蓝牙连接状态,无蓝牙连接一种状态,有蓝牙连接另一种状态;
2、在 ESP-IDF 中使用 FreeRTOS 的延时函数vTaskDelay,需要得到精准延时,需要加上pdMS_TO_TICKS。
习惯了 stm32 中 FreeRTOS 的vTaskDelay 的使用容易在这里出问题,在上面vTaskDelay(pdMS_TO_TICKS(2000));才是延时2s,如果不加时间不准确。
3、在上面创建 THread 任务的时候,给的任务栈是 1024 ,但是还是会有栈溢出,所以这里根据需要可以适当加大。
测试正常,SK6812 灯驱动添加成功。
驱动添加成功,现在来考虑一下如何使用蓝牙控制开发板的 SK6812 。
我们使用了一个 characteristic 来做传感器数据传输,我们同样可以用一个 characteristic 来做数据接收,这次我们使用一个只写的 characteristic :

通过我们以前可知,Service 中的 C characteristic 为只写的,而且我们知道他的句柄为 47。
而且我们对会回调函数的理解,这个灯的操作我们可以直接在回调函数中实现,本次主要是为了表达这种方法,所以我们使用比较简单的控制指令,看代码就知道:
(下图代码有问题,粗心大意!)

上面代码直接使用3字节的指令控制 0xA5 0x03 0x01 打开红灯,其他类似,记得把上面任务中 SK6812 测试代码去掉。
编译烧录测试…… ,我擦,有问题……:

这个是因为上面代码粗心大意!! 判断符写成了赋值,== 写成了= ,除了这个还有颜色红色和绿色搞反了,最后修改代码:
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 驱动中的颜色处理驱动函数是反过来的:

可以自行改正过来!
实际测试,效果一切正常:

❤️ 到这里,我们成功实现了手机通过蓝牙控制开发板的 SK6812 LED!
额外说明:
当然示例只是提供了最基本简单的思路,SK6812 是可以多个串联,然后还能支持调光的,使用蓝牙当然也可以实现。
虽然我们在示例中,直接在事件中通过判断写入的值来进行操作,但是也要明白,这个写入的值最后是直接写入了这个 characteristic 的 value 中,我们使用这个 characteristic 的值来改变 SK6812 LED的颜色也是可以的。
本来要结尾了,糟糕完成以后回家路上想了想,我可以发送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 值即可:

APP部分,如果要做,至少我想实现的是全色调光,实时的改变 LED 的颜色。这个市面上已经有许多成型的产品和 APP 了。
我这个… java 实在一言难尽,先暂时搁置,容我好好想想先 … …

本文使用 ESP32-C3 的蓝牙,实现了数据的上传和下行的控制,也算完成我们最初的小目标了。
我这里把本应用上传至资源备份: 本应用实例代码
本应用所有的代码,只要看过我的博文,各个部分都是有分析说明的,没有必要特意去下载。
本来想把 app_main.c 源码放出来给大家复制,但是一放文章直接显示3W多字,系统提示建议修改,怕影响文章曝光度, 就不放了, = =! 大家根据文中的图片自己敲吧……,好像也没多少,文章还是放了修改的部分代码的!
❤️
从最开始的面对蓝牙的迷茫,到现在实现了一个简单的应用。
乘风破浪会有时 ,直挂云帆济长海 !
❤️
其实做自媒体的成本并不高,入门只需要一部手机即可!在手机上找视频素材、使用手机剪辑视频、最后使用手机发布视频作品获得收益!方法并不难,今天这期内容就来给粉丝们分享一种小方法,每天稳定收益100-300,抓紧点赞收藏!1、找素材(1)使用手机拍摄自己喜欢的经典段落,使用程序把文案内容提取出来(2)也可以在豆瓣、知乎、微博等网站中找一些自己需要的文案素材(3)把文案进行润色修改,可以加入一些自己的观点(4)视频素材可以使用软件中自带的素材,也可以在素材网站中下载完整版的素材2、文案配音(1)把复制好的文案直接导入小程序中(2)调整音色、音调后一键合成音频即可(3)可以选择自己朗读配音,需要花一点时
文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,
说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时
手机访问电脑后AnyViewer可以做什么? 您成功将手机连接到Windows电脑后,然后您可以做任何您想做的事情,例如:查看文件和运行应用程序。电源管理:在远程会话中,点击电源管理,您可以看到三个项目:锁定、重启和关机,供您在不同情况下管理计算机。如果您需要暂时离开远程会话,可以锁定计算机。如果计算机死机,您可以重新启动它,然后再次连接。如果您已完成计算机上的所有工作,您可以使用手机远程关闭它。更改图像质量:当电脑和手机的网络都处于良好状态时,您可以选择高图像质量以获得更好的体验。当网络状况不佳时,您可以选择低图像质量以获得更流畅的操作。 显示桌面:我们无法在手机上按Windows+
恢复出厂设置后数据还在吗?格式化真的彻底吗?数据到底该怎么删?文章目录前言为什么不能彻底删除数据?手机如何彻底删除数据?第一步:恢复出厂设置第二步:手动覆写数据电脑如何彻底删除数据?方法一:命令提示符方法二:文件粉碎方法三:低级格式化硬盘总结前言个人数据安全再次成为大家关注的热门话题:在日常使用手机和电脑时,我们可能需要删除一些敏感数据,例如银行账户信息、个人照片、聊天记录等。数据删除的目的是保护个人隐私,避免泄露。以下是一些关于如何删除数据的方法。恢复出厂设置,不一定彻底清除手机数据电子产品迭代升级速度越来越快,大家家中的旧手机、旧电脑也越来越多,一键删除、格式化、恢复出厂设置能彻底清除个人
目录一、ESP32简单介绍二、ESP32Wi-Fi模块介绍三、ESP32Wi-Fi编程模型四、ESP32Wi-Fi事件处理流程 五、ESP32Wi-Fi开发环境六、ESP32Wi-Fi具体代码七、ESP32Wi-Fi代码解读6.1主程序app_main7.2自定义代码wifi_init_sta()八、ESP32Wi-Fi连接验证8.1测试方法8.2服务器模拟工具sscom58.3测试代码8.4测试结果前言为了开发一款亚马逊物联网产品,开始入手ESP32模块。为了能够记录自己的学习过程,特记录如下操作过程。一、ESP32简单介绍ESP32是一套Wi-Fi(2.4GHz)和蓝牙(4.2)双模解决方
运行有问题或需要源码请点赞关注收藏后评论区留言一、利用ContentResolver读写联系人在实际开发中,普通App很少会开放数据接口给其他应用访问。内容组件能够派上用场的情况往往是App想要访问系统应用的通讯数据,比如查看联系人,短信,通话记录等等,以及对这些通讯数据及逆行增删改查。首先要给AndroidMaifest.xml中添加响应的权限配置 下面是往手机通讯录添加联系人信息的例子效果如下分成三个步骤先查出联系人的基本信息,然后查询联系人号码,再查询联系人邮箱代码 ContactAddActivity类packagecom.example.chapter07;importandroid
解析数据 进入阿里云的IOTStdio,点击新建项目。 新建项目后点击新建Web应用。名称 应用名称随便填写 创建完成后我们进入应用。 在左侧组件处拖入一个指示灯和一个开关。 点击指示灯组件,点击配置数据源 选择我们的产品、数据、和属性。 我们还可以配置开和关的显示颜色。 点击按钮,配置交互动作。 选择设备和属性,设置值位置点击数据来源,选择组件值 配置完成后进入预览,点击按钮,在esp8266就会收到来自平台的json格式的数据,MCU端需要做的就是解析来自平台的数据,进而达到控制下
快捷目录前言一、涉及到的相关技术简介二、具体实现过程及踩坑杂谈1.安卓手机改造成linux系统实现方案2.改造后的手机Linux中软件的安装3.手机Linux中安装MySQL5.7踩坑实录4.手机Linux中安装软件的正确方法三、Linux服务器部署前后端分离项目流程1.前提准备(安装必要软件,搭建环境):2.前后端分离项目的详细部署过程:总结前言总体概述:本篇文章隶属于“手机改造服务器部署前后端分离项目”系列专栏,该专栏将分多个板块,每个板块独立成篇来详细记录:手机(安卓)改造成个人服务器(Linux)、Linux中安装软件、配置开发环境、部署JAVA+VUE+MySQL5.7前后端分离项目
ESP32学习笔记(七)复位和时钟目录:ESP32学习笔记(一)芯片型号介绍ESP32学习笔记(二)开发环境搭建VSCode+platformioESP32学习笔记(三)硬件资源介绍ESP32学习笔记(四)串口通信ESP32学习笔记(五)外部中断ESP32学习笔记(六)定时器ESP32学习笔记(七)复位和时钟1.复位2.系统时钟2.1时钟树2.2时钟源从时钟树可以看出时钟源共七种ESP32的时钟源分别来自外部晶振、内部PLL或振荡电路具体地说,这些时钟源为:2.2.1快速时钟PLL_CLK320MHz或480MHz内部PLL时钟XTL_CLK2~40MHz外部晶振时钟,模组板载的是40MHz晶