朗峰 发表于 2014-2-13 23:14:47

STM8S ADC多通道连续扫描问题

设计采用STM8S105K4芯片,AIN0和AIN1分别接直流电平,配置为多通道连续扫描模式。对采样值进行200次的平均。测试中发现AIN1通道始终为零,AIN0通道正常。对照手册仔细检查了几次代码,仍未发现问题,请高手指点!
程序代码如下:

main.c代码
void main ( void )
{
      uint16_t x_sen_data, y_sen_data;
      uint16_t cnt = 0;
      
      CLK_SYSCLKConfig(CLK_PRESCALER_HSIDIV4);
      
      UartInit();      
      AdcInit();
      
      printf("Hello, My Board.\n");
      
    while (1)
      {
                // ADC采样结束
                if (TRUE == g_samp_update_flag)
                {
                        g_samp_update_flag = FALSE;
                        
                        // 进行调平处理
                        GetAdcValue(&x_sen_data, &y_sen_data);
                        printf("%d    %d\n", x_sen_data, y_sen_data);
                        
                        AdcInit();
                }
      }
}
adc.c代码
// 采样数据长度
#define DATA_LEN      (200)

bool g_samp_update_flag = FALSE;

///@ 定义文件局部变量
static uint32_t m_x_sen_sum = 0;
static uint32_t m_y_sen_sum = 0;

static void delay_ms(uint32_t ms)
{
      while (ms--);
}

// ADC初始化
void AdcInit(void)
{
      // 配置ADC相关引脚
      GPIO_Init(SCR_PORT, SCR_PIN, GPIO_MODE_OUT_PP_LOW_SLOW);
      GPIO_Init(SGY_PORT, SGY_PIN, GPIO_MODE_IN_FL_NO_IT);
      GPIO_Init(SGX_PORT, SGX_PIN, GPIO_MODE_IN_FL_NO_IT);
      
      // 复位ADC1
      ADC1_DeInit();
      
      // 配置ADC1
      ADC1_Init(ADC1_CONVERSIONMODE_CONTINUOUS, ADC1_CHANNEL_1, ADC1_PRESSEL_FCPU_D4,
                  ADC1_EXTTRIG_TIM, DISABLE, ADC1_ALIGN_RIGHT,
                        ADC1_SCHMITTTRIG_CHANNEL1, DISABLE);

    ///@ 从ADC上电到开始ADC转换要间隔7us
      // 连续转换模式
      ADC1_ScanModeCmd(ENABLE);
      
      // 使能EOC中断
      ADC1_ITConfig(ADC1_IT_EOCIE, ENABLE);
      
      // 使能全局中断
      enableInterrupts();
      
      delay_ms(200);
      
      ///@ 是否够7us?也许是转换不稳定的主要原因
      // Start ADC Conversion
      ADC1_StartConversion();
}

// ADC中断处理程序
void AdcISR(void)
{
      static uint8_t samp_times = 0;
    uint16_t adc_data = { 0, 0 };
      
      // 读取采样点
      adc_data = ADC1_GetBufferValue(0x00);
      adc_data = ADC1_GetBufferValue(0x01);
      
      // 采样数据处理
      m_x_sen_sum += adc_data;
      m_y_sen_sum += adc_data;

      // 清除中断标志
      ADC1_ClearITPendingBit(ADC1_IT_EOC);
      
      // 采样点计数
      samp_times++;
      if (DATA_LEN == samp_times)
      {
                samp_times = 0;
//                g_sample_flag = FALSE;
                g_samp_update_flag = TRUE;
               
                // 关闭ADC
                ADC1_Cmd(DISABLE);
      }
}

// 获取ADC采样值
void GetAdcValue(uint16_t *p_data_x, uint16_t *p_data_y)
{
      *p_data_x = m_x_sen_sum / DATA_LEN;
      *p_data_y = m_y_sen_sum / DATA_LEN;
      
      m_x_sen_sum = 0;
      m_y_sen_sum = 0;
}

飞龙xyj 发表于 2015-11-9 15:46:15

