環境: wnidows 10, STM32CubeIDE 1.8.0
在這個教學將透過 PA0
和 PA1
腳位來使用 uart4。
專案初始化
首先在 CubeIDE 新增 stm32f407g 的專案,將專案命名為 lis302dl_test。
依據在 stm32f407g 使用 uart 設定好 uart4。
接下來按照下圖將 PE3
設為 GPIO_Output、PE0
設為 GPIO_EXT0。
設定 PA5
、PA6
、PA7
,開啟 SPI1。
啟用 EXTI line0 interrupt,並設定其 priority:
接下來按下 Ctrl+S 自動產生程式碼。
檢查 WHO_AM_I_ADDR
LIS302DL 有許多用來讀寫的 register,具體的編號以及功能可以參閱官方 datasheet 或是參閱 lis302dl.h,如果要直接 include lis302dl.h,請手動把缺失的相依函式庫補齊或刪除。
這裡列出本教學會使用的 register,可以將其定義在 /* USER CODE BEGIN PM */ 下方:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* Private macro -------------------------------*/
/* USER CODE BEGIN PM */
#define LIS302DL_WHO_AM_I_ADDR 0x0F
#define LIS302DL_CTRL_REG1_ADDR 0x20
#define LIS302DL_CTRL_REG2_ADDR 0x21
#define LIS302DL_CTRL_REG3_ADDR 0x22
#define LIS302DL_STATUS_REG_ADDR 0x27
#define LIS302DL_OUT_X_ADDR 0x29
#define LIS302DL_OUT_Y_ADDR 0x2B
#define LIS302DL_OUT_Z_ADDR 0x2D
#define LIS302DL_FF_WU_CFG1_REG_ADDR 0x30
#define LIS302DL_FF_WU_SRC1_REG_ADDR 0x31
#define LIS302DL_FF_WU_THS1_REG_ADDR 0x32
#define LIS302DL_FF_WU_DURATION1_REG_ADDR 0x33
/* USER CODE END PM */
接下來在 /* USER CODE BEGIN 0 */ 實作用來讀寫 SPI1 的函式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* Private user code --------------------------*/
/* USER CODE BEGIN 0 */
void MEMS_Write(uint8_t address, uint8_t data){
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1,&address,1,10);
HAL_SPI_Transmit(&hspi1,&data,1,10);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_SET);
}
void MEMS_Read(uint8_t address, uint8_t *data){
address |= 0x80;
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_3, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1,&address,1,10);
HAL_SPI_Receive(&hspi1,data,1,10);
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_3, GPIO_PIN_SET);
}
/* USER CODE END 0 */
然後在專案的 main 函式的 while 迴圈改寫如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1) {
uint8_t data;
MEMS_Read(LIS302DL_WHO_AM_I_ADDR, &data);
if(data == 0x3B)
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12);
HAL_Delay(500);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
如果三軸加速規型號為 LIS302DL,綠色 LED 燈會持續閃爍。
測試輸出 X、Y、Z 字串
參考 datasheet:
設定 CTRL_REG1
,output rate 設為 400 Hz,X、Y、Z 全都啟用:
1
2
3
/* USER CODE BEGIN 2 */
MEMS_Write(LIS302DL_CTRL_REG1_ADDR, 0x47);
/* USER CODE END 2 */
CTRL_REG2
不需要更動。
CTRL_REG3
以及之後的 register 在稍後使用 external interrupt 時才需要用到。
接下來改寫 while 迴圈,透過 uart4 持續每隔 0.1 秒印出 X、Y、Z 三軸的加速度:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1) {
uint8_t x, y, z;
MEMS_Read(LIS302DL_OUT_X_ADDR, &x);
MEMS_Read(LIS302DL_OUT_Y_ADDR, &y);
MEMS_Read(LIS302DL_OUT_Z_ADDR, &z);
char Monitor_data[100];
memset(Monitor_data,'\0',sizeof(Monitor_data));
sprintf(Monitor_data, "%3d %3d %3d\n\r", x, y, z);
HAL_UART_Transmit(&huart4, (uint8_t *)Monitor_data, strlen(Monitor_data), HAL_MAX_DELAY);
HAL_Delay(100);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
Demo:
測試使用 External Interrupt
一樣參考 datasheet,設置以下 register:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* USER CODE BEGIN 2 */
MEMS_Write(LIS302DL_CTRL_REG1_ADDR, 0x47);
MEMS_Write(LIS302DL_CTRL_REG2_ADDR, 0x00);
// use FF_WU_1 to trigger interrupt on INT1
MEMS_Write(LIS302DL_CTRL_REG3_ADDR, 0x01);
// enable interrupt on X high, Y high
MEMS_Write(LIS302DL_FF_WU_CFG1_REG_ADDR, 0x0A);
// free-fall/wake-up threshold (7 bit)
MEMS_Write(LIS302DL_FF_WU_THS1_REG_ADDR, 0x55);
// free-fall/wake-up duration (8 bit)
// Step 2.5 msec, from 0 to 637.5 msec if ODR=400Hz,
// else step 10 msec, from 0 to 2.55 sec when ODR=100Hz.
MEMS_Write(LIS302DL_FF_WU_DURATION1_REG_ADDR, 0x04);
/* USER CODE END 2 */
在 main.c 實作 HAL_GPIO_EXTI_Callback
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* USER CODE BEGIN 0 */
// ...
int is_handling = 0, count = 0;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
if (is_handling) {
return;
}
is_handling = 1;
char Monitor_data[100];
memset(Monitor_data,'\0', sizeof(Monitor_data));
sprintf(Monitor_data, "interrupt! %d\n\r", count++);
HAL_UART_Transmit(&huart4, (uint8_t *)Monitor_data, strlen(Monitor_data), HAL_MAX_DELAY);
is_handling = 0;
}
/* USER CODE END 0 */
執行成功後,預期每一次左右搖晃,uart4 都會印出 “interrupt!” 和當前 interrupt 次數: