找回密码
 立即注册
查看: 90|回复: 3

ADC_DMA程序调试中卡了很久的一个小问题 | 解决了!

[复制链接]
  • 打卡等级:偶尔看看I
  • 打卡总天数:19
  • 最近打卡:2025-08-01 22:27:17

18

主题

32

回帖

302

积分

中级会员

积分
302
发表于 2025-7-25 14:54:54 | 显示全部楼层 |阅读模式
ADC_DMA程序调试中卡了很久的一个小问题,解决了!
这几天,在学习ADC_DMA程序,参考“STC32G-DEMO-CODE-V9.6-20240418”实验程序中“60-DMA-ADC采样数据自动存储”文件加中“16路ADC转换使用DMA-串口2返回结果”工程文件进行程序改写。
原来的程序对16路进行DMA自动扫描,然后在串口2输出结果,每个通道采集4次,调试能正常执行。

然后把串口2改成串口1输出,调试正常。在原程序中把16路,改成任意几路,调试正常。

接着我从头自己仿照写程序,16路扫描功能一样,调试正常。接着当我修改转换通道数量时,发生了问题,转换完成,没有打印输出。我自己写的源程序如下:
  1. #include "STC32G12K128.h"
  2. #include "intrins.h"
  3. #include "stdio.h"
  4. #define         u8 unsigned char  
  5. #define         u16 unsigned int
  6. #define         u32 unsigned long
  7.         
  8. #define MAIN_Fosc     24000000L        //定义主时钟
  9. #define        ADC_CH                4        /* 1~16, ADC转换通道数, 需同步修改 DMA_ADC_CHSW 转换通道 */
  10. #define        ADC_DATA        4    /* 6~n, 每个通道ADC转换数据总数, 2*转换次数+4, 需同步修改 DMA_ADC_CFG2 转换次数 */
  11. /**************定义引脚*****************/
  12. /**************全局变量*****************/
  13. bit        DmaFlag;
  14. u8 xdata DmaBuffer[ADC_CH][ADC_DATA*2+4];
  15. /**************函数声明*****************/
  16. void GPIO_init();           //GPIO口初始化
  17. void        delay_ms(u8 ms);
  18. void Uart1_Init();        //115200bps@24.000MHz
  19. void ADC_init(); // ADC初始化
  20. void DMA_Config(void);  //DMA初始化
  21. /******************** 主函数 **************************/
  22. void main(void)
  23. {
  24.   u8        i,n;
  25.         
  26.         //初始化
  27.         WTST = 0;    //设置程序指令延时参数
  28.   EAXFR = 1;   //扩展寄存器(XFR)访问使能
  29.   CKCON = 0;   //提高访问XRAM速度
  30.         
  31.         GPIO_init();//GPIO口初始化
  32.         ADC_init(); // ADC初始化
  33.         
  34.         Uart1_Init();        //115200bps@24.000MHz
  35.         DMA_Config();
  36.         EA = 1; //允许总中断
  37.         printf("STC32G系列ADC DMA测试程序!\r\n");
  38. DmaFlag=0;
  39.         while(1)
  40.         {
  41.                 delay_ms(200);        
  42.                 if(DmaFlag)
  43.                 {
  44.                         printf("ADC DMA完成!\r\n");
  45.                         DmaFlag = 0;
  46.                         for(i=0; i<ADC_CH; i++)  //3个通道
  47.                         {
  48.                                 for(n=0; n<(ADC_DATA*2+4); n++)  
  49.                                 {
  50.                                         printf("0x%02x ",DmaBuffer[i][n]);
  51.                                 }
  52.                                 printf("\r\n");
  53.                         }
  54.                         printf("\r\n");
  55.                         
  56.                         DMA_ADC_CR = 0xc0;                //bit7 1:Enable ADC_DMA, bit6 1:Start ADC_DMA
  57.                 }
  58.         }
  59. }
  60. /******************** 子函数 **************************/
  61. void GPIO_init()//GPIO口初始化
  62. {
  63.     P0M1 = 0x7f;   P0M0 = 0x00;   //设置要做ADC的IO做高阻输入
  64.     P1M1 = 0xfb;   P1M0 = 0x00;   //设置要做ADC的IO做高阻输入
  65.     P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
  66.     P3M1 = 0x50;   P3M0 = 0x50;   //设置P3.4、P3.6为漏极开路(实验箱加了上拉电阻到3.3V)
  67.     P4M1 = 0x3c;   P4M0 = 0x3c;   //设置P4.2~P4.5为漏极开路(实验箱加了上拉电阻到3.3V)
  68.     P5M1 = 0x0c;   P5M0 = 0x0c;   //设置P5.2、P5.3为漏极开路(实验箱加了上拉电阻到3.3V)
  69.     P6M1 = 0xff;   P6M0 = 0xff;   //设置为漏极开路(实验箱加了上拉电阻到3.3V)
  70.     P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
  71. }
  72. void delay_ms(u8 ms)
  73. {
  74.         u16 i;
  75.         do
  76.         {
  77.                 i = MAIN_Fosc / 6000;
  78.                 while(--i);
  79.         }while(--ms);
  80. }
  81. void Uart1_Init(void)        //115200bps@24.000MHz
  82. {
  83.         SCON = 0x50;                //8位数据,可变波特率
  84.         AUXR |= 0x01;                //串口1选择定时器2为波特率发生器
  85.         AUXR |= 0x04;                //定时器时钟1T模式
  86.         T2L = 0xCC;                        //设置定时初始值
  87.         T2H = 0xFF;                        //设置定时初始值
  88.         AUXR |= 0x10;                //定时器2开始计时
  89.         TI=1;  //使用“printf()函数”,TI初始化一定要置1
  90. }
  91. void ADC_init() // ADC初始化
  92. {
  93.         ADCCFG = 0x2f;        //设置 ADC 时钟为系统时钟/2/16,数据结果右对齐 ADC_RES 低四位+ ADC_RESL 8位
  94.         ADCTIM = 0x3f;                //设置 ADC 内部时序,ADC采样时间建议设最大值
  95.         ADC_CONTR = 0x80;   //使能 ADC 模块,需等待1ms后稳定
  96. }
  97. /******************** DMA初始化 **************************/
  98. void DMA_Config(void)
  99. {
  100.   DMA_ADC_STA = 0x00;  //中断标志位复位
  101.         DMA_ADC_CFG = 0x80;                //开启ADC_DMA中断,中断优先级最低,数据总线访问优先级最低
  102.         DMA_ADC_RXAH = (u8)((u16)DmaBuffer >> 8);        //ADC转换数据存储地址
  103.         DMA_ADC_RXAL = (u8)((u16)DmaBuffer);
  104.         DMA_ADC_CFG2 = 0x09;        //每个通道ADC转换次数:4
  105.         DMA_ADC_CHSW0 = 0x0d;        //ADC通道使能寄存器 ADC3-P1.3,ADC0-P1.0
  106.         DMA_ADC_CHSW1 = 0x80;                //ADC15-内部测试电压1.19V
  107.         
  108.         DMA_ADC_CR = 0xc0;                //bit7 1:Enable ADC_DMA, bit6 1:Start ADC_DMA
  109. }
  110. void ADC_DMA_Interrupt(void) interrupt 13
  111. {
  112.         if (DMA_ADC_STA & 0x01)        //发送完成
  113.         {
  114.                 DMA_ADC_STA =0;  //复位中断标志位
  115.                 DmaFlag = 1;           //完成标志位置1
  116.         }
  117. }
