打印
[CW32F003系列]

ADC在弱信号时两路数据不一致的的问题及解决

[复制链接]
1448|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zhanan|  楼主 | 2023-7-9 14:14 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
做了一个东西,驱动一路电磁阀和一路加热器,电磁阀和加热器都是接到机箱外面,并且经常拆开检修,有可能接错线,或者没接好,或者短路,通过ADC检测电流来判断是否接对线及负载电阻是否正常,短路则用VC比较器中断实现。从CW32F003引脚功能上看,可以非常简单地实现。如图:

从图中可以看出几点:
1.电磁阀及加热器是用MOSFET驱动的,MOSFET栅极驱动电压较高,开通电压一般在4V,5V以上才可以完全开通。CW32F003可以工作在5.5V,所以芯片的电源电压就选了5.5V,用GPIO端口直接驱动MOSFET。

2.ADC输入口和VC的正极恰好有重叠的,检测电流及过流信号可接到同一个引脚上,电路非常简单。

3.取样信号是经过一个电阻接到引脚上的,因为短路时的信号电压会比较高,为保护芯片,此电阻当然是越高越好。但ADC要求输入电阻尽量小一些,所以折中一下选30k。

4.电流取样用0.1R电阻,正常工作时,电磁阀电流100mA,加热器电流500mA,信号电压范围0~50mV,特别是电磁阀的信号电压在0~10mV,可以说非常小。


比较器功能没什么好说的,必须好。用的时候只需简单设置一下:
  VC1->DIV = 0x47; // VCC分压0.7V@5.5V
  VC1->CR1 = 0x59; // 63uS滤波,上跳中断
  VC1->SR = 0x00; // 清中断标志
  VC1->CR0 = 0x802F; // VC1使能

  VC2->CR1 = 0x59; // 63uS滤波,上跳中断
  VC2->SR = 0x00; // 清中断标志
  VC2->CR0 = 0x862F; // VC2使能

  NVIC->ICPR[0] = 0xC000; // 解除VC1 VC2中断
  NVIC->ISER[0] = 0xC000; // 开VC1 VC2中断


问题由3和4引出的,按照一般做法,ADC序列转换可将电磁阀电流和加热器电流变换成数字量:
    ADC->SQR = 0x010075; // 序列配置: SV电流、JR电流
    ADC->CR0 = 0x1A19; // 单次序列,1.5V基准. 我没有打开BUF,因为在信号很小时BUF有底数,底数更难处理.
                                    // 因为信号太弱了,所以采样时间取最大.
    while((ADC->ISR & 0x80)==0); // 等ADC就绪
    ADC->START = 0x00; // ------------有过单次转换后再序列转换,必须这样写,序列转换才正常
    ADC->START = 0x01; // 启动转换
    while(ADC->START & 0x01); // 等完成
    njrdl=ADC->RESULT0; // JR电流
    nsvdl=ADC->RESULT1; // SV电流


   两个电流值经滤波变换成mA数,扩大了10倍,10mV对应100mA。但是观察试验数据,发现在实际电流基本一致的时候,两路的显示数相差较大,有一路低了20左右。后来干脆将两路的取样电压并在一起,理论上应相差很小才对,但仍然是相差很大。
   因为30k电阻的影响,显示数比理论数低一些是正常的。但两路输入信号已经是同一个了,显示数应该一致才是啊,折腾了好久也没解决。

   在把序列转换改成单次转换时,偶然间把两路转换次序换了一下,突然发现了一个规律,先转换的那一路数要大一些。后又改为序列转换,在序列中改变转换次序,也得到了同样的规律。


  这样,解决方案也出来了,轮流在前:这次转换,电磁阀先,加热器后,下次就是加热器先,电磁阀后。这样显示的数基本一致,相差±1。这个结果很好了,原始电压值不到10mV啊。

  static u8 nn; // 轮换状态
  if(nn)
  {
    nn=0;
    ADC->SQR = 0x010075; // 序列配置: SV电流、JR电流
    ADC->CR0 = 0x1A19; // 单次序列,1.5V基准
    while((ADC->ISR & 0x80)==0); // 等ADC就绪
    ADC->START = 0x00;
    ADC->START = 0x01; // 启动转换
    while(ADC->START & 0x01); // 等完成
    njrdl=ADC->RESULT0; // JR电流
    nsvdl=ADC->RESULT1; // SV电流
  }
  else
  {
    nn=1;
    ADC->SQR = 0x010057; // 序列配置: JR电流、SV电流
    ADC->CR0 = 0x1A19; // 单次序列,1.5V基准
    while((ADC->ISR & 0x80)==0); // 等ADC就绪
    ADC->START = 0x00;
    ADC->START = 0x01; // 启动转换
    while(ADC->START & 0x01); // 等完成
    nsvdl=ADC->RESULT0; // SV电流
    njrdl=ADC->RESULT1; // JR电流
  }


  大家如果也遇到这个问题, 可以试一试, 看是否有普遍性.  另有几路电压检测是电压≥0.3V,和万用表测的结果基本相符,也没再细究。


