你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

用DMA传输ADC转换结果, 数据不正确

[复制链接]
cpev 提问时间:2018-3-15 09:39 /
  我用的单片机是STM32F103VC,扫描ADC1的8个通道,用DMA1传输转换结果。DMA接收后的数据与实际ADC的结果不一致。
部分代码如下:
void CSL_ADC_Init(void)
{   
     GPIO_InitTypeDef GPIO_InitStructure;         
         ADC_InitTypeDef ADC_InitStructure;

         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC|RCC_APB2Periph_ADC1,ENABLE);         
         RCC_ADCCLKConfig(RCC_PCLK2_Div6);         //设置ADC分频因子6 72M/6=12M,ADC最大时间不能超过14M
         
         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6;         
         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                  //模拟输入引脚
         GPIO_Init(GPIOA,&GPIO_InitStructure);            
         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;         
         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                  //模拟输入引脚
         GPIO_Init(GPIOC,&GPIO_InitStructure);         

         //ADC1初始化
         ADC_DeInit(ADC1);         //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值         
         ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1工作在独立模式
         ADC_InitStructure.ADC_ScanConvMode = ENABLE; //模数转换工作在扫描模式
         ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //模数转换工作在单次转换模式
         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//转换由软件而不是外部触发启动
         ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐
         ADC_InitStructure.ADC_NbrOfChannel = 8; //顺序进行规则转换的ADC通道的数目
         ADC_Init(ADC1,&ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器            
         ADC_Cmd(ADC1,ENABLE);  //使能指定的ADC1
         
         //ADC1校准
         ADC_ResetCalibration(ADC1); //使能复位校准           
         while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束  
         ADC_StartCalibration(ADC1);  //开启AD校准
         while(ADC_GetCalibrationStatus(ADC1));   //等待校准结束

         //配置每个通道的转换次序和采样时间
         ADC_RegularChannelConfig(ADC1,ADC_Channel_1, 1,ADC_SampleTime_71Cycles5); //TC1                                  
         ADC_RegularChannelConfig(ADC1,ADC_Channel_2, 2,ADC_SampleTime_71Cycles5); //TC2                                  
         ADC_RegularChannelConfig(ADC1,ADC_Channel_3, 3,ADC_SampleTime_71Cycles5); //TC3                                  
         ADC_RegularChannelConfig(ADC1,ADC_Channel_4, 4,ADC_SampleTime_71Cycles5); //TC4          
         ADC_RegularChannelConfig(ADC1,ADC_Channel_5, 5,ADC_SampleTime_71Cycles5); //TC5                                  
         ADC_RegularChannelConfig(ADC1,ADC_Channel_6, 6,ADC_SampleTime_71Cycles5); //TC6                                  
         ADC_RegularChannelConfig(ADC1,ADC_Channel_10,7,ADC_SampleTime_71Cycles5); //Current1                                  
         ADC_RegularChannelConfig(ADC1,ADC_Channel_11,8,ADC_SampleTime_71Cycles5); //Current2                                           
}
void CSL_DMA_Init(void)
{      
        DMA_InitTypeDef DMA_InitStructure;
       
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);        //使能DMA传输
    DMA_DeInit(DMA1_Channel1);   //将DMA的通道1寄存器重设为缺省值
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&ADC1->DR); //DMA外设ADC1转换结果基地址
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADC1Result;  //DMA内存基地址  ADC1Result 为数组
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输方向,从外设读取数据到内存
        DMA_InitStructure.DMA_BufferSize = 32; //DMA通道的DMA缓存的大小
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址寄存器不变
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //数据宽度为32位
        DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Word; //数据宽度为32位
        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//工作在正常缓存模式
        DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA1通道1拥有中优先级
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
        DMA_Init(DMA1_Channel1,&DMA_InitStructure);   
        DMA_Cmd(DMA1_Channel1,ENABLE);
}


void APP_Measure_Temperature_Current(void)  //扫描ADC1 8个通道,用DMA传输数据  100ms周期调用
{             

         ADC_DMACmd(ADC1,ENABLE);          //开启ADC1 DMA传输         
         ADC_SoftwareStartConvCmd(ADC1,ENABLE); //使能指定的ADC1的软件转换启动功能           
         DMA_Cmd(DMA1_Channel1, ENABLE);          
         DMA_SetCurrDataCounter(DMA1_Channel1,32);         
         while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)); //等待转换结束  大约56us
         while(DMA_GetFlagStatus(DMA1_FLAG_TC1) != RESET)
         {
            DMA_ClearFlag(DMA1_FLAG_TC1);    //清除通道1传输完成标志
            break;
         }
         ADC_DMACmd(ADC1,DISABLE);                     //关闭ADC1 DMA传输         
         DMA_Cmd(DMA1_Channel1,DISABLE);
         ADC_SoftwareStartConvCmd(ADC1,DISABLE); //关闭指定的ADC1的软件转换启动功能  

}


