外部イベント割り込み
※ 外部イベント割り込み
ProjectName:"20201230ExternalInterruptTest"
タイマなどは内部カウントしてある時間になるとイベントを発生させるため,内部イベントと呼ばれる。
一方,ユーザのボタン操作やセンサの読み取り完了、データ受信などは外部イベント割り込みを利用する。
イベントを発生させるトリガは入力信号の立ち上がりや立ち下がり、或いは両方の設定が可能。
On CubeMX
GPIO >> PA0
Pinoutタブ >> GPIO_EXTI*
Configurationタブ >> GPIO ボタン
外部信号の立ち上がりでイベントを発生させる場合は
External Interrupt Mode with Rising edge trigger detection
立下りでイベント発生
Falling edge
両方のイベントを発生させる場合は
Rising/Falling
--------------------------------------------------------------------
GPIO Pull-up/Pull-down >> Pull up を選択
内部プルアップ抵抗が有効になり,外部にプルアップ抵抗が不要になる。そのため,PA0にスイッチを取り付け,片方をGNDへ落とすだけの配線でスイッチを落とすとイベントを発生させることができる。
Configurationタブ >> NVICボタン >> EXTI line*にチェック
割り込みを有効化する
EXTI割り込みを起こすための設定はスケルトンが全部やっている。
CubeMXが生成するスケルトンのEXTI処理手順は以下のとおり。
@ CPUが割り込みを受理し、CubeMXが生成したEXTI0_IRQHandler()が呼ばれる。
A EXTI0_IRQHandler()が、割り込み番号を引数としてHAL_GPIO_EXTI_IRQHandler()を呼ぶ。
B HAL_GPIO_EXTI_IRQHandler()が指定された割り込みが発生しているか確認し、発生していれば割り込みをクリアしてHAL_GPIO_EXTI_Callback()を呼ぶ。
※ HAL_GPIO_EXTI_IRQHandler()とHAL_GPIO_EXTI_Callback()は名前のとおりHALの関数であり、あらかじめ用意されている。
※「コールバックがHALに存在するのはおかしくない?」
HAL_GPIO_EXTI_Callback()はweakと宣言されており、同名の関数があるとそちらがリンクされ、あらかじめHAL内部に用意されている実体は無視される。うまい仕掛けではあるが、名前を間違えてコールバック関数を作ると、リンクエラーが起きないのに永遠に呼ばれない。
< stm32f3xx_it.c
>内の関数を見る
/******************************************************************************/
196 /*
STM32F3xx Peripheral Interrupt Handlers
*/
197 /* Add
here the Interrupt Handlers for the used peripherals.
*/
198 /* For
the available peripheral interrupt handler names,
*/
199 /* please
refer to the startup file (startup_stm32f3xx.s).
*/
200 /******************************************************************************/
201
202 /**
203 * @brief This function handles
EXTI line0 interrupt.
204 */
205
void EXTI0_IRQHandler(void)
206
{
207 /* USER CODE BEGIN EXTI0_IRQn 0 */
208
209 /* USER CODE END EXTI0_IRQn 0 */
210
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
211 /* USER CODE BEGIN EXTI0_IRQn 1 */
212
213 /* USER CODE END EXTI0_IRQn 1 */
214
}
この関数の中に割り込み処理を書く場合、「どの割り込みが発生したか」は自分で調べないといけない。
void
EXTI0_IRQHandler(void)内にコードを書くときは,もう少し低層をコントロールするときに検討すればよいかも。。。
< /Drivers/STM32F3xx_HAL_Driver/Src/stm32f3xx_hal_gpio.c
>内 の関数を見る
***
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
***
{
*** /* EXTI line interrupt detected */
*** if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) !=
0x00u)
*** {
*** __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
*** HAL_GPIO_EXTI_Callback(GPIO_Pin);
*** }
***
}
-------------------------------------------------------------------------------------------
*** __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
*** */
*** }
HAL_GPIO_EXTI_IRQHandler()
は割り込みをクリアする。割り込みクリア前にしたいこと、割り込みクリア後にしたいことを書く。今回はこのまま,実際はmain.cファイル内に
void
HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){ }
を追加して,その中に具体的な処理を書けばいいらしい。
ここでは発生した割り込みを受け取るハンドラの記述を行う。外部イベント割り込み関数
HAL_GPIO_EXTI_Callbackをグローバル関数として追加。外部イベント割り込みが発生するとこの関数が呼び出される。
今回はPA0で外部イベント割り込みを設定したため,GPIO_PIN_0で割り込みが発生した際の処理を行う。
<コーディング> main.c内
*** /*
USER CODE BEGIN 4 */
***
void HAL_GPIO_EXTI_Callback( uint16_t GPIO_Pin ) {
*** if ( GPIO_Pin == GPIO_PIN_0
){
***
HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
*** }
***
}
*** /*
USER CODE END 4 */
チャタリングが発生しているため,LED_Greenの反応にバタつきがある。
また余談だが,HAL_Delay(100);等を使うが想定通り動かなかった。割り込み内でディレイはあまりしないほうがよい?