使用特权

评论回复
沙发
mcu5i51| | 2023-7-9 17:53 | 只看该作者
应该是内部采样电容和输入电压不同,加延时或丢掉几次采样试试,好像有的芯片会在内部平均数据,这个芯片没有看过资料,最好是多次测量,丢掉前几次取平均值

使用特权

评论回复
板凳
chineseboyzxy| | 2023-7-10 08:35 | 只看该作者
3.取样信号是经过一个电阻接到引脚上的,因为短路时的信号电压会比较高,为保护芯片,此电阻当然是越高越好。但ADC要求输入电阻尽量小一些,所以折中一下选30k。

负载短路时,你的MOS管能活下去吗?

使用特权

评论回复
地板
zhanan|  楼主 | 2023-7-10 10:15 | 只看该作者
mcu5i51 发表于 2023-7-9 17:53
应该是内部采样电容和输入电压不同,加延时或丢掉几次采样试试,好像有的芯片会在内部平均数据,这个芯片没有 ...

谢谢, 对精度无要求, 数据能互相参考即可. 常规法总是一个高另一个低,  后续的判定标准就要分别对待.

使用特权

评论回复
5
zhanan|  楼主 | 2023-7-10 10:52 | 只看该作者
chineseboyzxy 发表于 2023-7-10 08:35
3.取样信号是经过一个电阻接到引脚上的,因为短路时的信号电压会比较高,为保护芯片,此电阻当然是越高越好 ...

所以, 比较器就很有用了,  在程序中ADC每10mS才测一次, 还要滤波平均, 对短路根本反应不过来.
比较器是微秒级, 为确认是短路, 还要加点延时再确认. CW32F003的比较器都做到了,  CPU只需在中断中关闭输出.

之前用8位机, 比较器只有一个,  引脚配置和电压配置都有限, 很难用好. ,我都用三极管来当比较器用, 三极管去触发外中断, 两个引脚才能完成测量和保护. 8位机的外中断也是很精贵的. 这样用做了很多板子了, 负载电压是48V-150V的. PCB上保险丝, 后来做板干脆布上线条短接了.

所以, CW32F003的这种用法可以当作经典, 芯源来给我加鸡腿.

使用特权

评论回复
6
xch| | 2023-7-10 12:23 | 只看该作者
中国产的ADC 通病。串音。检测每个通道之前用一个输入接地短路的ADC通道转换一次即可改善。

使用特权

评论回复
7
zhanan|  楼主 | 2023-7-10 17:16 | 只看该作者
xch 发表于 2023-7-10 12:23
中国产的ADC 通病。串音。检测每个通道之前用一个输入接地短路的ADC通道转换一次即可改善。 ...

