找回密码
 立即注册
查看: 283|回复: 13

关于AI8051U ADC_DMA转换时间间隔的问题

[复制链接]
  • 打卡等级:偶尔看看I
  • 打卡总天数:18
  • 最近打卡:2026-01-14 15:00:51
已绑定手机

9

主题

30

回帖

263

积分

中级会员

积分
263
发表于 2026-1-5 17:14:33 | 显示全部楼层 |阅读模式
今天通过阅读论坛贴子,如果要用自动轮巡ADC0~ADC7 8个通道的数据,使用PWM触发不可行。只能用ADC_DMA的方式。但是用这种方式怎么来控制两次轮巡ADC转换之间的时间间隔?AI8051U有 DMA_ADC_ITVX寄存器来控制,但手册上没有给出计算的公式。求助该寄存器如果配置。
截图202601051713385959.jpg
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:481
  • 最近打卡:2026-03-21 18:48:59
已绑定手机

104

主题

4193

回帖

9269

积分

荣誉版主

无情的代码机器

积分
9269
发表于 2026-1-5 17:27:18 | 显示全部楼层
“基于系统时钟”
系统时钟1Hz,设置1就是间隔1s.
系统时钟1000Hz,设置1就是间隔1ms.
x ms : x*10^-3*FOSC
三天不学习,赶不上刘少奇~
回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:724
  • 最近打卡:2026-03-18 07:56:47
已绑定手机

97

主题

7244

回帖

1万

积分

超级版主

积分
13791
发表于 2026-1-6 09:27:17 | 显示全部楼层
ADC采样和转换时间+DMA间隔=ADC采样周期
截图202601060926317040.jpg
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:18
  • 最近打卡:2026-01-14 15:00:51
已绑定手机

9

主题

30

回帖

263

积分

中级会员

积分
263
发表于 2026-1-6 15:26:58 | 显示全部楼层
ADC 设置DMA方式,并设置ADC0~ADC7。8个通道。设置轮巡4次。这个中断状态寄存器是每轮巡一次就中断。还是要轮巡完4次才中断?
截图202601061524074693.jpg
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:18
  • 最近打卡:2026-01-14 15:00:51
已绑定手机

9

主题

30

回帖

263

积分

中级会员

积分
263
发表于 2026-1-6 16:18:03 | 显示全部楼层
我的目的是想让 ADC 以DMA的方式,扫描ADC0~ADC7通道。每625微秒轮巡一次。无限循环。AI8051U 32位模式。如下配置,没有观察到P33翻转。

/*---------------------------------------------------------------------*/
/* --- Web: www.STCAI.com ---------------------------------------------*/
/*---------------------------------------------------------------------*/

/*************  功能说明    **************

本例程基于AI8051U为主控芯片的实验箱进行编写测试.

使用Keil C251编译器,Memory Model推荐设置XSmall模式,默认定义变量在edata,单时钟存取访问速度快。

edata建议保留1K给堆栈使用,空间不够时可将大数组、不常用变量加xdata关键字定义到xdata空间。

程序使用P0口来演示跑马灯,输出低驱动。

下载时, 选择时钟 24MHZ (用户可自行修改频率).

******************************************/


#include "stdio.h"
#include "intrins.h"
#include <AI8051U.H>

typedef         unsigned char        u8;
typedef         unsigned int        u16;
typedef         unsigned long        u32;


#define MAIN_Fosc        40000000UL

#define ADC_CH  8
#define ADC_DATA 6
u8 xdata AdcDmaBuff[ADC_CH][ADC_DATA] = {0};
u8 data  AdcDmaFlag = 0; // AdcDma中断标志位

void UartPutc(unsigned char dat)
{
    SBUF = dat;
    while(TI == 0);
    TI = 0;
}

char putchar(char c)
{
    UartPutc(c);
    return c;
}

//==========================================================================
void Uart1Init(void)        //115200bps@40.000MHz
{
    P3M0  &=~ 0X01;
        P3M1  &=~ 0X02;
        SCON = 0x50;                //8位数据,可变波特率
        AUXR |= 0x01;                //串口1选择定时器2为波特率发生器
        AUXR |= 0x04;                //定时器时钟1T模式
        T2L = 0xA9;                        //设置定时初始值
        T2H = 0xFF;                        //设置定时初始值
        AUXR |= 0x10;                //定时器2开始计时
        //ES = 1;                 //串口中断允许
}
//=============================================================================
void Uart1Send(u8 dat)
{
         SBUF = dat ; //
         while(TI==0)
           {;}
     TI = 0;  
}

