aerror 发表于 2025-8-4 14:39:54

梁工 发表于 2025-8-4 13:44
你使用串口发送脚做ADC输入,你是怎么监控ADC值的?

以上测试程序时,只修改target_input_value输入方式,其它代码保持完全一样。另外adc采样时,先start adc ,然后检查adc的完成flag,如果没有完成就去检查usart有没有收到数据,有完成就处理adc的输入值,然后马上开始下一次采样。 另外,测试例子有8/9个nop的指令的,我有测试加上和去掉这些nop,好像都没有影响测试结果。

ercircle 发表于 2025-8-4 14:40:35

aerror 发表于 2025-8-4 14:24
你好,这个是要做一个servo的程序,
1.p3.1采集电位器的电位值, adc使用了10bit的采样,即0-1023,名为...

单看这个描述感觉是一个pin上同时用两种外设互相干扰了。
请问输入周期是多少呢,是否尝试分时复用,ADC采集时取消设置串口试下?

aerror 发表于 2025-8-4 15:14:21

ercircle 发表于 2025-8-4 14:40
单看这个描述感觉是一个pin上同时用两种外设互相干扰了。
请问输入周期是多少呢,是否尝试分时复用,ADC ...

输入周期,可以认为就是usart就是输入出一次,9600bps, 然后后面都就不输入了。我试一下把usart关掉,这个好像只需停timer1,然后取消中断enable,就可以了吧?

两种外设互相干扰,我也是怀疑, 另外其实我也测试过adc 对于不同channel的采样,也是会冲突的。
测试办法如下:
1. 先对adc的channel 0 (p3.0) 采样,采样完成16次。
2. 再对adc的channel 1 (p3.1)采样,采样完成16次.

发现 channel 0和 channel 1 的值会相互污染。

然后,把次数改成100次,改成下面的样子,就好了。逻辑如下:
1. 先对adc的channel 0 (p3.0) 采样,采样完成100次。
2. 再对adc的channel 1 (p3.1)采样,采样完成100次.

aerror 发表于 2025-8-4 15:20:10

梁工 发表于 2025-8-4 13:44
你使用串口发送脚做ADC输入,你是怎么监控ADC值的?

补充,要是“当adc采样值 adc_input_value 和 target_input_value相差不过超2时” 这里这个2这个数值,要是改成10, 这个在usart打开的时候也比较稳定,但是效果无法满足设计要求,误差太大了。。。。也怀能是输入值有问题,只是测试usart打开,target_input_value直接写死512, 后面不修改了。测试结果看到 也是 “到达512附近时,无法停止转动,不停在正反的抖动。”

ercircle 发表于 2025-8-4 15:31:49

aerror 发表于 2025-8-4 15:14
输入周期,可以认为就是usart就是输入出一次,9600bps, 然后后面都就不输入了。我试一下把usart关掉, ...
还有把REN也可以禁掉。

两个ADC通道互相影响就不应该了。
可以参考开天斧开发板这个例程试下:

aerror 发表于 2025-8-4 18:04:50

ercircle 发表于 2025-8-4 15:31
还有把REN也可以禁掉。

两个ADC通道互相影响就不应该了。


好的,两个通道相互影响,会不会和我的使用方式有关的? 我看示例是阻塞型的,我改了使用异步的方式,这个会不会有影响?


例子中,是这样的取采样的:
u16        Get_ADC12bitResult(u8 channel)        //channel = 0~15
{
        ADC_RES = 0;
        ADC_RESL = 0;

    ADC_CONTR = (ADC_CONTR & 0xF0) | 0x40 | channel;    //启动 AD 转换
    _nop_();
    _nop_();
    _nop_();
    while((ADC_CONTR & 0x20) == 0);   //等待ADC结束
    ADC_CONTR &= ~0x20;   //清除ADC结束标志
    return (((u16)ADC_RES << 8) | ADC_RESL);
}



而我的是采样是这样取的:


u8 current_channel

void start_adc(u8 channel)
{
        ADC_RES = 0;
        ADC_RESL = 0;
        current_channel= channel;

    ADC_CONTR = (ADC_CONTR & 0xF0) | 0x40 | channel;    //启动 AD 转换
   
    _nop_();
    _nop_();
    _nop_();
}



