STM32 HALを使ってAD変換してみる

  • 2020.07.17
  • HAL
STM32 HALを使ってAD変換してみる

今回はAD変換についてお話します。

投稿時の開発環境を記しておきます。

PC:Windows10 OS
IDE: STM32CubeIDE Version1.3.0
Configurator: STM32CubeMX Version5.5.0
Board: STM32Nucleo-F401RE

ADCとは?

ADCはアナログ・ディジタル・コンバーターの略で、アナログの電圧をディジタルに変換するものです。

今回は可変抵抗に印加されている電圧を読みとってディジタル値に変換してみます。

接続

下表のとおりに接続します。

可変抵抗器の定数はいくつでも良いです。
私は手元にあった 2kΩのものを使いました。

可変抵抗器の中央をPA0端子に接続してアナログ電圧を読み込みます。
可変抵抗器の残る2つのピンを3.3VとGNDに接続します。
これはどちら側の足を3.3Vに接続しても構いません。
(可変抵抗器を右に回すと電圧が上がるか、下がるかの違いがあるだけです)

誤って3.3VとGNDを短絡しないようにしてください。

プロジェクトを作成する

IDEを起動し、File- New – STM32 Project を選択し、Target Selection ウィンドウが出たら Board Selector タブを選択し Boards List から NUCLEO-F401RE を選択し Next ボタンを押します。

Project 名に F401ADcHAL と入力し、Finishボタンを押します。
Initialize all peripherals with their default Mode ? と聞いてくるので Yesを押します。
This kind of project is associated with the STM32CubeMx perspective. Do you want to open this perspective now ? と聞いてくるので Yesを押します。

コードジェネレーターでADCを設定する

今回設定をする端子は左側の PA0 です。
PA0を右クリックし、リストから ADC1_IN0 を選択します。
これでこの端子はADCの入力端子に設定されます。

Project Explorer で F401ADcHAL を選択し、Project – Build Project でビルドします。

main.cに MX_ADC1_Init()が生成されてエラーがないことを確認します。

コードを追加する

main()の下に変数の宣言をします。

int main(void)
{
  /* USER CODE BEGIN 1 */
  __IO uint32_t ad;
  double v;

  /* USER CODE END 1 */

while()ループの中にAD変換処理を実装します。

  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
    HAL_ADC_Start(&hadc1);
    if( HAL_ADC_PollForConversion(&hadc1, 1000) == HAL_OK )
    {
	ad = HAL_ADC_GetValue(&hadc1);
        v = 3.3 * ad / 4095;
    }
    HAL_ADC_Stop(&hadc1);
  }
  /* USER CODE END 3 */

ビルドしてエラーがないことを確認しておきます。

コードの解説

__IO属性について:

__IOをダブルクリックして選択し、右クリックメニューから Open Declaration を選択します。
#define __IO volatile の定義に飛んでいきます。 __IO の正体は volatile でした。
volatile には「変わりやすい、不安定な」という意味があります。
( 変化するんだよ~ とコンパイラに教えているニュアンスでしょうか )
__IOはコンパイラに対して最適化を行わないように命令する修飾子になります。

HAL_ADC_GetValue()はレジスタの値を返す関数で、レジスタの値はAD変換の入力が変化していれば当然変化します。
ところがコンパイラには、このような話が通じないので最適化によっていつも同じ値が返ってくると解釈されてしまうことがあります。
それでは困るので最適化を行わないように指示するわけです。

まずHAL_ADC_Start()でAD変換を開始して
HAL_ADC_PollForConversion()でAD変換の完了を待ちます。
HAL_OKが得られたら HAL_ADC_GetValue()で値を読みとった後、HAL_ADC_Stop()で変換を停止します。

AD変換の分解能は 12, 10, 8, 6 の中から選択できるようになっています。
コンフィグレーターが出力したコードでは 12ビットが選択されています。

回路図を見るとVREF+入力がコイルを介してVDD(3.3V)に接続されていますので、可変抵抗器を目いっぱいプラス(VDD)側に回すとPA0端子への入力電圧はVREF+に近い値になるため変換された値は4095に近い値が得られます。

( 12ビットなので、最大値である2進数の 1111 1111 1111 は 10進数の 4095 )

またグランド側に回すと変換値は0に近い値が得られます。

中央あたりに合わせると 2000 前後の値が得られます。

プログラムを実行し、可変抵抗器を回しながら適当なタイミングで ad = HAL_ADC_GetValue(&hadc1); の部分で止めて adの値を読み取ってみてください。

また 12ビットの値だとピンと来ないので以下の式で電圧に変換して v を求めています。

v = 3.3 * ad / 4095;

思惑通りの値が得られれば成功です。

HALカテゴリの最新記事