入力キャプチャ
1.入力キャプチャの概要
入力キャプチャモードは、パルス幅または周波数を測定するために使用できます。次の図は、パルス幅測定を例として使用して、入力キャプチャの原理を示しています。
タイマーがアップカウントモードで動作すると仮定すると、図の時間t1-t2は、測定する必要がある低レベルの時間です。測定方法は、最初にタイマーチャネルxを立ち下がりエッジでキャプチャするように設定し、現在のCNT値をt1でキャプチャし、すぐにCNTをクリアして、チャネルxを立ち上がりエッジでキャプチャするように設定し、t2でキャプチャイベントを送信します。 、この時点でのCNT値(CCRx2と表示)を取得します。t1〜t2の間にN回のタイマーオーバーフローが発生する可能性があるため、低レベルが長すぎてデータが不正確にならないように、タイマーオーバーフローに対処する必要があります。
t1-t2間のカウント数は、N * ARR + CCRx2であり、CNTカウント期間を乗算して、低レベルの期間を取得します。
2.ハードウェア設計
この実験は、TIM5のチャネル1入力キャプチャ機能を介してKEY_UPボタンの高レベルの期間をキャプチャし、キャプチャされた高レベルの時間をprintf関数を介して出力し、D1インジケータを使用してシステムの通常の動作を示します。
- D1インジケーター
- K_UPボタン
- USART1シリアルポート
- TIM5
3.ソフトウェア設計
3.1 STM32CubeMX設定
- RCCは外部HSEを設定、クロックは72Mに設定
- PC0はGPIOプッシュプル出力モード、プルアップ、高速に設定され、デフォルトの出力レベルは高
- USART1は非同期通信モードとして選択され、ボーレートは115200ビット/秒に設定され、送信データ長は8ビット、パリティなし、1ストップビットです。
- TIM5を選択し、タイマークロックソースを内部クロックソースに設定し、チャネル1を入力キャプチャモードに設定し(PA0は自動的に選択されます)、NVIC設定でタイマー割り込みをアクティブにし、信号が入力されていないときのレベルを確保するためにGPIO設定でPA0をプルダウンします安定した
- プリスケーラ係数を72-1に設定し、カウントアップして、自動リロード値を0xFFFFに設定します。その後、タイマークロック周波数は1MHz、タイマー周期は1us、タイマーオーバーフロー周期は65535 * 1 = 65535usです。
- プロジェクト名を入力し、プロジェクトパス(中国語以外)を選択し、MDK-ARM V5を選択します。IPごとに「.c / .h」ファイルのペアとして生成されたペリフェラルの初期化を確認します。「コードを生成」をクリックしてプロジェクトコードを生成します
3.2 MDK-ARMプログラミング
- タイマー更新割り込み処理コールバック関数をtim.cファイルに書き込みます。
/* TIM5CH1_CAP_STA 各数据位说明
** bit7 捕获完成标志
** bit6 捕获到高电平标志
** bit5~0 捕获高电平后定时器溢出的次数*/
uint8_t TIM5CH1_CAP_STA = 0;
uint16_t TIM5CH1_CAP_VAL;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if((TIM5CH1_CAP_STA & 0X80) == 0){
//还未成功捕获
if(TIM5CH1_CAP_STA & 0X40){
//已经捕获到高电平
if((TIM5CH1_CAP_STA & 0X3F) == 0X3F){
//高电平时间太长了
TIM5CH1_CAP_STA |= 0X80; //标记为完成一次捕获
TIM5CH1_CAP_VAL = 0XFFFF; //计数器值
}
else
TIM5CH1_CAP_STA++; //溢出次数加1
}
}
}
- 入力キャプチャ割り込み処理コールバック関数をtim.cファイルに書き込みます
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){
if((TIM5CH1_CAP_STA & 0X80) == 0){
//还未成功捕获
if(TIM5CH1_CAP_STA & 0X40){
//捕获到上升沿后条件为真
TIM5CH1_CAP_STA |= 0X80; //标记为完成一次高电平捕获
TIM5CH1_CAP_VAL = HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1); //获取当前的计数器值
TIM_RESET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1); //清除原来的设置
TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING); //设置上升沿捕获
}
else{
TIM5CH1_CAP_STA = 0;
TIM5CH1_CAP_VAL = 0;
TIM5CH1_CAP_STA |= 0X40; //标记捕获到上升沿
__HAL_TIM_DISABLE(&htim5); //关闭定时器
__HAL_TIM_SET_COUNTER(&htim5,0); //计数器值清零
TIM_RESET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1); //清除原来的设置
TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING); //设置下降沿捕获
__HAL_TIM_ENABLE(&htim5); //使能定时器
}
}
}
ここでTIM_RESET_CAPTUREPOLARITY()関数にHALライブラリ関数エラーがあり、関数のコンパイル時にエラーが発生します。解決策は、stm32f1xx_hal_tim.hファイルで関数の定義を見つけ、余分なブラケットを削除することです) ')'
stm32f1xx_hal_tim.h
//修改前
#define TIM_RESET_CAPTUREPOLARITY(__HANDLE__, __CHANNEL__) \
(((__CHANNEL__) == TIM_CHANNEL_1) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC1P | TIM_CCER_CC1NP))) :\
((__CHANNEL__) == TIM_CHANNEL_2) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC2P | TIM_CCER_CC2NP)) :\
((__CHANNEL__) == TIM_CHANNEL_3) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC3P)) :\
((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC4P)))
//修改后
#define TIM_RESET_CAPTUREPOLARITY(__HANDLE__, __CHANNEL__) \
(((__CHANNEL__) == TIM_CHANNEL_1) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC1P | TIM_CCER_CC1NP)) :\
((__CHANNEL__) == TIM_CHANNEL_2) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC2P | TIM_CCER_CC2NP)) :\
((__CHANNEL__) == TIM_CHANNEL_3) ? ((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC3P)) :\
((__HANDLE__)->Instance->CCER &= ~(TIM_CCER_CC4P)))
- main.cファイルに高レベル期間処理コードを記述します
int main(void){
long long temp = 0;
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM5_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_IC_Start_IT(&htim5,TIM_CHANNEL_1); //一定要开启TIM5通道1的捕获中断
__HAL_TIM_ENABLE_IT(&htim5,TIM_IT_UPDATE); //一定要开启TIM5的更新中断
printf("This is TIM_CAP test...\n");
/* USER CODE END 2 */
while (1){
HAL_Delay(500);
if(TIM5CH1_CAP_STA & 0X80){
//完成一次高电平捕获
temp = TIM5CH1_CAP_STA & 0X3F;
temp *= 65536; //溢出总时间
temp += TIM5CH1_CAP_VAL; //总的高电平时间
printf("High level duration:%lld us\r\n",temp);
TIM5CH1_CAP_STA = 0; //准备下一次捕获
}
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);
}
}
4.ダウンロードの確認
コンパイルが正常に完了したら、開発ボードにダウンロードします。D1インジケーターが500msごとに1回点滅し、KEY_UPを押した後、シリアルポートが対応する高レベルの期間を印刷します。