@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的源碼嗎?