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

发布于 2022-04-15 16:49:16

@TOC

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

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

==写在前面:==
W800-KIT 的温湿度传感器有问题,大概率是传感器的问题。到发稿为止,这个问题依然没有解决。

一、项目概述

^^^^这篇教程主要关于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口即可。
在这里插入图片描述
^^^^开发板接收数据格式:

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

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

01234-7
LED0LED1LED2RGB开关保留

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

0-45-910-1415
RGB保留

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

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

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

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

2.2、RGB灯设计

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

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

0123
原数据长度三个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);
    else
        tls_gpio_write(WM_IO_PB_00,1);
    if(data >> 1&0x01 != 0)
        tls_gpio_write(WM_IO_PB_01,0);
    else
        tls_gpio_write(WM_IO_PB_01,1);
    if(data >> 2&0x01 != 0)
        tls_gpio_write(WM_IO_PB_02,0);
    else
        tls_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控制代码如下:


//PWM
pwm_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<<5)>>10 & 0x1f)*8,(u8)((rgb_data.rgb_i<<10)>>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的话,可以直接看图,看图是很明确的。
在这里插入图片描述
图中S表示开始,A表示ACK,Sr表示开始读,NA 表示NACK,P表示停止。具体IIC的协议不再讲解了,网上有很多的资料,可以自己去查看。把图翻译成白话文:开始-写设备地址(0x80)-写寄存器地址-等待20ms-写读设备地址(0x81)-一次读取四个字节的数据-停止。

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

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

/**
 * @brief    read 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] len    amount 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_l
    u8 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颜色在变化。
在这里插入图片描述

3 条评论

发布
问题