OpenEdv-开源电子网

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

DMA和ADC传输问题

[复制链接]

39

主题

234

帖子

0

精华

高级会员

Rank: 4

积分
630
金钱
630
注册时间
2016-8-25
在线时间
57 小时
发表于 2017-3-23 10:08:44 | 显示全部楼层 |阅读模式
5金钱
#include "dma.h"                                                                                                                                                     
#include "delay.h"                 

//DMAx的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_StreamxMA数据流,DMA1_Stream0~7/DMA2_Stream0~7
//chxMA通道选择,@ref DMA_channel DMA_Channel_0~DMA_Channel_7
//par:外设地址
//mar:存储器地址
//ndtr:数据传输量  
void MYDMA_Config(DMA_Stream_TypeDef *DMA_Streamx,u32 chx,u32 par,u32 mar,u16 ndtr)
{

        DMA_InitTypeDef  DMA_InitStructure;
       
        if((u32)DMA_Streamx>(u32)DMA2)//得到当前stream是属于DMA2还是DMA1
        {
          RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能
               
        }else
        {
          RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);//DMA1时钟使能
        }
  DMA_DeInit(DMA_Streamx);
       
        while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}//等待DMA可配置
       
  /* 配置 DMA Stream */
  DMA_InitStructure.DMA_Channel = chx;  //通道选择
  DMA_InitStructure.DMA_PeripheralBaseAddr = par;//DMA外设地址
  DMA_InitStructure.DMA_Memory0BaseAddr = mar;//DMA 存储器0地址
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//存储器到外设模式
  DMA_InitStructure.DMA_BufferSize = ndtr;//数据传输量
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;//存储器增量模式
  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_Medium;//中等优先级
  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(DMA_Streamx, &DMA_InitStructure);//初始化DMA Stream
       

}
//开启一次DMA传输
//DMA_StreamxMA数据流,DMA1_Stream0~7/DMA2_Stream0~7
//ndtr:数据传输量  
void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr)
{

        DMA_Cmd(DMA_Streamx, DISABLE);                      //关闭DMA传输
       
        while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}        //确保DMA可以被设置  
               
        DMA_SetCurrDataCounter(DMA_Streamx,ndtr);          //数据传输量  

        DMA_Cmd(DMA_Streamx, ENABLE);                      //开启DMA传输
}          

#include "adc.h"
void My_adc_init(void)
{
        GPIO_InitTypeDef GPIO_InitStruct;
        ADC_InitTypeDef ADC_InitStruct;
        ADC_CommonInitTypeDef ADC_CommonInitStruct;
       
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
        RCC_APB2PeriphClockCmd( RCC_APB2Periph_ADC1,ENABLE);
        //初始化ADC
        GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;
        GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AN;
        GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL;
        GPIO_Init(GPIOA,&GPIO_InitStruct);
       
        ADC_CommonInitStruct.ADC_Mode=ADC_Mode_Independent;
        ADC_CommonInitStruct.ADC_Prescaler=ADC_Prescaler_Div2;
        ADC_CommonInitStruct.ADC_DMAAccessMode=ADC_DMAAccessMode_Disabled;
        ADC_CommonInitStruct.ADC_TwoSamplingDelay=ADC_TwoSamplingDelay_10Cycles;
        ADC_CommonInit(&ADC_CommonInitStruct);
       
        ADC_InitStruct.ADC_Resolution=ADC_Resolution_12b;
        ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;
        ADC_InitStruct.ADC_NbrOfConversion=ADC_Channel_5;
        ADC_InitStruct.ADC_ContinuousConvMode=ENABLE;
        ADC_InitStruct.ADC_ScanConvMode=DISABLE;
        ADC_InitStruct.ADC_ExternalTrigConvEdge=ADC_ExternalTrigConvEdge_None;
        ADC_Init(ADC1,&ADC_InitStruct);
       
//        ADC_DMACmd(ADC1,ENABLE);
        ADC_Cmd(ADC1,ENABLE);
}
u16 get_result(void)
{       
        u16 ADC_result;
        ADC_RegularChannelConfig(ADC1,5,1,ADC_SampleTime_480Cycles);//每次转换需要配置规则模式
        ADC_SoftwareStartConv(ADC1);
        while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==DISABLE);
        ADC_result=ADC_GetConversionValue(ADC1);
        ADC_ClearFlag(ADC1,ADC_FLAG_EOC);
        return ADC_result;
}       