谢谢,  立竿见影

我用轮测法测了10个芯片, 依然有4个有较大差值, 差值6-15不等, 特别是0电压时显示数不为0. 没有从根本上解决问题.

CW32F003的ADC没有接地通道, PC01我没有用到, 把它接地, 10个芯片都试过, 圆满解决.
改进后的程序:
    ADC->SQR = 0x035676; // 序列配置: JR电流、接地、SV电流、接地
    ADC->CR0 = 0x1A19; // 1.5V基准,单次序列
    while((ADC->ISR & 0x80)==0); // 等ADC就绪
    ADC->START = 0x00;
    ADC->START = 0x01; // 启动转换
    while(ADC->START & 0x01); // 等完成
    nsvdl=nsvdl-nsvdl/16+ADC->RESULT1; if(nsvdl) nsvdl--; // sv电流检测,-1用于消除尾差
    njrdl=njrdl-njrdl/16+ADC->RESULT3; if(njrdl) njrdl--; // JR电流检测,-1用于消除尾差

把这一段程序放在测大电压的程序后面也没有问题.

使用特权

评论回复
8
zhanan|  楼主 | 2023-7-10 22:22 | 只看该作者
mcu5i51 发表于 2023-7-9 17:53
应该是内部采样电容和输入电压不同,加延时或丢掉几次采样试试,好像有的芯片会在内部平均数据,这个芯片没有 ...

谢谢, 你的方法也有效, 一开始没悟出来, 以为处理有点复杂.
经6楼大神提醒, 茅塞顿开, 你的方法就是一个通道测两次, 第一次的丢弃.
这在序列里面太简单了, 每个通道重复一次即可, 这样: ADC->SQR = 0x035577;

这个方法不会浪费引脚, 效果和接地的比, 似乎差一点点. 两个数总是差1-2, 接地的大多是同步的. 试验的时候是为了查找问题把两路并到一起, 实际两路各测各的. 不影响使用, 都是好方法.

使用特权

评论回复
9
szt1993| | 2023-7-11 21:12 | 只看该作者
ADC检测方法和轮询机制很好,思想上能够分开进行测量

使用特权

评论回复
10
zhanan|  楼主 | 2023-7-12 12:31 | 只看该作者
szt1993 发表于 2023-7-11 21:12
ADC检测方法和轮询机制很好,思想上能够分开进行测量

恰好遇到一个轮询有效果的, 没有发现本质问题.

本质问题是在弱信号时通道串扰影响很大, 幸好有高人指点, 自己再怎么想也不会往那上面想, 在8位机AVR上就没这个事.

使用特权

评论回复
11
zhanan|  楼主 | 2023-7-15 10:38 | 只看该作者
1楼的电路,电磁阀是100V高压电磁阀,有时候会用到12V低压电磁阀,CW32F003的优势又得以体现,只需在程序上美言几句即可实现,不需要外部提供12V电源,电路也无需大的改动。

电磁阀规格是12V6W,电阻值约24欧。

电磁阀上一定并联有续流二极管,高压电源给低压电磁阀供电,用斩波调压很方便,对电磁阀的性能几乎无影响,并且电磁阀的保持电压还可以调低一些。比如开通的时候用17V,保持的时候降到11V。

电源电压也可能是波动的,也可能为了适应不同电压等级,比如48V下能用,120V下也能用,要自适应电源电压。

看PB01 PB00口,AF5的复用功能正好在GTIM的两个通道上,设为PWM输出即可实现上述功能。
     AF0   AF1        AF2        AF3       AF4        AF5        AF6          AF7
PB00 GPIO  UART1_RXD  I2C_SDA    SPI_CS    ATIM_CH1B  GTIM_CH1   GTIM_TOGP    AWT_ETR
PB01 GPIO  UART1_TXD  LVD_OUT    I2C_SCL   ATIM_BK    GTIM_CH2   GTIM_TOGN    AWT_ETR

