2015年5月31日日曜日

STM32のAD変換01

今回からF4 discoveryではなくて、 自作F4基板でプログラムの評価をする。discoveryは周辺機能が盛りだくさんである一方で、使えるポートに制限があるので、ピッチ変換基板的な基板を作った。
詳しい話は、また別の機会に。
とりあえず、ポートの制限がなくなった。


さて本題。情報としては知っていたのだけれど、STM32のAD変換で、はまった。
STM32の12bitAD変換は変換結果を左詰にするか、右詰にするかを選べるのだけれど、右詰に設定しても、それが有効化されないのだ。

 花岡ちゃんに花束を(STM32F4のAD変換トラブル(その2))

このページで、ADCの初期化でADC_DeInit();を実行すれば良いとされているが、それだけでは解決されなかった。
試行錯誤の結果、ADCの初期化処理の最後にウェイト処理を追加することで解決したので、ADCの初期化が完了する前に、ADCを使い始めてしまったのだろうか?
おそらく、データシートには書いてあるのだろうけれど、詳しく見てないので分からない。

ソースコードは以下。






#include "stm32f4xx.h"
#include "uart1.h"
#include "stm32f4dis.h"


/* --------------------------------------
  time : 約1uSec,1000000=1sec
   -------------------------------------- */
void delay(uint32_t time){
  uint32_t t;
  volatile uint8_t i;
  
  for(i=0;i<24;i++){
    t = time;
    while(t--);
  }
} 

// -------------------------------------------------------------------
// systick 割込み(1msec毎に設定してある)
// stm32f4xx_it.c で呼び出している
// -------------------------------------------------------------------
volatile uint16_t time_sec=0;
volatile uint16_t time_msec=0;
void systick_1msec(void){
  static uint16_t cnt=0;
  
  cnt++;
  time_msec++;
  if(cnt>1000){
    time_msec=0;
    cnt=0;
 time_sec++;
  }
}

void Delay_ms(uint16_t msec){
  uint16_t cnt=0;
  
  cnt = time_msec;
  while(msec){
    if(cnt!=time_msec){
   cnt = time_msec;
   msec--;
 }
  }
}


// -------------------------------------------------------------------
//  ADC3 初期化
// -------------------------------------------------------------------
void adc3_init(void){
  ADC_InitTypeDef       ADC_InitStructure;
  GPIO_InitTypeDef      GPIO_InitStructure;
  
  //必要なペリフェラルにクロック供給開始
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
  
  //GPIO-Cの指定の入力をアナログに設定
  GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;  //PC[13:10]をアナログ入力に設定
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOC, &GPIO_InitStructure);

  ADC_DeInit();          // AD変換器のリセット

  //ADC3の変換モード設定。
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  // ↓ ENABLE(スキャンモード)、DISABLE(分割スキャンモード) 
  ADC_InitStructure.ADC_ScanConvMode         = DISABLE;
  // ↓ ENABLE(連続変換モード)、DISABLE(シングル変換モード)
  ADC_InitStructure.ADC_ContinuousConvMode   = DISABLE;  
  // ↓ AD変換開始トリガなし
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;  
  // ↓ AD変換後のデータ右詰  
  ADC_InitStructure.ADC_DataAlign            = ADC_DataAlign_Right;            
  // ↓ 入力を4本(チャネルを増やしたらここを変える)
  ADC_InitStructure.ADC_NbrOfConversion      = 4;        
  ADC_Init(ADC3, &ADC_InitStructure);
  
  ADC_Cmd(ADC3, ENABLE);  // ADC3を有効化
  delay(10000);           // 大切!
}

// -------------------------------------------------------
// 
// -------------------------------------------------------
int main(void)
{
  volatile uint16_t time_tmp=0;
  uint16_t adc1_data=0;      // ADC変換後のデータを格納 
  uint16_t adc2_data=0;      // ADC変換後のデータを格納 
  uint16_t adc3_data=0;      // ADC変換後のデータを格納 
  uint16_t adc4_data=0;      // ADC変換後のデータを格納 
 
 
  SystemInit();
  stm32f4_init();   set_led(0x01);
  delay(10000);
  adc3_init();      set_led(0x02);


  uart1_init(9600);
  usart1_printf(\"\\r\\n\");
  usart1_printf(\"micro mouse ver0.0.1\\r\\n\");

  // systick 設定(1msec)
  SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
  if(SysTick_Config(SystemCoreClock/1000)){
    while(1);                // error
  }
  
  while(1){
    // SW処理
    if(GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_13)){
      //ボタンが押されて1になっていたら以下を実行
      GPIO_ResetBits(GPIOB,GPIO_Pin_7);     // 点灯
   while(GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_13));  // ボタンを放したら以下を実行
    }else{
      GPIO_SetBits(GPIOB,GPIO_Pin_7);       // 消灯
    }
 // 1秒処理
 if(time_tmp!=time_sec){
   set_led(0x04);
   time_tmp = time_sec;

        ADC_RegularChannelConfig( ADC3, ADC_Channel_10, 1, ADC_SampleTime_56Cycles);
        ADC_SoftwareStartConv( ADC3 );              // AD変換開始
        while(ADC_GetFlagStatus(ADC3,ADC_FLAG_EOC) == RESET);
        adc1_data = ADC_GetConversionValue(ADC3);   // AD変換データの取り込み
        adc1_data = adc1_data *3300/0xFFF;          // 電圧に変換

     ADC_RegularChannelConfig( ADC3, ADC_Channel_11, 1, ADC_SampleTime_56Cycles);
        ADC_SoftwareStartConv( ADC3 );              // AD変換開始
        while(ADC_GetFlagStatus(ADC3,ADC_FLAG_EOC) == RESET);
        adc2_data = ADC_GetConversionValue(ADC3);   // AD変換データの取り込み
//        adc2_data = adc2_data *3300/0xFFF;          // 電圧に変換

     ADC_RegularChannelConfig( ADC3, ADC_Channel_12, 1, ADC_SampleTime_56Cycles);
        ADC_SoftwareStartConv( ADC3 );              // AD変換開始
        while(ADC_GetFlagStatus(ADC3,ADC_FLAG_EOC) == RESET);
        adc3_data = ADC_GetConversionValue(ADC3);   // AD変換データの取り込み
        adc3_data = adc3_data *3300/0xFFF;          // 電圧に変換

     ADC_RegularChannelConfig( ADC3, ADC_Channel_13, 1, ADC_SampleTime_56Cycles);
        ADC_SoftwareStartConv( ADC3 );              // AD変換開始
        while(ADC_GetFlagStatus(ADC3,ADC_FLAG_EOC) == RESET);
        adc4_data = ADC_GetConversionValue(ADC3);   // AD変換データの取り込み
        adc4_data = adc4_data *3300/0xFFF;          // 電圧に変換


        usart1_printf(\"%4d : AD ch1=%4d , ch2=0x%8X , ch3=%4d , ch4=%4d \\r\",
                 time_sec,adc1_data,adc2_data,adc3_data,adc4_data);

   set_led(0x00);
 }
  }
  return 0;
}




0 件のコメント:

コメントを投稿