void uart1_send_bytes_to_str(unsigned char *p,unsigned int length) //          // 串口 4 发CR数组里的数据,可以设置长度
{
         unsigned char code zi[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};         
   unsigned int i = 0;
         unsigned char tempH  ;
         unsigned char tempL  ;
         while(i<length)
          {
                        
                 tempH = zi[(*(p+i))>>4];
                 tempL = zi[(*(p+i)&0x0f)];
                       
           Uart1Send(tempH);
                 Uart1Send(tempL);       
                 Uart1Send(' ');       
           i++;
                               
         }
}

//======================================================================================

void  delay_ms(u8 ms);
/****************  外部函数声明和外部变量声明 *****************/
#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 */
void adc_gpio_init() // 设置ADC输入口为高阻输入
{
  P1M0 = 0x00; P1M1 = 0xff; // P1口设置成高阻输入
  P3M0 |= 0x08; P3M1 &= ~0x08; //P33 设备强推挽输出。用来测试
}

void adc_dma_config() // 初始化ADC
{

        ADCCFG &= ~0x0f;                //SPEED(0)  400KSPS@40.000MHz
            ADCTIM = 0xff;                        //CSSETUP(1), CSHOLD(3), SMPDUTY(31)

        ADC_CONTR = 0X80; //选择 1 通道          
                       
                DMA_ADC_STA = 0x00;
        DMA_ADC_CFG = 0x8A;     //bit7 1:Enable Interrupt   中断优先级2,数据总线优先级2
        DMA_ADC_RXAH = (u8)((u16)AdcDmaBuff >> 8);    //ADC转换数据存储地址
        DMA_ADC_RXAL = (u8)AdcDmaBuff;
        DMA_ADC_CFG2 = 0x00;    //每个通道ADC转换次数:1
        DMA_ADC_CHSW0 = 0xff;   //ADC通道使能寄存器 ADC7~ADC0
        DMA_ADC_CHSW1 = 0x00;   //ADC通道使能寄存器 ADC15~ADC8
                DMA_ADC_AMTH = 0XFF;  //设置循环扫描总次数寄存器 0XFFFF 表示无限循环
                DMA_ADC_AMT  = 0XFF;
                DMA_ADC_ITVH  = (u8)((40*625)/256 );//设置两次ADC之间的时间隔 625uS
                DMA_ADC_ITVL  = (u8)((40*625)%256 );
        DMA_ADC_CR = 0xc0;      //bit7 1:Enable ADC_DMA, bit6 1:Start ADC_DMA       
                                       
            EA = 1 ;
     
}



/******************** 主函数 **************************/
void main(void)
{
    WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
   // EAXFR = 1; //扩展寄存器(XFR)访问使能
        EAXSFR(); //扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度
   
    P0M1 = 0x00;   P0M0 = 0xff;   //设置为推挽输出
    P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
    P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口

    P3M0 |= 0x10; P3M1 &= ~0x10;
       
        Uart1Init();
    adc_gpio_init(); // 设置ADC输入口为高阻输入
        //       
        adc_dma_config() ;// 初始化ADC
       
       
       
    while(1)
    {
        delay_ms(200);
                P34 = !P34 ;
                printf("adc\n");
    }
}

//========================================================================
// 函数: void  delay_ms(unsigned char ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
// 返回: none.
// 版本: VER1.0
// 日期: 2013-4-1
// 备注:
//========================================================================
void  delay_ms(u8 ms)
{
     u16 i;
     do{
          i = MAIN_Fosc / 6000;
          while(--i);
     }while(--ms);
}
//============================================================
void ADC_ISR() interrupt 5  //ADC中断
{
       
   u16 new_data ;       
   ADC_CONTR &= ~0x20;                         //清中断标志
  // P33 = !P33; //测频
   new_data = ((unsigned int)ADC_RES << 8) + ADC_RESL;
}

