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