找回密码
 立即注册
查看: 2324|回复: 63

关于STC8 USB功能导致ADC读取跳动的问题

[复制链接]
  • 打卡等级:常住居民III
  • 打卡总天数:145
  • 最近打卡:2026-07-23 20:24:48

6

主题

83

回帖

997

积分

高级会员

积分
997
发表于 2026-1-9 20:20:10 来自手机 | 显示全部楼层 |阅读模式
我在使用STC8H2K08U时,实现USB转串口和键鼠(参考官方例程作出优化的程序)功能,USB通信都正常,USB串口使用bulk传输,键鼠使用中断模式,1ms间隔,由USB 5V供电,主频由USB时钟48MHz分频出24MHz。
然后在此功能上,加入ADC采样功能。ADC读取电源电压,由两个5.1kΩ电阻分压,ADC引脚并联100nF保证ADC采样保持误差小于1LSB,ADC采样时间调整为31,ADC时钟为主时钟6分频,单独验证ADC功能时,可以保证ADC读取结果跳动在±1以内。
但发现,在ADC采样时,电脑打开USB串口功能,不收发收据,此时ADC读取结果会收到较大影响,读取结果跳动会达到正负几十个数,关闭USB串口后ADC读取结果马上跳动恢复±1,程序在ADC采样时关闭EA效果也是一样。

单片机原电源接法:
VCC引脚和ADC_REF直连
,VCC由USB供电串联22Ω后在VCC引脚最短距离并联100nF+10μF电解电容,ADC_REF引脚并联100nF,Ucap并联100nF。
在USB串口打开时,可以用示波器看到在Ucap有较大的1ms间隔的电压毛刺,VCC引脚上亦会有此成分的干扰,关闭串口后1ms毛刺消失。

为此,我作出以下方案尝试改良:
1,把VCC电源的电解电容加大到470μF,VCC上毛刺减少大部分;再并联10μF陶瓷电容后,示波器基本在vcc上看不到电压毛刺(20mv档),但ADC受干扰现象依旧。
2,断开VCC引脚和ADC_REF,两引脚分别串联22Ω电阻到5V电源,电解电容保持470μF;示波器同样基本看不到毛刺,ADC受干扰现象依旧。
3,保持第二条,将Ucap电容换为10μF陶瓷电容,ADC受干扰现象依旧。
4,使用ME6210稳压器,将5V降为3.3V,VCC电解电容保持470μF,VCC引脚和ADC_REF直连;示波器看不到毛刺,ADC受干扰现象依旧;
5,使用ME6210稳压器,5V降为3.3V后直接连Ucap供电,Ucap电容使用470μF电解电容+10μF陶瓷电容,VCC和ADC_REF由USB经22Ω电阻后并联470μF+10μF陶瓷电容;此时示波器在Ucap和VCC上毛刺都非常小,但ADC受干扰现象依旧。

我尝试了以上手段均不能解决USB串口打开时导致ADC读取结果跳动大的问题,ADC和USB功能单独运行时都是良好的,不知道是不是还有什么遗漏,望能解决这个问题。


回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:470
  • 最近打卡:2026-07-24 11:46:47

851

主题

1万

回帖

2万

积分

管理员

积分
24460
发表于 2026-1-22 23:59:20 | 显示全部楼层
截图202601222358568594.jpg

【新提醒】完整的系统设计参考原理图@8H8K64U, [url=home.php?mod=space&uid=5]@32G12K128 - 电源/复位/省电模式/外部晶振/内部时钟/对外时钟输出/PLL-144MHz时钟 国芯人工智能技术交流网站 - AI32位8051交流社区[/url]
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:470
  • 最近打卡:2026-07-24 11:46:47

851

主题

1万

回帖

2万

积分

管理员

积分
24460
发表于 2026-1-23 22:05:44 | 显示全部楼层

截图202601232205413664.jpg

截图202601232204593009.jpg
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:470
  • 最近打卡:2026-07-24 11:46:47

851

主题

1万

回帖

2万

积分

管理员

积分
24460
发表于 2026-1-23 22:14:58 | 显示全部楼层
请严格按照我们的推荐来做,
楼主的描述和原理图,不一定吻合,但问题:
1,说 VCC串了 22欧电阻,这肯定不专业,直接短路;
2,ADC参考源 TL431的输出没有 并1个10uF电容到地,
     这是不会使用 TL431
3, 楼主一个简单的电路,原理图却搞得那么复杂,请参考下图简化

截图202601232217291388.jpg

回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:470
  • 最近打卡:2026-07-24 11:46:47

851

主题

1万

回帖

2万

积分

管理员

积分
24460
发表于 2026-1-9 21:01:19 | 显示全部楼层
1,电源线上坚决不要串电阻;