#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "adc.h"
#include "led.h"
#include "dma.h"

#define USART1_DR_BASE ((u32)0x40011004)
#define ADC1_DR_BASE  ((u32)0x4001204c)

#define SENDSIZE 1

__IO u16 result_data;

int main(void)
{
        u16 i;
        u8 j;
        delay_init(168);
        uart_init(115200);
        LED_Init();
        My_adc_init();
        MYDMA_Config(DMA2_Stream0,DMA_Channel_0,ADC1_DR_BASE,(u32)&result_data,SENDSIZE);
        while(1)
        {
                ADC_DMACmd(ADC1,ENABLE);
                MYDMA_Enable(DMA2_Stream0,SENDSIZE);
                ADC_RegularChannelConfig(ADC1,5,1,ADC_SampleTime_480Cycles);//每次转换需要配置规则模式
                ADC_SoftwareStartConv(ADC1);
                while(1)
                {
                if(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==ENABLE)
                        {
                                ADC_ClearFlag(ADC1,ADC_FLAG_EOC);
                                break;
                        }
                LED1=!LED1;
                delay_ms(500);
                }
                while(1)
                {
                        if(DMA_GetFlagStatus(DMA2_Stream0,DMA_FLAG_TCIF0)==ENABLE)
                        {
                                DMA_ClearFlag(DMA2_Stream0,DMA_FLAG_TCIF0);
                                break;
                        }
                LED0=!LED0;
                delay_ms(500);
                       
                }
                printf("the result is %d\r\n",result_data);

        }
}

请问我设置的是AD连续采样模式,和DMA循环模式。为什么串口显示如下
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
the result is 519
为什么不更新AD转换结果?求助

最佳答案

查看完整内容[请看2#楼]

问题已经找到,是由于在使能DMA请求的过程中,ADC产生了溢出,停止了ADC请求,只要将溢出位清零,然后再初始化就可以了。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

39

主题

234

帖子

0

精华

高级会员

Rank: 4

积分
630
金钱
630
注册时间
2016-8-25
在线时间
57 小时
 楼主| 发表于 2017-3-23 10:08:45 | 显示全部楼层
问题已经找到,是由于在使能DMA请求的过程中,ADC产生了溢出,停止了ADC请求,只要将溢出位清零,然后再初始化就可以了。
回复

使用道具 举报

39

主题

234

帖子

0

精华

高级会员

Rank: 4

积分
630
金钱
630
注册时间
2016-8-25
在线时间
57 小时
 楼主| 发表于 2017-3-23 10:09:12 | 显示全部楼层
求高手帮忙
回复

使用道具 举报

3

主题

13

帖子

0

精华

新手上路

积分
25
金钱
25
注册时间
2017-3-28
在线时间
6 小时
发表于 2017-3-28 19:49:57 | 显示全部楼层

你好 我最近也在学习这个 我想用读取两个模拟量 需要用到DMA 么
回复

使用道具 举报

3

主题

13

帖子

0

精华

新手上路

积分
25
金钱
25
注册时间
2017-3-28
在线时间
6 小时
发表于 2017-3-29 13:26:56 | 显示全部楼层
你好 可以一起请教一下吗
回复

使用道具 举报

39

主题

234

帖子

0

精华

高级会员

Rank: 4

积分
630
金钱
630
注册时间
2016-8-25
在线时间
57 小时
 楼主| 发表于 2017-3-29 14:38:43 | 显示全部楼层
vivian 发表于 2017-3-28 19:49
你好 我最近也在学习这个 我想用读取两个模拟量 需要用到DMA 么

这个好像一般不需要,DMA好像一般用于比较大的数据保存数据,不过也可以通过这个练习一下
回复

使用道具 举报

39

主题

234

帖子

0

精华

高级会员

Rank: 4

积分
630
金钱
630
注册时间
2016-8-25
在线时间
57 小时
 楼主| 发表于 2017-3-29 14:43:05 | 显示全部楼层
mxiaotao 发表于 2017-3-29 14:38
这个好像一般不需要,DMA好像一般用于比较大的数据保存数据,不过也可以通过这个练习一下

遇到问题可以大家讨论一下
回复

使用道具 举报

3

主题

13

帖子

0

精华

新手上路

积分
25
金钱
25
注册时间
2017-3-28
在线时间
6 小时
发表于 2017-3-29 15:11:07 | 显示全部楼层
mxiaotao 发表于 2017-3-29 14:43
遇到问题可以大家讨论一下

你好 我最近也在学习这个 我想用读取两个模拟量   


void  Adc_Init(void)
{   
  GPIO_InitTypeDef  GPIO_InitStructure;
        ADC_CommonInitTypeDef ADC_CommonInitStructure;
        ADC_InitTypeDef       ADC_InitStructure;
       
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);/
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);


  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//Ä£Äaêäèë
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOA, &GPIO_InitStructure);//3õê¼»ˉ  

        RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE);       
        RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE);                 

       
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;//¶àá¢Ä£ê½
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
  ADC_CommonInit(&ADC_CommonInitStructure);
       
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_8b;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode =DISABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;       
  ADC_InitStructure.ADC_NbrOfConversion =2;
  ADC_Init(ADC1, &ADC_InitStructure);ˉ
       

        ADC_Cmd(ADC1, ENABLE)

}                                  

