fxg2024 发表于 2025-7-25 14:54:54

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

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路扫描功能一样,调试正常。接着当我修改转换通道数量时,发生了问题,转换完成,没有打印输出。我自己写的源程序如下:
#include "STC32G12K128.h"
#include "intrins.h"
#include "stdio.h"

#define         u8 unsigned char
#define         u16 unsigned int
#define         u32 unsigned long
      
#define MAIN_Fosc   24000000L      //定义主时钟

#define      ADC_CH                4      /* 1~16, ADC转换通道数, 需同步修改 DMA_ADC_CHSW 转换通道 */
#define      ADC_DATA      4    /* 6~n, 每个通道ADC转换数据总数, 2*转换次数+4, 需同步修改 DMA_ADC_CFG2 转换次数 */
/**************定义引脚*****************/

/**************全局变量*****************/
bit      DmaFlag;
u8 xdata DmaBuffer;

/**************函数声明*****************/
void GPIO_init();         //GPIO口初始化
void      delay_ms(u8 ms);
void Uart1_Init();      //115200bps@24.000MHz
void ADC_init(); // ADC初始化
void DMA_Config(void);//DMA初始化

/******************** 主函数 **************************/
void main(void)
{
u8      i,n;
      
      //初始化
      WTST = 0;    //设置程序指令延时参数
EAXFR = 1;   //扩展寄存器(XFR)访问使能
CKCON = 0;   //提高访问XRAM速度
      
      GPIO_init();//GPIO口初始化
      ADC_init(); // ADC初始化
      
      Uart1_Init();      //115200bps@24.000MHz
      DMA_Config();
      EA = 1; //允许总中断
      printf("STC32G系列ADC DMA测试程序!\r\n");

DmaFlag=0;
      while(1)
      {
                delay_ms(200);      
                if(DmaFlag)
                {
                        printf("ADC DMA完成!\r\n");
                        DmaFlag = 0;
                        for(i=0; i<ADC_CH; i++)//3个通道
                        {
                              for(n=0; n<(ADC_DATA*2+4); n++)
                              {
                                        printf("0x%02x ",DmaBuffer);
                              }
                              printf("\r\n");
                        }
                        printf("\r\n");
                        
                        DMA_ADC_CR = 0xc0;                //bit7 1:Enable ADC_DMA, bit6 1:Start ADC_DMA
                }
      }
}
/******************** 子函数 **************************/
void GPIO_init()//GPIO口初始化
{
    P0M1 = 0x7f;   P0M0 = 0x00;   //设置要做ADC的IO做高阻输入
    P1M1 = 0xfb;   P1M0 = 0x00;   //设置要做ADC的IO做高阻输入
    P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    P3M1 = 0x50;   P3M0 = 0x50;   //设置P3.4、P3.6为漏极开路(实验箱加了上拉电阻到3.3V)
    P4M1 = 0x3c;   P4M0 = 0x3c;   //设置P4.2~P4.5为漏极开路(实验箱加了上拉电阻到3.3V)
    P5M1 = 0x0c;   P5M0 = 0x0c;   //设置P5.2、P5.3为漏极开路(实验箱加了上拉电阻到3.3V)
    P6M1 = 0xff;   P6M0 = 0xff;   //设置为漏极开路(实验箱加了上拉电阻到3.3V)
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
}
void delay_ms(u8 ms)
{
      u16 i;
      do
      {
                i = MAIN_Fosc / 6000;
                while(--i);
      }while(--ms);
}
void Uart1_Init(void)      //115200bps@24.000MHz
{
      SCON = 0x50;                //8位数据,可变波特率
      AUXR |= 0x01;                //串口1选择定时器2为波特率发生器
      AUXR |= 0x04;                //定时器时钟1T模式
      T2L = 0xCC;                        //设置定时初始值
      T2H = 0xFF;                        //设置定时初始值
      AUXR |= 0x10;                //定时器2开始计时
      TI=1;//使用“printf()函数”,TI初始化一定要置1
}

void ADC_init() // ADC初始化
{
      ADCCFG = 0x2f;      //设置 ADC 时钟为系统时钟/2/16,数据结果右对齐 ADC_RES 低四位+ ADC_RESL 8位
      ADCTIM = 0x3f;                //设置 ADC 内部时序,ADC采样时间建议设最大值
      ADC_CONTR = 0x80;   //使能 ADC 模块,需等待1ms后稳定
}
/******************** DMA初始化 **************************/
void DMA_Config(void)
{
DMA_ADC_STA = 0x00;//中断标志位复位
      DMA_ADC_CFG = 0x80;                //开启ADC_DMA中断,中断优先级最低,数据总线访问优先级最低

      DMA_ADC_RXAH = (u8)((u16)DmaBuffer >> 8);      //ADC转换数据存储地址
      DMA_ADC_RXAL = (u8)((u16)DmaBuffer);

      DMA_ADC_CFG2 = 0x09;      //每个通道ADC转换次数:4
      DMA_ADC_CHSW0 = 0x0d;      //ADC通道使能寄存器 ADC3-P1.3,ADC0-P1.0
      DMA_ADC_CHSW1 = 0x80;                //ADC15-内部测试电压1.19V
      
      DMA_ADC_CR = 0xc0;                //bit7 1:Enable ADC_DMA, bit6 1:Start ADC_DMA
}

void ADC_DMA_Interrupt(void) interrupt 13
{
      if (DMA_ADC_STA & 0x01)      //发送完成
      {
                DMA_ADC_STA =0;//复位中断标志位
                DmaFlag = 1;         //完成标志位置1
      }
}这段代码怎么都无法打印输出结果。
但是只要把转换通道改成16路通道,就可以正常打印输出。修改的地方如下,用多行注释标注的地方:
/******************** DMA初始化 **************************/
void DMA_Config(void)
{
DMA_ADC_STA = 0x00;//中断标志位复位
      DMA_ADC_CFG = 0x80;                //开启ADC_DMA中断,中断优先级最低,数据总线访问优先级最低

      DMA_ADC_RXAH = (u8)((u16)DmaBuffer >> 8);      //ADC转换数据存储地址
      DMA_ADC_RXAL = (u8)((u16)DmaBuffer);

      DMA_ADC_CFG2 = 0x09;      //每个通道ADC转换次数:4
/*********************************************************************/
      DMA_ADC_CHSW0 = 0xff;      //ADC通道使能寄存器 ADC3-P1.3,ADC0-P1.0
      DMA_ADC_CHSW1 = 0xff;      //ADC15-内部测试电压1.19V</font>
/*********************************************************************/      
      DMA_ADC_CR = 0xc0;                //bit7 1:Enable ADC_DMA, bit6 1:Start ADC_DMA
}这个问题,我查了很久,最终和源程序一条一条对比尝试,终于找到问题。下面时找到DEBUG后,修改后的程序,就在主程序中删掉了一条指令就正常了,转换几路通道都可以。
#include "STC32G12K128.h"
#include "intrins.h"
#include "stdio.h"

#define         u8 unsigned char
#define         u16 unsigned int
#define         u32 unsigned long
      
#define MAIN_Fosc   24000000L      //定义主时钟

#define      ADC_CH                4                        /* 1~16, ADC转换通道数, 需同步修改 DMA_ADC_CHSW 转换通道 */
#define      ADC_DATA      4                        /* 6~n, 每个通道ADC转换数据总数, 2*转换次数+4, 需同步修改 DMA_ADC_CFG2 转换次数 */
/**************定义引脚*****************/

/**************全局变量*****************/
bit      DmaFlag;
u8 xdata DmaBuffer;

/**************函数声明*****************/
void GPIO_init();         //GPIO口初始化
void      delay_ms(u8 ms);
void Uart1_Init();      //115200bps@24.000MHz
void ADC_init(); // ADC初始化
void DMA_Config(void);//DMA初始化



/******************** 主函数 **************************/
void main(void)
{
u8      i,n;
      
      //初始化
      WTST = 0;    //设置程序指令延时参数
EAXFR = 1;   //扩展寄存器(XFR)访问使能
CKCON = 0;   //提高访问XRAM速度
      
      GPIO_init();//GPIO口初始化
      ADC_init(); // ADC初始化
      
      Uart1_Init();      //115200bps@24.000MHz
      DMA_Config();
      EA = 1; //允许总中断
      printf("STC32G系列ADC DMA测试程序!\r\n");

      while(1)
      {
                delay_ms(200);      
                if(DmaFlag)
                {
                        printf("ADC DMA完成!\r\n");
                        DmaFlag = 0;
                        for(i=0; i<ADC_CH; i++)//3个通道
                        {
                              for(n=0; n<(ADC_DATA*2+4); n++)//
                              {
                                        printf("0x%02x ",DmaBuffer);
                              }
                              printf("\r\n");
                        }
                        printf("\r\n");
                        
                        DMA_ADC_CR = 0xc0;                //bit7 1:Enable ADC_DMA, bit6 1:Start ADC_DMA
                }
      }
}
/******************** 子函数 **************************/
void GPIO_init()//GPIO口初始化
{
    P0M1 = 0x7f;   P0M0 = 0x00;   //设置要做ADC的IO做高阻输入
    P1M1 = 0xfb;   P1M0 = 0x00;   //设置要做ADC的IO做高阻输入
    P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    P3M1 = 0x50;   P3M0 = 0x50;   //设置P3.4、P3.6为漏极开路(实验箱加了上拉电阻到3.3V)
    P4M1 = 0x3c;   P4M0 = 0x3c;   //设置P4.2~P4.5为漏极开路(实验箱加了上拉电阻到3.3V)
    P5M1 = 0x0c;   P5M0 = 0x0c;   //设置P5.2、P5.3为漏极开路(实验箱加了上拉电阻到3.3V)
    P6M1 = 0xff;   P6M0 = 0xff;   //设置为漏极开路(实验箱加了上拉电阻到3.3V)
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
}
void delay_ms(u8 ms)
{
      u16 i;
      do
      {
                i = MAIN_Fosc / 6000;
                while(--i);
      }while(--ms);
}
void Uart1_Init(void)      //115200bps@24.000MHz
{
      SCON = 0x50;                //8位数据,可变波特率
      AUXR |= 0x01;                //串口1选择定时器2为波特率发生器
      AUXR |= 0x04;                //定时器时钟1T模式
      T2L = 0xCC;                        //设置定时初始值
      T2H = 0xFF;                        //设置定时初始值
      AUXR |= 0x10;                //定时器2开始计时
      TI=1;//使用“printf()函数”,TI初始化一定要置1
}

void ADC_init() // ADC初始化
{
      ADCCFG = 0x2f;      //设置 ADC 时钟为系统时钟/2/16,数据结果右对齐 ADC_RES 低四位+ ADC_RESL 8位
      ADCTIM = 0x3f;                //设置 ADC 内部时序,ADC采样时间建议设最大值
      ADC_CONTR = 0x80;   //使能 ADC 模块,需等待1ms后稳定
}
/******************** DMA初始化 **************************/
void DMA_Config(void)
{
DMA_ADC_STA = 0x00;//中断标志位复位
      DMA_ADC_CFG = 0x80;                //开启ADC_DMA中断,中断优先级最低,数据总线访问优先级最低

      DMA_ADC_RXAH = (u8)((u16)DmaBuffer >> 8);      //ADC转换数据存储地址
      DMA_ADC_RXAL = (u8)((u16)DmaBuffer);

      DMA_ADC_CFG2 = 0x09;      //每个通道ADC转换次数:4
      DMA_ADC_CHSW0 = 0x0d;      //ADC通道使能寄存器 ADC3-P1.3,ADC0-P1.0
      DMA_ADC_CHSW1 = 0x80;                //ADC15-内部测试电压1.19V
      
      DMA_ADC_CR = 0xc0;                //bit7 1:Enable ADC_DMA, bit6 1:Start ADC_DMA
}

void ADC_DMA_Interrupt(void) interrupt 13
{
      if (DMA_ADC_STA & 0x01)      //发送完成
      {
                DMA_ADC_STA =0;//复位中断标志位
                DmaFlag = 1;         //完成标志位置1
      }

}



fxg2024 发表于 2025-7-25 15:21:00

在主程序中,删除了while(1)前面的“DmaFlag = 0;”指令,程序就正常了。
想了想原因:
      应该是ADC_DMA自动转换速度太快了,当转换完成并执行中断程序把DmaFlag置1后,主程序还没执行到while(1)指令,先执行了“DmaFlag = 0;”指令,
      while(1)
      {
         if(DmaFlag)
         {
                //这里面的程序将执行不了,所以就不能再次启动转换了。
         }
      }

梁工 发表于 2025-7-25 16:21:58

fxg2024 发表于 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");

fxg2024 发表于 2025-7-25 21:29:58

梁工 发表于 2025-7-25 16:21
那是因为你启动ADC DMA后,就发送字符串,这个需要时间,而ADC DMA很快完成,之后你清除标志才进入主循环 ...

谢谢,是这样的。{:baoquan:}
页: [1]
查看完整版本: ADC_DMA程序调试中卡了很久的一个小问题 | 解决了!