//============================================================
void ADC_DMA_Interrupt(void) interrupt 13
{
        if( DMA_ADC_STA &0x01 ) //ADC DMA中断
        {
           DMA_ADC_STA = 0;
           printf("e");
           P33 = !P33; //测频
       
        }
  
}
//============================================================

回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:18
  • 最近打卡:2026-01-14 15:00:51
已绑定手机

9

主题

30

回帖

263

积分

中级会员

积分
263
发表于 2026-1-6 16:30:05 | 显示全部楼层
想配置成如下模式,ADC0~ADC7 配置成DMA方式。每625微秒轮巡一次。无限次数。通过ADCDMA中断入口来看是否正常工作。目前的配置方式不能工作。代码如下。求助!

#include "stdio.h"
#include "intrins.h"
#include <AI8051U.H>

typedef         unsigned char        u8;
typedef         unsigned int        u16;
typedef         unsigned long        u32;


#define MAIN_Fosc        40000000UL

#define ADC_CH  8    // 8个通道
#define ADC_DATA 6   // 每个通道轮巡一次 数据为  2n+ 4  = 6
u8 xdata AdcDmaBuff[ADC_CH][ADC_DATA] = {0};
u8 data  AdcDmaFlag = 0; // AdcDma中断标志位

void UartPutc(unsigned char dat)
{
    SBUF = dat;
    while(TI == 0);
    TI = 0;
}

char putchar(char c)
{
    UartPutc(c);
    return c;
}

//==========================================================================
void Uart1Init(void)        //115200bps@40.000MHz
{
    P3M0  &=~ 0X01;
        P3M1  &=~ 0X02;
        SCON = 0x50;                //8位数据,可变波特率
        AUXR |= 0x01;                //串口1选择定时器2为波特率发生器
        AUXR |= 0x04;                //定时器时钟1T模式
        T2L = 0xA9;                        //设置定时初始值
        T2H = 0xFF;                        //设置定时初始值
        AUXR |= 0x10;                //定时器2开始计时
        //ES = 1;                 //串口中断允许
}
//=============================================================================
void Uart1Send(u8 dat)
{
         SBUF = dat ; //
         while(TI==0)
           {;}
     TI = 0;  
}

void uart1_send_bytes_to_str(unsigned char *p,unsigned int length) //          // 串口 4 发CR数组里的数据,可以设置长度
{
         unsigned char code zi[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};         
     unsigned int i = 0;
         unsigned char tempH  ;
         unsigned char tempL  ;
         while(i<length)
          {
                        
                 tempH = zi[(*(p+i))>>4];
                 tempL = zi[(*(p+i)&0x0f)];
                       
             Uart1Send(tempH);
                 Uart1Send(tempL);       
                 Uart1Send(' ');       
           i++;                       
         }
}

//======================================================================================

void  delay_ms(u8 ms);
/****************  外部函数声明和外部变量声明 *****************/

void adc_gpio_init() // 设置ADC输入口为高阻输入
{
  P1M0 = 0x00; P1M1 = 0xff; // P1口设置成高阻输入
  P3M0 |= 0x08; P3M1 &= ~0x08; //P33 设备强推挽输出。用来测试
}

void adc_dma_config() // 初始化ADC
{
        ADCCFG &= ~0x0f;                //SPEED(0)  400KSPS@40.000MHz
            ADCTIM = 0xff;                        //CSSETUP(1), CSHOLD(3), SMPDUTY(31)

        ADC_CONTR = 0X80; //打开ADC电源
                       
                DMA_ADC_STA = 0x00;
        DMA_ADC_CFG = 0x8A;     //bit7 1:Enable Interrupt   中断优先级2,数据总线优先级2
        DMA_ADC_RXAH = (u8)((u16)AdcDmaBuff >> 8);    //ADC转换数据存储地址
        DMA_ADC_RXAL = (u8)AdcDmaBuff;
        DMA_ADC_CFG2 = 0x00;    //每个通道ADC转换次数:1
        DMA_ADC_CHSW0 = 0xff;   //ADC通道使能寄存器 ADC7~ADC0
        DMA_ADC_CHSW1 = 0x00;   //ADC通道使能寄存器 ADC15~ADC8
                DMA_ADC_AMTH = 0XFF;  //设置循环扫描总次数寄存器 0XFFFF 表示无限循环
                DMA_ADC_AMT  = 0XFF;
                DMA_ADC_ITVH  = (u8)((u16)(40*625)/256 );//设置两次ADC之间的时间隔 625uS
                DMA_ADC_ITVL  = (u8)((u16)(40*625)%256 );
        DMA_ADC_CR = 0xc0;      //bit7 1:Enable ADC_DMA, bit6 1:Start ADC_DMA       
                                       
            EA = 1 ;  //开总中断
}