第一个问题,如下设置后:
ADC1_ScanModeCmd(ENABLE);
ADC1_DataBufferCmd(ENABLE);
ADC1_ITConfig(ADC1_IT_EOCIE, ENABLE);
enableInterrupts();当所有通道转换结束后才会进入中断,这个时候你在中断中去读取每个通道的AD值
INTERRUPT_HANDLER(ADC1_IRQHandler, 22)
{
    /* In order to detect unexpected events during development,
       it is recommended to set a breakpoint on the following instruction.
    */
       
        //static uint8_t samp_times = 0;
            //uint16_t adc_data = {0,0,0,0,0,0,0,0};

        ADC1_IRQ_Count++;
        //samp_times++;
      // Get the ADC value of every channel
      adc_data = ADC1_GetBufferValue(0x00);
      adc_data = ADC1_GetBufferValue(0x01);
          adc_data = ADC1_GetBufferValue(0x02);
      adc_data = ADC1_GetBufferValue(0x03);
          adc_data = ADC1_GetBufferValue(0x04);
      adc_data = ADC1_GetBufferValue(0x05);
          adc_data = ADC1_GetBufferValue(0x06);
      adc_data = ADC1_GetBufferValue(0x07);

      //sum of ADC value of every channel
      channel0_adc_value_sum += adc_data;
      channel1_adc_value_sum += adc_data;
          channel2_adc_value_sum += adc_data;
      channel3_adc_value_sum += adc_data;
       channel4_adc_value_sum += adc_data;
      channel5_adc_value_sum += adc_data;
          channel6_adc_value_sum += adc_data;
      channel7_adc_value_sum += adc_data;



      // Count of the sample times
      samp_times++;

       // Sample times up to ADC_SAMPLE_TIMES
      if (ADC_SAMPLE_TIMES == samp_times)
      //if (10 == samp_times)
      {
                samp_times = 0;//Reset the samp_times
                g_samp_update_flag = TRUE;
                ADC1_Cmd(DISABLE);// Disable the ADC1
      }

        // Clear the interupt flag
      ADC1_ClearITPendingBit(ADC1_IT_EOC);

        #if 1
        /* Clear the ADC1 channels */
       ADC1->CSR &= (uint8_t)(~ADC1_CSR_CH);
        /* Select the ADC1 channel */
        ADC1->CSR |= (uint8_t)(ADC1_CHANNEL_7);
        #endif
       
}


我是在主函数中调用如下函数去对转换得到的数据求平均
void GetAdcValue(u16 *channel0_adc1_value, u16 *channel1_adc1_value,u16 *channel2_adc1_value,u16 *channel3_adc1_value,u16 *channel4_adc1_value,u16 *channel5_adc1_value,u16 *channel6_adc1_value,u16 *channel7_adc1_value)
{
        if(g_samp_update_flag==TRUE)//End of all the ADC
        {
                g_samp_update_flag=FALSE;
               
                *channel0_adc1_value = channel0_adc_value_sum / ADC_SAMPLE_TIMES;
                *channel1_adc1_value = channel1_adc_value_sum / ADC_SAMPLE_TIMES;
                  *channel2_adc1_value = channel2_adc_value_sum / ADC_SAMPLE_TIMES;
                  *channel3_adc1_value = channel3_adc_value_sum / ADC_SAMPLE_TIMES;
                  *channel4_adc1_value = channel4_adc_value_sum / ADC_SAMPLE_TIMES;
                  *channel5_adc1_value = channel5_adc_value_sum / ADC_SAMPLE_TIMES;
                  *channel6_adc1_value = channel6_adc_value_sum / ADC_SAMPLE_TIMES;
                  *channel7_adc1_value = channel7_adc_value_sum / ADC_SAMPLE_TIMES;
                
                channel0_adc_value_sum=0;
                  channel1_adc_value_sum=0;
                  channel2_adc_value_sum=0;
                  channel3_adc_value_sum=0;
                  channel4_adc_value_sum=0;
                  channel5_adc_value_sum=0;
                  channel6_adc_value_sum=0;
                  channel7_adc_value_sum=0;

               ADC1_Config();          
               
        }
}

当然,上面的参数用一个数组比如ADC_Val,ADC_Val_Sum更好,不用写这么多次

ADC配置的函数如下:
void ADC1_Config(void)
{

ADC1_DeInit();

/*-------------------CONTINUOUS mode----------------------*/
#if 1
ADC1_Init(ADC1_CONVERSIONMODE_CONTINUOUS, ADC1_CHANNEL_7, ADC1_PRESSEL_FCPU_D8,
                  ADC1_EXTTRIG_TIM, DISABLE, ADC1_ALIGN_RIGHT, ADC1_SCHMITTTRIG_ALL, DISABLE);
#endif

ADC1_ScanModeCmd(ENABLE);

ADC1_DataBufferCmd(ENABLE);

ADC1_ITConfig(ADC1_IT_EOCIE, ENABLE);

enableInterrupts();

DelayXms(1);
//DelayXus(20);

ADC1_StartConversion();

}


