どうもcaketetuです。
前回、HALライブラリでLチカできました。今回はその他使いそうな機能のテストプログラムのメモです。
タイマ割込み
特別な設定なく一定間隔でのタイマ割込みをかけます。TIM15を使用し、間隔は1sです。
タイマ割込みでLチカするのでIO出力の設定も必要になります。IO出力は前回参照です。
CubeMX設定
赤部分がデフォルトから変更した箇所です。割込み周波数は1Hzなのでソース周波数(ここでは32MHz)をPrescaler(10000カウント)で割り、さらにそれをCounter Period(3200カウント)分カウントアップすると1Hzになります。画像は間違ってますね…Counter Period=3199が正しいです。
ここで設定値は0からのカウントなので例えば10000カウントしたければ10000-1=9999を設定します。10000-1と書いても大丈夫なようです。
サンプルプログラム
割込みでLEDをON-OFFします。割込みをmain.cに持ってきたかったので新しく関数を作りstm32f3xx.it.cで呼び出すようにしています。
//Private user code(60行目付近) /* USER CODE BEGIN 0 */ void tim15_tick(void){ HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_2); } //stm32f3xx_it.c内 void TIM1_BRK_TIM15_IRQHandler(void) { /* USER CODE BEGIN TIM1_BRK_TIM15_IRQn 0 */ tim15_tick(); //関数を追加 /* USER CODE END TIM1_BRK_TIM15_IRQn 0 */ HAL_TIM_IRQHandler(&htim15); /* USER CODE BEGIN TIM1_BRK_TIM15_IRQn 1 */ /* USER CODE END TIM1_BRK_TIM15_IRQn 1 */ } //mainループ(100行目付近) /* USER CODE BEGIN 2 */ HAL_TIM_Base_Start_IT(&htim15); //タイマスタート /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */
PWM出力
TIM1をPWM出力に割り当てます。周期は1kHzです。PWMでLEDの光量を操作します。Prescalerは32カウント、Counter Periodは1000カウントで1KHzですね。
CubeMX設定
赤部分がデフォルトから変更した箇所です。
サンプルプログラム
上記でCounter Period=0~999で設定したので、この間の数値でデューティ比を決めます。
50%なら499になりますね。
/* Initialize all configured peripherals */ MX_GPIO_Init(); MX_TIM1_Init(); /* USER CODE BEGIN 2 */ HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //PWMスタート HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2); //PWMスタート /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ for(int i=0; i<999; i++){ __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, i); //PWM出力 __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, 999-i); //PWM出力 HAL_Delay(1); } for(int i=0; i<999; i++){ __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 999-i); //PWM出力 __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, i); //PWM出力 HAL_Delay(1); } } /* USER CODE END 3 */
AD変換
ADC1、CH4でAD変換します。デバックにPWMを使うので上記方法で設定しておきます。
今回は最も簡単なワンショットでの測定です。ADCの分解能が12bitなのでPWMのCounter periodは4095に設定します。これでAD値をそのままぶち込めばぴったりDuty比0~100になりますね。
CubeMX設定
サンプルプログラム
AD変換値をそのままPWM出力しLEDを点灯させます。
/* USER CODE BEGIN 2 */ HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ //AD変換 HAL_ADC_Start(&hadc1); HAL_ADC_PollForConversion(&hadc1, 100); HAL_ADC_Stop(&hadc1); int ad_val = HAL_ADC_GetValue(&hadc1); //PWM出力 __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, ad_val); //PWM出力 } /* USER CODE END 3 */
シリアル通信
送信値をそのまま返すエコーバックを作ってみます。UART2を使用し、受信は割込みで送信はメイン関数で行います。
CubeMX設定
赤部分がデフォルトから変更した箇所です。NVIC設定で割込みを有効にします。
サンプルプログラム
//グローバル変数定義(50行目付近) /* USER CODE BEGIN PV */ //シリアル関連 char recv_buf[256]; char recv_data[256]; char recv_data_len=0; /* USER CODE END PV */ //mainループ(100行目付近) /* USER CODE BEGIN 2 */ HAL_UART_Receive_IT(&huart1, &recv_buf, 1); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ //データがあるとき if(recv_data_len){ HAL_Delay(10); //データをすべて読み出し HAL_UART_Transmit( &huart1, recv_data, recv_data_len, 0xFFFF); recv_data_len=0; } } /* USER CODE END 3 */ } //コールバック関数(230行目付近) /* USER CODE BEGIN 4 */ //シリアル受信割込みコールバック関数 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle) { HAL_UART_Receive_IT(&huart1, &recv_buf, 1); recv_data[recv_data_len] = recv_buf[0]; recv_data_len++; } /* USER CODE END 4 */
エンコーダモード
タイマ機能のエンコーダモードを使用し、エンコーダ入力をカウントします。使用しているエンコーダはFaulhaver1524モータについてきたIEH2-4096です。これはエンコーダが二相あり回転方向が分かるやつなのでEncoder Modeを二相に設定します。
CubeMX設定
赤部分がデフォルトから変更した箇所です。今回はTIM2、TIM3でモータ二つ分の入力をとってみます。どちらも設定は同じです。デバックでシリアルを使うので上記の要領で設定します。
サンプルプログラム
カウント値をシリアルで送信します。値が増えていれば正転、減っていれば逆転になります。
/* USER CODE BEGIN 2 */ HAL_TIM_Encoder_Start(&htim2,TIM_CHANNEL_ALL); //読み取りスタート HAL_TIM_Encoder_Start(&htim3,TIM_CHANNEL_ALL); //読み取りスタート /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ int enc1 = TIM2 -> CNT; //TIM2の値を取り出してcntに格納 int enc2 = TIM3 -> CNT; //TIM3の値を取り出してcntに格納 //シリアル書き出し char buf[100]; sprintf(buf , "%d %d \r\n",enc1, enc2 ); HAL_UART_Transmit( &huart1, buf, strlen(buf) + 1, 0xFFFF); HAL_Delay(100); } /* USER CODE END 3 */ }
動作の様子
今回は以上です。とりあえず試してみたい機能はできたと思います。次回から本格的なハードウェア制御用マイコンとして使っていきたいですね。