OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 7215|回复: 8

想用STM32f103接外部的adc模块(AD9220),将数据采集保存到DMA中,应该怎么实现?

[复制链接]

1

主题

1

帖子

0

精华

新手入门

积分
15
金钱
15
注册时间
2019-7-5
在线时间
4 小时
发表于 2019-8-2 15:07:13 | 显示全部楼层 |阅读模式
3金钱
买了一个外部ADC模块(AD9220),10M的采样频率,比32的内部ADC采样频率要高,但是想要采集并保存很高频率的信号时,由于读取采集adc的值需要时间,所以有一种方法是设置adc模块为连续采集,将数据保存在DMA中,之后通过定时器中断每隔一段时间对DMA进行读取,应该怎么实现?网上的教程都是使用的内部ADC,如果使用外部ADC的话应该怎么实现?

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165371
金钱
165371
注册时间
2010-12-1
在线时间
2110 小时
发表于 2019-8-3 01:40:09 | 显示全部楼层
慢慢搞吧,没人有代码的
回复

使用道具 举报

10

主题

29

帖子

0

精华

初级会员

Rank: 2

积分
171
金钱
171
注册时间
2018-6-2
在线时间
77 小时
发表于 2019-10-15 14:48:02 | 显示全部楼层
看过一个帖子,spi+dma+adc,将adc采集到的数据通过spi+dma的方式搬到内存,不需要CPU介入
回复

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
18
金钱
18
注册时间
2020-1-3
在线时间
5 小时
发表于 2020-1-3 15:02:58 | 显示全部楼层
有搞出来吗
回复

使用道具 举报

4

主题

77

帖子

0

精华

高级会员

Rank: 4

积分
637
金钱
637
注册时间
2019-1-12
在线时间
67 小时
发表于 2020-3-2 13:19:38 | 显示全部楼层
淘淘追梦 发表于 2019-10-15 14:48
看过一个帖子,spi+dma+adc,将adc采集到的数据通过spi+dma的方式搬到内存,不需要CPU介入

可以告诉我哪里有代码吗?
回复

使用道具 举报

2

主题

6

帖子

0

精华

初级会员

Rank: 2

