这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » 国产MCU » 学习AI8051开发板例程:30AI8051的DMA方式接收读取ADC的数据,并

共1条 1/1 1 跳转至

学习AI8051开发板例程:30AI8051的DMA方式接收读取ADC的数据,并返回给串口

高工
2026-03-02 20:18:19     打赏

 在之前的帖子分享了AI8051在串口通讯中,使用DMA的方式进行数据的交互,今天和大家分享使用DMA的方式实现ADC的数据读取。

 使用AI8051U的DMA进行ADC数据采集,可以极大地减轻CPU的负担,实现高效、自动化的多通道模拟信号采集。下面我将为你详细解析其核心原理、关键寄存器配置,并提供实践步骤和代码示例。

 一:核心原理:数据的“自动化处理”功能

 类似于其他的32位单片机一样,DMA方式类似于一个智能的数据搬运工一样,可以将数据从内核到外设,或者是外设到内核的之间的数据交互,具体的工作流程如下所示:

 1:启动DMA功能,单片机需要告知DMA控制器,此时立即开始工作,这个时候单片机就可以去处理其他任务了。

 2:数据转换:ADC的通道按照初始化配置的时序,通道,自动对指定的模拟通道进行采集,转换等。

 3:数据搬运:当ADC转换完成后,数据会被DMA控制器主动的放到内存(XDATA)中的配置的缓冲区内,此过程不经过mcu的干预。

 4:产生中断:当DMA传输的数据个数到达设定次数的时候,DMA控制器会产生中断,告知CPU,数据接收完成可以进行处理

二:配置参数

2.1 传输次数与循环模式

  你需要告诉DMA总共要传输多少次ADC结果。这通过配置 DMA_ADC_AMT 寄存器来实现。例如,如果你想采集8个通道,每个通道转换4次,那么总传输次数就是32次。

  此外,你还需要决定传输完成后的行为。如果设置为单次模式,传输32次后DMA就会停止;如果设置为循环模式,DMA会在完成32次传输后,自动从头开始新一轮的采集,周而复始。

2.2 转换间隔时间

   这是AI8051U DMA-ADC功能的一个亮点。你可以通过 DMA_ADC_ITVH 和 DMA_ADC_ITVL 寄存器来设置两次ADC转换启动之间的间隔时间。这个功能让你能够精确控制采样率,而无需依赖定时器中断。

2.3 多通道与多次采样

   你可以设置DMA依次扫描多个模拟通道。通过配置 DMA_ADC_CFG2 等寄存器,可以指定每个通道连续转换的次数。这使得“一轮”采集可以包含对多个通道的多次采样,非常灵活。

三:软件代码:

3.1 初始化系统与IO口

设置系统时钟,使能访问XFR(扩展特殊功能寄存器)的开关(如 P_SW2 |= 0x80)。

将用作ADC输入的IO口(如P1.0)设置为高阻输入模式。

#define ADC_SPEED   15      /* 0~15, ADC转换时间(CPU时钟数) = (n+1)*32  ADCCFG */
#define RES_FMT     (1<<5)  /* ADC结果格式 0: 左对齐, ADC_RES: D11 D10 D9 D8 D7 D6 D5 D4, ADC_RESL: D3 D2 D1 D0 0 0 0 0 */
                            /* ADCCFG     1: 右对齐, ADC_RES: 0 0 0 0 D11 D10 D9 D8, ADC_RESL: D7 D6 D5 D4 D3 D2 D1 D0 */

#define ADC_CH      16      /* ADC转换通道数 */
#define ADC_TIMES   4       /* 每个通道ADC转换数据次数 */

3.2 配置DMA功能

设置源地址:将DMA的外设地址指向ADC的结果寄存器(ADC_RES 和 ADC_RESL)。

设置目的地址:在XDATA空间定义一个数组作为缓冲区,并将DMA的目的地址设置为该数组的首地址。

设置传输计数:向 DMA_ADC_AMT 寄存器写入你要传输的总次数。例如,要采集8通道各4次,共32次。

设置间隔时间:根据需要,向 DMA_ADC_ITVH/L 寄存器写入值,以控制采样率。

配置工作模式:设置DMA为循环模式或单次模式,并使能DMA传输完成中断(可选)。

void DMA_Config(void)
{
    DMA_ADC_STA = 0x00;
    DMA_ADC_CFG = 0x80;     //bit7 1:Enable Interrupt
    DMA_ADC_RXAH = (u8)((u16)&DmaBuffer >> 8);    //ADC转换数据存储地址
    DMA_ADC_RXAL = (u8)((u16)&DmaBuffer);
    DMA_ADC_CFG2 = CVTIMESEL;   //每个通道ADC转换次数
    DMA_ADC_CHSW0 = 0xff;   //ADC通道使能寄存器 ADC7~ADC0
    DMA_ADC_CHSW1 = 0xff;   //ADC通道使能寄存器 ADC15~ADC8
    DMA_ADC_CR = 0xc0;      //bit7 1:Enable ADC_DMA, bit6 1:Start ADC_DMA
}

3.3 启动DMA中断服务函数

启动DMA传输。通常是通过向DMA控制寄存器的“启动”位写入1来完成。

编写DMA传输完成中断服务函数。在函数中,清除中断标志,并对缓冲区中的ADC数据进行处理(如取平均值、转换电压值等)。

void ADC_DMA_Interrupt(void) interrupt 13
{
    DMA_ADC_STA = 0;
    DmaFlag = 1;
}

3.4 主函数:

实现ADC通道的数据上传功能:

        if(DmaFlag)     //判断ADC DMA是否转换完成
        {
            DmaFlag = 0;    //清除ADC DMA转换完成标志
            for(i=0; i<ADC_CH; i++)
            {
                printf("ADC%02d = ",DmaBuffer[i].Channel);   //串口打印ADC通道
                for(n=0; n<ADC_TIMES; n++)
                {
                    printf("0x%04x ",DmaBuffer[i].Data[n]); //串口打印当前通道的每次采样数据
                }
                printf(", AVER:0x%04x\r\n",DmaBuffer[i].average);   //串口打印平均值
            }
            DMA_ADC_CR = 0xc0;  //bit7 1:Enable ADC_DMA, bit6 1:Start ADC_DMA
        }

四:测试结果如下:

ai30-1.png

可见,16个通道的ADC数据全部上传到串口了,




关键词: AI8051     DMA     ADC    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]