@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灯的亮灭。
^^^^为了方便大家理解,本节主要将整个项目的分解为三个部分。
^^^^通信是项目的基础,因此第一步首先对数据格式进行封装,规定传输的协议,保证数据传输的正确性,同时为下文数据的采集做前期的准备(比如,蓝牙是通过字节进行传输的,而开发板上传的数据为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数据,本文蓝牙传输的时候采用的是单字节传输,因此需要将数据进行一下转换。转换使用共同体实现,具体查看下文传感器设计小节。
^^^^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);
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.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、逻辑分析仪测试
^^^^使用逻辑分析仪查看三组数据是否正确:写地址和写寄存器、延时、读数据。
如图所示,终端写设备地址,然后写寄存器地址正常。
延时时间正常。
读数据正常。
2.3.4、题外话
^^^^到目前为止。通过分析IIC读写数据都正常,看似一切正常。==但是,终端打印出的数据如下==:
==这数据明显不对啊,这。。。。温度一直都是30左右,湿度倒是会变化,但是这湿度对吗???==
我曾经一度怀疑我是不是哪里错了,但是我看过手册,也对标官方的代码试过。都是错误数据,所以我只有怀疑板子的硬件坏了。。。。。同时我也请教过官方,官方也说数据有问题。哈哈哈哈 ,硬件问题不讨论,程序逻辑是按照手册来的。。。。大家重点看思路,掌握学习方法即可。
^^^^直接上代码把:
//发送数据的长度: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颜色在变化。
这么好的东西,先点赞收藏,再评论!厉害!
请问,能找到android的源码吗?