STM32F303K8T6のADCとPWMの実験
実際の仕事のコーディングを始めた所、ADコンバーターとPWMを使用しなければならない事が判り、ADCとPWMを実験しました。
ADCに繋がった照度測定センサーで周囲の明るさを調べて、LEDランプ調光用のPWM信号を出力させます。実験はADCに可変抵抗器を接続してPWM信号はオシロスコープで計測します。
使用する全てのI/Oの設定を行っていた為、今回の実験で使用しないI/Oも設定しています。
いつもの様に自分の他の記事と重複している所は、省略しています。
STM32CubeIDEを立ち上げて、「STM32F303K8T6」のプロジェクトを作っていきます。
端子の設定
プロジェクト作成後、「Pinout & Configuration」にて、
・PA0を「ADC1_IN1」に設定。
・PA8を「TIM1_CH1」に設定。(PWM出力に使用。)
・PA9を「USART1_TX」に設定。
・PA10を「USART1_RX」に設定。
他の端子も設定されていますが、今回使用していません。
クロックの設定
いつもと同様に「Clock Configuration」の設定を行います。
ADC1の設定
IN1を「IN1 Single-ended」に設定するだけで使用出来る様だ。
非同期、12bit、右アライメントになっていた。
「Pinout & Configuration」に戻り「Analog」の「ADC1」を選択
「ADC1 Mode and Configuration」の「Mode」にて
・IN1を「IN1 Single-ended」に設定する。
DACの設定を確認する。
PINの設定だけで使用できるようになっています。使用していませんが、、、
USART1を設定する。
今回ADCで読み込んだ値をデバックの為、USART1で送信する事にした。以前と同様にDMAと割込みを使用する。
「Connectivity」の「USART1」を選択。
「USART1 Mode and Configuration」内の
・「Mode」を「Asynchronous」に設定。
・「Configuration」の「Parameter Settings」タブ内
「Baud Rate」を「115200」に設定。
DMAの設定。「Configuration」の「DMA Settings」タブ内にて
・「Add」をクリックして、「USART1_RX」と「USART1_TX」を追加する。
「Configuration」の「NVIC Settings」タブ内にて
・「USART1 global interrupt/…」をEnabledにする。
今回使用しないがUSART2を設定している。
初期化関数の順番の確認
「Project Manager」内「Advanced Settings」で、
「MX_DMA_Init」の後に「MX_USART1_UART_Init」と「MX_USART2_UART_Init」が来る様にする。
(自分の環境では最初からその順番だった。)
PWMの設定
TIM1設定(PWM、1mS周期、分解能250段階、割込みを使用しない。)
「Timers」にて「TIM1」を選択する。
「TIM1 Mode and Configuration」内の
・「Mode」の「Clock Source」を「Internal Clock」に設定する。(※記述が漏れていた。)
・「Mode」の「Channel1」を「PWM Generation CH1」に設定する。
・「Configuration」の「Parameter Settings」タブ内
「Prescaler」を240-1に設定。「Counter Priod」を250-1に設定する。
TIM2の設定
1mSインターバルタイマー、割込み使用。
「Timers」にて「TIM2」を選択する。
「TIM2 Mode and Configuration」内の
・「Mode」の「Clock Source」を「Internal Clock」に設定する。(※記述が漏れていた。)
・「Configuration」の「Parameter Settings」タブ内
「Prescaler」を6000-1に設定。「Counter Priod」を10-1に設定する。
・「Configuration」の「NVIC Settings」タブ内にて
「TIM2 global interrupt」をEnabledにする。
「保存」をクリックしてコードを生成する。
生成されたmain.cにコードを追加していく。
main.cの以下の部分のみコードを追加している。
・「/* USER CODE BEGIN 0 */」と「/* USER CODE END 0 */」の間の部分。
・「/* USER CODE BEGIN 2 */」と「/* USER CODE END 2 */」の間の部分。
・「/* USER CODE BEGIN 3 */」と「/* USER CODE END 3 */」の間の部分。
今回使用したADC関係のAPI関数
今回使用したPWM関係のAPI関数
__HAL_TIM_SET_COMPARE関数
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, count);
countの変数を変更してPWMのデューティ比を変えている。
資料に記述が無かった。
「/* USER CODE BEGIN 0 */」と「/* USER CODE END 0 */」の間に追加したコード
/* USER CODE BEGIN 0 */
#include "my_usart1.h" /* USART1 */
/* USER CODE END 0 */
「/* USER CODE BEGIN 2 */」と「/* USER CODE END 2 */」の間に追加したコード
/* USER CODE BEGIN 2 */
/* I/O初期化 */
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); /* TIM1 PWM Start */
HAL_ADC_Start(&hadc1); /* ADC1 Start */
my_usart1_init(); /* USART1初期化 */
/* USER CODE END 2 */
「/* USER CODE BEGIN 3 */」と「/* USER CODE END 3 */」の間に追加したコード
/* USER CODE BEGIN 3 */
uint32_t ad;
uint16_t count;
ad = HAL_ADC_GetValue(&hadc1); HAL_ADC_Start(&hadc1); /* ADC1 Start(毎回再スタート) */
my_usart1_fputs_ui32(ad); my_usart1_fputc('\r'); my_usart1_fputc('\n'); /* ADC値送信 */
count = (uint16_t)(ad >> 4); /* 4096 -> 256 */
if (count == 0) count = 1; /* 1~250(1/250~100%) */
else if (count > 250) count = 250;
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, count); /* TIM1 PWM duty ratio(1/250~100% OK) */
my_usart1_err_ckcl(); /* エラーチェックとフラグクリア */
HAL_Delay(1000);
}
/* USER CODE END 3 */
「Core」フォルダ内「Inc」フォルダに以下のコードを「my_usart1.h」と名前を付けて保存した。
#if !defined(_MY_USART1_H_)
#define _MY_USART1_H_
/* USART1変数*/
uint8_t ust1_rx_buf[1]; /* 受信API側で保存 */
uint8_t ust1_rx_q_buf[256]; /* ユーザー側受信バッファ */
uint8_t ust1_rx_q_rdix; /* ユーザー側受信バッファ読込位置 */
uint8_t ust1_rx_q_wtix; /* ユーザー側受信バッファ書込位置 */
uint8_t ust1_tx_buf[1]; /* 送信APIに渡す */
uint8_t ust1_tx_it_flg; /* 送信割込みリクエスト状態(送信割込み設定中に次のデータをセット防止用)*/
uint8_t ust1_tx_q_buf[256]; /* ユーザー側送信バッファ */
uint8_t ust1_tx_q_rdix; /* ユーザー側送信バッファ読込位置 */
uint8_t ust1_tx_q_wtix; /* ユーザー側送信バッファ書込位置 */
/****************************/
/* USART1 function */
/****************************/
/* 受信初期化 */
void my_usart1_rx_init(void)
{
ust1_rx_q_rdix = ust1_rx_q_wtix = 0; /* Qバッファインデックス初期化 */
HAL_UART_Receive_DMA(&huart1, ust1_rx_buf, 1); /* DMA受信と割込みスタート*/
}
/* 受信とチェック */
int my_usart1_fgetc(void)
{
if (ust1_rx_q_rdix != ust1_rx_q_wtix) /* 受信データが有る時 */
return ust1_rx_q_buf[ust1_rx_q_rdix++];
else /* 受信データが無い時 */
return -1;
}
/* 送信初期化 */
void my_usart1_tx_init(void)
{
ust1_tx_q_rdix = ust1_tx_q_wtix = 0; /* Qバッファインデックス初期化 */
ust1_tx_it_flg = 0; /* 送信割込みリクエスト状態解除 */
}
/* 送信割込スタートとデータセット */
void my_usart1_tx_it_st(void)
{
ust1_tx_buf[0] = ust1_tx_q_buf[ust1_tx_q_rdix++]; /* 送信Qバッファから読込 */
HAL_UART_Transmit_DMA(&huart1, ust1_tx_buf, 1); /* DMA送信と割込みスタート */
ust1_tx_it_flg = 1; /* 送信割込みリクエスト状態設定 */
}
/* 一文字送信 */
void my_usart1_fputc(uint8_t ch)
{
ust1_tx_q_buf[ust1_tx_q_wtix++] = ch;
if (ust1_tx_it_flg == 0) /* 送信割込み中でなかったら */
my_usart1_tx_it_st(); /* 送信割込みスタート */
}
/* 4bitバイナリーをアスキーコードに */
int bin2asc(int bin)
{
if (bin <= 9) return bin + '0';
else return bin - 10 + 'A';
}
/* uint32_tの数値を16進文字に変換して送信 */
void my_usart1_fputs_ui32(uint32_t dt)
{
my_usart1_fputc(bin2asc((dt >> 28) & 0x0F));
my_usart1_fputc(bin2asc((dt >> 24) & 0x0F));
my_usart1_fputc(bin2asc((dt >> 20) & 0x0F));
my_usart1_fputc(bin2asc((dt >> 16) & 0x0F));
my_usart1_fputc(bin2asc((dt >> 12) & 0x0F));
my_usart1_fputc(bin2asc((dt >> 8) & 0x0F));
my_usart1_fputc(bin2asc((dt >> 4) & 0x0F));
my_usart1_fputc(bin2asc(dt & 0x0F));
}
/* 0終端を持つ文字列を送信(fputsは改行なしなのでなし) */
void my_usart1_fputs(uint8_t *ss)
{
while (*ss != '\0') my_usart1_fputc(*ss++);
}
/* 送受信初期化 */
void my_usart1_init(void)
{
my_usart1_rx_init();
my_usart1_tx_init();
}
/****************************/
/* USART Callback */
/****************************/
/* データ受信全て完了 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/* USART1 */
if (huart->Instance == USART1) {
ust1_rx_q_buf[ust1_rx_q_wtix++] = ust1_rx_buf[0]; /* 受信Qバッファに積む */
HAL_UART_Receive_DMA(&huart1, ust1_rx_buf, 1); /* (次の)DMA受信と割込みスタート*/
}
}
/* データ送信全て完了 */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
/* USART1 */
if (huart->Instance == USART1) {
ust1_tx_it_flg = 0; /* 送信割込みリクエスト状態解除 */
if (ust1_tx_q_rdix != ust1_tx_q_wtix) /* 送信データはあるか? */
my_usart1_tx_it_st(); /* 送信割込みスタート */
}
}
/****************************/
/* USART ERR C'K */
/****************************/
/* エラーチェックとフラグクリア(コールバック関数ではなくアイドルループに入れる) */
void my_usart1_err_ckcl(void)
{
if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_ORE)) { /* オーバーランエラー時 */
__HAL_UART_CLEAR_FLAG(&huart1, /* エラークリア */
UART_CLEAR_NEF |
UART_CLEAR_OREF |
UART_FLAG_RXNE |
UART_FLAG_ORE);
}
else if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_NE) || /* 他のエラー時 */
__HAL_UART_GET_FLAG(&huart1, UART_FLAG_FE) ||
__HAL_UART_GET_FLAG(&huart1, UART_FLAG_PE) ) {
HAL_UART_Abort(&huart1); /* エラークリア */
}
else return; /* エラーが無ければ復帰 */
HAL_UART_Receive_DMA(&huart1, ust1_rx_buf, 1); /* DMA受信と割込みスタート*/
}
#endif /* _MY_USART1_H_ */
ビルドし、マイコンに書き込んで実行する。
動作している様子の動画です。
以上。
この記事が気に入ったらサポートをしてみませんか?