找回密码
 立即注册
查看: 101|回复: 4

Ai8H单片机ADC采样,定时器触发,DMA的问题求助

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2025-07-29 09:04:21

2

主题

2

回帖

43

积分

新手上路

积分
43
发表于 2025-7-18 17:21:04 | 显示全部楼层 |阅读模式
我的问题如下:
单片机是Ai8H8K64U,工作频率内部时钟11.0592MHz。目标是想通过ADC采样,然后计算获取交流电的有效电压值。
现在已经使用ADC查询的方式,连续采样16次计算一个平均值作为一个采样点,共计得到512个这样的数值,再通过计算得到交流电的有效电压值。
从验证的结果看,这个方式的误差基本上可以保证在2%以内,但是比较耗费单片机的CPU的时间。
目前想做一点改进:
1、在20ms内(一个周期),通过定时器/PWM来触发ADC,采样512个点(测试过,256个点的误差有点大,而且平均值偏差也比较大)。
2、采样的数据点,通过DMA的方式传输到缓存(XDATA的一个数组)。
3、512个点采样结束后,给出一个结束标志位(中断标志,或者是自定义的标志位都可以),然后根据结束标志位启动计算过程。
我自己也曾经尝试过用DMA来传输数据,不过失败了,得到的结果总是一个固定数值。所以才来这里求助。
无论是官方的高手(比如梁工)还是路过的大神,帮我提供一下思路,我去尝试下。

回复

使用道具 举报 送花

3

主题

247

回帖

-795

积分

等待验证会员

积分
-795
发表于 2025-7-18 17:23:00 | 显示全部楼层
尊敬的用户:

您好!感谢您对STC8H系列单片机的深入使用与探索。针对您提出的问题,我们将从ADC采样、定时器触发、DMA传输及数据处理等方面进行专业分析,并提供可行的解决方案。

一、系统概述

您所使用的单片机为STC8H8K64U,其内部时钟频率为11.0592MHz(注意:您提到的是“110592MHz”,应为11.0592MHz)。目标是通过ADC采集交流电的有效电压值,目前采用查询方式完成16次采样取平均值,共采集512个点,最终计算有效值。当前方法精度满足要求,但CPU占用较高,因此希望优化为定时器触发ADC+DMA传输的方式,以提升效率并减少CPU负担。

二、问题分析与建议

1. 定时器触发ADC采样

您希望在20ms内(即一个工频周期)完成512次采样,这意味着每点间隔约为 39.0625μs。对于STC8H系列单片机而言,若使用内部时钟11.0592MHz,其机器周期为 1/11.0592MHz × 12 = 1.087μs,因此可以配置定时器实现精确的采样间隔。
推荐方式:使用定时器中断或PWM输出作为ADC触发源。
注意事项:
ADC采样速率需匹配定时器频率;
确保ADC采样时间足够(一般建议至少10μs以上);
若使用PWM触发ADC,需确保PWM输出频率与采样率一致。

2. DMA传输ADC数据

您尝试使用DMA传输ADC数据失败,结果固定不变,可能原因如下:
DMA通道未正确配置:ADC数据寄存器地址与目标缓冲区地址未设置正确;
ADC未启用DMA请求:需在ADC控制寄存器中开启DMA使能;
DMA优先级冲突:其他外设可能抢占DMA资源;
缓存区未初始化:XDATA数组未正确分配空间或未清空;
ADC未进入正常工作模式:如未开启ADC、未选择正确的输入通道等。

建议步骤:

1. 配置ADC为连续采样模式,并启用DMA请求;
2. 设置DMA通道,将ADC数据寄存器(如ADCDATA)映射到XDATA数组;
3. 启动ADC和DMA后,等待DMA传输完成标志;
4. 检查DMA状态寄存器,确认是否发生错误或未完成。

3. 采样完成后触发计算

当DMA完成512个数据的传输后,可通过以下方式触发计算:
DMA传输完成中断:在DMA中断服务程序中设置标志位;
DMA传输完成标志位:通过读取DMA状态寄存器判断是否完成;
软件轮询:在主循环中检测标志位,触发计算过程。

建议使用DMA中断方式,避免主循环频繁轮询,提高系统响应性。

