找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1070|回复: 11
收起左侧

关于STC8G1K08多路ADC电压采集问题

[复制链接]
ID:1114732 发表于 2024-3-29 22:04 | 显示全部楼层 |阅读模式
由于项目需要用到5路的ADC采样,但是我发现多路通道之间的采样值会互相影响,是需要在程序上进行处理吗
回复

使用道具 举报

ID:213173 发表于 2024-3-30 07:13 | 显示全部楼层
端口模式要设置高阻,切换通道后丢弃前两次采样值
int ADC_rotate(char ch)
{
        int Vin;
        ADC_Read(ch);                 //丢掉两次检测
        ADC_Read(ch);
        VADC=ADC_Read(ch);            //取第ch通道ADC结果
        Vin=VCC*(long)VADC/4096;    //计算输入电压mV
        return Vin;
}
回复

使用道具 举报

ID:1109793 发表于 2024-3-30 10:45 | 显示全部楼层
怎么个影响?我用两个通道,没感觉到问题啊
回复

使用道具 举报

ID:230500 发表于 2024-3-30 14:10 | 显示全部楼层
STC还有一个坑要注意; 由于内部电容充电时间的问题; 采集数据切换端口候不能马上立即采集; 需要稍微等待几十个US后等待电容充电稳定后再采集;也就是前面采集的几次数据要丢掉;
回复

使用道具 举报

ID:401564 发表于 2024-3-30 14:58 | 显示全部楼层
程序只要是对的,就不会有什么影响的,我试有有多加了几个不要结果的ADC,对实际的结果并没有什么改善
一样的抖动,ADC加个滤波就可以了
你也可以把你的代码上传上来,看一下怎么回事
回复

使用道具 举报

ID:1109793 发表于 2024-3-30 16:02 | 显示全部楼层
建议把采样速度降到较低水平,不要用很高的速度,高速就不怎么稳定。
回复

使用道具 举报

ID:1114732 发表于 2024-3-30 16:34 | 显示全部楼层
xiaobendan001 发表于 2024-3-30 10:45
怎么个影响?我用两个通道,没感觉到问题啊

我贴一下程序麻烦帮我看一下,详见9楼

                        if((i==6)&&(j<512))
                                {
                                                P37=0;          //这里只有我一上电给通道6低于512的电压他才会给P37置低,后面给电压他就没反应
                                }
                        if((i==7)&&(j<512))
                                {
                                                  P37=0;        //同上
                                }

回复

使用道具 举报

ID:1114732 发表于 2024-3-30 16:35 | 显示全部楼层
a399288395 发表于 2024-3-30 14:10
STC还有一个坑要注意; 由于内部电容充电时间的问题; 采集数据切换端口候不能马上立即采集; 需要稍微等待 ...

丢弃了一次可以吗,我把ADC的采样速度设置得比较快,上面贴了一下程序可以帮忙看一下吗
回复

使用道具 举报

ID:1114732 发表于 2024-3-30 16:39 | 显示全部楼层
Y_G_G 发表于 2024-3-30 14:58
程序只要是对的,就不会有什么影响的,我试有有多加了几个不要结果的ADC,对实际的结果并没有什么改善
一 ...

好的代码如下:/*************        PCA配置函数        **************//*****************************************/

void        PCA_config( u8 clk, u8 wide)
{
        CR = 0;   //停止PCA定时器
        CMOD = (CMOD & ~0x0E) | ((clk & 7) << 1);                // PCA时钟选择, 0: 12T,  1: 2T, 2: Timer0溢出率, 3: ECI引脚输入, 4: 1T,  5: 4T,  6: 6T,  7: 8T
        PCA0_PWM(wide);        //PWM宽度        0: 8位PWM,  1: 7位PWM,  2: 6位PWM,  3: 10位PWM                       
        P_SW1 = (P_SW1 & ~0x30) | 0x00;        // 将PCA/PWM切换到 P5.5(ECI) P3.1(CCP0) P3.3(CCP1) P5.4(CCP2)
        P1n_push_pull(0x02);        //头文件的宏, P1.1 设置为推挽输出                       
        CH = 0;
        CL = 0;
        CR   = 1;        // 运行PCA定时器
}

