LSM6DSR(2)----中斷獲取陀螺儀數(shù)據(jù))
STM32C5開發(fā)LSM6DSR .2--輪詢獲取陀螺儀數(shù)據(jù)概述視頻教學(xué)樣品申請源碼下載硬件準(zhǔn)備參考程序串口配置IIC配置CS和SA0設(shè)置INT設(shè)置生成項目導(dǎo)入STM32CubeIDE設(shè)置工程編碼添加頭文件printf 重定向參考程序CMake設(shè)置頭文件設(shè)置初始換管腳獲取ID復(fù)位傳感器BDU設(shè)置配置輸出數(shù)據(jù)率與測量量程配置加速度計低通濾波器外部中斷回調(diào)函數(shù)中斷配置輪詢讀取傳感器數(shù)據(jù)演示.2–輪詢獲取陀螺儀數(shù)據(jù))概述本章節(jié)介紹基于 STM32C542 的 陀螺儀中斷采集功能。通過配置 INT1 數(shù)據(jù)就緒中斷當(dāng)陀螺儀產(chǎn)生新數(shù)據(jù)時觸發(fā) MCU 中斷讀取三軸角速度數(shù)據(jù)并進(jìn)行單位轉(zhuǎn)換實現(xiàn)高實時性的運動數(shù)據(jù)采集。需要樣片的可以加qun申請925643491 / 615061293 。視頻教學(xué)https://www.bilibili.com/video/BV1sZtf61Eg1/樣品申請https://www.wjx.top/vm/OhcKxJk.aspx#源碼下載https://download.csdn.net/download/qq_24312945/93403551硬件準(zhǔn)備首先需要準(zhǔn)備一個開發(fā)板這里我準(zhǔn)備的是自己繪制的開發(fā)板需要的可以進(jìn)行申請。主控為STM32C542CC陀螺儀為LSM6DSR磁力計為LIS2MDL。參考程序https://github.com/CoreMaker-lab/STM32C542_LSM6DSR_LIS2MDLhttps://gitee.com/CoreMaker/STM32C542_LSM6DSR_LIS2MDL串口配置查看原理圖PA9和PA10設(shè)置為開發(fā)板的串口。在左側(cè) Peripherals 中選擇 Connectivity → USART1Mode 選擇 Async表示配置為異步串口模式Function used by the component 顯示為 UART說明 USART1 在異步模式下使用 UART HAL 驅(qū)動串口參數(shù)配置為115200 波特率、8 位數(shù)據(jù)位、無校驗、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通過擴(kuò)展接口與傳感器模塊連接其中PB6作為I2C時鐘線SCLPB7作為I2C數(shù)據(jù)線SDA首先在 STM32CubeMX2 中進(jìn)入 Peripherals 外設(shè)配置頁面在 Connectivity 分類中選擇 I2C1并將 I2C1 外設(shè)使能。如圖所示本實驗的 I2C1 配置步驟如下點擊左側(cè) Peripherals 外設(shè)配置入口在 Connectivity 分類中選擇 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 模式對應(yīng)電平SA0 需要固定為高電平或低電平將 PA1 和 PB2 配置為普通 GPIO。在 STM32CubeMX2 的 Pinout 頁面中將 PA1 和 PB2 配置為普通 GPIO。SA0用于選擇 LSM6DSR 的 I2C 地址CS用于選擇 LSM6DSR 的通信接口模式在右側(cè) Pin signals 中將對應(yīng)引腳設(shè)置為 GPIO → Configured表示該引腳將作為普通 GPIO 使用由用戶程序控制輸出高低電平。進(jìn)入 System → GPIO 配置頁面可以看到 PA1 和 PB2 已經(jīng)被加入 GPIO 配置列表。本實驗中將 PB2 作為 CS 控制腳 , 將 PA1 作為 SA0 控制腳 。由于還有一個磁力計需要把該CS也使能。在 STM32CubeMX2 的 Pinout 頁面中將 PA6配置為普通 GPIO。進(jìn)入 System → GPIO 配置頁面 PA6 作為 CS2 控制腳 。INT設(shè)置硬件連接中IMU 的 INT1Pin4連接至 MCU 的 PB0用于觸發(fā)陀螺儀數(shù)據(jù)更新中斷。在 Pinout 頁面中將 PB2 配置為 GPIO 輸入并開啟 EXTI 功能。在 GPIO 配置頁面中PB0 對應(yīng) EXTI2 中斷線觸發(fā)方式選擇 Falling edge。開啟 EXTI0 Interrupt并生成 IRQ Handler。生成項目修改配置后左下角會提示 Click to save需要先保存當(dāng)前工程配置點擊左側(cè) Project settings進(jìn)入工程生成設(shè)置頁面在 IDE Project Generation 中選擇工程格式和工具鏈本例選擇 CMake GCC然后點擊 Generate IDE project 生成工程導(dǎo)入STM32CubeIDE打開 STM32CubeIDE點擊菜單欄 File選擇 Import…準(zhǔn)備導(dǎo)入 STM32CubeMX2 生成的 CMake 工程在 Import 窗口中展開 Import STM32 Project選擇 STM32 CMake Project點擊 Next進(jìn)入 CMake 工程路徑選擇頁面Project name填寫導(dǎo)入到 STM32CubeIDE 中顯示的工程名稱Source directory選擇 STM32CubeMX2 生成的 CMake 工程目錄點擊 Next繼續(xù)完成工程導(dǎo)入Toolchain選擇 MCU ARM GCC表示使用 ARM GCC 工具鏈進(jìn)行編譯MCU確認(rèn)芯片型號為 STM32C542CCTx與前面 STM32CubeMX2 中選擇的 MCU 保持一致CPU/Core確認(rèn)內(nèi)核為 Cortex-M33Core 為 0點擊 Finish完成 CMake 工程導(dǎo)入設(shè)置工程編碼在 Project Explorer 中選中當(dāng)前工程點擊菜單欄 Project選擇 Properties進(jìn)入工程屬性設(shè)置在工程屬性中選擇 ResourceText file encoding 選擇 Other編碼格式輸入 GBK點擊 Apply and Close 保存設(shè)置添加頭文件在 main.c 中添加頭文件#includemx_usart1.h#includestdio.h#includestring.hprintf 重定向為了讓 printf() 輸出到 USART1需要重寫 _write() 函數(shù)。GCC 工程中printf() 底層會調(diào)用 _write() 輸出字符因此只需要在 _write() 中調(diào)用 HAL_UART_Transmit()就可以把 printf() 的內(nèi)容通過串口發(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添加對應(yīng)驅(qū)動程序。CMake設(shè)置把lsm6dsv80x_reg.c 加入 CMake 編譯 。target_sources(${CMAKE_PROJECT_NAME}PRIVATE#Add additional source files herelsm6dsr_reg.c)printf 輸出浮點數(shù)需要額外開啟 float printf 支持。CMake 官方說明 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寫入以及為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。對應(yīng)的獲取ID驅(qū)動程序,如下所示。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ù)位傳感器該代碼首先對 傳感器進(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ù)通常被存儲在輸出寄存器中這些寄存器分為兩部分MSB和LSB。這兩部分共同表示一個完整的數(shù)據(jù)值。例如在一個加速度計中MSB和LSB可能共同表示一個加速度的測量值。連續(xù)更新模式BDU ‘0’在默認(rèn)模式下輸出寄存器的值會持續(xù)不斷地被更新。這意味著在你讀取MSB和LSB的時候寄存器中的數(shù)據(jù)可能會因為新的測量數(shù)據(jù)而更新。這可能導(dǎo)致一個問題當(dāng)你讀取MSB時如果寄存器更新了接下來讀取的LSB可能就是新的測量值的一部分而不是與MSB相對應(yīng)的值。這樣你得到的就是一個“拼湊”的數(shù)據(jù)它可能無法準(zhǔn)確代表任何實際的測量時刻。塊數(shù)據(jù)更新BDU模式BDU ‘1’當(dāng)激活BDU功能時輸出寄存器中的內(nèi)容不會在讀取MSB和LSB之間更新。這就意味著一旦開始讀取數(shù)據(jù)無論是先讀MSB還是LSB寄存器中的那一組數(shù)據(jù)就被“鎖定”直到兩部分都被讀取完畢。這樣可以確保你讀取的MSB和LSB是同一測量時刻的數(shù)據(jù)避免了讀取到代表不同采樣時刻的數(shù)據(jù)。簡而言之BDU位的作用是確保在讀取數(shù)據(jù)時輸出寄存器的內(nèi)容保持穩(wěn)定從而避免讀取到拼湊或錯誤的數(shù)據(jù)。這對于需要高精度和穩(wěn)定性的應(yīng)用尤為重要。可以向CTRL3_C(12h)的BDU寄存器寫入1進(jìn)行開啟。對應(yīng)的驅(qū)動程序,如下所示。/* Enable Block Data Update */lsm6dsr_block_data_update_set(dev_ctx,PROPERTY_ENABLE);配置輸出數(shù)據(jù)率與測量量程該代碼用于配置 LSM6DSR 加速度計和陀螺儀的基本采樣參數(shù)● 將加速度計和陀螺儀的輸出數(shù)據(jù)率均設(shè)置為 12.5 Hz即每秒產(chǎn)生約 12.5 組新的傳感器數(shù)據(jù)?!?將加速度計量程設(shè)置為 ±2 g適合檢測幅度較小的運動和姿態(tài)變化此時靈敏度為 0.061 mg/LSB?!?將陀螺儀量程設(shè)置為 ±2000 dps可測量較大的旋轉(zhuǎn)角速度此時靈敏度為 70 mdps/LSB。其中加速度計參數(shù)寫入 CTRL1_XL 寄存器陀螺儀參數(shù)寫入 CTRL2_G 寄存器。對應(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);配置加速度計低通濾波器該代碼用于配置數(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)生中斷信號后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;}}中斷配置傳感器支持加速度計獨立數(shù)據(jù)就緒中斷。通過配置使能數(shù)據(jù)更新中斷并將中斷信號映射到 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;輪詢讀取傳感器數(shù)據(jù)當(dāng) INT1 中斷觸發(fā)后thread_wake 被置位。主循環(huán)檢測到該標(biāo)志后通過 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;}}}演示