void main()
{
       
        u16 adc_acc;
        u16 ch0_adc = 0;
        u16 ch1_adc = 0;
       
        start_adc(0);
        while(1)
        {

                if((ADC_CONTR & 0x20))
                {

                        ADC_CONTR &= ~0x20;   //清除ADC结束标志
                        adc_acc =(((u16)ADC_RES << 8) | ADC_RESL);


                        if(current_channel == 0)
                        {
                                if(ch0_adc == 0 )
                                {
                                        ch0_adc = adc_acc;
                                }
                                else
                                {
                                        ch0_adc = (ch0_adc*15 + adc_acc)/16;
                                }
                                start_adc(1);//轮到ch1采样
                        }
                        else
                        {

                                if(ch1_adc == 0 )
                                {
                                        ch1_adc = adc_acc;
                                }
                                else
                                {
                                        ch1_adc = (ch1_adc*15 + adc_acc)/16;
                                }

                                start_adc(0); //轮到ch0采样

                        }
                }

                //TODO
                process_other_option();

        }

}

ercircle 发表于 2025-8-4 18:11:01

aerror 发表于 2025-8-4 18:04
好的,两个通道相互影响,会不会和我的使用方式有关的? 我看示例是阻塞型的,我改了使用异步的方式,这 ...


参考这个结构图不支持异步,一个采集完 再切换另一个。

aerror 发表于 2025-8-4 19:16:13

ercircle 发表于 2025-8-4 18:11
参考这个结构图不支持异步,一个采集完 再切换另一个。



我也换了一个办法,先采样16个每个,完了再换下一个, 实际只是adc的过程中,我要有机率去做一些其它事情,如计算pwm的宽度,usart的指令处理,更新电机的控制pwm等,
这是异步,而不是并发, 确实这样也会有问题? 我老实先按例子改了试试


u8 current_channel

void start_adc(u8 channel)
{
      ADC_RES = 0;
      ADC_RESL = 0;
      current_channel= channel;

    ADC_CONTR = (ADC_CONTR & 0xF0) | 0x40 | channel;    //启动 AD 转换
   
    _nop_();
    _nop_();
    _nop_();
}



void main()
{
      
      u16 adc_acc;
      u16 ch0_adc = 0;
      u16 ch1_adc = 0;
      u16 num_sample= 0;
      
      start_adc(0);
      while(1)
      {

                if((ADC_CONTR & 0x20))
                {

                        ADC_CONTR &= ~0x20;   //清除ADC结束标志
                        adc_acc =(((u16)ADC_RES << 8) | ADC_RESL);

                        num_sample ++;
                        if(current_channel == 0)
                        {
                              if(ch0_adc == 0 )
                              {
                                        ch0_adc = adc_acc;
                              }
                              else
                              {
                                        ch0_adc = (ch0_adc*15 + adc_acc)/16;
                              }
                              if(num_sample>16)
                              {
                                     num_sample = 0;
                                    start_adc(1);//轮到ch1采样
                              }
                              else
                              {
                                    start_adc(0);
                              }
                        }
                        else
                        {

                              if(ch1_adc == 0 )
                              {
                                        ch1_adc = adc_acc;
                              }
                              else
                              {
                                        ch1_adc = (ch1_adc*15 + adc_acc)/16;
                              }
                                 if(num_sample>16)
                                 {
                                           num_sample = 0;
                                        start_adc(0); //轮到ch0采样
                                 }
                                 else
                              {
                                    start_adc(1);
                              }

                        }
                }

                //TODO
                process_other_option();

      }

}

aerror 发表于 2025-8-4 19:16:33

aerror 发表于 2025-8-4 19:16
我也换了一个办法,先采样16个每个,完了再换下一个, 实际只是adc的过程中,我要有机率去做一些其它事 ...

这个办法也是有问题的。

ercircle 发表于 2025-8-4 21:11:50

aerror 发表于 2025-8-4 19:16
这个办法也是有问题的。

“adc的过程中,我要有机率去做一些其它事情”
一个是参考手册里的,中断方式ADC:



另一个,8G手册看了下没DMA,要是换8H8K64U,则可参考库函数例程包的ADC_DMA例程:
https://www.stcaimcu.com/data/download/DemoCode/AI8051U-SOFTWARE-LIB.zip


页: 1 2 3 [4] 5
查看完整版本: STC8G1K08-20,ADC采样的数据不稳定