延时函数:
void DelayXus(u16 cnt)
{
        while(cnt--)
        {
                nop();
               nop();
                nop();
                nop();
        }
}



void DelayXms(u16 cnt)
{
        u16 i;

        while(cnt--)
        {
                for(i=0;i<1000;i++)
                {
                        nop();
                       nop();
                        nop();
                        nop();
                }

        }
}




飞龙xyj 发表于 2015-6-30 19:01:09

楼主您好,我今天用连续扫描模式调通了8个模拟通道(AIN0-AIN7)的AD采集,看了下您的代码,发现有两处问题:
一是ADC初始化时,设置成模拟输入的通道应该禁止施密特触发,我是全部禁止了,如下:
#if 1
ADC1_Init(ADC1_CONVERSIONMODE_CONTINUOUS, ADC1_CHANNEL_7, ADC1_PRESSEL_FCPU_D8,
                  ADC1_EXTTRIG_TIM, DISABLE, ADC1_ALIGN_RIGHT, ADC1_SCHMITTTRIG_ALL, DISABLE);
#endif
你可以调用库函数ADC1_SchmittTriggerConfig(ADC1_SchmittTrigg_TypeDef ADC1_SchmittTriggerChannel, FunctionalState NewState)去禁止你用于模拟输入的两个通道;

二是在中断后没有重新载入扫描系列新的最后的通道号,比如我的如下:
// Clear the interupt flag
      ADC1_ClearITPendingBit(ADC1_IT_EOC);

        #if 1
        /* Clear the ADC1 channels */
       ADC1->CSR &= (uint8_t)(~ADC1_CSR_CH);
        /* Select the ADC1 channel */
        ADC1->CSR |= (uint8_t)(ADC1_CHANNEL_7);
        #endif
希望能对你有帮助,谢谢!

发表于 2014-2-14 10:17:48

RE:STM8S ADC多通道连续扫描问题

ADC1_SCHMITTTRIG_CHANNEL1= (uint8_t)0x01, /**&lt; Schmitt trigger disable on AIN1 */
输入这个值,是说明关闭AIN1,我理解这里不采集哪些就直接输入哪些就可以了,如下:
ADC1_SCHMITTTRIG_CHANNEL2|ADC1_SCHMITTTRIG_CHANNEL3

你好我好大家好! 发表于 2015-9-6 12:37:25

飞龙xyj 发表于 2015-6-30 19:01
楼主您好,我今天用连续扫描模式调通了8个模拟通道(AIN0-AIN7)的AD采集,看了下您的代码,发现有两处问题 ...

想请教大神两个问题:
1.这个8各通道转换后的数据是按照什么顺序存储在数据缓冲区的呢
2,我可以只扫描0通道和2通道吗?不管一通道的事......谢谢大神了

飞龙xyj 发表于 2015-11-9 16:01:50

本帖最后由 飞龙xyj 于 2015-11-9 16:04 编辑

你好我好大家好! 发表于 2015-9-6 12:37
想请教大神两个问题:
1.这个8各通道转换后的数据是按照什么顺序存储在数据缓冲区的呢
2,我可以只扫描0 ...
第二个问题:按照STM8S官方参考手册,如果是连续扫描,应该是0-2之间所有通道都扫描,不管你需不需要AIN1的数据,AIN1所在的IO口都不可以设置为输出状态,因为这个IO口的输出功能被禁止了,所以扫描模式的话还是建议用连续的模拟通道,中间不要断开,不然的话就不要用扫描吧,直接单次转换,这是我个人的理解,希望能帮到你,你自己也可以多测试下!

file:///C:\Users\Administrator\AppData\Roaming\Tencent\Users\545483362\QQ\WinTemp\RichOle\


TamTan 发表于 2016-4-14 16:00:07

学习了,不知有没有人用过模拟看门狗

zcl201207 发表于 2016-4-14 20:43:46

:):):):):)

lanmanck 发表于 2016-5-3 19:40:32

手册提到的buffer是8个还是10个,这个到底怎么定的?草

咋就这么帅呢 发表于 2016-12-3 15:07:35

飞龙xyj 发表于 2015-6-30 19:01
楼主您好,我今天用连续扫描模式调通了8个模拟通道(AIN0-AIN7)的AD采集,看了下您的代码,发现有两处问题 ...

按您的提示 成功了 需要重新载入扫描系列新的最后的通道号 这步是关键
赞赞赞
页: [1] 2
查看完整版本: STM8S ADC多通道连续扫描问题