見出し画像

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」に設定。
他の端子も設定されていますが、今回使用していません。

PA0をADC1_IN1に、PA8をTIM1_CH1に設定。

クロックの設定
いつもと同様に「Clock Configuration」の設定を行います。

Clock Configurationの設定

ADC1の設定
IN1を「IN1 Single-ended」に設定するだけで使用出来る様だ。
非同期、12bit、右アライメントになっていた。
「Pinout & Configuration」に戻り「Analog」の「ADC1」を選択
「ADC1 Mode and Configuration」の「Mode」にて
・IN1を「IN1 Single-ended」に設定する。

IN1を「IN1 Single-ended」を選択する。

DACの設定を確認する。
PINの設定だけで使用できるようになっています。使用していませんが、、、

DACの設定を確認する。

USART1を設定する。
今回ADCで読み込んだ値をデバックの為、USART1で送信する事にした。以前と同様にDMAと割込みを使用する。
「Connectivity」の「USART1」を選択。
「USART1 Mode and Configuration」内の
・「Mode」を「Asynchronous」に設定。
・「Configuration」の「Parameter Settings」タブ内
「Baud Rate」を「115200」に設定。

「Mode」を「Asynchronous」に設定、「Baud Rate」を「115200」に設定。

DMAの設定。「Configuration」の「DMA Settings」タブ内にて
・「Add」をクリックして、「USART1_RX」と「USART1_TX」を追加する。

「USART1_RX」と「USART1_TX」を追加する。

「Configuration」の「NVIC Settings」タブ内にて
・「USART1 global interrupt/…」をEnabledにする。

「USART1 global interrupt/…」をEnabledにする。

今回使用しないがUSART2を設定している。

USART2の設定①
USART2の設定②
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」に設定する。

「Channel1」を「PWM Generation CH1」に設定

・「Configuration」の「Parameter Settings」タブ内
「Prescaler」を240-1に設定。「Counter Priod」を250-1に設定する。

「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に設定する。

「Prescaler」を6000-1に設定。「Counter Priod」を10-1に設定する。

・「Configuration」の「NVIC Settings」タブ内にて
「TIM2 global interrupt」をEnabledにする。

「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関数

HAL_ADC_Start関数
HAL_ADC_GetValue関数

今回使用したPWM関係のAPI関数

HAL_TIM_PWM_Start関数

__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_  */

ビルドし、マイコンに書き込んで実行する。
動作している様子の動画です。
以上。


この記事が気に入ったらサポートをしてみませんか?