STM32F401でのアナログジョイスティックの使い方

STM32F401-Nucleoでアナログジョイスティックを使おうと思う。
そのためにはDMA変換をつかってアナログ入力を2チャンネルで行う必要がある。
STM32を使うと、だいたいDMAが難しくて挫折したくなる。
しかし、難しいけど覚えると非常に便利な機能なのでぜひとも使っていきたい。

DMAとは

Direct Memory Access(ダイレクトメモリーアクセス)の略。
ピンから読みこまれたアナログデータを変換して特定のレジスタに格納してくれる。
CPUは毎回、そこを確認すれば入力されたデータを確認できるのでCPUに余計な負荷をかけなくて済む。
要約すると、メモリ間のデータのやり取りをCPUを使わずに行えるものである。
しかし、よくわからないので複数のADCを使えるのも位の感覚でいいと思う。
ADC以外でも使えるみたいだけど、まだよくわからないので勉強していこうと思う。


CubeMXでピンの設定を行う


まずはピンにADCを使う設定を行う。
二つ使うので「A0」と「A1」を使っていく。
STM32では「PA0」と「PA1」になる。

[Analog]→[ADC1]で詳細設定画面を開く。

[DMA_Settings]をクリックする。


「Add」をクリックする。
「DMA Request」を「ADC1」にする。
「DMA Request Settings」のModeを「Circular」に設定する。
「Priority」を「High」にする。



「Parameter Settings」クリックして詳細設定を行っていく。

[ADC_Settings]から設定する。
「Scan Conversion Mode」を「Enabled」にする。
「Continuous Conversion Mode」を「Enabled」にする。
「Discontinuous Conversion Mode」を「Disabled」にする。
「DMA Continuous Requests」を「Enabled」にする。
それ以外の設定はデフォルトの設定で何もいじらない。

[ADC_Regular_ConversionMode]の設定。
「Number Of Conversion」を「2」にする。
「Rank」が二つになっていると思う。

「Channel」が「1」と「0」とそれぞれ設定されていることを確認する。
「Sampling Time」からそれぞれピンから入力されるデータの更新頻度を変えることが出来る。
今回は特に変えず、「3 Cycles」の設定で行っていく。



設定が完了したら、保存を行ってピン設定のプログラムを更新する。

main.cでプログラムを書いていく

コンソール画面に表示するプログラムは調べるとたくさんあるので、LCDに表示するプログラムを書いていこうと思う。

LCDは過去に使ったこともあるAQM0802を使っていく。

こんな感じにアナログジョイスティック用の関数を作ってみた。


// ----------------------------------------
// アナログジョイスティック
// ----------------------------------------
uint32_t g_ADCValue;
int g_MeasurementNumber;
enum{ ADC_BUFFER_LENGTH = 1024 };
uint16_t g_ADCBuffer[ADC_BUFFER_LENGTH];
ADC_ChannelConfTypeDef sConfig;

void ajoy_Init(void)
{
 memset(g_ADCBuffer, 0, sizeof(g_ADCBuffer));
 HAL_ADC_Start_DMA(&hadc1, g_ADCBuffer, ADC_BUFFER_LENGTH);
}

int ajoyGet( void )
{
   int y = g_ADCBuffer[1];
 int x = g_ADCBuffer[0];

 int ret = 0;
 if( y > 2000 ) ret |= 8; // 上
 if( y < 1200 ) ret |= 4; // 下
 if( x < 1200 ) ret |= 2; // 左
 if( x > 2000 ) ret |= 1; // 右

 return ret;
}

ajoyGet()関数の数値は調整の必要がある。
調整するときはコンソール画面を使ってやるとやりやすい。

実際の動きを決めるプログラムがこんな感じ。

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_USART2_UART_Init();
  MX_I2C1_Init();
  LCD_Init();
  ajoy_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  int aj;
  char str[32];
  char moji[32];
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
   aj=ajoyGet();
   if( aj & 1 ){
    LCD_WriteInstraction(0x01);
    strcpy(moji,"right");
    lcdDisp1(moji);
   }
   if( aj & 2 ){
    LCD_WriteInstraction(0x01);
    strcpy(moji,"left");
    lcdDisp1(moji);
   }
   if( aj & 4 ){
    LCD_WriteInstraction(0x01);
    strcpy(moji,"down");
    lcdDisp1(moji);
   }
   if( aj & 8 ){
    LCD_WriteInstraction(0x01);
    strcpy(moji,"up");
    lcdDisp1(moji);
   }
   if( aj == 0 ){
    LCD_WriteInstraction(0x01);
   }

   HAL_Delay(30);

   //sprintf(str,"adc[0]:%04d, adc[1]:%04d\r", g_ADCBuffer[0], g_ADCBuffer[1]);
   //HAL_UART_Transmit(&huart2, (uint8_t *)str, strlen(str), 0xFFFF);
   //HAL_Delay(300);
  }
  /* USER CODE END 3 */

コメントアウトしたコードはコンソール画面で調整する用のコードになる。

実際に動かした感じはこのようになる。












コメント

このブログの人気の投稿

STM32CubeIDEに日本語化プラグインを導入する

STM32F401でLチカをする(LED点灯)

STM32F401-Nucleoでシリアル通信をやってみる