你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM8S ADC多通道连续扫描问题

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

main.c代码
  1. void main ( void )
  2. {
  3.         uint16_t x_sen_data, y_sen_data;
  4.         uint16_t cnt = 0;
  5.         
  6.         CLK_SYSCLKConfig(CLK_PRESCALER_HSIDIV4);
  7.         
  8.         UartInit();        
  9.         AdcInit();
  10.         
  11.         printf("Hello, My Board.\n");
  12.         
  13.     while (1)
  14.         {
  15.                 // ADC采样结束
  16.                 if (TRUE == g_samp_update_flag)
  17.                 {
  18.                         g_samp_update_flag = FALSE;
  19.                         
  20.                         // 进行调平处理
  21.                         GetAdcValue(&x_sen_data, &y_sen_data);
  22.                         printf("%d    %d\n", x_sen_data, y_sen_data);
  23.                         
  24.                         AdcInit();
  25.                 }
  26.         }
  27. }
复制代码

adc.c代码
  1. // 采样数据长度
  2. #define DATA_LEN      (200)

  3. bool g_samp_update_flag = FALSE;

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

  7. static void delay_ms(uint32_t ms)
  8. {
  9.         while (ms--);
  10. }

  11. // ADC初始化
  12. void AdcInit(void)
  13. {
  14.         // 配置ADC相关引脚
  15.         GPIO_Init(SCR_PORT, SCR_PIN, GPIO_MODE_OUT_PP_LOW_SLOW);
  16.         GPIO_Init(SGY_PORT, SGY_PIN, GPIO_MODE_IN_FL_NO_IT);
  17.         GPIO_Init(SGX_PORT, SGX_PIN, GPIO_MODE_IN_FL_NO_IT);
  18.         
  19.         // 复位ADC1
  20.         ADC1_DeInit();
  21.         
  22.         // 配置ADC1
  23.         ADC1_Init(ADC1_CONVERSIONMODE_CONTINUOUS, ADC1_CHANNEL_1, ADC1_PRESSEL_FCPU_D4,
  24.                   ADC1_EXTTRIG_TIM, DISABLE, ADC1_ALIGN_RIGHT,
  25.                           ADC1_SCHMITTTRIG_CHANNEL1, DISABLE);

  26.     ///@ 从ADC上电到开始ADC转换要间隔7us
  27.         // 连续转换模式
  28.         ADC1_ScanModeCmd(ENABLE);
  29.         
  30.         // 使能EOC中断
  31.         ADC1_ITConfig(ADC1_IT_EOCIE, ENABLE);
  32.         
  33.         // 使能全局中断
  34.         enableInterrupts();
  35.         
  36.         delay_ms(200);
  37.         
  38.         ///@ 是否够7us?也许是转换不稳定的主要原因
  39.         // Start ADC Conversion
  40.         ADC1_StartConversion();
  41. }

  42. // ADC中断处理程序
  43. void AdcISR(void)
  44. {
  45.         static uint8_t samp_times = 0;
  46.     uint16_t adc_data[2] = { 0, 0 };
  47.         
  48.         // 读取采样点
  49.         adc_data[0] = ADC1_GetBufferValue(0x00);  
  50.         adc_data[1] = ADC1_GetBufferValue(0x01);
  51.         
  52.         // 采样数据处理
  53.         m_x_sen_sum += adc_data[0];
  54.         m_y_sen_sum += adc_data[1];

  55.         // 清除中断标志
  56.         ADC1_ClearITPendingBit(ADC1_IT_EOC);
  57.         
  58.         // 采样点计数
  59.         samp_times++;
  60.         if (DATA_LEN == samp_times)
  61.         {
  62.                 samp_times = 0;
  63. //                g_sample_flag = FALSE;
  64.                 g_samp_update_flag = TRUE;
  65.                
  66.                 // 关闭ADC
  67.                 ADC1_Cmd(DISABLE);
  68.         }
  69. }

  70. // 获取ADC采样值
  71. void GetAdcValue(uint16_t *p_data_x, uint16_t *p_data_y)
  72. {
  73.         *p_data_x = m_x_sen_sum / DATA_LEN;
  74.         *p_data_y = m_y_sen_sum / DATA_LEN;
  75.         
  76.         m_x_sen_sum = 0;
  77.         m_y_sen_sum = 0;
  78. }
复制代码

<
收藏 2 评论16 发布时间:2014-2-13 23:14

举报

16个回答
飞龙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[8] = {0,0,0,0,0,0,0,0};

        ADC1_IRQ_Count++;
        //samp_times++;
        // Get the ADC value of every channel
        adc_data[0] = ADC1_GetBufferValue(0x00);  
        adc_data[1] = ADC1_GetBufferValue(0x01);
          adc_data[2] = ADC1_GetBufferValue(0x02);  
        adc_data[3] = ADC1_GetBufferValue(0x03);
          adc_data[4] = ADC1_GetBufferValue(0x04);  
        adc_data[5] = ADC1_GetBufferValue(0x05);
          adc_data[6] = ADC1_GetBufferValue(0x06);  
        adc_data[7] = ADC1_GetBufferValue(0x07);

        //sum of ADC value of every channel
        channel0_adc_value_sum += adc_data[0];
        channel1_adc_value_sum += adc_data[1];
          channel2_adc_value_sum += adc_data[2];
        channel3_adc_value_sum += adc_data[3];
         channel4_adc_value_sum += adc_data[4];
        channel5_adc_value_sum += adc_data[5];
          channel6_adc_value_sum += adc_data[6];
        channel7_adc_value_sum += adc_data[7];



        // 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[8],ADC_Val_Sum[8]更好,不用写这么多次

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口的输出功能被禁止了,所以扫描模式的话还是建议用连续的模拟通道,中间不要断开,不然的话就不要用扫描吧,直接单次转换,这是我个人的理解,希望能帮到你,你自己也可以多测试下!

[img]file:///C:\Users\Administrator\AppData\Roaming\Tencent\Users\545483362\QQ\WinTemp\RichOle\[Q9YMLL[0QMIEDEZR%)DU3S.png[/img]


ADC扫描模式时IO状态

ADC扫描模式时IO状态
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采集,看了下您的代码,发现有两处问题 ...

按您的提示 成功了 需要重新载入扫描系列新的最后的通道号 这步是关键
赞赞赞
12下一页
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版