記事ディレクトリ
外部割り込みによるキーキャプチャコードの実装と分析
1 コード フローの分析
2 コード
の実装 ライブラリ関数 HAL_Init(void) の分析:
HAL_StatusTypeDef HAL_Init(void)
{
/* Configure Flash prefetch, Instruction cache, Data cache */
#if (INSTRUCTION_CACHE_ENABLE != 0U) //0U表示无符号整型 0 , 1U 表示无符号整型1 ~0U就是对无符号数0取反。
__HAL_FLASH_INSTRUCTION_CACHE_ENABLE();
#endif /* INSTRUCTION_CACHE_ENABLE 允许指令缓存*/
#if (DATA_CACHE_ENABLE != 0U)
__HAL_FLASH_DATA_CACHE_ENABLE();
#endif /* DATA_CACHE_ENABLE */
#if (PREFETCH_ENABLE != 0U)
__HAL_FLASH_PREFETCH_BUFFER_ENABLE();
#endif /* PREFETCH_ENABLE */
/* Set Interrupt Group Priority 中断优先级分组*/
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
/* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */
HAL_InitTick(TICK_INT_PRIORITY); //初始化系统时钟
/* Init the low level hardware 初始化底层硬件(堆栈指针)*/
HAL_MspInit(); //使用HAL_Delay延时
/* Return function status */
return HAL_OK;
}
ヒント1: 関数の記述形式
/****************
*函数名:main
*函数的描述:通过中断实现按键的捕获
*输入参教:
*输出参数:
*返回值:
*图数作者:
*创建时间:
*更改说明:
*****************/
ヒント 2: CMSIS 遅延の使用方法
HAL_Delay() システム遅延手順:
その実装手順は次のとおりです。
1. 変数を使用してシステム クロック ソース カウンタの値を取得します。
2. 遅延時間のパラメータ値を取得します
。 3. 2 つのサイズを比較します (値が異なる場合)。クロック カウンタが実現する値より大きい場合、遅延された値はループ内にトラップされますが、それ以外の場合はループが飛び出し、遅延が完了します。
/**
* @brief此函数提供最小延迟(以毫秒为单位)对变量递增。
* @note在默认实现中,SysTick计时器是基准时间的来源。
*它用于在固定的时间间隔生成中断,其中uwTick是递增的。
这个函数被声明为__weak,在其他情况下会被覆盖实现在用户文件。
*@param Delay指定延迟时间长度,单位为毫秒。
*@retval无
*/
__weak void HAL_Delay(uint32_t Delay)
{
uint32_t tickstart = HAL_GetTick(); //获得起始时钟
uint32_t wait = Delay;
/* Add a freq to guarantee minimum wait */
if (wait < HAL_MAX_DELAY) //#define HAL_MAX_DELAY 0xFFFFFFFFU=1111 1111 1111 1111 1111 1111 1111 1111
{
// HAL_TICK_FREQ_1KHZ = 1U,
// HAL_TICK_FREQ_DEFAULT = HAL_TICK_FREQ_1KHZ
wait += (uint32_t)(uwTickFreq); //作用是给wait加1。HAL_TickFreqTypeDef uwTickFreq = HAL_TICK_FREQ_DEFAULT; /* 1KHz */
}
while((HAL_GetTick() - tickstart) < wait) //当前时钟-起始时钟的值小于wait(delay)就重复操作,直到计时结束
{
}
}
GetTick 関数のプロトタイプ
/**
调用这个函数是为了增加一个全局变量“uwTick”用作申请时基。
在默认实现中,这个变量每1ms增加一次在SysTick ISR。
这个函数被声明为__weak,在其他情况下会被覆盖实现在用户文件。
* @retval无
*/
__weak void HAL_IncTick(void)
{
uwTick += uwTickFreq;
}
/**
* @brief提供以毫秒为单位的tick值。
这个函数被声明为__weak,在其他情况下会被覆盖实现在用户文件。
@retval tick value
*/
__weak uint32_t HAL_GetTick(void)
{
return uwTick;
}
ベアメタルレベルに関しては、他に隠されたものはなく、自分で解析すれば、プログラムの動作の詳細やタイミング関係を整理することができます。遵守すべき原則:
1. メイン プログラムではデッドウェイト遅延を使用しないようにします 2. 各サブルーチン (タスクとも呼ばれます) のクエリ頻度は、メイン プログラムの実行時間より大きくする必要があります。例: 広告サンプリング、100 ミリ秒ごとにサンプリングすると、メイン プログラムは 100 ミリ秒以内に実行される必要があります。
待機遅延は米国レベルになる可能性があり、タイミングが高い場合は、大きな遅延に対してタイマーが使用されます。
stm32f407_intr_handle.c解析
割り込み処理関数: void EXTI4_IRQHandler
start_stm32f407xx.s のハンドラーの説明に従って、対応するブレークポイント処理関数を記述します。
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD DebugMon_Handler ; Debug Monitor Handler
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
実行関数: HAL_GPIO_EXTI_IRQHandler(KEY0_PIN)、stm32f4xx_hal_gpio.c で void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin) を呼び出します。関数の定義は次のとおりです。
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* EXTI line interrupt detected */
//#define __HAL_GPIO_EXTI_GET_IT(__EXTI_LINE__) (EXTI->PR & (__EXTI_LINE__))
//__EXTI_LINE__ specifies the EXTI line flag to check.
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET) // RESET = 0U(stm32f4xx.h),表明检测到了中断
{
/**
* @brief Clears the EXTI's line pending bits.
* @param __EXTI_LINE__ specifies the EXTI lines to clear.
* This parameter can be any combination of GPIO_PIN_x where x can be (0..15)
* @retval None
*/
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}
HAL_GPIO_EXTI_Callback のコールバック関数は、HAL では明示的に実装されていない (弱い宣言) ため、実装関数を自分で構築する必要があります。
プロトタイプは次のとおりです。
/**
* @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
*/
}
コールバック関数は key.c で書き換えられます。
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == KEY0_PIN) // KEY0_PIN被按下
{
Led_Ctrl(LED0_PIN_ROW, LED0_PIN, LED_ON); //执行点灯操作
}
}
uint16_t Detect_key(uint16_t key_pin) はこのセクションでは使用されません。
デバッグプロセス
デバッグ用の割り込み処理関数とuwTick自己増加演算関数で割り込みを設定します。
void EXTI4_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(KEY0_PIN);
}
void SysTick_Handler(void)
{
HAL_IncTick(); //uwTick自加操作 uwTick += uwTickFreq;
}
ソフトウェアシミュレーションデバッグ
ソフトウェア シミュレーションを使用してデバッグを開始し、メイン関数の LED0_Init() 関数で停止します。
操作中にエラーが発生しました: *** エラー 65: 0x40023830 でのアクセス違反:
対応する CPU が指定されていないため、「書き込み」権限がありません:
解決策:
- 1 新しい cpu.ini を作成し、次のように記述します。
map 0x40000000,0x400FFFFF read write
- 2 cpu.ini をデバッグに追加します。
2 つのコードの比較
割り込みモードでは、CPU 占有率が小さくなり、待ち時間が短くなり、CPU 占有率が低下します。
授業の宿題の後:
1: Bincheng マニュアル (第 30 章) で USART コントローラーの説明をプレビューします。
2: KEY1 を押した後、割り込みによってプログラムを実装します。LED1 を 0.5 秒間隔で点滅させ、5 秒後に消灯させ、コードを実装し、ボードのデバッグ