2020征文-鴻蒙開發(fā)板6.WiFi IoT智能家居套件 - 溫度傳感器和OLED實(shí)踐
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
https://harmonyos.51cto.com/#zz
這是一份遲來的文章,代碼寫好幾天了,由于太忙,一直沒來得及上傳。
在開發(fā)板套件中,有一個(gè)OLED屏幕擴(kuò)展板,溫濕度傳感器擴(kuò)展板,本次我們就用這兩個(gè)擴(kuò)展板來實(shí)現(xiàn)一個(gè)簡易數(shù)字溫度計(jì)。初步的打算是做一個(gè)儀表盤,用指針指示溫度和濕度,但是由于OLED只有128*64,因此儀表盤不會(huì)很清晰,我們?cè)谂赃呍儆脭?shù)字直接顯示一下。雖然簡陋一點(diǎn),但是只要原理學(xué)會(huì)了,其他復(fù)雜的儀表盤我們同樣可以做出來。

OLED屏幕為128*64的點(diǎn)陣,通信接口為I2C0,從機(jī)地址為0x3C
溫濕度傳感器AHT20,通信接口也是I2C0,從機(jī)地址為0x38
熟悉I2C的朋友都知道,I2C是多從機(jī)模式,只要從機(jī)地址不同,我們可以掛在同一個(gè)總線下,進(jìn)行復(fù)用。
既然如此,那我們就可以同時(shí)使用這兩個(gè)擴(kuò)展板。
1. OLED驅(qū)動(dòng)
OLED驅(qū)動(dòng)開發(fā)方法,參考許思維老師的代碼 https://gitee.com/hihopeorg/harmonyos-ssd1306
此處不再贅述
2. 溫濕度傳感器AHT20驅(qū)動(dòng)
參考許思維老師的代碼 https://gitee.com/hihopeorg/harmonyos-aht20
此處不再贅述。
3. 畫表盤
由于表盤是半個(gè)圓,而且一般是從9點(diǎn)鐘方向開始,順指針旋轉(zhuǎn),與實(shí)際的溫度值相對(duì)應(yīng),9點(diǎn)鐘對(duì)應(yīng)最小值,3點(diǎn)鐘對(duì)應(yīng)最大值,
因此我們畫表盤的時(shí)候最好從9點(diǎn)鐘對(duì)應(yīng)的角度為0, 12點(diǎn)鐘對(duì)應(yīng)的角度90度,3點(diǎn)鐘對(duì)應(yīng)的角度為180度。
畫表盤就是設(shè)置好圓心(x,y)和半徑r,然后計(jì)算圓周上的兩個(gè)點(diǎn),將相鄰的兩個(gè)點(diǎn)調(diào)用畫直線函數(shù)連接起來。
- /*DrawArc.畫一個(gè)半圓
- * start_angle in degree
- * sweep in degree
- * x,y是圓心的位置
- * radius是半徑
- * start_angle 起始角度,9點(diǎn)鐘作為0角度
- * sweep 掃描角度
- * 從9點(diǎn)鐘開始作為0角度,順時(shí)針旋轉(zhuǎn)
- */
- void ssd1306_DrawArc_from9(uint8_t x, uint8_t y, uint8_t radius, uint16_t start_angle, uint16_t sweep, SSD1306_COLOR color) {
- float approx_degree;
- uint32_t approx_segments;
- uint8_t xp1,xp2;
- uint8_t yp1,yp2;
- uint32_t count = 0;
- uint32_t loc_sweep = 0;
- float rad;
- loc_sweep = ssd1306_NormalizeTo0_360(sweep);
- count = (ssd1306_NormalizeTo0_360(start_angle));
- approx_segments = loc_sweep;
- approx_degree = 1;
- while(count < approx_segments)
- {
- rad = ssd1306_DegToRad(count*approx_degree);
- xp1 = x - (int8_t)(cos(rad)*radius);
- yp1 = y - (int8_t)(sin(rad)*radius);
- count++;
- if(count != approx_segments)
- {
- rad = ssd1306_DegToRad(count*approx_degree);
- }
- else
- {
- rad = ssd1306_DegToRad(loc_sweep);
- }
- xp2 = x - (int8_t)(cos(rad)*radius);
- yp2 = y - (int8_t)(sin(rad)*radius);
- ssd1306_DrawLine(xp1,yp1,xp2,yp2,color);
- }
- return;
- }
4.畫指針
畫指針比較簡單,就是在圓周上找一個(gè)點(diǎn),將這個(gè)點(diǎn)和圓心連接,就變成了一個(gè)指針,改變半徑的大小,就可以實(shí)現(xiàn)指針的長短。
難點(diǎn)是如何將指針的角度和實(shí)際的溫度值對(duì)應(yīng)起來。假設(shè)溫度的范圍為-15攝氏度到45攝氏度,共60攝氏度,則每一個(gè)角度對(duì)應(yīng)的溫度值為60/180;
如果當(dāng)前溫度是20度,則對(duì)應(yīng)的角度為20*60/180度。
- /*
- 畫一條圓心到圓周的直線,實(shí)現(xiàn)指針
- */
- void ssd1306_draw_line_of_arc(uint8_t x, uint8_t y, uint8_t radius, uint16_t angle,SSD1306_COLOR color)
- {
- float approx_degree;
- uint8_t xp1;
- uint8_t yp1;
- uint32_t count = 0;
- float rad;
- count = (ssd1306_NormalizeTo0_360(angle));
- approx_degree = 1;
- rad = ssd1306_DegToRad(count*approx_degree);
- xp1 = x - (int8_t)(cos(rad)*radius);
- yp1 = y - (int8_t)(sin(rad)*radius);
- ssd1306_DrawLine(x, y, xp1, yp1, color);
- }
5. 畫刻度
畫刻度的方法,可以參考上面畫指針的方法,從同一個(gè)角度畫出的直線,與兩個(gè)同圓心不同半徑的圓的交點(diǎn),將這兩個(gè)交點(diǎn)連接起來就是刻度
- /*
- 畫一條刻度線
- */
- void ssd1306_draw_line_of_kedu(uint8_t x, uint8_t y, uint8_t radius, uint16_t angle,SSD1306_COLOR color)
- {
- float approx_degree;
- uint8_t xp1,xp2;
- uint8_t yp1,yp2;
- uint32_t count = 0;
- float rad;
- count = (ssd1306_NormalizeTo0_360(angle));
- approx_degree = 1;
- rad = ssd1306_DegToRad(count*approx_degree);
- xp1 = x - (int8_t)(cos(rad)*radius);
- yp1 = y - (int8_t)(sin(rad)*radius);
- xp2 = x - (int8_t)(cos(rad)*(radius-4));//刻度線的長度為4
- yp2 = y - (int8_t)(sin(rad)*(radius-4));
- ssd1306_DrawLine(xp1, yp1, xp2, yp2, color);
- }
6. 使用上面幾個(gè)函數(shù),畫出我們?cè)O(shè)計(jì)的溫度表
- //更新溫度和濕度
- void ssd1306_update_temper(float temp, float humi)
- {
- int angle = 0;
- char buf[100] = {0};
- ssd1306_Fill(Black);
- uint8_t x,y,r;
- //溫度表盤,半圓形
- x=30;
- y=28;
- r=28;
- ssd1306_DrawCircle(x,y,2,White);
- ssd1306_SetCursor(x-r, y);
- ssd1306_DrawString("-15", Font_6x8, White);
- ssd1306_SetCursor(x+r-6, y);
- ssd1306_DrawString("45", Font_6x8, White);
- ssd1306_SetCursor(x-6, y-r+6);
- ssd1306_DrawString("15", Font_6x8, White);
- ssd1306_DrawArc_from9(x, y, r, 0, 180, White);
- //ssd1306_DrawArc_from9(x, y, r-1, 0, 180, White);
- ssd1306_draw_line_of_kedu(x,y,r,45,White);
- ssd1306_draw_line_of_kedu(x,y,r,90,White);
- ssd1306_draw_line_of_kedu(x,y,r,135,White);
- angle = (int)((temp + 15 )*180/60);
- ssd1306_draw_line_of_arc(x, y, r-2,angle, White);
- ssd1306_SetCursor(x+r+6, y-r/2);
- sprintf(buf, "%.1fC", temp);
- ssd1306_DrawString(buf, Font_7x10, White);
- //濕度表盤,半圓形
- x=30;
- y=55;
- r=22;
- ssd1306_DrawCircle(x,y,2,White);
- ssd1306_SetCursor(x-r-4, y);
- ssd1306_DrawString("20", Font_6x8, White);
- ssd1306_SetCursor(x+r-6, y);
- ssd1306_DrawString("100", Font_6x8, White);
- ssd1306_SetCursor(x-6, y-r+6);
- ssd1306_DrawString("60", Font_6x8, White);
- ssd1306_DrawArc_from9(x, y, r, 0, 180, White);
- //ssd1306_DrawArc_from9(x, y, r-1, 0, 180, White);
- ssd1306_draw_line_of_kedu(x,y,r,45,White);
- ssd1306_draw_line_of_kedu(x,y,r,90,White);
- ssd1306_draw_line_of_kedu(x,y,r,135,White);
- angle = (int)((humi - 20 )*180/80);
- ssd1306_draw_line_of_arc(x, y, r-2,angle, White);
- ssd1306_SetCursor(x+r+6, y-r/2);
- sprintf(buf, "%%%.1f", humi);
- ssd1306_DrawString(buf, Font_7x10, White);
- //ssd1306_TestArc();
- ssd1306_UpdateScreen();
- }
7. I2C管腳的初始化和任務(wù)初始化
- void Ssd1306TestTask(void* arg)
- {
- (void) arg;
- uint32_t retval = 0;
- GpioInit();
- IoSetFunc(WIFI_IOT_IO_NAME_GPIO_13, WIFI_IOT_IO_FUNC_GPIO_13_I2C0_SDA);
- IoSetFunc(WIFI_IOT_IO_NAME_GPIO_14, WIFI_IOT_IO_FUNC_GPIO_14_I2C0_SCL);
- I2cInit(WIFI_IOT_I2C_IDX_0, OLED_I2C_BAUDRATE);
- WatchDogDisable();
- usleep(20*1000);
- ssd1306_Init();
- ssd1306_Fill(Black);
- ssd1306_SetCursor(0, 0);
- ssd1306_DrawString("Hello HarmonyOS!", Font_7x10, White);
- uint32_t start = HAL_GetTick();
- ssd1306_UpdateScreen();
- uint32_t end = HAL_GetTick();
- printf("ssd1306_UpdateScreen time cost: %d ms.\r\n", end - start);
- //
- retval = AHT20_Calibrate();
- printf("AHT20_Calibrate: %d\r\n", retval);
- TestGetTick();
- while (1) {
- float temp = 0.0, humi = 0.0;
- //retval = AHT20_StartMeasure();
- //printf("AHT20_StartMeasure: %d\r\n", retval);
- retval = AHT20_GetTemperHumi(&temp, &humi);
- printf("AHT20_GetMeasureResult: %d, temp = %.2f, humi = %.2f\r\n", retval, temp, humi);
- ssd1306_update_temper(temp, humi);
- sleep(1);
- //ssd1306_TestAll();
- }
- }
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
https://harmonyos.51cto.com/#zz