どうも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 */
}
動作の様子
今回は以上です。とりあえず試してみたい機能はできたと思います。次回から本格的なハードウェア制御用マイコンとして使っていきたいですね。




















