【学習記録】 STM32 学習記録 (3) ボタンで LED ライトを制御するこのアプリケーションでは、ボタンのデバウンスはソフトウェア遅延の方法を採用し、遅延にはインターフェイス関数 HAL_Delay() を使用します。この遅延デバウンス方式はプロセッサの実行時間を占有し、遅延処理中はプロセッサが他の処理を行うことができなくなり、プロセッサの使用率が低下する。
実際の開発やエンジニアリングの応用では、ステートマシンとタイミング割り込みを組み合わせてキーの検出を完了する方法が一般的に使用されます。
ステート マシンは抽象的な概念であり、プロセスがいくつかの状態間の遷移に抽象化され、これらの状態間には特定の接続が存在することを意味します。ステート マシンには主に 4 つの要素が含まれています。
1. 現在の状態: 現在の状態を指します。
2. 条件: 条件が満たされると、アクションがトリガーされるか、状態遷移が実行されます。
3. アクション: 条件が満たされた後に実行される特定の操作。アクションの実行後、新しい状態に移行することも、元の状態にとどまることもできます。アクションは必要ありません。条件が満たされると、アクションを実行せずに新しい状態に直接移行できます。
4. 2 番目の状態: 条件が満たされた後に移行する新しい状態。「二次状態」は「現在の状態」に対して相対的なものであり、「二次状態」が活性化されると新たな「現在の状態」に変化する。
4 要素の理解: ステート マシンは、現在の状態 (現在の状態) でアクションを繰り返し実行し、その状態にジャンプするための条件を検出し続けます。ある条件が突然満たされると、次の状態(二次状態)へ移行し始め、別の動作を繰り返します。このときの二次状態が現在の状態となる。
ステートマシンプログラミングの手順: 1. 製品の機能要件を分析し、状態を抽出する; 2. 状態図を描き、状態の切り替え関係を明確にし、状態遷移の条件をマークする; 3. ステートマシンで実現する機能を明確にするステートマシン; 4. コードを記述します。
一般的なステート マシンは switch ブランチ ステートメントによって実装されます。
ボタン監視では、単一のボタンを単純なシステムとみなして、ボタンの動作とボタンの確認プロセスをボタンの動作プロセス全体に従って分析し、それを状態遷移図を使用して表現して記述します。状態図に従ってアプリケーション プログラムを実行します。
ステート マシンの原理に従って、ボタン プロセスを 3 つの状態に抽象化できます。
ボタンアップ状態:ボタンが押されていない状態。
キーデバウンス状態: キーの揺れを解消します。
ボタン解放待ち状態:ボタンが離されるのを待っています。
具体的な状態遷移プロセスは次のとおりです。
キーを離したときにキー信号が有効であれば(キー制御ピンがアクティブレベルを読み取る)、キーデバウンス状態に切り替わり、キーのジッターを除去する準備を開始します。ボタン信号が無効な場合は、現在の状態を変更しないでください。
ボタンデバウンス状態にある場合、ボタン信号が有効であれば、ボタンの揺れが解消され、ボタンが安定した閉じ状態にあり、現在のボタンに対応する白番号(キーデコード)を取得できることを示します。ボタン信号が無効な場合は、前のボタン信号が干渉信号である可能性があることを意味し、ボタンアップ状態に戻ります。
キーが離されるのを待っているときに、キー信号が有効であれば、キーはまだ押された状態にあることを意味し、状態の変更は行われません。ボタン信号が無効な場合は、ボタンが放されたことを示し、ボタンアップ状態に移行する必要があります。ここまでで、キー検出のプロセス全体が完了しました。
ボタンの状態遷移過程と遷移条件を下図に示します。
実験内容:ステートマシンの設計思想を利用してボタン処理プログラムを作成し、ボタン押下後の動作(LED1の状態を反転)を実行します。
実験デザインのアイデア:
- 3 つの列挙型メンバーを含む列挙型によって実現されるキー状態データ型 KEY_STATE を設計します。 KEY_UP はキー アップ状態を示し、KEY_DEBOUNCE はキー デバウンス状態を示します。 KEY_WAIT_RELEASE はキーの解放待ち状態を示します。
- キースキャン関数 KeyScan() を設計し、Switch-Case マルチブランチ言語を使用し、キーピンのレベルを検出してキー状態の変換を実現します。
- タイマを使用して 10ms の定期割り込みを生成し、定期割り込みサービス ルーチンでキー スキャン関数を呼び出します。キー スキャン機能は 10 ミリ秒ごとに呼び出され、この時間間隔を使用してキー ジッターを排除し、CPU 使用率を向上させることができます。
- フロントエンドとバックエンドのプログラミング モードを採用します。フラグ変数KeyFlagを設定し、タイマ割り込みによりKeyFlagを設定します。バックグラウンドプログラムは while (1) ループ内で KeyFlag を継続的に検出し、それが true であればキー処理タスクを実行します。
実験的なペリフェラル構成
時間厳守の Atom Explorer を使用してください。
- CubeMX を開いて設定し、対応するピン設定で stm32F407ZGT6 を選択します。PE4 ピンは GPIO_Input に設定され、PF10 ピンは GPIO_Output に設定されます。
- クロックツリー構成を実行する
3. タイマーを設定し、tim1 を有効にします (その他も選択可能)
4. コードを生成する
実験的なコード
1. データ型設計、変数定義、関数宣言
/* USER CODE BEGIN PTD */
typedef enum{
KEY_UP, //按键抬起
KEY_DEBOUNCE, //按键消抖
KEY_WAIT_RELEASE //按键等待释放
}KEY_STATE;
/* USER CODE END PTD */
/* USER CODE BEGIN PV */
KEY_STATE KeyState=KEY_UP;//按键状态,设置按键抬起为初试状态
uint8_t KeyFlag=0; //按键有效检测标识符,0无效,1有效
/* USER CODE END PV */
/* USER CODE BEGIN PFP */
void KeyScan();//按键扫描函数声明
/* USER CODE END PFP */
2. ボタンハンドラー
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim1);//启动定时器1,使能定时器1中断
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if(KeyFlag)
{
KeyFlag=0;
HAL_GPIO_TogglePin(GPIOF,GPIO_PIN_10);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
3. キースキャナー
/* USER CODE BEGIN 4 */
void KeyScan()
{
switch(KeyState)
{
case KEY_UP:
{
//读到低电平,转换到按键消除状态
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)==GPIO_PIN_RESET)
{
KeyState=KEY_DEBOUNCE;
}
break;
}
case KEY_DEBOUNCE:
{
//读到低电平,转换到按键等待释放状态,并设置按键有效标识
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)==GPIO_PIN_RESET)
{
KeyState=KEY_WAIT_RELEASE;
KeyFlag=1;
}
//读到高电平,说明是干扰信号,转换到按键抬起状态
else
{
KeyState=KEY_UP;
}
break;
}
case KEY_WAIT_RELEASE:
{
//读到高电平,说明按键释放,转换到按键抬起状态
if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)==GPIO_PIN_SET)
{
KeyState=KEY_UP;
}
break;
}
default:break;
}
}
/* USER CODE END 4 */
4. タイマ割り込みコールバック関数
/* USER CODE BEGIN 0 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==htim1.Instance)
{
KeyScan();
}
}
/* USER CODE END 0 */