积分
53
金钱
53
注册时间
2019-7-10
在线时间
31 小时
发表于 2020-3-5 22:12:13 | 显示全部楼层
#define abx(s)    s>0?s:-s
uint16_t measure[Sample_Num][Channel_Num]={0};//用来存放2个通道的各20个采样值,以后用来求平均值
void measure_init(void)
{

        DMA_InitTypeDef       DMA_InitStructure;
        GPIO_InitTypeDef      GPIO_InitStructure;
        ADC_CommonInitTypeDef ADC_CommonInitStructure;
        ADC_InitTypeDef       ADC_InitStructure;

       

   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA时钟

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //使能ADC1时钟

         RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能


          GPIO_InitStructure.GPIO_Pin =Channel_S|Channel_T;//ADC1通道0,1

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模拟输入

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//不带上下拉

    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化  

          RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE);          //ADC1复位

          RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE);        //复位结束         

       

    ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式

    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;//两个采样阶段之间的延迟5个时钟

    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //DMA失能,后面有专门的函数使能

    ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//预分频4分频。ADCCLK=PCLK2/4=84/4=21Mhz,ADC时钟最好不要超过36Mhz

    ADC_CommonInit(&ADC_CommonInitStructure);//初始化

       

     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//12位模式

     ADC_InitStructure.ADC_ScanConvMode = ENABLE;//扫描模式使能

     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//使能连续转换,想用定时器中断,不断调用

     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止触发检测,使用软件触发

     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐       

     ADC_InitStructure.ADC_NbrOfConversion = 2;//2个转换在规则序列中 也就是只转换2个规则序列

     ADC_Init(ADC1, &ADC_InitStructure);//ADC初始化



       DMA_DeInit(DMA2_Stream0);
          while (DMA_GetCmdStatus(DMA2_Stream0) != DISABLE){;}//等待DMA可配置        

          /* 配置 DMA Stream */

          DMA_InitStructure.DMA_Channel = DMA_Channel_0;  //通道选择

          DMA_InitStructure.DMA_PeripheralBaseAddr =(u32)&ADC1->DR;//DMA外设地址ADC1的数据寄存器

          DMA_InitStructure.DMA_Memory0BaseAddr =(u32)measure;//数组的地址

          DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//外设到内存

          DMA_InitStructure.DMA_BufferSize = Sample_Num*Channel_Num;//数据传输量

          DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式

          DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式

          DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设数据长度:16位

          DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//存储器数据长度:16位

          DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;// 使用循环模式

          DMA_InitStructure.DMA_Priority = DMA_Priority_High;//高等优先级

          DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         

          DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;

          DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发单次传输

          DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发单次传输

          DMA_Init(DMA2_Stream0, &DMA_InitStructure);//初始化DMA Stream

          DMA_Cmd(DMA2_Stream0,ENABLE);
                                       
          //采样时间28周期
                                        //单通道采样时间1/21MHz*(28+12)=1.9us
                                        //2通道采样时间
        ADC_RegularChannelConfig(ADC1,ADC_Channel_0,Right,ADC_SampleTime_28Cycles);//采样时间28周期

        ADC_RegularChannelConfig(ADC1,ADC_Channel_1,Left,ADC_SampleTime_28Cycles);//单通道采样时间1/21MHz*(28+12)=1.9us

        ADC_DMARequestAfterLastTransferCmd(ADC1,ENABLE);

       

    ADC_DMACmd(ADC1,ENABLE);                //使能ADC的DMA
        ADC_Cmd(ADC1, ENABLE);                  //开启AD转换器       
        ADC_SoftwareStartConv(ADC1);                //使能指定的ADC1的软件转换启动功能       
}       
static red_measure red_meassure;
void GetADCAverageV(void)//获取每个通道采样的平均值
{

        u8 i,j;
        static u8 a,b;
        u32 sum=0;
        u16 ADCAverageValue[Channel_Num]={0};
        static int measure_count=0;
        if(DMA_GetFlagStatus(DMA2_Stream0,DMA_FLAG_TCIF0)!=RESET)    //DMA完成了某一次的传输
        {
            for(i=0;i<Channel_Num;i++)
            {
                                for(j=0;j<Sample_Num;j++)
                                {
                    sum=sum+measure[j][i];
                                }
                                ADCAverageValue[i]=sum/Sample_Num;//这个数组是最终的结果,求均值
                                sum=0;
            }
                        //延时判断,避免误判
                red_meassure.measure_num[0]=(float)(ADCAverageValue[0]*3.3)/4096*100;
                red_meassure.measure_num[1]=(float)(ADCAverageValue[1]*3.3)/4096*100;
                        if(measure_count%20==0)
                        {
                        a=red_meassure.measure_num[0];//last_text
                        b=red_meassure.measure_num[1];//last_text                               
                        }
      if(measure_count%40==0)
                        {
                                red_meassure.measure_num[2]=red_meassure.measure_num[0];
                                red_meassure.measure_num[3]=red_meassure.measure_num[1];                               
                        }
                        if(abx(red_meassure.measure_num[2]-a)<20||abx(red_meassure.measure_num[3]-b)<20)
                        {
                                                red_meassure.i_judge=1;               
                        }
                       

//                  printf("Channel_S=%f\t",measure_true[0]);//打印到串口查看结果
//                        printf("Channel_T=%f\t",measure_true[1]);
//            printf("\r\n");
                        measure_count++;
            DMA_ClearFlag(DMA2_Stream0,DMA_FLAG_TCIF0);//清除标志

        }

}
回复

使用道具 举报

10

主题

29

帖子

0

精华

初级会员

Rank: 2

积分
171
金钱
171
注册时间
2018-6-2
在线时间
77 小时
发表于 2020-4-15 15:56:40 | 显示全部楼层
send 发表于 2020-3-2 13:19
可以告诉我哪里有代码吗?