2,ADC_VREF 要接 参考源,如直接接到 VCC
     要用 内部的 1.19V 参考信号源 反推 VCC 及其他输入通道的输入电压
截图202601092100306465.jpg

截图202601092101161452.jpg
回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:783
  • 最近打卡:2026-07-24 11:23:17

9

主题

696

回帖

4849

积分

论坛元老

积分
4849
发表于 2026-1-10 11:57:38 | 显示全部楼层
应该是供电和PCB走线不合理引起的,
一方面,供电线串电阻瞬态负载变化导致供电波动.
另一方面,ADC检测通道的地线电流通道跟其他负载电流通道公用PCB走线,其他负载电流变化时,在地线上的压降影响ADC采样值.
重点检查ADC采样回路的地线电流通道,避免跟其他负载电流共用地线通道.
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:145
  • 最近打卡:2026-07-23 20:24:48

6

主题

83

回帖

997

积分

高级会员

积分
997
发表于 2026-1-11 23:15:36 | 显示全部楼层
网*** 发表于 2026-1-10 11:57
应该是供电和PCB走线不合理引起的,
一方面,供电线串电阻瞬态负载变化导致供电波动.
另一方面,ADC检测通道的 ...

我已检查过信号回路和地线回路,供电和信号的负极回路一个在左一个在右,两个回路电流互不干扰且单点接地。

且用示波器检查了信号进入ADC的波形和电源,开启USB和关闭USB是一致的,
就是会在USB开启后,ADC的结果跳动由原来的 ±1 变大到 ±3 到 ±5 左右。

各位如果手头上有官方开发板,可以尝试下这个操作,ADC读取一个固定电压值,不要进行滤波,直接显示结果,
然后开启和关闭USB转串口功能,对比前后的ADC值跳动是否有差异。

这个问题对有USB和小信号ADC应用的场景非常重要,每一个LSB值都要有意义才行,不然就要舍弃ADC有效位数了。
回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:606
  • 最近打卡:2026-07-24 08:56:12
已绑定手机

116

主题

4992

回帖

1万

积分

超级版主

无情的代码机器

积分
10913
发表于 2026-1-12 09:11:24 | 显示全部楼层
貌似和USB无关,可以对比下串口的

参考此例程软件防抖:
09-ADC采样NTC数据-软件防抖-过采样使用-串口1返回结果.zip (85.88 KB, 下载次数: 39)
三天不学习,赶不上刘少奇~
回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:783
  • 最近打卡:2026-07-24 11:23:17

9

主题

696

回帖

4849

积分

论坛元老

积分
4849
发表于 2026-1-12 11:58:25 | 显示全部楼层
rm5*** 发表于 2026-1-11 23:15
我已检查过信号回路和地线回路,供电和信号的负极回路一个在左一个在右,两个回路电流互不干扰且单点接地 ...

3.3V供电的话,1个字对应0.8mV左右,3个字对应2.4mV左右,
电脑USB供电含有大量低频纹波和射频尖刺,普通的供电系统很难做到几个mV的波动.
特别是射频干扰,会通过空间耦合,不是加大滤波电容就能抑制的.
示波器的带宽和分辨率有限,低噪都可能超过1mV了,直接测量供电波形看不出什么异常的
ADC不做滤波的话不可能做到只跳1个字.
另外,STC单片机没有独立的AGND管脚,片内模拟和数字负载电流不可避免会有公共通道.这也是一个跳字因素.
做产品方案时,要留有足够余量.压榨到极限使用的话,批量生产也会出问题.

回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:145
  • 最近打卡:2026-07-23 20:24:48

6

主题

83

回帖

997

积分

高级会员

积分
997
发表于 2026-1-12 20:46:46 来自手机 | 显示全部楼层
网老四 发表于 2026-1-12 11:58
3.3V供电的话,1个字对应0.8mV左右,3个字对应2.4mV左右,
电脑USB供电含有大量低频纹波和射频尖刺,普通的供 ...

STC的单片机ADC确实可以在良好的条件下实现只跳±1,这个可以用电池验证的。重点是保证ADC_VREF稳定,而且我在实际使用中,用普通的稳压器结合合理的电路设计也可以实现良好的数值稳定性,再加上结合与周期性干扰同步的方式,读出来的ADC结果在不滤波的情况下确实是可以在±1跳动。
我这个电路中是在USB不开时ADC跳±1,USB打开跳动变大,我也感觉有可能是内部模块的串扰,因为只有STC8H3K系列才有独立的模拟量引脚,当时用过只要电源稳定也是可以保证很稳定的ADC结果,不需要软件滤波,每一次采样都是有效的
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:145
  • 最近打卡:2026-07-23 20:24:48

