
實驗整體介紹
背景
光照傳感器用于檢測光照強度,其工作原理是将檢測光照強度值并将其轉化為電壓值,目前在智能家居,智慧城市,智慧農業,智慧工廠等物聯網領域被大量使用。
本實驗的主要結果是通過I2C總線控制光強度傳感器AP3216C對環境光強度及物體接近情況進行測量并擷取環境光強度及是否有物體靠近,然後通過OLED顯示屏将讀取到的光強度、接近程度、紅外資訊顯示在HaaS EDU K1的螢幕上。
HaaS EDU K1搭載了豐富實用的傳感器,開發者可以使用這些傳感器針對實際場景需求開發自己的應用。
涉及的知識點
- AP3216C光照與接近傳感器原理
- OLED繪圖
開發環境準備
硬體
開發用電腦一台
HAAS EDU K1 開發闆一塊
USB2TypeC 資料線一根
- 1
- 2
- 3
軟體
AliOS Things開發環境搭建
開發環境的搭建請參考 @ref HaaS_EDU_K1_Quick_Start (搭建開發環境章節),其中詳細的介紹了AliOS Things 3.3的IDE內建開發環境的搭建流程。
HaaS EDU K1 DEMO 代碼下載下傳
HaaS EDU K1 DEMO 的代碼下載下傳請參考 @ref HaaS_EDU_K1_Quick_Start (建立工程章節),其中,
選擇解決方案: 基于教育開發闆的示例
選擇開發闆: haaseduk1 board configure
代碼編譯、燒錄
參考 @ref HaaS_EDU_K1_Quick_Start (3.1 編譯工程章節),點選 ✅ 即可完成編譯固件。
參考 @ref HaaS_EDU_K1_Quick_Start (3.2 燒錄鏡像章節),點選 "⚡️" 即可完成燒錄固件。
上手把玩
實驗運作結果如下:
- 室内自然燈光下:
- 用手機閃光燈照射螢幕上方的透明孔位
- 螢幕前沒有遮擋情況下
- 拿物體靠近螢幕上方的透明孔位
實際應用場景(産品)介紹
目前光強度傳感器及接近傳感器在以下日常生活、工業生産等環境中都有非常廣泛的應用。
- 家庭智能燈系統
- 檢測到光強度低于一定亮度之後,觸發信号控制客廳自動開燈
- 檢測到光強度低于一定亮度之後,有人體靠近則自動打開夜燈/燈帶
- 智能路燈
- 智慧路燈安裝光強度傳感器後可以自動的感覺環境強度,進而做到智能開關,保證交通安全的同時節省了系統能源
- 智能手機/平闆/電視等
- 智能手機、平闆、電視等消費類電子需要感覺環境光溫度并根據環境光溫度自動調節螢幕亮度,給使用者最佳的視覺體驗的同時也降低了系統的功耗
- 智能手機上都存在的距離傳感器還可以在通話過程中檢測到聽筒靠近頭部的時候自動熄滅螢幕,防止誤觸碰
- 智能手機還會用距離傳感器與其它感應器實作反轉手機靜音及解鎖/鎖屏等操作
這些是我們日常生活中最常見的幾個應用場景。
光強度傳感器是一種光電傳感器,光電傳感器擁有更廣泛的應用範圍,比如煙霧報警系統、工廠煙塵檢測系統、條形碼掃描器、産品計數器、轉速檢測系統等等。
硬體介紹
電路原理圖
AP3216晶片位于螢幕上方,是通過OLED擴充接口和HaaS EDU K1主機闆連接配接,最終連接配接到HaaS1000的I2C1通道。
AP3216C傳感器
AP3216C外觀
AP3216C晶片特性
- 7-bit位址模式,位址:0x1E
- 支援I2C接口Fast Mode (400kbps)
- 支援多種連續測量/單次測量及光強度、接近名額單獨測試及組合測試
- 内置溫度補償電路
- 工作溫度範圍:-30°C到+80°C
-
光強度傳感器
16-bit有效線性輸出
4種動态可選範圍
-
接近傳感器
10-bit有效線性輸出
AP3216C内部框圖
AP3216C主要包含如下幾部分。
- 光亮度敏感元件
- 接近度敏感元件
- ADC數模轉換子產品
- 内部邏輯控制電路(包含條件觸發中斷功能)
- I2C總線控制器
- 紅外LED發射二極管
AP3216C工作模式
根據AP3216C的datasheet說明,在正常工作時,它共有3種工作模式:
-
ALS模式
在這種模式下,AP3216C隻對光強度進行量測
-
PS+IR模式
在這種模式下,AP3216C隻對接近程度進行量測
-
ALS+PS+IR模式
在這種模式下,AP3216C會同時對光強度及接近程度進行量測
三種模式均支援單次量測也支援循環量測,其量測穩定時間如下:
AP3216C中斷模式
AP3216C提供中斷檢測功能,MCU可以設定ALS及PS中斷觸發門限及持續時間門檻值。在環境亮度及接近程度到達門限值後持續時間超出持續時間門檻值之後,會向INT管腳發送中斷通知MCU進行處理。
本案例中未使用中斷模式。
AP3216C工作流程
AP3216C的典型工作流程如下:
對AP3226C進行複位之後,設定工作模式(連續/單次測量,ALS/PS/IR組合設定),之後等待硬體測量穩定時間,再發起讀取測量值的過程。
其中,複位及模式設定是對AP3216C的System Configuration寄存器進行操作,datasheet中對System Configuration寄存器定義及描述如下:
-
複位操作
參考datasheet的描述,是通過I2C 向位址為0x00的寄存器寫入0x4 (對應二進制的100)。
-
模式設定
ALS only連續測量模式:是通過I2C 向位址為0x00的寄存器寫入0x4 (對應二進制的100)。
PS/IR only連續測量模式:是通過I2C 向位址為0x00的寄存器寫入0x1 (對應二進制的001)。
ALS+PS/IR連續測量模式:是通過I2C 向位址為0x00的寄存器寫入0x2 (對應二進制的010)。
ALS only單次測量模式:是通過I2C 向位址為0x00的寄存器寫入0x5 (對應二進制的101)。
PS/IR only單次測量模式:是通過I2C 向位址為0x00的寄存器寫入0x6 (對應二進制的110)。
ALS+PS/IR單次測量模式:是通過I2C 向位址為0x00的寄存器寫入0x7 (對應二進制的111)。
-
讀取測量結果
ALS、PS、IR值可以通過如下寄存器的值來擷取。寄存器位址及所讀取數值詳細解析方法請參考下表:
ALS光強度解析
通過讀取ALS資料寄存器(0x0C和0x0D)得到16bit的ADC count資料之後,需要根據ALS Configuration寄存器的ALS Gain欄位将ADC count資料根據晶片手冊的說明轉換成以lux為機關的亮度值。如下圖所示:
PS/IR資料解析
PS Data寄存器詳細定義如下:
- PS 有效位數為10bit。
- OBJ bit在有物體靠近的時候被設定成1,否則設定為0。
- IR_OF bit被設定成1代表PS值無效(高強度紅外光的情況下會出現)
IR資料有效位數同樣為10bit,也有一個IR_OF來辨別IR/PS資料是否有效。
AP3216C判斷物體靠近和遠離的動作是通過兩組PS 高低門檻值寄存器和PS Data寄存器進行比對,PS Data高于PS High Threshold之後,則判定為物體遠離;PS Data低于PS Low Threshold之後,則視為物體靠近。
- PS Low Threshold計算方法:Value(Reg_0x2B) * 4 + Value(Reg_0x2A)
- PS High Threshold計算方法:Value(Reg_0x2D) * 4 + Value(Reg_0x2C)
PS中斷模式說明
在開啟了AP3216C的中斷模式,為了避免靠近物體抖動帶來頻繁觸發中斷的情況,在PS Data高于PS High Threashold或低于PS Low Threshold之後,需要等待一個PS persist時間,如果PS persist時間之内,PS Data狀态沒有發生變化,則觸發中斷。
PS Persist的時間可以通過配置PS Configuration寄存器的bit 0:1。
I2C總線技術
HaaS EDU K1上AP3216C和HaaS1000通過I2C1接口進行通信。
I2C總線是飛利浦公司在80年代為了讓CPU可以連接配接低速周邊裝置而設計的。外接傳感器是I2C總線最典型的應用場景。目前I2C Spec已經發展到了6.0版本。可以通過https://www.nxp.com.cn/docs/en/user-guide/UM10204.pdf 進行下載下傳
I2C采用多主從結構,I2C主裝置基于位址對I2C從裝置進行尋址,采用8-bit資料傳輸模式,支援7-bit/10-bit位址模式。I2C總線對I2C傳輸開始/結束/資料傳輸/ACK機制/時鐘同步/沖突仲裁等進行了詳細的定義。這裡就不再贅述。
軟體介紹
HaaS EDU K1的edk_demo 應用程式中包含多個應用案例,所有的案例軟體設計都遵循HaaS EDK應用架構的設計思想。其設計思想可以參考“HaaS EDK主系統架構”中的“添加新應用”小節的說明。
簡單來說,所有的子應用頁面都需要實作MENU_TYP結構體。
光照資訊屏應用代碼位于:solutions/eduk1_demo/k1_apps/lightmeter/lightmeter.c中。
MENU_TYP lightmeter = {
"lightmeter",
&lightmeter_cover,
&lightmeter_tasks,
NULL,
&lightmeter_child_list};
- 4
- 5
- 6
在HaaS EDU K1上電之後,按K1或K2鍵左右切換應用的時候,如果切換到光照資訊屏頁面再到退出該頁面的過程中,lightmeter下面的API會依此被呼叫:
- lightmeter_init
- lightmeter_uninit
軟體流程
軟體流程圖如下所示。
在進入光照資訊屏頁面後,啟動名為lightmeter_task的task,周期性的讀取ALS/PS/IR資料并判斷物體靠近标志之後将相關資料按照一定的規則列印到OLED螢幕上。
代碼實作
光照資訊屏頁面
代碼位置:solutions/eduk1_demo/k1_apps/lightmeter/lightmeter.c
詳細代碼及注釋如下:
#include <stdio.h>
#include <stdlib.h>
#include "lightmeter.h"
#include "aos/kernel.h"
#include "ap3216c.h"
/* 按照主程式架構的規則,聲明頁面相關相關資訊(封面、初始化、反初始化、子頁面等)*/
MENU_COVER_TYP lightmeter_cover = {MENU_COVER_NONE};
MENU_TASK_TYP lightmeter_tasks = {
lightmeter_init,
lightmeter_uninit};
MENU_LIST_TYP lightmeter_child_list = {NULL, 0};
MENU_TYP lightmeter = {
"lightmeter",
&lightmeter_cover,
&lightmeter_tasks,
NULL,
&lightmeter_child_list};
/* 頁面初始化函數 */
int lightmeter_init(void)
{
printf("lightmeter_init begin\n");
/* AP3216C 初始化函數 */
ap3216c_init();
printf("lightmeter_init done\n");
/* 清空OLED螢幕 */
OLED_Clear();
OLED_Refresh_GRAM();
/* 啟動光照資訊屏主任務 */
aos_task_new("lightmeter_task", lightmeter_task, NULL, 1000);
printf("aos_task_new lightmeter_task \n");
return 0;
}
void lightmeter_task(void)
{
uint16_t tmp[3];
uint8_t als[20];
uint8_t ps[20];
uint8_t ir[20];
while (1)
{
/* 從AP3216C讀取ALS、PS、IR資料 */
tmp[0] = ap3216c_read_ambient_light();
tmp[1] = ap3216c_read_ir_data();
tmp[2] = ap3216c_read_ps_data();
/* 列印ALS/IR資訊字串 */
sprintf(als, "ALS: %d", tmp[0]);
sprintf(ir, "IR : %d", tmp[1]);
/* 将lightmeter圖示及ALS/IR資訊輸出到螢幕 */
OLED_Clear();
OLED_Icon_Draw(20, 14, &icon_lighter_32_32, 0);
OLED_Show_String(64, 6, als, 12, 1);
OLED_Show_String(64, 20, ir, 12, 1);
/* 判斷是否有物體靠近,并顯示在螢幕上 */
if ((tmp[2] >> 15) & 1)
OLED_Show_String(64, 36, "near !", 16, 1);
else
OLED_Show_String(64, 40, "far !", 16, 1);
/* 将左右按鍵标志輸出到螢幕上 */
OLED_Icon_Draw(2, 24, &icon_skip_left, 0);
OLED_Icon_Draw(122, 24, &icon_skip_right, 0);
/* 重新整理螢幕資料 */
OLED_Refresh_GRAM();
/* 休眠150ms */
aos_msleep(150);
}
}
/* 光照資訊屏頁面退出處理函數 */
int lightmeter_uninit(void)
{
/* 删除光照資訊屏主任務 */
aos_task_delete("lightmeter_task");
printf("aos_task_delete lightmeter_task \n");
return 0;
}
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
AP3216C驅動
代碼位置:components/peripherals/sensor/drv/drv_als_ps_ir_liteon_ap3216c.c
以ap3216C初始化和讀取ALS數值為例,詳細代碼及注釋如下:
/**
* This function initializes ap3216c registered device driver
*
* @param no
*
* @return the ap3216c device.
*/
void ap3216c_init(void)
{
/**
1. ap3216c連接配接到HaaS edu k1的I2C1端口, 是以i2c_dev的端口好需要設定為1
2. ap3216c為7-bit位址模式
3. haas1000晶片内部的I2C1作為主模式, ap3216c作為從裝置
4. ap3216c外設定制用AP3216C_ADDR聲明
*/
#if 1
i2c_dev.port = 1;
i2c_dev.config.address_width = I2C_HAL_ADDRESS_WIDTH_7BIT;
i2c_dev.config.freq = I2C_BUS_BIT_RATES_100K;
i2c_dev.config.mode = I2C_MODE_MASTER;
i2c_dev.config.dev_addr = AP3216C_ADDR;
/* 呼叫hal_i2c_init對haas1000内部的I2C1控制器進行初始化 */
hal_i2c_init(&i2c_dev);
#endif
/* 複位ap3216c晶片, 向system configuration寄存器寫入0x0對其進行軟體複位 */
reset_sensor();
/* 等待ap3216c複位穩定時間 */
aos_msleep(100);
/* 設定ap3216c工作在連續量測ALS/PS/IR模式 */
ap3216c_set_param(AP3216C_SYSTEM_MODE, AP3216C_MODE_ALS_AND_PS);
/* 休眠150ms等待量測到穩定值 */
aos_msleep(150); // delay at least 150ms
/* 配置中斷腳 和 中斷資料 - 函數内部實作置空 */
ap3216c_int_Config();
ap3216c_int_init();
}
/**
* This function reads light by ap3216c sensor measurement
*
* @param no
*
* @return the ambient light converted to float data.
*/
uint16_t ap3216c_read_ambient_light(void)
{
uint16_t brightness = 0; // default error data
uint16_t read_data;
uint8_t range;
/*分别讀取 0x0c和0x0d的值,組成16-bit的ALS ADC count */
read_data = (uint16_t )read_low_and_high(AP3216C_ALS_DATA_L_REG, 1);
/* 讀取ALS range 配置 */
ap3216c_get_param(AP3216C_ALS_RANGE, &range);
/* 根據ALS range 配置,完成從ADC count到lux的換算 */
if (range == AP3216C_ALS_RANGE_20661)
{
brightness = 0.36 * read_data; //sensor ambient light converse to reality
}
else if (range == AP3216C_ALS_RANGE_5162)
{
brightness = 0.089 * read_data; //sensor ambient light converse to reality
}
else if (range == AP3216C_ALS_RANGE_1291)
{
brightness = 0.022 * read_data; //sensor ambient light converse to reality
}
else if (range == AP3216C_ALS_RANGE_323)
{
brightness = 0.0056 * read_data; //sensor ambient light converse to reality
}
return brightness;
}
/**
* This function is convenient to getting data except including high and low data for this sensor.
* note:after reading lower register first,reading higher add one.
*/
/* 讀取從reg開始的兩個位元組, 并對資料進行合并*/
static uint32_t read_low_and_high(uint8_t reg, uint8_t len)
{
uint32_t data;
uint8_t buf = 0;
read_regs( reg, len, &buf); // 讀低位元組
data = buf;
read_regs( reg + 1, len, &buf); // 讀高位元組
data = data + (buf << len * 8); // 合并資料
return data;
}
/* 讀寄存器的值 */
static void read_regs(uint8_t reg, uint8_t len, uint8_t *buf)
{
hal_i2c_mem_read(&i2c_dev, i2c_dev.config.dev_addr, reg, 1, buf, len, 100);
}
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
這裡的hal_i2c_mem_read的實作和AP3216C datasheet上面讀取寄存器的描述相比對。
- MCU I2C 主裝置先将寄存器位址通過I2C寫操作發給AP3216C從裝置
-
MCUI2C 主裝置發起讀操作從AP3216C從裝置讀取寄存器的值
AP3216C寄存器讀取的整個I2C傳輸過程中,詳細資料傳輸過程如下圖所示:
讀取AP3216C的PS和IR寄存器的過程和讀取ALS的過程中I2C的傳輸過程完全一緻,這裡就不再贅述。
開發者支援
HaaS官方:
https://haas.iot.aliyun.com/HaaS技術社群:
https://blog.csdn.net/HaaSTech開發者釘釘群和公衆号見下圖,開發者釘釘群每天都有技術支援同學值班。