基于stm32f103的adc采集+dma传输实验
一.adc配置:设置规则序列
typedef struct
{
uint32_t ADC_Mode; // adc模式位(具体参考不完全手册)
FunctionalState ADC_ScanConvMode; // 用来设置是否开启扫描模式(disable关闭,ENABLE开启扫描)
FunctionalState ADC_ContinuousConvMode; // 用来设置是否开启连续转换模式(disable关闭,ENABLE开启扫描)
uint32_t ADC_ExternalTrigConv; // 用来设置启动规则转换组转换的外部事件,软件触发选ADC_ExternalTrigConv_None 即可
uint32_t ADC_DataAlign; // 数据对其方式(左对齐,右对齐)
uint8_t ADC_NbrOfChannel; // 设置规则序列长度 (在多通道扫描模式下需要给每个通道设置执行顺序这个顺序就是根据规则序列表里面排列的通道顺序来执行的因此我们要设置这个表里面有多少个通道)
}ADC_InitTypeDef;
adc配置流程:
1.使能io时钟和adc时钟(不用使能端口复用功能,adc挂载在APB2总线下,只有在其他总线下的外外设才需要端口复用)
2.设置adc时钟分配因子以确定adc工作时钟频率。
3.重置adc寄存器。
4.初始化adc结构体参数。(ADC_Init())
5.使能adc。
6.开启复位校准。
7.开启ad校准。
最后一步
8.为通道设置采样时间(如果是多通道则需要配置每个通道的采样优先级即:规则序列表)
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime)
注意:转换时间=采样事件+12.5周期
若ADC_CLOCK=14M,采样时间1.5周期那么转换时间为1m即是1us(ADC_CLOCK最高频率不能超过14m一般设置6分频即72M/6=12M)。
二.dma配置步骤:
typedef struct
{
uint32_t DMA_PeripheralBaseAddr; //dma外设地址(u32类型例如:(u32)&(ADC1->DR))
uint32_t DMA_MemoryBaseAddr; //内存地址(u32类型例如:(u32)a(数组名)
uint32_t DMA_DIR; // 传输方向(内存--外设,外设---内存,内存---内存)
uint32_t DMA_BufferSize; //一次传输数据量的大小
uint32_t DMA_PeripheralInc; //传输数据的时候外设地址是不变还是递增
uint32_t DMA_MemoryInc; //传输数据的时候内存地址是不变还是递增
uint32_t DMA_PeripheralDataSize; //外设的的数据长度是为字节传输(8bits),半字传输 (16bits)还是字传输 (32bits)
uint32_t DMA_MemoryDataSize; //内存的的数据长度是为字节传输(8bits),半字传输 (16bits)还是字传输 (32bits)
uint32_t DMA_Mode; //设置 DMA 模式是否循环采集(可选单词采集和循环采集)
uint32_t DMA_Priority; //各个通道优先级
uint32_t DMA_M2M; //是 否 是 存 储 器 到 存 储 器 模 式 传 输 ,
}DMA_InitTypeDef;
注意 :DMA_MemoryDataSize和DMA_PeripheralDataSize库函数设置的时候两个的值不同。
例如:#define DMA_PeripheralDataSize_Word ((uint32_t)0x00000200)
#define DMA_MemoryDataSize_Word ((uint32_t)0x00000800)
dma配置步骤:
1.使能相应时钟
2.将dma相应通道寄存器值设置为缺省值
3.初始化结构体参数
4.初始化dma
5.使能dma
到这里已经配置完dma最后一步:
6.使能相应外设dma(例如:ADC_DMACmd(ADC1,ENABLE);只用使能一次)
完整代码:
int DMA_Config(DMA_Channel_TypeDef* CHx,u32 PBaseAddr,u32 MBaseAddr,u32 buffsize)
{
DMA_InitTypeDef DMA_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
DMA_DeInit(CHx);
DMA_InitStruct.DMA_PeripheralBaseAddr=PBaseAddr; //外设基地址
DMA_InitStruct.DMA_MemoryBaseAddr=MBaseAddr; //内存寄存器
DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralSRC; //数据传输方向 外设到内存
DMA_InitStruct.DMA_BufferSize=32; //通道缓存大小
DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable; //外设寄存器地址不递增
DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Disable; //关闭内存寄存器地址递增
DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord; //外围数据宽度32位
DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_Word; //内存数据宽度
DMA_InitStruct.DMA_Mode=DMA_Mode_Circular; //循环传输模式
DMA_InitStruct.DMA_Priority=DMA_Priority_High; //优先级
DMA_InitStruct.DMA_M2M=DMA_M2M_Disable; //不开启内存到内存
DMA_Init(CHx ,&DMA_InitStruct); //初始化DMA
//USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
DMA_Cmd(CHx ,ENABLE);
return 1;
}
void Adc_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
ADC_InitTypeDef ADC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,ENABLE);//使能时钟
//配置GPIOA_5口模拟输入
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AIN;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//ADC时钟分频因子
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
//重置ADC寄存器
ADC_DeInit(ADC1);
ADC_InitStruct.ADC_Mode= ADC_Mode_Independent;//独立模式
ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right; //数据右对齐
ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None ; //无外部触发
ADC_InitStruct.ADC_ContinuousConvMode=ENABLE; //enable开启连续扫描
ADC_InitStruct.ADC_NbrOfChannel=1; //规则转换通道数目
ADC_InitStruct.ADC_ScanConvMode=DISABLE; //DISABLE单通道模式,enable多通道扫描模式
ADC_Init(ADC1,&ADC_InitStruct);
ADC_Cmd(ADC1,ENABLE); //使能adc
ADC_ResetCalibration(ADC1);//开启复位校准
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1); //开启ad校准
while(ADC_GetCalibrationStatus(ADC1));
}
u16 Get_Adc(u8 ch1,u8 ch2)
{
u16 count=0;
ADC_RegularChannelConfig(ADC1,ch1,1,ADC_SampleTime_239Cycles5);
while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC))
{
count++;
if(count==60000)
break;
}
return ADC_GetConversionValue(ADC1); //返回adc数据寄存器器的值
注意:由于将 DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord; //外围数据宽度32位
DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_Word; //内存数据宽度
改为: DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord; //外围数据宽度32位
DMA_InitStruct.DMA_MemoryDataSize=DMA_PeripheralDataSize_HalfWord; //内存数据宽度
这样接收到的数据只有8位也就是最大值255
注意:在DMA传输过程中使用内存地址递增模式,循环传输时到传输到数组结尾时返回的位置是传入的地址处,而不是数组首地址。
例如:
int a[10];
DMA_Config(DMA1_Channel1,(u32)&ADC1->DR,(u32)(&a[1]),(u32)buffsize); //dma初始化注意此时传入的地址是a+1
当dma传输数据到a[10]后继续从a[1]地址处继续传输,而不是从数组首地址a[0]处。。。