void        UpdatePwm( u16 pwm_value)
{
                PCA_PWM0 = (PCA_PWM0 & ~0x32) | (u8)((pwm_value >> 4) & 0x30);
                CCAP0H = (u8)pwm_value;
        //        PWM0_NORMAL();               
}
/*****************************************/
/*****************************************/

/*************        PID函数        ******************/
/*****************************************/

typedef struct PID_Value
{
    int   KP;
    int   KI;
    int          KD;
    int   Inck;
    int   EkSum;
    int   Vref;
    int   Vin;
    int   Ek;
    int   Ek_1;
    int   Ek_2;
    int   dacOutAmp;
    int   Acutual_pidout;
}PID_ValueStr;

PID_ValueStr pidStr;

void PID_initial(void)
{
    pidStr.KP=10;
    pidStr.KI=1;

}

void PID_Caculate()
{                        
    pidStr.Ek=243-VCC ;                                                          
        pidStr.Inck=pidStr.KP*(pidStr.Ek  - pidStr.Ek_1) + pidStr.KI*pidStr.Ek  ;
    pidStr.Ek_2 = pidStr.Ek_1;                                          
    pidStr.Ek_1 = pidStr.Ek;                                                                                                    
        pidStr.dacOutAmp -= pidStr.Inck;                         
        if(pidStr.dacOutAmp<128)                                                          
    pidStr.dacOutAmp = 128;
    if(pidStr.dacOutAmp>243)
    pidStr.dacOutAmp = 243;                                                                                                                  
    pwm_value=pidStr.dacOutAmp;                                                         
}


/*****************************************/
/*****************************************/


/*************        中断INT0函数        **********/
/*****************************************/
void INT0_Isr() interrupt 0
{   
         P37=0;
         FLAG=30;                                           
}
/*****************************************/
/*****************************************/
/*************        ADC函数        **************/
/*************************************/

uint Get_ADCResult(u8 channel)
{       
           ADC_RES = 0;
        ADC_RESL = 0;
        ADC_CONTR = (ADC_CONTR & 0xf0) | 0x40 | channel;
        //delay1us();                        //对ADC_CONTR操作后等待会儿再访问
        while ((ADC_CONTR & 0x20)==0);
        ADC_CONTR &=~0x20;  
        ADC1_DATA=(ADC_RES<<8)|ADC_RESL;
    return ADC1_DATA;       
}

void ADC_Isr() interrupt 5
{       
        EADC=0;
    ADC_CONTR &= ~0x20;                         //清中断标志
           VCC=(ADC_RES<<8)|ADC_RESL;               
        PID_Caculate();                                                                           
        UpdatePwm(pwm_value);                                                //更新PWM       
}

/*****************************************/
/*****************************************/
/*********************************************
/*函数名称:Timer0_Config(u8 mode, u16 time)
/*函数功能:Timer0配置函数
/*输入参数:mode:速度模式
/*                                        mode=1, 1T模式; mode=2,12T模式
/*                                        time:定时时间
/*        1T模式(max=5.9ms):1ms=1000,2ms=500,5ms=200
/*        12T模式(max=71ms):1ms=1000,10ms=100
/*返回值:无
*********************************************/
void Timer0_Config()
{
         
        AUXR |= 0x80;                //定时器0为1T模式
        TH0 = 0xFD;
        TL0 = 0xE4;
        TMOD &= 0xF0;                //设置定时器为模式0,16位自动重装载
        TR0 = 1;                                //启动定时器
        ET0 = 1;                                //打开定时器中断
}



void Timer0() interrupt TIMER0_VECTOR
{       
        ADC_RES = 0;
        ADC_RESL = 0;
        ADC_CONTR = (ADC_CONTR & 0xf0) | 0x40 | 4;
        while ((ADC_CONTR & 0x20)==0);
        ADC_CONTR &=~0x20;
        EADC=1;       
        ADC_RES = 0;
        ADC_RESL = 0;
        ADC_CONTR = (ADC_CONTR & 0xf0) | 0x40 | 4;     
}




/*************************************
/*函数名称:LED_Init()
/*函数功能:LED初始化函数
/*输入参数:无
/*返回值:无
*************************************/
void LED_Init(void)
{
        //P1M1 &= ~(1<<2);        P1M0 |= (1<<2);        //设置P1.2为推挽输出
        //P1M1 &= ~(1<<3);        P1M0 |= (1<<3);        //设置P1.3为推挽输出
        LED1 = 1;                //初始化LED1
        LED2 = 1;                //初始化LED2
}