/******************** 主函数 **************************/
void main(void)
{
    WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
   // EAXFR = 1; //扩展寄存器(XFR)访问使能
        EAXSFR(); //扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度
   
    P0M1 = 0x00;   P0M0 = 0xff;   //设置为推挽输出
    P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
    P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
       
        Uart1Init();
    adc_gpio_init(); // 设置ADC输入口为高阻输入
        adc_dma_config() ;// 初始化ADC
               
       
    while(1)
    {
        delay_ms(200);
                P34 = !P34 ;
                printf("adc\n");
    }
}

//========================================================================
// 函数: void  delay_ms(unsigned char ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
// 返回: none.
// 版本: VER1.0
// 日期: 2013-4-1
// 备注:
//========================================================================
void  delay_ms(u8 ms)
{
     u16 i;
     do{
          i = MAIN_Fosc / 6000;
          while(--i);
     }while(--ms);
}
//============================================================
void ADC_ISR() interrupt 5  //ADC中断
{
       
   u16 new_data ;       
   ADC_CONTR &= ~0x20;                         //清中断标志
  // P33 = !P33; //测频
   new_data = ((unsigned int)ADC_RES << 8) + ADC_RESL;
}

//============================================================
void ADC_DMA_Interrupt(void) interrupt 13
{
        if( DMA_ADC_STA &0x01 ) //ADC DMA中断
        {
           DMA_ADC_STA = 0;
          // printf("e");
           P33 = !P33; //测频
        }
  
}

点评

interrupt 13 是用户中断,要使用需要借asm跳转。 可以直接使用ADC DMA自己的中断号。 [attachimg]128097[/attachimg]  详情 回复 发表于 2026-1-6 16:46
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:481
  • 最近打卡:2026-03-21 18:48:59
已绑定手机

104

主题

4193

回帖

9269

积分

荣誉版主

无情的代码机器

积分
9269
发表于 2026-1-6 16:46:13 | 显示全部楼层
jrh20*** 发表于 2026-1-6 16:30
想配置成如下模式,ADC0~ADC7 配置成DMA方式。每625微秒轮巡一次。无限次数。通过ADCDMA中断入口来看是否正 ...

interrupt 13 是用户中断,要使用需要借asm跳转。

可以直接使用ADC DMA自己的中断号。


截图202601061646062826.jpg
三天不学习,赶不上刘少奇~
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:18
  • 最近打卡:2026-01-14 15:00:51
已绑定手机

9

主题

30

回帖

263

积分

中级会员

积分
263
发表于 2026-1-6 16:55:08 | 显示全部楼层
截图202601061650168193.jpg 有中断文件
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:18
  • 最近打卡:2026-01-14 15:00:51
已绑定手机

9

主题

30

回帖

263

积分

中级会员

积分
263
发表于 2026-1-7 09:20:45 | 显示全部楼层
贴上代码,求助

01-ADC_DMA.rar

51.33 KB, 下载次数: 1

点评

不进DMA中断是配置了无限循环导致的 要进中断,就修改AMT次数,中断里重新DMA_ADC_CR触发下一轮 [attachimg]128174[/attachimg]  详情 回复 发表于 2026-1-7 09:34
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:481
  • 最近打卡:2026-03-21 18:48:59
已绑定手机

104

主题

4193

回帖

9269

积分

荣誉版主

无情的代码机器

积分
9269
发表于 2026-1-7 09:34:24 | 显示全部楼层
jrh20*** 发表于 2026-1-7 09:20
贴上代码,求助

不进DMA中断是配置了无限循环导致的

要进中断,就修改AMT次数,中断里重新DMA_ADC_CR触发下一轮
截图202601070933191281.jpg
三天不学习,赶不上刘少奇~
回复

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2026-3-22 06:23 , Processed in 0.121673 second(s), 88 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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