u16 Get_Adc(u8 ch)   
{
                 
        ADC_RegularChannelConfig(ADC1,ch,ch, ADC_SampleTime_480Cycles );
  
        ADC_SoftwareStartConv(ADC1);               
         
        while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC )==RESET);

  //ADC_ClearFlag(ADC1, ADC_FLAG_EOC );
       
        return ADC_GetConversionValue(ADC1);       
       
}

主程序这样写的

u16 ADC_1;
u16 ADC_2;

u8  ADC_1_L8;
u8  ADC_1_H8;

int main(void)
{

           TIM4CH_PWM_Init(500-1,84-1);

   

           delay_init(168);               
       
     uart_init(9600);       

        while(1)
        {   
                        Adc_Init();
               
  
                    ADC_1=Get_Adc(ADC_Channel_1);
               
                    USART_SendData(USART1,ADC_1);   delay_ms(2000);

                    ADC_2=Get_Adc(ADC_Channel_2);

                     USART_SendData(USART1,ADC_2);   delay_ms(2000);

       
        }
       
}

然后串口返回数据有时候必须RESET 一下才有  本来读取的是两个 但是明显知识一个IO口的值 卡了我一天了  还是找不到错位


回复

使用道具 举报

39

主题

234

帖子

0

精华

高级会员

Rank: 4

积分
630
金钱
630
注册时间
2016-8-25
在线时间
57 小时
 楼主| 发表于 2017-3-29 22:02:27 | 显示全部楼层
vivian 发表于 2017-3-29 15:11
你好 我最近也在学习这个 我想用读取两个模拟量   

仿真的时候看一下寄存器
回复

使用道具 举报

39

主题

234

帖子

0

精华

高级会员

Rank: 4

积分
630
金钱
630
注册时间
2016-8-25
在线时间
57 小时
 楼主| 发表于 2017-3-29 22:04:19 | 显示全部楼层
vivian 发表于 2017-3-29 15:11
你好 我最近也在学习这个 我想用读取两个模拟量   

这个ADC采用的是外部触发吗?
回复

使用道具 举报

39

主题

234

帖子

0

精华

高级会员

Rank: 4

积分
630
金钱
630
注册时间
2016-8-25
在线时间
57 小时
 楼主| 发表于 2017-3-29 22:06:00 | 显示全部楼层
vivian 发表于 2017-3-29 15:11
你好 我最近也在学习这个 我想用读取两个模拟量   

两个通道ADC转换,是不是需要打开ADC扫描模式
回复

使用道具 举报

39

主题

234

帖子

0

精华

高级会员

Rank: 4

积分
630
金钱
630
注册时间
2016-8-25
在线时间
57 小时
 楼主| 发表于 2017-3-29 22:08:27 | 显示全部楼层
vivian 发表于 2017-3-29 15:11
你好 我最近也在学习这个 我想用读取两个模拟量   

扫描模式
此模式用于扫描一组模拟通道。
通过将 ADC_CR1 寄存器中的 SCAN 位置 1 来选择扫描模式。将此位置 1 后, ADC 会扫描
在 ADC_SQRx 寄存器(对于规则通道)或 ADC_JSQR 寄存器(对于注入通道)中选择的
所有通道。为组中的每个通道都执行一次转换。每次转换结束后,会自动转换该组中的下一
个通道。如果将 CONT 位置 1,规则通道转换不会在组中最后一个所选通道处停止,而是再
次从第一个所选通道继续转换。
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-8-22 17:50

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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