端口及PWM设置:
  GPIOB->AFRL = 0x0055; //PB1 0输出复用:PB00-GTIM_CH1,PB01-GTIM_CH2
  GTIM->CNT = 0;
  GTIM->ARR = 2500-1; // 频率400Hz:1M/400 (CPU主频是1M)
  GTIM->CCR1 = 0; // CH1占空比
  GTIM->CCR2 = 0; // CH2占空比
  GTIM->CMMR = 0xFF; // 正向占空比输出
  GTIM->CR0 = 0x01; // GTIM启动

程序中电磁阀动作实现:
  ...
  // 动作输出(每10mS执行一次)
  if(sv1输出)
  {
    GTIM->CCR1=250*(170-nnn)/电源电压; // SV1动作,动作后电压逐渐降低
    if(nnn<60) nnn++; // 60*10mS后保持在170-60=110(11V)
  }
  else
  {
    GTIM->CCR1=0;
    nnn=0; // 清0,为下次开通作准备
  }
  ...


占空比计算公式:
        2500*电磁阀电压/电源电压
  2500是ARR的周期数,比如电磁阀电压是17V,电源电压是100V,CCR1=17/100*2500=425
  直接用12V计算会不够用,每次减1就是减去1V,调整幅度太大,所以将电磁阀电压扩大10倍,相当于每次减0.1V。
  于是公式变成:2500*(电磁阀电压*10)/10/电源电压 = 250*(电磁阀电压*10)/电源电压

  电源电压是ADC变换及换算出的数,就是电压的整数。这是ADC的功能,这里不多说。

关于PWM频率:当然是越高越好,但是因为有续流二极管,太高了没有意义。从200Hz~500Hz都可以,再高就要考虑MOS管的驱动问题。我的电路是mcu直接驱动MOS管,为防止意外,其间加了电阻,电阻值10k,如MOS管明显发热,阻值就降低一些。

使用特权

评论回复
12
zhanan|  楼主 | 2023-7-15 10:44 | 只看该作者
用PWM驱动,取样电流就是波动的了,没法直接用。因为是用于判断电磁阀的工作状态,对精度无要求,同时也不想在程序上费神,加大取样电压后的电容滤波,电容量加大到0.33uF。

但是这样一来,将短路脉冲也给平滑掉了,除非比较器的输入信号改到取样电阻那里,两个信号分两路,电路又变得复杂。

但实践证明,按我这套高压电源驱动低压电磁阀方法,高压和低压相差较大条件下,比较器可不用,在10mS间隔中判断电流大小也能实现短路保护。理论上驱动脉宽有300uS,MOS管能扛过这个时间的短路,我也百思不得其解,觉得这个电路有用的朋友可一起深入探讨。
   

使用特权

评论回复
13
tpgf| | 2023-8-8 10:42 | 只看该作者
用一个连接器搞定啊 这样就不会在中间有接错线的问题了

使用特权

评论回复
14
qcliu| | 2023-8-8 10:52 | 只看该作者
多通道测量为什么通道之间会产生干扰呢

使用特权

评论回复
15
drer| | 2023-8-8 11:41 | 只看该作者
是否可以通过降低adc的电压基准来提高采集精度呢

使用特权

评论回复
16
coshi| | 2023-8-8 11:57 | 只看该作者
drer 发表于 2023-8-8 11:41
是否可以通过降低adc的电压基准来提高采集精度呢

这种方式只能适合那种电压一直都比较低的情况

使用特权

评论回复
17
kxsi| | 2023-8-8 13:20 | 只看该作者
这种弱信号非常容易被干扰信号所覆盖啊

使用特权

评论回复
18
wiba| | 2023-8-8 14:43 | 只看该作者
如何能保证ad采集的时候可以保证高电压和低电压的采集精度呢

使用特权

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

本版积分规则

10

主题

183

帖子

0

粉丝