ししかわです。
社員研修の一環で、自作マウスを作って大会に出場します。
記事一覧 – 元Web屋のマイクロマウス製作記 | RT MicroMouse
前回はマウスモジュール側の開発環境構築をしました。
これから数回に渡って、マウスモジュール側にセンサやモータを繋いで動かしてみます。
今回はSTM32で光センサの値を読み取ってみました。

LEDと光センサで迷路の壁を見る
マイクロマウスで迷路の壁の有無を判断するためには、
- 赤外線LEDを発光させる
- 壁に反射した光を光センサで読み取る
- 読み取った値がしきい値を超えていれば「壁あり」と判断する
という方法を取るのがメジャーです。
赤外線LEDの代わりに可視光(緑色)のLEDを使ったり、ToFセンサと組み合わせたりする方もいます。
マイクロマウスの光センサについてはアールティのショップブログの解説が詳しいです。
- マイクロマウスのセンサについて① – RT Robot Shop Blog
- マイクロマウスのセンサについて② – RT Robot Shop Blog
- マイクロマウスのセンサについて③ – RT Robot Shop Blog
私のマウスは次の部品を使います。どちらもマイクロマウスで動作実績があります。
以降では、STM32にフォトトランジスタを繋いで動作確認させてみます。
フォトトランジスタは受光した光量に比例して電流が流れる素子です。
この電流を抵抗に流すと、電流値に応じて電圧が変わる回路になります。
この電圧値をSTM32のA/Dコンバータで読み取ります。

STM32の開発の流れ
今回用意したSTM32環境での基本的な開発の流れは、次のステップで行います。
- STM32CubeMX(以下CubeMX)でSTM32のピンやクロックの設定を変更する
- コード雛形を出力する
- 必要な処理を書き足す
場合によっては開発の途中でピンやクロック設定を変更したくなるでしょう。
そんなときは1.~3.を繰り返せばOKです。
これを繰り返すと、3. でユーザが書いた処理が2.で出力される雛形で全て上書きされてしまいそうに見えますが、
CubeMXは雛形のうち /* USER CODE BEGIN|END */ で囲まれた部分は上書きしないようになっています。
開発の際は上記のコメントで囲まれた部分を編集するよう注意しましょう。
STM32の設定
CubeMXを開いて、AD変換のための設定を加えます。
- 「Pinout & Configuration」タブから、左カラムのAnalog->ADC1をクリック
- 「ADC1 Mode and Configuration」メニューのIN0にチェック

「Configuration」で様々な設定ができますが、動作確認では特に手を加えません。
雛形の出力
「GENERATE CODE」をクリックして雛形を出力します。
出力した雛形には新たにA/Dコンバータ初期化のコードが加わっています。
// adc.cから抜粋
/**
* @brief ADC1 Initialization Function
* @param None
* @retval None
*/
static void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
必要な処理を書き足す
出力した雛形は初期化までを行いますが、
AD変換の開始・停止や値の読み取り処理はユーザ側で追記する必要があります。
CubeMXのデフォルト設定の場合、次の3つの関数を実行することでAD変換された電圧値を取得できます。
- AD変換の開始:HAL_ADC_Start
- AD変換処理を待つ:HAL_ADC_PollForConversion
- 変換された値を取得する:HAL_ADC_GetValue
コード例は次のようになります。
(本来はエラーハンドリングのコードも必要ですが、簡単のため省略しています)
// main.cから抜粋
/* USER CODE BEGIN 2 */
uint16_t adcValue = 0;
uint16_t delay = 0;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
/* ADC */
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 1000);
adcValue = HAL_ADC_GetValue(&hadc1);
delay = 100 + (adcValue >> 1);
HAL_Delay(delay);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
例では取得した値の大小に応じてLチカの間隔を変化させてみました。

プリントデバッグやJTAGを使ったデバッグの方法も近く記事にします。
