---
tags: 嵌入式作業系統分析與實作
---
# lab2-sensor_and_interrupt
contributed by <`RusselCK` >
###### tags: `RusselCK`
## 作業要求
* Must use sensor interrupt : motion detection.
* When you shake your board, it will trigger the interrupt.
* Please use the deferred interrupt handling task.
* Use semephore.
* ISR will give the semephore and the handler task enters the running state.
* At the beginning,the green LED blinking,then shake the board, the red LED triggered(switch state) by ISR and the orange LED blinking five times in handler task.
* When orange LED blinking, you should not trigger the sensor interrupt if you shake the board.
## Pinout & Configuration





## 程式架構

`vLab02_task_1` : the Green LED blinking
`ISR` : the Red LED triggered (switch state)
`vLab02_Handler_task` : the Orange LED blinking 5 times
**Priority** : `ISR` > `vLab02_Handler_task` > `vLab02_task_1`
## 程式碼與解說
### Include, Macro and Variables
```c
/* USER CODE BEGIN Includes */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/* USER CODE END Includes */
```
```c
/* Private macro -----------------------------------------------------------------------*/
/* USER CODE BEGIN PM */
#define Green_LED_High HAL_GPIO_WritePin(Green_LED_GPIO_Port, GPIO_PIN_12, GPIO_PIN_SET)
#define Green_LED_Low HAL_GPIO_WritePin(Green_LED_GPIO_Port, GPIO_PIN_12, GPIO_PIN_RESET)
#define Orange_LED_High HAL_GPIO_WritePin(Red_LED_GPIO_Port, GPIO_PIN_13, GPIO_PIN_SET)
#define Orange_LED_Low HAL_GPIO_WritePin(Red_LED_GPIO_Port, GPIO_PIN_13, GPIO_PIN_RESET)
#define Red_LED_High HAL_GPIO_WritePin(Red_LED_GPIO_Port, GPIO_PIN_14, GPIO_PIN_SET)
#define Red_LED_Low HAL_GPIO_WritePin(Red_LED_GPIO_Port, GPIO_PIN_14, GPIO_PIN_RESET)
#define Red_LED_Toggle HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_14)
/* USER CODE END PM */
```
為了方便之後程式碼的閱讀,我們將會用到的 GPIO Read/Write/Toggle 指令換成可讀性較高的 Macro
```c
/* USER CODE BEGIN PV */
SemaphoreHandle_t xSemaphore;
/* USER CODE END PV */
```
我們先 declare 之後會用到的 SemaphoreHandle
### Motion Sensor Interrupt
- [ ] [MEMS digital output motion sensor: ultra-low-power high-performance three-axis “nano” accelerometer](https://www.st.com/resource/en/datasheet/lis3dsh.pdf)
- [ ] [LIS3DSH: 3-axis digital output accelerometer](https://www.st.com/resource/en/application_note/dm00026768-lis3dsh-3axis-digital-output-accelerometer-stmicroelectronics.pdf)
```c
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 vLab02_sensor_init()
{
MEMS_Write(0x21,0x01);
MEMS_Write(0x23,0x48);
MEMS_Write(0x20,0x67);
MEMS_Write(0x24,0x00);
MEMS_Write(0x57,0x55);
MEMS_Write(0x40,0x05);
MEMS_Write(0x41,0x11);
MEMS_Write(0x59,0xFC);
MEMS_Write(0x5A,0xFC);
MEMS_Write(0x5B,0x01);
}
```



只要參照文件設置 Registers 的 Values,我們就可以達成「晃動板子便有 interrupt signal」的效果
### `vLab02_task_1()`
```c
void vLab02_task_1( void *pvParameters )
{
while(1)
{
/* Green LED blinking */
Green_LED_High; // Green LED ON
vTaskDelay(500);
Green_LED_Low; // Green LED OFF
vTaskDelay(500);
}
}
```
Task1 要做的事情是「綠燈不斷閃爍」,從程式碼的註解可以很直觀的明白每一行程式碼在做的事情
### ISR
```c
/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_PIN)
{
/* switch Red LED state */
Red_LED_Toggle;
/* semaphore give */
BaseType_t xHigherPriorityTaskWoken;
xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR( xSemaphore,
&xHigherPriorityTaskWoken );
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
/* USER CODE END 4 */
```
> `EXIT` stand for External Interrupt
ISR 要做的事情就是「改變 Red LED state」 和「give a semaphore」
#### Interrupt handler
`Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c`
```c
/**
* @brief This function handles EXTI interrupt request.
* @param GPIO_Pin Specifies the pins connected EXTI line
* @retval None
*/
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* EXTI line interrupt detected */
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}
/**
* @brief EXTI line detection callbacks.
* @param GPIO_Pin Specifies the pins connected EXTI line
* @retval None
*/
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(GPIO_Pin);
/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_GPIO_EXTI_Callback could be implemented in the user file
*/
}
```
根據原生程式碼的提示,我們需要將 ISR 的內容寫在 `main.c` 的 `HAL_GPIO_EXTI_Callback()` 裡頭
### `vLab02_Handler_task()`
```c
#define LONG_TIME 0xFFFF
void vLab02_Handler_task(void *pvParameters)
{
while(1)
{
if(xSemaphoreTake( xSemaphore, LONG_TIME ) == pdTRUE)
{
/* Orange LED blinking 5 times */
for (int i = 0; i < 5; ++i)
{
Orange_LED_High;
vTaskDelay(500);
Orange_LED_Low;
vTaskDelay(500);
}
}
}
}
```
當 `vLab02_Handler_task()` 成功接收到 semephore 時,Handler task 就會執行「橘燈閃爍 5 次」
## 使用方式
```c
void vLab02_start (void *pvParameters)
{
vLab02_sensor_init();
xSemaphore = xSemaphoreCreateBinary();
xTaskCreate(vLab02_task_1, "Lab02_task_1", 1000, NULL, 3, NULL);
xTaskCreate(vLab02_Handler_task, "Lab02_Handler_task", 1000, NULL, 2, NULL);
vTaskDelete(NULL);
}
int main (void)
{
...
/* USER CODE BEGIN 2 */
xTaskCreate(vLab02_start, "Lab02_Start", 1000, NULL, 1, NULL);
vTaskStartScheduler();
/* USER CODE END 2 */
...
}
```
## 問題與解決
### Q1. Sensor interrup 只會執行一次
將 `vLab02_sensor_init();` 加到 `ISR` 、 `vLab02_Handler_task` 或 `vLab02_task_1` 之中,達到 sensor register reinitialization 的效果。
### Q2. 如何在橘燈閃爍的途中,避免 sensor interrup 的執行?
等橘燈閃爍完之後再初始化 sensor register
```c
void vLab02_Handler_task(void *pvParameters)
{
while(1)
{
if(xSemaphoreTake( xSemaphore, LONG_TIME ) == pdTRUE)
{
/* Orange LED blinking 5 times */
for (int i = 0; i < 5; ++i)
{
Orange_LED_High
vTaskDelay(500);
Orange_LED_Low
vTaskDelay(500);
}
/* reset motion sensor registers */
vLab02_sensor_init();
}
}
}
```