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
}
}
在主程序中,删除了while(1)前面的“DmaFlag = 0;”指令,程序就正常了。
想了想原因:
应该是ADC_DMA自动转换速度太快了,当转换完成并执行中断程序把DmaFlag置1后,主程序还没执行到while(1)指令,先执行了“DmaFlag = 0;”指令,
while(1)
{
if(DmaFlag)
{
//这里面的程序将执行不了,所以就不能再次启动转换了。
}
}
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");
梁工 发表于 2025-7-25 16:21
那是因为你启动ADC DMA后,就发送字符串,这个需要时间,而ADC DMA很快完成,之后你清除标志才进入主循环 ...
谢谢,是这样的。{:baoquan:}
页:
[1]