STM32 ADC数据采集 5通道 DMA传输 数据读取

2019-08-28 13:30发布

各位大神,我碰到了些问题,希望有朋友能帮忙解答一下!
问题描述:我现在在做的是用 开发板产生4路PWM波去驱动舵机,脉宽是持续变化的,每10ms更新一次(这个已经实现),然后用ADC采集这四路通道的数据和另外一路的电压数据,共5路。我希望每个高电平阶段采集一次,但现在无法采集到数据,不知道问题出在哪里!使用芯片为:STM32F103C8T6
部分代码如下:
#define ADC1_DR_Address  ((u32)0x40000000+0x10000+0x2400+0x4c)//在程序中没用到
__IO uint16_t ADC_ConvertedValue[5];//用来存储DMA传来的数据

void ADC1_Configuration(void)
{
//定义结构体变量,该变量中包含了初始化ADC相关的参数,对该变量的成员变量进行初始化,然后调用ADC_Init()函数即可实现对ADC相关寄存器最终的初始化
ADC_InitTypeDef   ADC_InitStructure;

RCC_ADCCLKConfig(RCC_PCLK2_Div6);//因为PCLK2时钟频率为72MHz,所以ADC1输入时钟为PCLK2的6分频,即12MHz
//将外设ADC1全部寄存器设置为缺省值
ADC_DeInit(ADC1);
//设置ADC工作在独立模式
ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;
//设置扫描模式,对多个通道进行采样
ADC_InitStructure.ADC_ScanConvMode=ENABLE;//DISABLE;//规定AD转换工作模式,当对一个通道采样时,后为DISABLE,当对多个通道采样时,后为ENABLE.
//设置连续工作模式,连续转化
ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;//DISABLE//设定AD转化在连续模式,连续转换模式开启
//不需要外部触发ADC转换,在本实验中使用软件触发ADC转换
ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//不使用外部触发转换,外部触发开关关闭
//数据对齐方式选择右对齐,因为16位的ADC数据寄存器中只保存了12位的有效数据(ADC的分辨率为12位),所以才有数据对齐的问题
ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//对齐方式,ADC结果是12位的,显然有个对齐左边还是右边的问题,一般是右对齐
//设置转换的通道数目,使用多个通道时,这里需要改为确切的通道数目
ADC_InitStructure.ADC_NbrOfChannel=5;//设定要转换的AD通道数目
//实现对相关寄存器的初始化工作
ADC_Init(ADC1,&ADC_InitStructure);
//设置ADC输入通道的采样周期数。ADC总转换时间计算式:Tconv = (采样周期数+12.5)个周期
//例如,当ADCCLK = 12MHz,采样时间为239.5个周期时,ADC的转换时间Tconv = (239.5+12.5)个周期 = 21us
//ADC1,ADC通道x,规则采样顺序值为y,采样时间为239.5周期
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_239Cycles5);//规则模式通道配置。配置ADC1的通道0为239.5个采样周期
ADC_RegularChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_239Cycles5);//规则模式通道配置。配置ADC1的通道1为239.5个采样周期
ADC_RegularChannelConfig(ADC1,ADC_Channel_2,3,ADC_SampleTime_239Cycles5);//规则模式通道配置。配置ADC1的通道2为239.5个采样周期
ADC_RegularChannelConfig(ADC1,ADC_Channel_3,4,ADC_SampleTime_239Cycles5);//规则模式通道配置。配置ADC1的通道3为239.5个采样周期
ADC_RegularChannelConfig(ADC1,ADC_Channel_5,5,ADC_SampleTime_239Cycles5);//规则模式通道配置。配置ADC1的通道5为239.5个采样周期

//使能ADC1的DMA功能,因为其他还有DMA功能
ADC_DMACmd(ADC1,ENABLE);//Enable ADC1 DMA

//使能ADC1功能
ADC_Cmd(ADC1,ENABLE);//ENABLE ADC1
//以下四行,复位校准寄存器,待校准寄存器复位后,开启ADC校准功能,待ADC校准结束后,即可启动ADC转换。
ADC_ResetCalibration(ADC1);//复位校准寄存器
while(ADC_GetResetCalibrationStatus(ADC1));//等待校准寄存器复位完成
ADC_StartCalibration(ADC1);//ADC校准
while(ADC_GetCalibrationStatus(ADC1));//等待校准完成
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//由于没有采用外部触发,所以使用软件触发ADC转换。这句话一定得有,这里如果不出现则必须出现在主函数中
//配置完后,AD每转换一次,DMA都会将转换结果搬到变量ADC_ConvertedValue中,而不需要每次都用赋值语句来读取AD的值
}


