打印
[STM8]

STM8S ADC多通道连续扫描问题

[复制链接]
555|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
cr315|  楼主 | 2021-1-5 09:44 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
设计采用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();
  •                 }
  •         }
  • }

[color=rgb(51, 102, 153) !important]复制代码


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[2] = { 0, 0 };
  •         // 读取采样点
  •         adc_data[0] = ADC1_GetBufferValue(0x00);
  •         adc_data[1] = ADC1_GetBufferValue(0x01);
  •         // 采样数据处理
  •         m_x_sen_sum += adc_data[0];
  •         m_y_sen_sum += adc_data[1];
  •         // 清除中断标志
  •         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;
  • }

[color=rgb(51, 102, 153) !important]复制代码

[color=rgb(51, 102, 153) !important]


使用特权

评论回复
沙发
labasi| | 2021-2-1 23:44 | 只看该作者
硬件连接有没有检查

使用特权

评论回复
板凳
paotangsan| | 2021-2-1 23:49 | 只看该作者
如果换一种方式进行读取 会不会有所改善

使用特权

评论回复
地板
renzheshengui| | 2021-2-1 23:51 | 只看该作者
用万用表量着是多少啊

使用特权

评论回复
5
wakayi| | 2021-2-1 23:52 | 只看该作者
其他通道采集的数据正常吗

使用特权

评论回复
6
wowu| | 2021-2-1 23:54 | 只看该作者
使用单通道采集试试看

使用特权

评论回复
7
豌豆爹| | 2021-2-2 09:29 | 只看该作者
楼主您好,我今天用连续扫描模式调通了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
希望能对你有帮助,谢谢!

使用特权

评论回复
8
七毛钱| | 2021-2-2 09:30 | 只看该作者
第一个问题,如下设置后:
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();
                }

          }
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1289

主题

3509

帖子

0

粉丝