给你贴上代码,我找不到从哪看到的了,这是当时保存的代码。如果我没记错的话,ad芯片型号是一样的。
void SPI1_Init(void)
{         
        GPIO_InitTypeDef  GPIO_InitStructure;
        SPI_InitTypeDef  SPI_InitStructure;

        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,enable);//使能GPIOA时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);//使能SPI1时钟

        //PA5,6,7初始化设置
        GPIO_InitStructure.GPIO_Pin =GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;//PA5~7复用功能输出        
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
        GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;//上拉  
        GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化

        GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);//PA5复用为 SPI1
        GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);//PA6复用为 SPI1
        GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);//PA7复用为 SPI1

        //这里只针对SPI口初始化
        RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,ENABLE);//复位SPI1
        RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,DISABLE);//停止复位SPI1

        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
        SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                //为主SPI
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;                //SPI发送接收16位帧结构
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;                //串行同步时钟的空闲状态为低电平
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2EDGE;        //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                //NSS信号由软件管理
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;  //波特率预分频值为4(21MHz)
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;        //数据从MSB位开始
        SPI_InitStructure.SPI_CRCPolynomial = 7;        //CRC值计算的多项式
        SPI_Init(SPI1, &SPI_InitStructure);

        SPI_Cmd(SPI1, ENABLE); //使能SPI外设
}

void DMA_Config(void)
{
        DMA_InitTypeDef DMA_InitStructure;
        
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

        /* DMA disable*/
        DMA_Cmd(DMA2_Stream2, DISABLE);
        DMA_Cmd(DMA2_Stream3, DISABLE);
        
        DMA_DeInit(DMA2_Stream2);
        DMA_DeInit(DMA2_Stream3);
         
        //   SPI1 RX DMA 配置  Stream2
        DMA_InitStructure.DMA_Channel = DMA_Channel_6;
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR;         //指定DMA的外设基地址为SPI1的数据地址
        DMA_InitStructure.DMA_memory0BaseAddr = (uint32_t)SPI1_Rx_Buff;         //指定DMA的内存基地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;                 //DMA传输方向为读外设 写到内存
        DMA_InitStructure.DMA_BufferSize = 4;//DataSize;                            //传输数量(0-65535,不能为0)
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;        //失能外设地址增长
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                 //使能内存地址增长 免去FOR循环
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;        //PSIZE=16bit
        DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord;        //MSIZE=16bit
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA_Mode_Normal;//       //DMA模式为非循环模式,非循环模式只进行单次传输。
        DMA_InitStructure.DMA_Priority = DMA_Priority_High;                     //优先权为高
        DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;                  //失能FIFO模式
        DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;       //FIFO的阀值为半满
        DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;                    //内存突发传输为单一
        DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;     //外设突发传输为单一
        DMA_Init(DMA2_Stream2, &DMA_InitStructure);                             //初始化DMA2_Stream2
        //DMA_ITConfig(DMA2_Stream2, DMA_IT_TC, ENABLE);//使能传输完成中断
        
        //   SPI1 TX DMA 配置   Stream3
        DMA_InitStructure.DMA_Channel = DMA_Channel_6;        
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR;         //指定DMA的外设基地址为SPI1的数据地址
        DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)SPI1_Tx_Buff;         //指定DMA的内存基地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;                 //DMA传输方向为读内存,写外设
        DMA_InitStructure.DMA_BufferSize = 4;//DataSize;                            //传输数量(0-65535,不能为0)
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;        //失能外设地址增长
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                 //失能内存地址增长
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;        //PSIZE=16bit
        DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord;        //MSIZE=16bit           
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA_Mode_Normal;//       //DMA模式为非循环模式,非循环模式只进行单次传输。
        DMA_InitStructure.DMA_Priority = DMA_Priority_Medium ;                  //优先权为中等
        DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;                  //失能FIFO模式
        DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;       //FIFO的阀值为半满
        DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;                    //内存突发传输为单一
        DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;     //外设突发传输为单一
        DMA_Init(DMA2_Stream3, &DMA_InitStructure);                             //初始化DMA2_Stream3
        //DMA_ITConfig(DMA2_Stream3, DMA_IT_TC, ENABLE);                        //因为是发送虚拟数据。不需要中断
        
        /* DMA enable*/
        DMA_Cmd(DMA2_Stream2, ENABLE);
        DMA_Cmd(DMA2_Stream3, ENABLE);
}

