> 文档中心 > W800-KIT-蓝牙-温湿度传感器(cht8305c)-RGB灯-demo

W800-KIT-蓝牙-温湿度传感器(cht8305c)-RGB灯-demo

这是目录

  • 一、项目概述
  • 二、工程设计
    • 2.1、蓝牙数据传输
    • 2.2、RGB灯设计
    • 2.3、传感器设计
    • 2.4、数据打包发送
  • 三、测试

蓝牙参考文章:
W801蓝牙收发数据与控制设计(一)-INDICATE
W801蓝牙收发数据与控制设计(二)-NOTIFY方式

本文使用环境:
主控:W800-KIT (开发板,有温湿度就行)
兼容:W800 AIR101
开发环境:CDK

写在前面:
W800-KIT 的温湿度传感器有问题,大概率是传感器的问题。到发稿为止,这个问题依然没有解决。
拿到官方开发板的第一次下载程序之前需要注意:按住boot按键,然后再按回车

一、项目概述

^^^^这篇教程主要关于W800-KIT开发板的基础使用(不包含音频),板载一个温湿度传感器(cht8305c)、一个RGB等,当然还有音频相关,但本文不涉及音频。
^^^^官方给的demo是基于命令行的,我觉得稍微有点麻烦,因此以下所有开发都是基于CDK,同时工程基于前文的w801bt。可以查看前文的bt文章,对于整体的把握有帮助,当然觉得麻烦的大佬,可以直接下载本文的代码,直接read code。本文github地址;
本文涉及到一些知识点,包括C语言,数据收发,根据手册进行程序设计等等。对于新手是非常有帮助的,新手我建议仔细看一下。老手可以忽略

^^^^程序功能: 开发板采集温湿度传感器数据、CPU温度和电压数据并通过蓝牙上传到手机端APP,手机端APP也可以调节开发板RGB灯的亮灭。

二、工程设计

^^^^为了方便大家理解,本节主要将整个项目的分解为三个部分。

2.1、蓝牙数据传输

^^^^通信是项目的基础,因此第一步首先对数据格式进行封装,规定传输的协议,保证数据传输的正确性,同时为下文数据的采集做前期的准备(比如,蓝牙是通过字节进行传输的,而开发板上传的数据为float类型,因此需要对数据进行封装)。

2.1.1、开发板数据接收格式
^^^^查看原理图可知,RGB灯实际是三个led,因此分别使用三个IO口控制,为了实现不同颜色,采用是三个WPM控制三个IO口即可。
在这里插入图片描述
^^^^开发板接收数据格式:

包头 原数据 校验和 包尾
0XA5 3字节(三个灯,一位RGB开关信号,2字节的RGB值) 所有原数据的和 0X5A

^^^^表格中原数据包含三个字节,前一个字节一共八位分别表示:

0 1 2 3 4-7
LED0 LED1 LED2 RGB开关 保留

^^^^后两个字节表示RGB灯的三个IO口的PWM值,为了方便,本文使用类似于RGB555的数据封装,每一个颜色采用5位表示。

0-4 5-9 10-14 15
R G B 保留

2.1.2、开发板数据发送格式
开发板发送数据主要包括:CPU温度(float)、CPU电压(float)、传感器温度(float)、传感器湿度(float)。

^^^^开发板发送数据格式:

包头 原数据 校验和 包尾
0XA5 16字节(cou电压(4)、cpu温度(4)、传感器温度(4)、传感器湿度(4)) 所有原数据的和 0X5A

^^^^注意到这些数据都是float数据,本文蓝牙传输的时候采用的是单字节传输,因此需要将数据进行一下转换。转换使用共同体实现,具体查看下文传感器设计小节。

2.2、RGB灯设计

^^^^RGB灯设计采用了两种方式,单独控制和WPM控制。两种控制需要单独实现,本文主要使用PWM,所以单独控制已经屏蔽了,需要的可以自己打开,重新编译。

^^^^从蓝牙接收的原数据存放在msg[4]数组中:

0 1 2 3
原数据长度 三个LED和RGB开关状态 PWM高八位 PWM低八位

2.2.1、RGB灯单独控制

^^^^单独控制只使用前三位,程序设计如下:

void led_on_off(u8 data){//分别判断每一位数据,注意需要把每一位数据移到最低位进行判断,对应开关灯:00 开  其他数据 关if(data & 0x01 != 0)tls_gpio_write(WM_IO_PB_00,0);elsetls_gpio_write(WM_IO_PB_00,1);if(data >> 1&0x01 != 0)tls_gpio_write(WM_IO_PB_01,0);elsetls_gpio_write(WM_IO_PB_01,1);if(data >> 2&0x01 != 0)tls_gpio_write(WM_IO_PB_02,0);elsetls_gpio_write(WM_IO_PB_02,1);}

注意:在判断时需要单独取出每一位数据,因此需要右移并&0x01,屏蔽到其他位数据。

2.2.2、RGB灯PWM控制

^^^^PWM控制稍微复杂一些,APP发过来的PWM数据是单独的两个字节,因此需要将两个字节的数据合成一个字节。本文采用共同体实现:

typedef union RGB_DATA{u8 rgb_u8[2];    int16 rgb_i;    }RGB_DATA;

注意:简单解释一下这样使用的原理,共同体表示所有的数据都采用相同的地址(取最大的地址为基准),从可以看出,16位的rgb_i和rgb_u8[2]使用相同的内存地址。因此将蓝牙的数据放入rgb_u8的数组中,可以直接从rgb_i读取出合成的16位数据,这种方式可以方便快捷的进行数据转换。当然有人会问?为什么不通过移位操作呢?确实int类型的数据可以通过移位进行处理,但是float类型呢???所以统一采用共同体实现数据的转换。下文的float同样采用这样的方式。
此外,还有一点需要注意,大小端会对数据拼接造成影响,当然一般单片机不用考虑这个问题。

^^^^PWM控制代码如下:

//PWMpwm_demo(0,100000,255,4,0);pwm_demo(1,100000,255,4,0);pwm_demo(2,100000,255,4,0);...void led_pwm_rgb(RGB_DATA rgb_data){tls_pwm_duty_config(0,255 - (u8)(rgb_data.rgb_i>>10 & 0x1f)*8);tls_pwm_duty_config(1,(u8)((rgb_data.rgb_i<<5)>>10 & 0x1f)*8+1);tls_pwm_duty_config(2,255 - (u8)((rgb_data.rgb_i<<10)>>10 & 0x1f)*8);//printf("%d  pwm: %d   %d   %d ",rgb_data.rgb_i,(u8)(rgb_data.rgb_i>>10 & 0x1f)*8,255 - (u8)((rgb_data.rgb_i<>10 & 0x1f)*8,(u8)((rgb_data.rgb_i<>10 & 0x1f)*8);}...//RGB开//第4位数据表示RGB是否打开,可以通过发送数据关闭。if(msg[1]>>3 &0x01 != 0)led_pwm_rgb(rgb_data);else{tls_pwm_duty_config(0,255);tls_pwm_duty_config(1,255);tls_pwm_duty_config(2,255);}

^^^^函数pwm_demo(0,100000,255,4,0)比较坑,和我之前使用的HAL库不一样,浪费了我一个多小时的时间。函数的形参分别表示:通道、频率、duty值和period范围。重点说一下,这个函数的period为0表示持续输出PWM,因此直接写0,duty为占空比的值,在程序中修改duty可以直接改变占空比。函数tls_pwm_duty_config表示修改duty值,第一个参数为通道号,第二个为duty值。范围是0-255。本文使用B0、B1、B2分别对应通道0、1和2。

^^^^pwm参数rgb_data.rgb_i一共是15位有效数据,分别提取出来赋值给RGB,还有一点注意:5位数字只能表示到31,需要对其进行放大,因此R/G/B分别*8其实这个代码可以精简,直接右移然后&0x1f就行,不用左移再右移

2.3、传感器设计

2.3.1、温湿度传感器手册查阅

^^^^第一步查看手册,一般来说手册内容都很多,查看的时候找重点数据查看就行,首先查看目录。
在这里插入图片描述^^^^从上图可以看出,重点的就三个地方,第一个是寄存器相关,第二个是温度测量的步骤,第三个是手册提供的demo。只是读取数据的话,可以直接查看demo,如果有其他的需求,就需要单独查看每一个寄存器的作用,本文不做扩展只读取数据(官方硬件设计固定,无法实现报警等功能)。

查看数据读取步骤:
在这里插入图片描述
^^^^从框选出的文字可以看出,读取数据前不需要进行任何的设置,直接读取0x00寄存器的数据即可,那么接下来就简单了,直接看官方的demo。
在这里插入图片描述
在这里插入图片描述
可以直接按照上图流程进行设计。官方手册有错误,ct8305少写了一个h。
^^^^具体的温湿度转换手册1.1.4小节有说明:
在这里插入图片描述
^^^^手册也给出了IIC的读写执行顺序。如果了解IIC的话,可以直接看图,看图是很明确的。
W800-KIT-蓝牙-温湿度传感器(cht8305c)-RGB灯-demo
图中S表示开始,A表示ACK,Sr表示开始读,NA 表示NACK,P表示停止。具体IIC的协议不再讲解了,网上有很多的资料,可以自己去查看。把图翻译成白话文:开始-写设备地址(0x80)-写寄存器地址-等待20ms-写读设备地址(0x81)-一次读取四个字节的数据-停止。

2.3.2、温湿度传感器数据读取

^^^^温湿度传感器通过IIC进行数据的读取,因此首先需要处理IIC的数据读取和写入。具体代码直接查看源文件把,这里至列举出核心代码。

/** * @briefread multibytes from the specified address of the eeprom * @param[in] dev_addr the dev address  * @param[in] addr the eeprom address will be read from * @param[in] buf Pointer to data buffer * @param[in] lenamount of data to be read * @retval    null */void IIC_ReadLenByte(u8 dev_addr,u16 reg_addr,u8 *buf,u16 len){  //printf("\nread len addr=%x\n",ReadAddr);//1表示开始信号tls_i2c_write_byte(dev_addr,1);   tls_i2c_wait_ack(); tls_i2c_write_byte(reg_addr,0);   tls_i2c_wait_ack(); tls_i2c_stop();tls_os_time_delay(22);  tls_i2c_write_byte(dev_addr|0x01,1);tls_i2c_wait_ack();while(len > 0){*buf++ = tls_i2c_read_byte(1,0);tls_i2c_wait_ack();len --;}tls_i2c_stop();}typedef union CHT_DATA{    u8 cht_i[8];    float cht_f[2];}CHT_DATA;void read_cht8305c_read(CHT_DATA *cht_data){uint16 temp_i = 0;uint16 humi_i = 0;//数据说明:temp_h temp_l humi_h humi_lu8 cht_d[4] = {0};IIC_ReadLenByte(i2c_cht8305c_addr,0x00,cht_d,4);temp_i = (cht_d[0]<<8) + cht_d[1];humi_i = (cht_d[2]<<8) + cht_d[3];cht_data->cht_f[0] = (165*temp_i)/65535.0-40.0;cht_data->cht_f[1] = humi_i/65535.0;cht_data->cht_f[0] = (int)(cht_data->cht_f[0]*100)/100.0;cht_data->cht_f[1] = (int)(cht_data->cht_f[1]*100)/100.0;printf("%f   %f  %x  %x  %x  %x\r\n",cht_data->cht_f[0],cht_data->cht_f[1],cht_d[0],cht_d[1],cht_d[2],cht_d[3]);}

上述代码中dev_addr为0x80。从手册中可以看出,AD0的接线不同,地址会不一样,W800这个开发板直接接地,因此使用第一个地址。(下图的地址不包括读写位,所以只有七位。)
在这里插入图片描述
浮点数据和定点数据依然采用共同体进行数据的转换。

2.3.3、逻辑分析仪测试

^^^^使用逻辑分析仪查看三组数据是否正确:写地址和写寄存器、延时、读数据。

    1. 写地址和写寄存器

在这里插入图片描述
如图所示,终端写设备地址,然后写寄存器地址正常。

    1. 延时20ms

在这里插入图片描述
延时时间正常。

    1. 读数据

在这里插入图片描述
读数据正常。
2.3.4、题外话
^^^^到目前为止。通过分析IIC读写数据都正常,看似一切正常。但是,终端打印出的数据如下
在这里插入图片描述
这数据明显不对啊,这。。。。温度一直都是30左右,湿度倒是会变化,但是这湿度对吗???
我曾经一度怀疑我是不是哪里错了,但是我看过手册,也对标官方的代码试过。都是错误数据,所以我只有怀疑板子的硬件坏了。。。。。同时我也请教过官方,官方也说数据有问题。哈哈哈哈 ,硬件问题不讨论,程序逻辑是按照手册来的。。。。大家重点看思路,掌握学习方法即可。

2.4、数据打包发送

^^^^直接上代码把:

//发送数据的长度:0x5a+data_len+校验+0xa5校验位是有效数据的和不包括帧头和尾部,cpu8字节温湿度8字节bt_send_data_len = 11+8;typedef union ADC_DATA{    u8 adc_i[8];    //包含CPU电压和温度    float adc_f[2];}ADC_DATA;//0xa5(0) 8个数据(1-8) 校验(9) 0x5a(10)..............以下代码不是完成的函数,是部分代码,完整的下载github工程......................//加入头帧send_data[0] = 0xA5;send_data[bt_send_data_len-2] = 0;for(u8 i=0;i<8;i++){//转存cpu电压和温度数据到发送数组send_data[i+1] = adc_data.adc_i[i];//转存温湿度传感器数据到发送数组send_data[i+8+1] = cht_data.cht_i[i];//计算校验和,有效数据之和send_data[bt_send_data_len-2] += adc_data.adc_i[i];send_data[bt_send_data_len-2] += cht_data.cht_i[i];}//加入尾帧send_data[bt_send_data_len-1] = 0x5A;//printf("send state:%d \r\n",tls_ble_server_demo_api_send_msg(send_data,3));tls_ble_server_demo_api_send_notify_msg(send_data,bt_send_data_len);

三、测试

CPU电压、CPU温度、温湿度传感器数据正常。
在这里插入图片描述
开发板正常:打开关闭LED_RGB正常。滑动按钮LED颜色在变化。
在这里插入图片描述