void DMA_Configuration(void)
{
    DMA_InitTypeDef   DMA_InitStructure;

DMA_DeInit(DMA1_Channel1);//开启DMA1的第一通道,将与DMA有关的寄存器设为初始值
//数据搬移的起始地址,起始地址为ADC1的数据寄存器的地址。DMA对应的外设基地址,定义DMA外设基地址,这里的ADC1_DR_Address是用户自己定义的,即为存放转换结果的寄存器,它的作用就是告诉DMA取数就到ADC1_DR_Address这里来取
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;//ADC1_DR_Address;
//设置DMA搬移数据的单位,即每次搬移一个字,还是半个字,或是一个字节。对于32位的处理器,一个字的数据长度为4个字节,因为ADC1数据寄存器长度为16位,所以应初始化为半个字长度
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//设定外设数据宽度,即告诉DMA要取的数的大小
//数据搬移的结束地址,结束地址为数据缓冲区的地址。定义的内存基地址,即告诉DMA要将从AD中取来的数放到ADC_ConvertedValue中,单片机采集后存储的值的地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_ConvertedValue;
//设置数据传输方向,从ADC1的数据寄存器到内存中的数据缓冲区进行数据传输。定义AD外设作为数据传输的来源,即告诉DMA是将AD中的数据取出放到内存中,不能反过来
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
//当使用外设到存储器的数据传输时,需要设置为DMA_M2M_Disable
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//M2M表示内存到内存传输数据
//设置DMA搬移数据的单位,即每次搬移一个字,还是半个字,或是一个字节。对于32位的处理器,一个字的数据长度为4个字节,因为ADC1数据寄存器长度为16位,所以应初始化为半个字长度
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//HalfWord,DMA搬运的数据尺寸,设定内存的宽度
//设置数据指针调整模式,这里设置地址指针不自动增加
//设定内存地址递增,即每次DMA都是将该外设寄存器中的值传到5个内存空间中
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//Enable,此处有争议//设定内存地址固定,即每次DMA,只将数搬到固定的内存中。接收一次数据后,目标内存地址是否后移,用来采集多个数据的,多通道的时候需要使能它
//设置数据指针调整模式,这里设置地址指针不自动增加
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//设定寄存器地址固定,即告诉DMA只从固定的一个地方取数
//选择循环模式,在循环模式下当数据传输的数目变为0时,将会自动地被恢复成配置通道时设置的初值,DMA操作将会继续进行。此功能可以用于多路AD扫描。
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//设定DMA工作在循环缓存模式,即告诉DMA要不停地搬运,不能偷懒
//设置DMA通道请求优先级,仲裁器根据通道请求的优先级来启动对外设或存储器的访问
DMA_InitStructure.DMA_Priority = DMA_Priority_High;//设定DMA选定的通道软件优先级,DMA优先级高
//设置数据传输的长度,在此每次只传输一个长度,为16个二进制位,这是由ADC1数据寄存器的长度决定的
DMA_InitStructure.DMA_BufferSize = 5;//指定DMA通道缓存大小,即告诉DMA开辟几个内存空间,看你需要取几个通道的数据就开通几个,1*16个
//调用DMA_Init()函数,实现对DMA控制器相关寄存器的初始化工作
DMA_Init(DMA1_Channel1,&DMA_InitStructure);//用这个函数给DMA吩咐任务

//DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE);//允许DMA1通道1传输结束后中断
DMA_Cmd(DMA1_Channel1,ENABLE);//Enable DMA Channel1,CPU有好几个DMA秘书,现在只用DMA1_Channel1这个秘书,启动DMA通道,必须要有,也可以在主函数中出现
}



另外就是,我定义了5个1000字节的数组,将这5组数据分别存在这5个数组中,因为频率为100Hz,采集时间为10s,共1000个数据。每次转换结束就用DMA讲数据搬运到已定义的ADC_ConvertedValue[5]。然后分别将ADC_ConvertedValue[0],ADC_ConvertedValue[1],ADC_ConvertedValue[2],ADC_ConvertedValue[3],ADC_ConvertedValue[4]赋给已定义的5个1000字节的数组,一次赋值后,地址加一,下一次的数据存在数组的第二个元素位置,以此类推。。。我是这么考虑的,但不知道问题出在哪里。。。
请问这些设置有什么问题吗?或者说可能的问题出在哪里?
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。