void TIM1_Init(u16 period)//period设置24以1MHz采样,period设置240以100KHz采样,period设置2400以10KHz采样,period设置24000以1KHz采样,
{
        GPIO_InitTypeDef  GPIO_InitStructure;
        
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
        TIM_OCInitTypeDef TIM_OCInitStructure;

        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);//使能GPIOE时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
        
        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8 |GPIO_Pin_9 | GPIO_Pin_12 |GPIO_Pin_13;
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;//模式必须为复用
        //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//频率为快速
        GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;
        GPIO_Init(GPIOE, &GPIO_InitStructure);
        GPIO_PinAFConfig(GPIOE, GPIO_PinSource8, GPIO_AF_TIM1);//PE8 作为 AD的/convst信号
        GPIO_PinAFConfig(GPIOE, GPIO_PinSource9, GPIO_AF_TIM1);
        GPIO_PinAFConfig(GPIOE, GPIO_PinSource12, GPIO_AF_TIM1);//PE12 作为 AD的/CS信号
        GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_TIM1);
        
        //初始化
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //死区控制用。
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数
        TIM_TimeBaseStructure.TIM_Prescaler = 7 - 1;   //Timer clock = 168M /(TIM_Prescaler+1) = 24M
        TIM_TimeBaseStructure.TIM_RepetitionCounter = 4;
        TIM_TimeBaseStructure.TIM_Period = period - 1;
        TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure);
        
        //配置输出比较,产生PWM方波
        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//PWM1为正常占空比模式,PWM2为反极性模式
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
        TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
        TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;//输出反相 TIM_OCNPolarity_Low;//输出同相,
        TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
        TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;

        TIM_OCInitStructure.TIM_Pulse = 1;//ccr1;//PE8 作为 AD的/convst信号
        TIM_OC1Init(TIM1,&TIM_OCInitStructure);//触发DMA2_Stream3 channel6
        
        TIM_OCInitStructure.TIM_Pulse = 1;//ccr2;
        TIM_OC2Init(TIM1,&TIM_OCInitStructure);//触发DMA2_Stream2 channel6
        
        TIM_OCInitStructure.TIM_Pulse = 23;//ccr3;//PE12 作为 AD的/CS信号
        TIM_OC3Init(TIM1,&TIM_OCInitStructure);

        TIM_Cmd(TIM1,ENABLE);
        TIM_CtrlPWMOutputs(TIM1,ENABLE);
        
        /* TIM1 DMA 请求使能 */
        TIM_DMACmd(TIM1, TIM_DMA_CC1 | TIM_DMA_CC2, ENABLE);//\\
}

int main(void)
{
        SPI1_Init();
        DMA_Config();
        TIM1_Init(24);//1MHz
        //PWM_Init(240);//100KHz
        //PWM_Init(2400);//10KHz
        //PWM_Init(24000);//1KHz
        while(1)
        {
                //CPU很闲
        };   
}
回复

使用道具 举报

4

主题

77

帖子

0

精华

高级会员

Rank: 4

积分
637
金钱
637
注册时间
2019-1-12
在线时间
67 小时
发表于 2020-4-26 11:35:43 | 显示全部楼层
好的,谢谢,我去研究一下
回复

使用道具 举报

17

主题

78

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
456
金钱
456
注册时间
2021-9-6
在线时间
59 小时
发表于 2022-6-9 14:18:26 | 显示全部楼层
楼主搞出来吗,分享一下
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-25 15:14

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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