摘要:本文為你帶來LiteOS基於Sensorhub的超聲波模組移植的應用。
1、Sensor Hub
LiteOS傳感框架即Sensor Hub,是一個基於Huawei LiteOS物聯網操作系統的傳感器管理框架。
隨着物聯網的發展,物聯網終端越來越智能化,例如在個人穿戴、智能家居、家用醫療等終端上將配置越來越多的傳感器,來獲取更多傳感數據,使終端更加智能,使得開發和維護變得復雜和困難。LiteOS傳感框架將物聯網終端設備上例如加速計(Accelerometer)、陀螺儀(Gyroscope)、氣壓儀(Barometer)、溫濕度計(Humidometer)等不同類型的傳感器統一管理,通過抽象不同類型傳感器接口,屏蔽其硬件細節,做到“硬件”無關性,非常方便於物聯網設備的開發、維護和功能擴展。
LiteOS傳感框架主要包括了Sensor Manager、BSP manager,Converged Algorithms。
- Sensor Manager:統一的傳感器交互管理,如Sensor的配置、采樣、上報和管理。
- BSP Manager:統一的驅動接口,負責Sensor驅動管理、電源管理、Sensor交互管理,如Sensor的打開、關閉、讀寫、數據更新等。
- Converged Algorithms:融合算法庫(算法基於具體的業務模型),根據具體業務模型,在端側MCU進行算法融合,例如環境監測算法、計步算法等,從傳統、簡單采集算法升級到智能算法,應用直接調用,提升傳感數據的業務精准度,降低數據采集時延。
2、SR04超聲波模組
HC-SR04超聲波測距模塊可提供2cm-400cm的非接觸式距離感測功能,測距精度可達高到3mm;模塊包括超聲波發射器、接收器與控制電路。基本工作原理:(1)采用IO口TRIG觸發測距,給至少10us的高電平信號;(2)模塊自動發送8個40khz的方波,自動檢測是否有信號返回;(3)有信號返回,通過IO口ECHO輸出一個高電平,高電平持續的時間就是超聲波從發射到返回的時間。測試距離=(高電平時間*聲速(340M/S))/2;2、實物圖:如右圖接線,VCC供5V電源,GND為地線,TRIG觸發控制信號輸入,ECHO回響信號輸出等四支線。圖一實物圖3、電氣參數:電氣參數HC-SR04超聲波模塊工作電壓DC 5 V工作電流15mA工作頻率40Hz最遠射程4m最近射程2cm測量角度15度輸入觸發信號10uS的TTL脈沖輸出回響信號輸出TTL電平信號,與射程成比例規格尺寸45*20*15mm。
從時序圖表明你只需要提供一個10uS以上脈沖觸發信號,該模塊內部將發出8個40kHz周期電平並檢測回波。一旦檢測到有回波信號則輸出回響信號。回響信號的脈沖寬度與所測的距離成正比。由此通過發射信號到收到的回響信號時間間隔可以計算得到距離。公式:uS/58=厘米或者uS/148=英寸;或是:距離=高電平時間*聲速(340M/S)/2;建議測量周期為60ms以上,以防止發射信號對回響信號的影響。
3、sensorhub的HC-SR04驅動
通過時序圖可以完成一個簡單的讀取傳感器的接收程序:(這里用GPIOA1和GPIOA4舉例)
uint32_t hcsr04_read (void) { local_time=0; HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET); // pull the TRIG pin HIGH delay(2); // wait for 2 us HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET); // pull the TRIG pin HIGH delay(10); // wait for 10 us HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET); // pull the TRIG pin low // read the time for which the pin is high while (!(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4))); // wait for the ECHO pin to go high while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4)) // while the pin is high { local_time++; // measure time for which the pin is high delay (1); } return local_time * .034/2; }
4、將驅動注冊到SensorHub上
先寫iO操作,初始化、打開、關閉和讀取數據的操作
STATIC INT32 SR04Init(SensorType *sensor) { (VOID)(sensor); GPIO_InitTypeDef GPIO_InitStruct; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOA_CLK_ENABLE(); /*Configure GPIO pin : PD11 */ GPIO_InitStruct.Pin = GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /*Configure GPIO pins : PD12 PD13 PD14 PD15 */ GPIO_InitStruct.Pin = GPIO_PIN_4; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); return LOS_OK; } STATIC INT32 SR04ReadData(SensorType *sensor) { PRINTK("read data\n"); INT32 *data = (INT32 *)sensor->sensorData; data[0] = hcsr04_read(); return LOS_OK; } STATIC INT32 SR04Open(SensorType *sensor, OpenParam *para) { UINT32 ret; (VOID)(para); SR04 *SR04 = (SR04 *)sensor->priv; if ((sensor->sensorStat == SENSOR_STAT_OPEN) && (sensor->interval == SR04Period)) { return LOS_OK; } if (SR04->gyroTimerId != INVALID_TIMER_ID) { ret = LOS_SwtmrDelete(SR04->gyroTimerId); SR04->gyroTimerId = INVALID_TIMER_ID; if (ret != LOS_OK) { PRINT_ERR("delete a timer failed!\n"); return LOS_NOK; } } // creat a timer, first parameter is ticks. ret = LOS_SwtmrCreate(sensor->interval, LOS_SWTMR_MODE_PERIOD, (SWTMR_PROC_FUNC)GypoTimerFunc, &SR04->gyroTimerId, (UINT32)sensor); if (ret != LOS_OK) { PRINT_ERR("creat a timer failed!\n"); return LOS_NOK; } ret = LOS_SwtmrStart(SR04->gyroTimerId); if (ret != LOS_OK) { PRINT_ERR("start timer err\n"); } SR04Period = sensor->interval; PRINTK("SR04 on.\n"); return LOS_OK; } STATIC INT32 SR04Close(SensorType *sensor) { UINT32 ret; if (sensor->sensorStat == SENSOR_STAT_CLOSE) { PRINT_DEBUG("sr04 has been closed\n"); return LOS_OK; } __HAL_RCC_GPIOA_CLK_DISABLE(); PRINTK("SR04 off.\n"); return LOS_OK; }
然后將設計的驅動注冊到框架上
STATIC struct SensorOperation Sr04Ops = { .Init = SR04Init, .Open = SR04Open, .Close = SR04Close, .ReadData = SR04ReadData, }; STATIC SensorType g_sensorSR04 = { .sensorOp = &Sr04Ops, .sensorData = &g_SR04Data, .sensorDataLen = sizeof(g_SR04Data), .priv = &g_SR04Priv, .tag = TAG_BEGIN, .cmd = CMD_CMN_INTERVAL_REQ, .interval = DEFAULT_INTERVAL, }; VOID SR04Register(VOID) { SensorRegister(&g_sensorSR04); }
將驅動注冊到通用sensor驅動模塊上。今天的代碼移植基本完成,后續有傳感器和板子進行驗證
總結
這個驅動是有問題,就是這個是讀取時阻塞的程序,后面試過,需要設計時采用定時器和外部中斷完成,可以將這個阻塞的程序改成非阻塞的,效率大大提升,后續講解如何用定時器和外部觸發中斷完成這個驅動設計。