發(fā)LSM6DSR(2)----中斷獲取陀螺儀數(shù)據(jù))
STM32C5開(kāi)發(fā)LSM6DSR .2--輪詢(xún)獲取陀螺儀數(shù)據(jù)概述視頻教學(xué)樣品申請(qǐng)?jiān)创a下載硬件準(zhǔn)備參考程序串口配置IIC配置CS和SA0設(shè)置INT設(shè)置生成項(xiàng)目導(dǎo)入STM32CubeIDE設(shè)置工程編碼添加頭文件printf 重定向參考程序CMake設(shè)置頭文件設(shè)置初始換管腳獲取ID復(fù)位傳感器BDU設(shè)置配置輸出數(shù)據(jù)率與測(cè)量量程配置加速度計(jì)低通濾波器外部中斷回調(diào)函數(shù)中斷配置輪詢(xún)讀取傳感器數(shù)據(jù)演示.2–輪詢(xún)獲取陀螺儀數(shù)據(jù))概述本章節(jié)介紹基于 STM32C542 的 陀螺儀中斷采集功能。通過(guò)配置 INT1 數(shù)據(jù)就緒中斷當(dāng)陀螺儀產(chǎn)生新數(shù)據(jù)時(shí)觸發(fā) MCU 中斷讀取三軸角速度數(shù)據(jù)并進(jìn)行單位轉(zhuǎn)換實(shí)現(xiàn)高實(shí)時(shí)性的運(yùn)動(dòng)數(shù)據(jù)采集。需要樣片的可以加qun申請(qǐng)925643491 / 615061293 。視頻教學(xué)https://www.bilibili.com/video/BV1sZtf61Eg1/樣品申請(qǐng)https://www.wjx.top/vm/OhcKxJk.aspx#源碼下載https://download.csdn.net/download/qq_24312945/93403551硬件準(zhǔn)備首先需要準(zhǔn)備一個(gè)開(kāi)發(fā)板這里我準(zhǔn)備的是自己繪制的開(kāi)發(fā)板需要的可以進(jìn)行申請(qǐng)。主控為STM32C542CC陀螺儀為L(zhǎng)SM6DSR磁力計(jì)為L(zhǎng)IS2MDL。參考程序https://github.com/CoreMaker-lab/STM32C542_LSM6DSR_LIS2MDLhttps://gitee.com/CoreMaker/STM32C542_LSM6DSR_LIS2MDL串口配置查看原理圖PA9和PA10設(shè)置為開(kāi)發(fā)板的串口。在左側(cè) Peripherals 中選擇 Connectivity → USART1Mode 選擇 Async表示配置為異步串口模式Function used by the component 顯示為 UART說(shuō)明 USART1 在異步模式下使用 UART HAL 驅(qū)動(dòng)串口參數(shù)配置為115200 波特率、8 位數(shù)據(jù)位、無(wú)校驗(yàn)、1 位停止位、收發(fā)模式GPIO TxUSART1_TX 選擇 PA9GPIO RxUSART1_RX 選擇 PA10PA9 / PA10 均配置為 Alternate 復(fù)用功能模式Pull 選擇 No pull-up and no pull-downOutput type 選擇 Push pullSpeed 選擇 LowIIC配置STM32C542CCT6通過(guò)擴(kuò)展接口與傳感器模塊連接其中PB6作為I2C時(shí)鐘線(xiàn)SCLPB7作為I2C數(shù)據(jù)線(xiàn)SDA首先在 STM32CubeMX2 中進(jìn)入 Peripherals 外設(shè)配置頁(yè)面在 Connectivity 分類(lèi)中選擇 I2C1并將 I2C1 外設(shè)使能。如圖所示本實(shí)驗(yàn)的 I2C1 配置步驟如下點(diǎn)擊左側(cè) Peripherals 外設(shè)配置入口在 Connectivity 分類(lèi)中選擇 I2C1將 I2C1 Mode 設(shè)置為 I2C并確認(rèn) I2C1 顯示為 ActiveSpeed frequency 設(shè)置為 Fast mode - 400 kHz確認(rèn) I2C1 的 GPIO 引腳映射SCL 為 PB6SDA 為 PB7CS和SA0設(shè)置確認(rèn)I2C 模式選擇和地址選擇CS 需要處于 I2C 模式對(duì)應(yīng)電平SA0 需要固定為高電平或低電平將 PA1 和 PB2 配置為普通 GPIO。在 STM32CubeMX2 的 Pinout 頁(yè)面中將 PA1 和 PB2 配置為普通 GPIO。SA0用于選擇 LSM6DSR 的 I2C 地址CS用于選擇 LSM6DSR 的通信接口模式在右側(cè) Pin signals 中將對(duì)應(yīng)引腳設(shè)置為 GPIO → Configured表示該引腳將作為普通 GPIO 使用由用戶(hù)程序控制輸出高低電平。進(jìn)入 System → GPIO 配置頁(yè)面可以看到 PA1 和 PB2 已經(jīng)被加入 GPIO 配置列表。本實(shí)驗(yàn)中將 PB2 作為 CS 控制腳 , 將 PA1 作為 SA0 控制腳 。由于還有一個(gè)磁力計(jì)需要把該CS也使能。在 STM32CubeMX2 的 Pinout 頁(yè)面中將 PA6配置為普通 GPIO。進(jìn)入 System → GPIO 配置頁(yè)面 PA6 作為 CS2 控制腳 。INT設(shè)置硬件連接中IMU 的 INT1Pin4連接至 MCU 的 PB0用于觸發(fā)陀螺儀數(shù)據(jù)更新中斷。在 Pinout 頁(yè)面中將 PB2 配置為 GPIO 輸入并開(kāi)啟 EXTI 功能。在 GPIO 配置頁(yè)面中PB0 對(duì)應(yīng) EXTI2 中斷線(xiàn)觸發(fā)方式選擇 Falling edge。開(kāi)啟 EXTI0 Interrupt并生成 IRQ Handler。生成項(xiàng)目修改配置后左下角會(huì)提示 Click to save需要先保存當(dāng)前工程配置點(diǎn)擊左側(cè) Project settings進(jìn)入工程生成設(shè)置頁(yè)面在 IDE Project Generation 中選擇工程格式和工具鏈本例選擇 CMake GCC然后點(diǎn)擊 Generate IDE project 生成工程導(dǎo)入STM32CubeIDE打開(kāi) STM32CubeIDE點(diǎn)擊菜單欄 File選擇 Import…準(zhǔn)備導(dǎo)入 STM32CubeMX2 生成的 CMake 工程在 Import 窗口中展開(kāi) Import STM32 Project選擇 STM32 CMake Project點(diǎn)擊 Next進(jìn)入 CMake 工程路徑選擇頁(yè)面Project name填寫(xiě)導(dǎo)入到 STM32CubeIDE 中顯示的工程名稱(chēng)Source directory選擇 STM32CubeMX2 生成的 CMake 工程目錄點(diǎn)擊 Next繼續(xù)完成工程導(dǎo)入Toolchain選擇 MCU ARM GCC表示使用 ARM GCC 工具鏈進(jìn)行編譯MCU確認(rèn)芯片型號(hào)為 STM32C542CCTx與前面 STM32CubeMX2 中選擇的 MCU 保持一致CPU/Core確認(rèn)內(nèi)核為 Cortex-M33Core 為 0點(diǎn)擊 Finish完成 CMake 工程導(dǎo)入設(shè)置工程編碼在 Project Explorer 中選中當(dāng)前工程點(diǎn)擊菜單欄 Project選擇 Properties進(jìn)入工程屬性設(shè)置在工程屬性中選擇 ResourceText file encoding 選擇 Other編碼格式輸入 GBK點(diǎn)擊 Apply and Close 保存設(shè)置添加頭文件在 main.c 中添加頭文件#includemx_usart1.h#includestdio.h#includestring.hprintf 重定向?yàn)榱俗?printf() 輸出到 USART1需要重寫(xiě) _write() 函數(shù)。GCC 工程中printf() 底層會(huì)調(diào)用 _write() 輸出字符因此只需要在 _write() 中調(diào)用 HAL_UART_Transmit()就可以把 printf() 的內(nèi)容通過(guò)串口發(fā)送出去。int_write(intfile,char*ptr,intlen){hal_uart_handle_t*huart1mx_usart1_uart_gethandle();if(huart1!NULL){HAL_UART_Transmit(huart1,ptr,len,1000);}returnlen;}參考程序https://github.com/STMicroelectronics/lsm6dsr-pid添加對(duì)應(yīng)驅(qū)動(dòng)程序。CMake設(shè)置把lsm6dsv80x_reg.c 加入 CMake 編譯 。target_sources(${CMAKE_PROJECT_NAME}PRIVATE#Add additional source files herelsm6dsr_reg.c)printf 輸出浮點(diǎn)數(shù)需要額外開(kāi)啟 float printf 支持。CMake 官方說(shuō)明 target_link_options() 就是給可執(zhí)行目標(biāo)添加 linker options 的命令。target_link_options(${CMAKE_PROJECT_NAME}PUBLIC#Add additional linker flags here-u _printf_float)頭文件設(shè)置添加頭文件。#includelsm6dsr_reg.h初始換管腳由于需要向LSM6DSR_I2C_ADD_L寫(xiě)入以及為IIC模式。所以使能CS為高電平配置為IIC模式。配置SA0為低電平。printf(HELLO\n);HAL_GPIO_WritePin(CS1_PORT,CS1_PIN,HAL_GPIO_PIN_SET);HAL_GPIO_WritePin(SA0_PORT,SA0_PIN,HAL_GPIO_PIN_RESET);HAL_GPIO_WritePin(CS2_PORT,CS2_PIN,HAL_GPIO_PIN_SET);變量定義。/* Private macro -------------------------------------------------------------*/#defineBOOT_TIME10//ms#defineCNT_FOR_OUTPUT100/* Private variables ---------------------------------------------------------*/staticint16_tdata_raw_acceleration[3];staticint16_tdata_raw_angular_rate[3];staticint16_tdata_raw_temperature;staticfloat_tacceleration_mg[3];staticfloat_tangular_rate_mdps[3];staticfloat_ttemperature_degC;staticuint8_twhoamI;staticuint8_ttx_buffer[1000];/* Extern variables ----------------------------------------------------------*//* Private functions ---------------------------------------------------------*//* * WARNING: * Functions declare in this section are defined at the end of this file * and are strictly related to the hardware platform used. * */staticint32_tplatform_write(void*handle,uint8_treg,constuint8_t*bufp,uint16_tlen);staticint32_tplatform_read(void*handle,uint8_treg,uint8_t*bufp,uint16_tlen);staticvoidtx_com(uint8_t*tx_buffer,uint16_tlen);staticvoidplatform_delay(uint32_tms);staticvoidplatform_init(void*handle);staticuint8_twhoamI,rst;staticstmdev_ctx_tdev_ctx;staticuint8_tlg_xl_data_valid0;staticuint8_thg_xl_data_valid0;staticuint8_tgyro_data_valid0;staticuint8_ttemp_data_valid0;staticvolatileuint8_tthread_wake0;獲取ID我們可以向WHO_AM_I (0Fh)獲取固定值判斷是否為0x6B。對(duì)應(yīng)的獲取ID驅(qū)動(dòng)程序,如下所示。stmdev_ctx_tdev_ctx;/* Initialize mems driver interface */dev_ctx.write_regplatform_write;dev_ctx.read_regplatform_read;dev_ctx.mdelayplatform_delay;dev_ctx.handlemx_i2c1_i2c_gethandle();/* Init test platform */// platform_init(dev_ctx.handle);/* Wait sensor boot time */platform_delay(BOOT_TIME);/* Check device ID */lsm6dsr_device_id_get(dev_ctx,whoamI);printf(LSM6DSR_ID0x%x,id0x%x\n,LSM6DSR_ID,whoamI);if(whoamI!LSM6DSR_ID)while(1);復(fù)位傳感器該代碼首先對(duì) 傳感器進(jìn)行軟件復(fù)位。/* Restore default configuration */lsm6dsr_reset_set(dev_ctx,PROPERTY_ENABLE);do{lsm6dsr_reset_get(dev_ctx,rst);}while(rst);BDU設(shè)置在很多傳感器中數(shù)據(jù)通常被存儲(chǔ)在輸出寄存器中這些寄存器分為兩部分MSB和LSB。這兩部分共同表示一個(gè)完整的數(shù)據(jù)值。例如在一個(gè)加速度計(jì)中MSB和LSB可能共同表示一個(gè)加速度的測(cè)量值。連續(xù)更新模式BDU ‘0’在默認(rèn)模式下輸出寄存器的值會(huì)持續(xù)不斷地被更新。這意味著在你讀取MSB和LSB的時(shí)候寄存器中的數(shù)據(jù)可能會(huì)因?yàn)樾碌臏y(cè)量數(shù)據(jù)而更新。這可能導(dǎo)致一個(gè)問(wèn)題當(dāng)你讀取MSB時(shí)如果寄存器更新了接下來(lái)讀取的LSB可能就是新的測(cè)量值的一部分而不是與MSB相對(duì)應(yīng)的值。這樣你得到的就是一個(gè)“拼湊”的數(shù)據(jù)它可能無(wú)法準(zhǔn)確代表任何實(shí)際的測(cè)量時(shí)刻。塊數(shù)據(jù)更新BDU模式BDU ‘1’當(dāng)激活BDU功能時(shí)輸出寄存器中的內(nèi)容不會(huì)在讀取MSB和LSB之間更新。這就意味著一旦開(kāi)始讀取數(shù)據(jù)無(wú)論是先讀MSB還是LSB寄存器中的那一組數(shù)據(jù)就被“鎖定”直到兩部分都被讀取完畢。這樣可以確保你讀取的MSB和LSB是同一測(cè)量時(shí)刻的數(shù)據(jù)避免了讀取到代表不同采樣時(shí)刻的數(shù)據(jù)。簡(jiǎn)而言之BDU位的作用是確保在讀取數(shù)據(jù)時(shí)輸出寄存器的內(nèi)容保持穩(wěn)定從而避免讀取到拼湊或錯(cuò)誤的數(shù)據(jù)。這對(duì)于需要高精度和穩(wěn)定性的應(yīng)用尤為重要。可以向CTRL3_C(12h)的BDU寄存器寫(xiě)入1進(jìn)行開(kāi)啟。對(duì)應(yīng)的驅(qū)動(dòng)程序,如下所示。/* Enable Block Data Update */lsm6dsr_block_data_update_set(dev_ctx,PROPERTY_ENABLE);配置輸出數(shù)據(jù)率與測(cè)量量程該代碼用于配置 LSM6DSR 加速度計(jì)和陀螺儀的基本采樣參數(shù)● 將加速度計(jì)和陀螺儀的輸出數(shù)據(jù)率均設(shè)置為 12.5 Hz即每秒產(chǎn)生約 12.5 組新的傳感器數(shù)據(jù)?!?將加速度計(jì)量程設(shè)置為 ±2 g適合檢測(cè)幅度較小的運(yùn)動(dòng)和姿態(tài)變化此時(shí)靈敏度為 0.061 mg/LSB?!?將陀螺儀量程設(shè)置為 ±2000 dps可測(cè)量較大的旋轉(zhuǎn)角速度此時(shí)靈敏度為 70 mdps/LSB。其中加速度計(jì)參數(shù)寫(xiě)入 CTRL1_XL 寄存器陀螺儀參數(shù)寫(xiě)入 CTRL2_G 寄存器。對(duì)應(yīng)程序如下所示。/* Set Output Data Rate */lsm6dsr_xl_data_rate_set(dev_ctx,LSM6DSR_XL_ODR_12Hz5);lsm6dsr_gy_data_rate_set(dev_ctx,LSM6DSR_GY_ODR_12Hz5);/* Set full scale */lsm6dsr_xl_full_scale_set(dev_ctx,LSM6DSR_2g);lsm6dsr_gy_full_scale_set(dev_ctx,LSM6DSR_2000dps);配置加速度計(jì)低通濾波器該代碼用于配置數(shù)字濾波鏈/* Configure filtering chain(No aux interface) * Accelerometer - LPF1 LPF2 path */lsm6dsr_xl_hp_path_on_out_set(dev_ctx,LSM6DSR_LP_ODR_DIV_100);lsm6dsr_xl_filter_lp2_set(dev_ctx,PROPERTY_ENABLE);外部中斷回調(diào)函數(shù)當(dāng) 傳感器 的 INT1 引腳產(chǎn)生中斷信號(hào)后MCU 進(jìn)入 EXTI 中斷處理流程并調(diào)用 HAL_EXTI_TriggerCallback()。voidHAL_EXTI_TriggerCallback(hal_exti_handle_t*hexti,hal_exti_trigger_ttrigger){if(HAL_EXTI_GetInstance(hexti)HAL_EXTI_GPIO_0){thread_wake1;}}中斷配置傳感器支持加速度計(jì)獨(dú)立數(shù)據(jù)就緒中斷。通過(guò)配置使能數(shù)據(jù)更新中斷并將中斷信號(hào)映射到 INT1 引腳。lsm6dsr_pin_int1_route_tpin_int{0};/* LSM6DSR: H_LACTIVE1 requires PP_OD0 (datasheet Table 55). * Use push-pull active low, with MCU EXTI falling edge. */if((lsm6dsr_pin_mode_set(dev_ctx,LSM6DSR_PUSH_PULL)!0)||(lsm6dsr_pin_polarity_set(dev_ctx,LSM6DSR_ACTIVE_LOW)!0)||(lsm6dsr_data_ready_mode_set(dev_ctx,LSM6DSR_DRDY_LATCHED)!0)){printf(LSM6DSR INT1 configuration error\r\n);while(1);}pin_int.int1_ctrl.int1_drdy_xlPROPERTY_ENABLE;pin_int.int1_ctrl.int1_drdy_gPROPERTY_ENABLE;if(lsm6dsr_pin_int1_route_set(dev_ctx,pin_int)!0){printf(LSM6DSR INT1 routing error\r\n);while(1);}thread_wake1U;輪詢(xún)讀取傳感器數(shù)據(jù)當(dāng) INT1 中斷觸發(fā)后thread_wake 被置位。主循環(huán)檢測(cè)到該標(biāo)志后通過(guò) all_sources_get 讀取傳感器數(shù)據(jù)就緒狀態(tài)并分別判斷加速度、陀螺儀以及溫度數(shù)據(jù)是否更新。while(1){if(thread_wake!0U){/* Clear before reading; a later interrupt may set it again. */thread_wake0U;lsm6dsr_status_reg_tstatus{0};int32_tret;/* Read output only if new data is available */retlsm6dsr_status_reg_get(dev_ctx,status);/* Read all ready output registers before conversion and printf. * Reading STATUS_REG alone does not release the latched DRDY. */if((ret0)(status.xlda!0U)){memset(data_raw_acceleration,0x00,3*sizeof(int16_t));retlsm6dsr_acceleration_raw_get(dev_ctx,data_raw_acceleration);}if((ret0)(status.gda!0U)){memset(data_raw_angular_rate,0x00,3*sizeof(int16_t));retlsm6dsr_angular_rate_raw_get(dev_ctx,data_raw_angular_rate);}if((ret0)(status.tda!0U)){memset(data_raw_temperature,0x00,sizeof(int16_t));retlsm6dsr_temperature_raw_get(dev_ctx,data_raw_temperature);}if(ret!0){printf(LSM6DSR read error, retrying\r\n);platform_delay(100);thread_wake1U;continue;}if(status.xlda!0U){acceleration_mg[0]lsm6dsr_from_fs2g_to_mg(data_raw_acceleration[0]);acceleration_mg[1]lsm6dsr_from_fs2g_to_mg(data_raw_acceleration[1]);acceleration_mg[2]lsm6dsr_from_fs2g_to_mg(data_raw_acceleration[2]);printf(Acceleration [mg]:%4.2f\t%4.2f\t%4.2f\r\n,(double)acceleration_mg[0],(double)acceleration_mg[1],(double)acceleration_mg[2]);}if(status.gda!0U){angular_rate_mdps[0]lsm6dsr_from_fs2000dps_to_mdps(data_raw_angular_rate[0]);angular_rate_mdps[1]lsm6dsr_from_fs2000dps_to_mdps(data_raw_angular_rate[1]);angular_rate_mdps[2]lsm6dsr_from_fs2000dps_to_mdps(data_raw_angular_rate[2]);printf(Angular rate [mdps]:%4.2f\t%4.2f\t%4.2f\r\n,(double)angular_rate_mdps[0],(double)angular_rate_mdps[1],(double)angular_rate_mdps[2]);}if(status.tda!0U){temperature_degClsm6dsr_from_lsb_to_celsius(data_raw_temperature);printf(Temperature [degC]:%6.2f\r\n,(double)temperature_degC);}/* XL and GY share INT1. A source may become ready while INT1 * is already active, so check once before waiting for a new edge. */retlsm6dsr_status_reg_get(dev_ctx,status);if(ret!0){printf(LSM6DSR read error, retrying\r\n);platform_delay(100);thread_wake1U;}elseif((status.xlda!0U)||(status.gda!0U)){thread_wake1U;}}}演示