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