/*************************************
/*函数名称:LED_Toggle(unsigned char led_id)
/*函数功能:LED状态取反函数
/*输入参数:LED序号(led_id=1~n)
/*返回值:无
*************************************/
void LED_Toggle(unsigned char led_id)
{
        switch(led_id)
        {
                case 1:
                        LED1 = ~LED1;                //LED1状态取反
                        break;
                case 2:
                        LED2 = ~LED2;                //LED2状态取反
                        break;
        }
}


/******************** 主函数 **************************/
void main(void)
{
        P0M1 = 0;   P0M0 = 0;   //设置为准双向口
        P1M1 = 0;   P1M0 = 0;   //设置为准双向口
        P2M1 = 0;   P2M0 = 0;   //设置为准双向口
        P3M1 = 0;   P3M0 = 0;   //设置为准双向口
    P1M0 = (P1M0 & ~0xf8) | 0x04; P1M1 = (P1M1 & ~0x04) | 0xf8;           //P1.2推挽输出 P1.3 P1.4 P1.5 P1.6 P1.7 高阻输入
    P3M0 |= 0xac; P3M1 &= ~0xac;             //        P3.2 P3.3 P3.5 P3.7  推挽输出
        PID_initial();
        PCA_config(4,0);
        LED_Init();                                        //LED初始化函数
        Timer0_Config();                        //定时器0配置,12T模式,time=10ms                                                                                                     
        P_SW2 |= 0x80;                               
    ADCTIM = 0x0a;                              
    P_SW2 &= 0x7f;                                                                //设置ADC内部时序
    ADCCFG = 0x20;                              //设置ADC时钟为系统时钟/2/16
    ADC_CONTR = 0x80;                           //使能ADC模块
    IT0 = 1;                                    //使能INT0下降沿中断
    EX0 = 1;                                    //使能INT0中断
        IPH=0x03;
        IP=0x21;
    EA = 1;                                                                                //允许总中断       
       
        while(1)
        { u8 i ;
          u16 j ;
                 for(i=5; i<8; i++)
                {
                        Get_ADCResult(i);
                        j=Get_ADCResult(i);
                        if((i==6)&&(j<512))
                                {
                                P37=0;   //主要是这里,只有一开始上电给低于512的电压他才能给P37置低,如果开始电压比较高,后续再给低电压也不行
                                }
                        if((i==7)&&(j<512))
                                {
                                                  P37=0;  //这里同上
                                }
                }                     
        }
}


回复

使用道具 举报

ID:1114732 发表于 2024-3-30 16:40 | 显示全部楼层
xiaobendan001 发表于 2024-3-30 16:02
建议把采样速度降到较低水平,不要用很高的速度,高速就不怎么稳定。

主要是有一路要用来稳住电压,对adc的采样速度要求较高
回复

使用道具 举报

ID:401564 发表于 2024-3-31 15:11 | 显示全部楼层
你在定时器中断中打开了ADC中断,却又在主程序中使用了轮询的方式进行ADC
但STC的ADC实际上只有一个
而且,在定时器中断中,你又有了
ADC_RES = 0;
ADC_RESL = 0;
这两个是ADC结果的寄存器,它会影响Get_ADCResult返回值的

要么是ADC都用中断的方式,要么就都用轮询的方式
ADC用轮询方式的话,ADC对主程序的影响不大,但ADC优先权就不大
ADC用中断的方式,ADC对主程序影响就很大,因为每次ADC完成,都要进入ADC中断一次,最终还是要看你整个程序的需求
回复

使用道具 举报

ID:1034262 发表于 2024-3-31 19:23 | 显示全部楼层
a399288395 发表于 2024-3-30 14:10
STC还有一个坑要注意; 由于内部电容充电时间的问题; 采集数据切换端口候不能马上立即采集; 需要稍微等待 ...

说法不对,不采样时是断开连接的,等多久都没用。
正确方法是设置采样时间,用稍长的采样时间,一般到3us以上就没问题了。
或者切换通道后先做一次ADC并丢弃结果。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表