6

主题

83

回帖

997

积分

高级会员

积分
997
发表于 2026-1-12 20:50:08 来自手机 | 显示全部楼层
ercircle 发表于 2026-1-12 09:11
貌似和USB无关,可以对比下串口的

参考此例程软件防抖:

在USB打开前ADC结果都很稳定,
不需要软件做任何滤波处理,
USB串口打开后,传不传数据都会造成ADC结果跳动变大,
USB主机一直在询问从机有没有数据包要返回。

回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:470
  • 最近打卡:2026-07-24 11:46:47

851

主题

1万

回帖

2万

积分

管理员

积分
24460
发表于 2026-1-13 09:12:56 | 显示全部楼层
请将您的原理图 PDF 发上来,不要只有文字,
还有 PCB 正反截图,实物照片
回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:145
  • 最近打卡:2026-07-23 20:24:48

6

主题

83

回帖

997

积分

高级会员

积分
997
发表于 2026-1-22 23:15:26 | 显示全部楼层
神*** 发表于 2026-1-13 09:12
请将您的原理图 PDF 发上来,不要只有文字,
还有 PCB 正反截图,实物照片
...

原电路板由于功能比较多,测试可能会存在干扰项。


为排除其他干扰项,我单独做了一块ADC验证板来排查问题。
测试板只保留了USB和硬件串口和ADC功能,尽量使用简单而短的布线;

板子的工程文件在附件,使用立创EDA专业版绘制。
PCB:
截图202601222234025784.jpg
截图202601222234475060.jpg
截图202601222235394802.jpg
IMG_20260122_231410.jpg
截图202601222236064167.jpg
截图202601222236295930.jpg
原理图:
SCH_Schematic1_1-P1_2026-01-22.png
SCH_Schematic1_2-P2_2026-01-22.png

实际电路板上,Ω电阻不是全部焊接,用作跳线功能:
单片机VCC使用线性稳压器的3.3V供电;
单片机的ADC参考电压直连单片机VCC,没有使用431电路进行稳压;
单片机的Ucap使用线性稳压的3.3V供电;
电源的电容全部焊接;
电池和USB电源焊接二极管选择供电,实际使用电池供电;

单片机测试程序是从原工程的基础上简化来的,主要功能是进行USB转串口,
源代码没有作整理,只展示部分相关的功能代码;

单片机主频设置为24MHz,使用USB的内部48MHz时钟进行分频;
ADC时钟设置为4分频,
ADCTIM设置:采样时间31,通道保持时间3,通道选择时间0;
ADC每次采样都关闭全局中断 EA,采样结束后再打开 EA;

测试软件运行逻辑:
每100ms读取一次6个通道的ADC值,读取16次后进行最大最小值以及平均值的统计输出;
数据同时向USB转串口以及硬件串口进行发送;

输出格式为文本:

xxx_ADC = ADC值,MAX = ADC值,MIN = ADC值,Jump = ADC值\r\n


xxx_ADC 是通道采样的平均值,MAX 是16次采样的最大值,MIN 是16次采样的最小值,Jump 是16次采样的最大值减最小值;

读取ADC值的函数:
  1. void read_adc_val(void)
  2. {
  3. u8 i;
  4.         u16 adc_tmp[6];
  5.        
  6.         if(adc_r_cnt < 16){
  7.         // 读ADC结果
  8.         adc_tmp[0] = ADC_get(VIN1_CHN);
  9.         adc_tmp[1] = ADC_get(VIN2_CHN);
  10.         adc_tmp[2] = ADC_get(VIN3_CHN);
  11.         adc_tmp[3] = ADC_get(VIN4_CHN);
  12.         adc_tmp[4] = ADC_get(VREF_CHN);
  13.         adc_tmp[5] = ADC_get(VCC_CHN);
  14.        
  15.         // 储存最值
  16.         for(i = 0;i < 6;i++){
  17.                 adc_read[i] += adc_tmp[i];
  18.                
  19.                 if(adc_tmp[i] > adc_res_max[i]){
  20.                         adc_res_max[i] = adc_tmp[i];
  21.                 }
  22.                 if(adc_tmp[i] < adc_res_min[i]){
  23.                         adc_res_min[i] = adc_tmp[i];
  24.                 }
  25.         }       
  26.        
  27.         adc_r_cnt++;
  28.         }
  29.         else{
  30.                 show_adc_flag = true;
  31.         }
  32. }
复制代码


