はじめに
こんにちは、槇原です。前回は基板の設計をしてきました。今回からはマイコンのペリフェラルについて書いていきます。今回はタイトルの通りSTM32マイコンでADCをする際に各チャンネルの変換を1つずつ行う方法について説明します。
やりたいこと
今回のマウスの壁センサでは125 µsおきに4つある壁センサのうち1つのセンサの値を取得するという動きをさせます。高速でADCを行うことでマウス全体の制御周期(1 ms)より早くすべてのセンサの値を更新できるようにします。
マイコンのピンアサインは次の通りです。
ピン | ADC |
---|---|
PA0 | ADC1_IN1 |
PA1 | ADC1_IN2 |
PA2 | ADC1_IN3 |
PA3 | ADC1_IN4 |
CubeMXでの設定は次のとおりです。設定自体は1ch用の変換の設定をして、プログラム上でどのチャンネルの変換をするか切り替えます。
毎回ソフトウェアをトリガーでADCをするためEnable Regular ConversionsをEnable、External Trigger Conversion SourceをRegular Conversion launched by softwareに指定します。
プログラム
今回は毎周期ごとに、1ch分の通常のADCを行います。さらに毎回必要なチャンネルを切り替える必要があるため。HAL_ADC_ConfigChannel関数によって毎回チャンネルを指定します。
必要な設定項目はADC_ChannelConfTypeDefという構造体に必要な部分を設定します。特に今回はChannelを読みたいポートに合わせて指定します。
ChannelはマイコンのピンのADC_INxに対応します。ここではReadADCという関数を作りました。引数にチャンネルを取り、それに合わせて読み取るチャンネルを指定します。
uint16_t ReadADC(int ch){ ADC_ChannelConfTypeDef sConfig = {0}; sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5; sConfig.SingleDiff = ADC_SINGLE_ENDED; sConfig.OffsetNumber = ADC_OFFSET_NONE; sConfig.Offset = 0; switch(ch){ case 1: sConfig.Channel = ADC_CHANNEL_1; break; case 2: sConfig.Channel = ADC_CHANNEL_2; break; case 3: sConfig.Channel = ADC_CHANNEL_3; break; case 4: sConfig.Channel = ADC_CHANNEL_4; break; } if(HAL_ADC_ConfigChannel(&hadc1, &sConfig) !=HAL_OK){ Error_Handler(); } if(HAL_ADC_Start(&hadc1) == HAL_OK){ if (HAL_ADC_PollForEvent(&hadc1,ADC_EOSMP_EVENT, 200) == HAL_OK){ uint16_t data=HAL_ADC_GetValue(&hadc1); return data; } } return -1; }
壁センサの値を取得するためには発光側のLEDを光らせて一定時間待機してからADCを行います。
これを125 µsおきに呼び出すポートを変えてセンサ値を取得します。割り込み中にADCを行うため、for文で一定時間待機させます。
HAL_GPIO_WritePin(LED_R_GPIO_Port, LED_R_Pin, GPIO_PIN_SET); for(int i=0;i<loop_num;i++); right_adc_value= ReadADC(2); HAL_GPIO_WritePin(LED_R_GPIO_Port, LED_R_Pin, GPIO_PIN_RESET);
ここまで書いてしまったのですが、これを作成してからRankを付けておけばひとつずつ呼び出すだけで順番にADCしてくれるらしいという話を聞きました。次からはこちらを使おうと思います…
参考
次回はFlashの書き込みについて書いていきます。