复制代码
这段代码怎么都无法打印输出结果。
但是只要把转换通道改成16路通道,就可以正常打印输出。修改的地方如下,用多行注释标注的地方:
  1. /******************** DMA初始化 **************************/
  2. void DMA_Config(void)
  3. {
  4.   DMA_ADC_STA = 0x00;  //中断标志位复位
  5.         DMA_ADC_CFG = 0x80;                //开启ADC_DMA中断,中断优先级最低,数据总线访问优先级最低
  6.         DMA_ADC_RXAH = (u8)((u16)DmaBuffer >> 8);        //ADC转换数据存储地址
  7.         DMA_ADC_RXAL = (u8)((u16)DmaBuffer);
  8.         DMA_ADC_CFG2 = 0x09;        //每个通道ADC转换次数:4
  9. /*********************************************************************/
  10.         DMA_ADC_CHSW0 = 0xff;        //ADC通道使能寄存器 ADC3-P1.3,ADC0-P1.0
  11.         DMA_ADC_CHSW1 = 0xff;        //ADC15-内部测试电压1.19V</font>
  12. /*********************************************************************/        
  13.         DMA_ADC_CR = 0xc0;                //bit7 1:Enable ADC_DMA, bit6 1:Start ADC_DMA
  14. }
复制代码
这个问题,我查了很久,最终和源程序一条一条对比尝试,终于找到问题。下面时找到DEBUG后,修改后的程序,就在主程序中删掉了一条指令就正常了,转换几路通道都可以。
  1. #include "STC32G12K128.h"
  2. #include "intrins.h"
  3. #include "stdio.h"
  4. #define         u8 unsigned char  
  5. #define         u16 unsigned int
  6. #define         u32 unsigned long
  7.         
  8. #define MAIN_Fosc     24000000L        //定义主时钟
  9. #define        ADC_CH                4                        /* 1~16, ADC转换通道数, 需同步修改 DMA_ADC_CHSW 转换通道 */
  10. #define        ADC_DATA        4                        /* 6~n, 每个通道ADC转换数据总数, 2*转换次数+4, 需同步修改 DMA_ADC_CFG2 转换次数 */
  11. /**************定义引脚*****************/
  12. /**************全局变量*****************/
  13. bit        DmaFlag;
  14. u8 xdata DmaBuffer[ADC_CH][ADC_DATA*2+4];
  15. /**************函数声明*****************/
  16. void GPIO_init();           //GPIO口初始化
  17. void        delay_ms(u8 ms);
  18. void Uart1_Init();        //115200bps@24.000MHz
  19. void ADC_init(); // ADC初始化
  20. void DMA_Config(void);  //DMA初始化
  21. /******************** 主函数 **************************/
  22. void main(void)
  23. {
  24.   u8        i,n;
  25.         
  26.         //初始化
  27.         WTST = 0;    //设置程序指令延时参数
  28.   EAXFR = 1;   //扩展寄存器(XFR)访问使能
  29.   CKCON = 0;   //提高访问XRAM速度
  30.         
  31.         GPIO_init();//GPIO口初始化
  32.         ADC_init(); // ADC初始化
  33.         
  34.         Uart1_Init();        //115200bps@24.000MHz
  35.         DMA_Config();
  36.         EA = 1; //允许总中断
  37.         printf("STC32G系列ADC DMA测试程序!\r\n");
  38.         while(1)
  39.         {
  40.                 delay_ms(200);        
  41.                 if(DmaFlag)
  42.                 {
  43.                         printf("ADC DMA完成!\r\n");
  44.                         DmaFlag = 0;
  45.                         for(i=0; i<ADC_CH; i++)  //3个通道
  46.                         {
  47.                                 for(n=0; n<(ADC_DATA*2+4); n++)  //
  48.                                 {
  49.                                         printf("0x%02x ",DmaBuffer[i][n]);
  50.                                 }
  51.                                 printf("\r\n");
  52.                         }
  53.                         printf("\r\n");
  54.                         
  55.                         DMA_ADC_CR = 0xc0;                //bit7 1:Enable ADC_DMA, bit6 1:Start ADC_DMA
  56.                 }
  57.         }
  58. }
  59. /******************** 子函数 **************************/
  60. void GPIO_init()//GPIO口初始化
  61. {
  62.     P0M1 = 0x7f;   P0M0 = 0x00;   //设置要做ADC的IO做高阻输入
  63.     P1M1 = 0xfb;   P1M0 = 0x00;   //设置要做ADC的IO做高阻输入
  64.     P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
  65.     P3M1 = 0x50;   P3M0 = 0x50;   //设置P3.4、P3.6为漏极开路(实验箱加了上拉电阻到3.3V)
  66.     P4M1 = 0x3c;   P4M0 = 0x3c;   //设置P4.2~P4.5为漏极开路(实验箱加了上拉电阻到3.3V)
  67.     P5M1 = 0x0c;   P5M0 = 0x0c;   //设置P5.2、P5.3为漏极开路(实验箱加了上拉电阻到3.3V)
  68.     P6M1 = 0xff;   P6M0 = 0xff;   //设置为漏极开路(实验箱加了上拉电阻到3.3V)
  69.     P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
  70. }
  71. void delay_ms(u8 ms)
  72. {
  73.         u16 i;
  74.         do
  75.         {
  76.                 i = MAIN_Fosc / 6000;
  77.                 while(--i);
  78.         }while(--ms);
  79. }
  80. void Uart1_Init(void)        //115200bps@24.000MHz
  81. {
  82.         SCON = 0x50;                //8位数据,可变波特率
  83.         AUXR |= 0x01;                //串口1选择定时器2为波特率发生器
  84.         AUXR |= 0x04;                //定时器时钟1T模式
  85.         T2L = 0xCC;                        //设置定时初始值
  86.         T2H = 0xFF;                        //设置定时初始值
  87.         AUXR |= 0x10;                //定时器2开始计时
  88.         TI=1;  //使用“printf()函数”,TI初始化一定要置1
  89. }
  90. void ADC_init() // ADC初始化
  91. {
  92.         ADCCFG = 0x2f;        //设置 ADC 时钟为系统时钟/2/16,数据结果右对齐 ADC_RES 低四位+ ADC_RESL 8位
  93.         ADCTIM = 0x3f;                //设置 ADC 内部时序,ADC采样时间建议设最大值
  94.         ADC_CONTR = 0x80;   //使能 ADC 模块,需等待1ms后稳定
  95. }
  96. /******************** DMA初始化 **************************/
  97. void DMA_Config(void)
  98. {
  99.   DMA_ADC_STA = 0x00;  //中断标志位复位
  100.         DMA_ADC_CFG = 0x80;                //开启ADC_DMA中断,中断优先级最低,数据总线访问优先级最低
  101.         DMA_ADC_RXAH = (u8)((u16)DmaBuffer >> 8);        //ADC转换数据存储地址
  102.         DMA_ADC_RXAL = (u8)((u16)DmaBuffer);
  103.         DMA_ADC_CFG2 = 0x09;        //每个通道ADC转换次数:4
  104.         DMA_ADC_CHSW0 = 0x0d;        //ADC通道使能寄存器 ADC3-P1.3,ADC0-P1.0
  105.         DMA_ADC_CHSW1 = 0x80;                //ADC15-内部测试电压1.19V
  106.         
  107.         DMA_ADC_CR = 0xc0;                //bit7 1:Enable ADC_DMA, bit6 1:Start ADC_DMA
  108. }
  109. void ADC_DMA_Interrupt(void) interrupt 13
  110. {
  111.         if (DMA_ADC_STA & 0x01)        //发送完成
  112.         {
  113.                 DMA_ADC_STA =0;  //复位中断标志位
  114.                 DmaFlag = 1;           //完成标志位置1
  115.         }
  116. }
复制代码




回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:19
  • 最近打卡:2025-08-01 22:27:17

18

主题

32

回帖

302

积分

中级会员

积分
302
发表于 2025-7-25 15:21:00 | 显示全部楼层
在主程序中,删除了while(1)前面的“DmaFlag = 0;”指令,程序就正常了。
想了想原因:
      应该是ADC_DMA自动转换速度太快了,当转换完成并执行中断程序把DmaFlag置1后,主程序还没执行到while(1)指令,先执行了“DmaFlag = 0;”指令,
      while(1)
      {
           if(DmaFlag)
           {
                //这里面的程序将执行不了,所以就不能再次启动转换了。
           }
      }
截图202507251515425303.jpg

点评

那是因为你启动ADC DMA后,就发送字符串,这个需要时间,而ADC DMA很快完成图,之后你清除标志才进入主循环,一直没有再触发DMA了。 printf("STC32G系列ADC DMA测试程序!\r\n"); DmaFlag=0; 正常逻辑,你应该先清除  详情 回复 发表于 2025-7-25 16:21
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:147
  • 最近打卡:2025-08-11 00:11:03

76

主题

6608

回帖

1万

积分

超级版主

积分
13759
发表于 2025-7-25 16:21:58 | 显示全部楼层
fxg2*** 发表于 2025-7-25 15:21
在主程序中,删除了while(1)前面的“DmaFlag = 0;”指令,程序就正常了。
想了想原因:
      应该是ADC_DM ...

那是因为你启动ADC DMA后,就发送字符串,这个需要时间,而ADC DMA很快完成,之后你清除标志才进入主循环,一直没有再触发DMA了。
printf("STC32G系列ADC DMA测试程序!\r\n");
DmaFlag=0;

正常逻辑,你应该先清除标志,再启动DMA,这是正常的逻辑顺序。
DmaFlag=0;
DMA_Config();
EA = 1; //允许总中断printf("STC32G系列ADC DMA测试程序!\r\n");
printf("STC32G系列ADC DMA测试程序!\r\n");
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:19
  • 最近打卡:2025-08-01 22:27:17

18

主题

32

回帖

302

积分

中级会员

积分
302
发表于 2025-7-25 21:29:58 | 显示全部楼层
梁*** 发表于 2025-7-25 16:21
那是因为你启动ADC DMA后,就发送字符串,这个需要时间,而ADC DMA很快完成,之后你清除标志才进入主循环 ...

谢谢,是这样的。
回复 支持 反对

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-8-11 13:19 , Processed in 0.121787 second(s), 69 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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