是配置问题,还是其他。请赐教,第一次使用DMA。
1 收藏 评论23 发布时间:2018-3-15 09:39

举报

23个回答
OHWIXP 回答时间:2018-9-24 16:00:44
本帖最后由 OHWIXP 于 2018-9-24 16:30 编辑

楼主程序里DMA传输数据宽度部分,应该是配置错了:
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //数据宽度为32位
        DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Word; //数据宽度为32位
——改为:
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //数据宽度为16位
        DMA_InitStructure.DMA_MemoryDataSize =  DMA_MemoryDataSize_HalfWord; //数据宽度为16位
废鱼 回答时间:2018-3-15 10:26:15
DMA_InitStructure.DMA_BufferSize = 缓冲区的大小;

        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
        DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord;
cpev 回答时间:2018-3-15 11:13:10
安 发表于 2018-3-15 11:08
你缓冲区怎么定义的?要定义为16位的。

我现在只试验传一路ADC配置如下:
        DMA_InitTypeDef DMA_InitStructure;
       
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);        //使能DMA传输
    DMA_DeInit(DMA1_Channel1);   //将DMA的通道1寄存器重设为缺省值
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&ADC1->DR); //DMA外设ADC1转换结果基地址
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADCConvertedValue;//(u32)DMA1Buf;  //DMA内存基地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输方向,从外设读取数据到内存
        DMA_InitStructure.DMA_BufferSize = 1; //DMA通道的DMA缓存的大小
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址寄存器不变
        DMA_InitStructure.DMA_MemoryInc = DMA_PeripheralInc_Disable;//DMA_MemoryInc_Enable;  //内存地址寄存器递增
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//DMA_PeripheralDataSize_Word; //数据宽度为32位
        DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord;//DMA_PeripheralDataSize_Word; //数据宽度为32位
        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//工作在正常缓存模式
        DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA1通道1拥有中优先级
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
        DMA_Init(DMA1_Channel1,&DMA_InitStructure);   
有问题吗
废鱼 回答时间:2018-3-15 09:44:52
楼主能否描述一下数据是怎么样的不对,我们一般使用DMA中断方式处理。配置上看是一样的。可以只测试一路ADC,保证采集正确后,再增加其他路。
七哥 回答时间:2018-3-15 09:58:13
怎么个不对法?
函数固件库中样例程序走起,有用DMA来ADC的样例。我第一次用ADC就是DMA的,非常省事。 傲游截图20180315095854.png
琦子 回答时间:2018-3-15 10:00:31
看不出来什么问题  请教一下楼主用的vref是多少 采集的信号量超过vref了没有 还有就是可以直接将采集信号连接到地或者上限 看看数值对不对 还有也可以试试将采样时间设置到最大 这样也可以增加采样的稳定性
cpev 回答时间:2018-3-15 10:21:17
安 发表于 2018-3-15 09:44
楼主能否描述一下数据是怎么样的不对,我们一般使用DMA中断方式处理。配置上看是一样的。可以只测试一路ADC ...

只测试一路的话,数据也不对。DMA_InitStructure.DMA_BufferSize DMA_InitStructure.DMA_PeripheralDataSize         DMA_InitStructure.DMA_MemoryDataSize 这三个该怎么设置, ADC转换结果寄存器是32位的.
cpev 回答时间:2018-3-15 10:35:10
安 发表于 2018-3-15 10:26
DMA_InitStructure.DMA_BufferSize = 缓冲区的大小;

        DMA_InitStructure.DMA_PeripheralDataSize = DMA_Pe ...

为什么是DMA_PeripheralDataSize_HalfWord,ADC转换结果寄存器是32位的,应该是DMA_PeripheralDataSize_Word的吧,如果只转一路的话,DMA_InitStructure.DMA_BufferSize 为4个字节吗?
废鱼 回答时间:2018-3-15 10:54:36
ADC的数据最大是12位,用16位存储即可。如图:
微信截图_20180315105341.png
MrJiu 回答时间:2018-3-15 10:58:16
Cube走起。。。初始化配置一般直接OK!!!
cpev 回答时间:2018-3-15 11:04:58
安 发表于 2018-3-15 10:54
ADC的数据最大是12位,用16位存储即可。如图:

嗯 我改成16位的,但得到的结果只有低8位,高8位传不过来。
废鱼 回答时间:2018-3-15 11:08:21
你缓冲区怎么定义的?要定义为16位的。
miracle533 回答时间:2018-3-15 11:11:06
cpev 发表于 2018-3-15 11:04
嗯 我改成16位的,但得到的结果只有低8位,高8位传不过来。

问一下楼主,没有flash模块可以使用DMA吗?
废鱼 回答时间:2018-3-15 11:16:02
ADCConvertedValue,这个是怎么定义的。
cpev 回答时间:2018-3-15 11:16:55
安 发表于 2018-3-15 11:16
ADCConvertedValue,这个是怎么定义的。

如下定义 :__IO u16 ADCConvertedValue;  
12下一页

所属标签

相似问题

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版