发送ADC数据函数:
  1. // 发送ADC结果
  2. void show_adc_res(void)
  3. {
  4.         u16 u_tmp;
  5.         xdata char c_buf[20];
  6. // 数据采集完成
  7.         if(show_adc_flag == true){
  8.                 // 发送字符串
  9.                 put_up_string(uart_adc_name[show_adc_idx]);
  10. // 发送平均值
  11.                 print_NUM_to_string(c_buf,(adc_read[show_adc_idx]/16),4,0,false);
  12.                 put_up_string(c_buf);
  13.                
  14.                 put_up_string(",MAX = ");
  15.                 // 发送最大值
  16.                 print_NUM_to_string(c_buf,adc_res_max[show_adc_idx],4,0,false);
  17.                 put_up_string(c_buf);
  18.                
  19.                 put_up_string(",MIN = ");
  20.                 // 发送最小值
  21.                 print_NUM_to_string(c_buf,adc_res_min[show_adc_idx],4,0,false);
  22.                 put_up_string(c_buf);
  23.                
  24.                 put_up_string(",Jump = ");
  25. // 发送跳动值
  26.                 u_tmp = (adc_res_max[show_adc_idx] - adc_res_min[show_adc_idx]);
  27.                 print_NUM_to_string(c_buf,u_tmp,4,0,false);
  28.                 put_up_string(c_buf);
  29.                
  30.                 put_up_string("\r\n");
  31.                 // 复位计数器
  32.                 adc_r_cnt = 0;
  33.                 adc_read[show_adc_idx] = 0;
  34.                 adc_res_max[show_adc_idx] = 0;
  35.                 adc_res_min[show_adc_idx] = 4096;
  36.                 // 发送循环
  37.                 show_adc_idx ++;
  38.                 if(show_adc_idx > 5){
  39.                         show_adc_idx = 0;
  40.                         show_adc_flag = false;
  41.                 }
  42.                 // 发送数据
  43.                 Check_UART_Busy_Send();
  44.         }
  45.        
  46. }
复制代码


ADC通道的 VIN4_ADC 连接电池使用可调电阻分压;
ADC通道的 VREF_ADC 连接单片机 ADC_REF 引脚进行对半分压;
ADC通道的 VCC_ADC 连接单片机 VCC 引脚进行对半分压;
其余ADC通道使用分压电阻连接,分压电阻输入悬空(约等于10KΩ电阻下拉);

在打开USB转串口功能时,单片机读取的ADC结果(取其一):

                    VIN1_ADC = 0001,MAX = 0006,MIN = 0000,Jump = 0006
                    VIN2_ADC = 0000,MAX = 0005,MIN = 0000,Jump = 0005
                    VIN3_ADC = 0000,MAX = 0005,MIN = 0000,Jump = 0005
                    VIN4_ADC = 3147,MAX = 3148,MIN = 3143,Jump = 0005
                    VREF_ADC = 2044,MAX = 2047,MIN = 2040,Jump = 0007
                    VCC_ADC  = 2045,MAX = 2051,MIN = 2043,Jump = 0008


关闭USB转串口功能时,单片机读取的ADC结果(取其一):

                    VIN1_ADC = 0000,MAX = 0001,MIN = 0000,Jump = 0001
                    VIN2_ADC = 0000,MAX = 0000,MIN = 0000,Jump = 0000
                    VIN3_ADC = 0000,MAX = 0000,MIN = 0000,Jump = 0000
                    VIN4_ADC = 3147,MAX = 3148,MIN = 3147,Jump = 0001
                    VREF_ADC = 2044,MAX = 2045,MIN = 2044,Jump = 0001
                    VCC_ADC  = 2044,MAX = 2045,MIN = 2044,Jump = 0001


经过多次测试基本是相同的结果。
测试视频已上传到附件。

使用此ADC测试板测得的问题现象与原工程上出现的现象基本一致,
都是在打开USB功能时出现ADC跳动值变大的现象,关闭USB功能后ADC值正常。

如果需要此测试电路板的可以联系寄出,
如果需要继续测试哪些内容的请继续提出。




ProPrj_STC_ADC_Test_V01.epro2

377.26 KB, 下载次数: 33

ADC测试板工程文件

video_20260122_222613_edit.mp4

99.24 MB, 下载次数: 37

测试视频

点评

电路有些不合理的地方,注意红色标记: 下图中R1~R4=22R太小,起不到保护作用,改为200R更好。电位器输出串联1K电阻。电容不是越多越好,打红叉的电容去掉。 [attachimg]130396[/attachimg] TL431去掉C18,但是要  详情 回复 发表于 2026-1-24 20:58
可以对比下usb替换为串口的: 场景1,pc不发只收 场景2,pc定时发送模拟usb轮询  详情 回复 发表于 2026-1-22 23:44
回复

使用道具 举报 送花

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

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-7-25 08:34 , Processed in 0.084462 second(s), 108 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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