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口即可。
在這裡插入圖片描述
^^^^開發板接收數據格式:

包頭 原數據 校驗和 包尾
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);
    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 條評論

發布
問題