三、参考代码结构(伪代码)
  1. c
  2. // 定义ADC与DMA相关变量
  3. define ADCSAMPLECOUNT 512
  4. unsigned int adcbuffer[ADCSAMPLECOUNT]; // XDATA数组
  5. volatile unsigned char dmacompleteflag = 0;
  6. // 初始化ADC
  7. void ADCInit(void) {
  8.     ADCEN = 1;                // ADC使能
  9.     ADCCON1 |= 0x08;          // 选择通道0
  10.     ADCCON1 |= 0x01;          // 选择连续采样模式
  11.     ADCCON1 |= 0x40;          // 开启DMA请求
  12. }
  13. // 初始化DMA
  14. void DMAInit(void) {
  15.     DMACON = 0x00;            // 清除DMA配置
  16.     DMACON |= 0x01;           // 选择DMA通道0
  17.     DMASRC0 = (unsigned int)&ADCDATA; // ADC数据寄存器地址
  18.     DMADST0 = (unsigned int)adcbuffer; // 缓冲区地址
  19.     DMALN0 = ADCSAMPLECOUNT  2; // 数据长度(16位)
  20.     DMACON |= 0x80;           // 启动DMA
  21. }
  22. // 定时器初始化(用于触发ADC)
  23. void TimerInit(void) {
  24.     TMOD = 0x01;              // 定时器0模式1
  25.     TH0 = 0x00;
  26.     TL0 = 0x00;
  27.     ET0 = 1;                  // 开启定时器0中断
  28.     TR0 = 1;                  // 启动定时器
  29. }
  30. // 定时器中断服务函数
  31. void Timer0ISR(void) interrupt 1 {
  32.     // 触发一次ADC采样(可配合PWM或直接触发)
  33.     ADCCON1 |= 0x80;          // 触发ADC转换
  34. }
  35. // DMA中断服务函数
  36. void DMAISR(void) interrupt 15 {
  37.     if (DMACON & 0x01) {      // 判断DMA通道0是否完成
  38.         dmacompleteflag = 1;
  39.         DMACON &= ~0x01;      // 清除DMA标志
  40.     }
  41. }
  42. // 主循环
  43. void main(void) {
  44.     ADCInit();
  45.     DMAInit();
  46.     TimerInit();
  47.     while(1) {
  48.         if (dmacompleteflag) {
  49.             // 执行有效值计算
  50.             float Vrms = CalculateVrms(adcbuffer, ADCSAMPLECOUNT);
  51.             // ...后续处理
  52.             dmacompleteflag = 0;
  53.         }
  54.     }
  55. }
复制代码

四、常见问题排查建议

| 问题 | 原因 | 解决方案 |
|------|------|----------|
| DMA传输数据始终为0 | ADC未正确配置或未启动 | 检查ADC使能、通道选择、采样模式 |
| DMA未触发 | DMA配置错误或未启用 | 检查DMA通道、源地址、目标地址、长度 |
| 计算误差大 | 采样点不足或采样不准确 | 增加采样点数或调整采样频率 |
| CPU占用高 | 查询方式效率低 | 改用DMA+中断方式 |

五、总结

通过定时器触发ADC与DMA传输数据相结合的方式,可以显著降低CPU负载,提高系统效率。建议按上述步骤进行配置,并结合实际测试不断调试参数。如仍有疑问,欢迎进一步交流。

祝您项目顺利!

——国芯人工智能团队

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 1 反对 0

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:137
  • 最近打卡:2025-07-31 12:11:20

76

主题

6281

回帖

1万

积分

超级版主

积分
13347
发表于 2025-7-18 18:15:04 | 显示全部楼层
你可以搜搜本站关于交流电采样计算电压、电流有效值的帖子。
我做过不少交流互感器、霍尔互感器(交直流兼容)、直接采样的方式,采样计算交流电压有效值、电流有效值、有功功率、视在功率、功率因数,得益于STC的低噪声、高精度的12位ADC,测量结果非常满意!
ADC采样交流电计算有效值,采样速度为一个周期20ms采样4的倍数次,次数越多越好,但是次数太多会很占CPU时间,2个通道不超过20KHz(一个周期采样400次,可以连续采样4个周期1600次),6个通道不超过10KHz(一个周期采样200次,可以连续采样10个周期1600次)。
如果只测量一路交流电压或电流,则使用PWMA自动触发ADC、ADC中断读取数据并计算平方和,是最优方案。
如果是多路ADC,则使用ADC DMA,但ADC DMA不能设置采样率,所以要用定时器中断来启动ADC DMA。定时器中断设置为最高优先级。
比如使用ADC DMA采样6个通道(三相交流电压、电流),定时器中断触发ADC DMA,DMA中断读取结果。通道安排顺序为:电压1、电流1、电压2、电流2、电压3、电流3,这样同一相电压和电流相位差不超过0.15度。
ADC速度控制在6~8us,定时器中断10KHz,触发ADC DMA,无符号长整形变量最多可连续累加2000次的平方和而不会溢出,对应时间为200ms。
回复 支持 1 反对 0

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2025-07-29 09:04:21

2

主题

2

回帖

43

积分

新手上路

积分
43
发表于 2025-7-19 10:21:33 | 显示全部楼层
国芯人*** 发表于 2025-7-18 17:23
尊敬的用户:

您好!感谢您对STC8H系列单片机的深入使用与探索。针对您提出的问题,我们将从ADC采样、定时 ...

非常感谢你的帮助,我按照你的思路去试试。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:5
  • 最近打卡:2025-07-29 09:04:21

2

主题

2

回帖

43

积分

新手上路

积分
43
发表于 2025-7-19 10:22:00 | 显示全部楼层
梁*** 发表于 2025-7-18 18:15
你可以搜搜本站关于交流电采样计算电压、电流有效值的帖子。
我做过不少交流互感器、霍尔互感器(交直流兼 ...

好的,也非常感谢你的回复。
回复 支持 反对

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-8-1 01:08 , Processed in 0.109986 second(s), 74 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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