STM32F10X ADC多通道读取小教程(包含DMA)
2018-02-19 13:42
316 查看
前沿: 今天是雨水,哎可是我这还是大太阳!!!
ADC采样,说白了就是采集电压,这个功能是极其重要的,通常的我们的都是对各种传感器采集电压,来进行判断,开环闭环控制,今天,向大家介绍ADC的多通道采样,和DMA的采样方式。DMA的采样方式,可有效节省CMU在ADC的运行时间,提高效率,尤其是在系统构建的时候,必须要考虑好,你的效率问题。
这里我用的开发板时正点原子的MiniSTM32,芯片型号为STM32F103RCT6. This is easy, so you can do that very easily![objc] view plain copy ***REMENBER STM32 is you! :)
我们在这里进行通俗的讲解,详细的内容,可以在以后再去看STM32手册。
了解ADC:
有 18 个通道,可测量 16 个外部和 2 个内部信号源。各通道的 A/D 转换可以单次、连续、扫描或间断模式执行 ;ADC的结果可以左对齐或右
eef7
对齐方式存储在 16 位数据寄存器中 ;模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高 / 低阈值。
接下来让我们分析两种方式(注意这里我们这里的代码是连续的):第一种:
这里我们使用ADC1 ,相应的打开时钟,最后一步很重要,就是要给ADC分频,有个要求就是ADC工作频率不能超过14MHz
以上初始化使到的Pin,有PA1 --ADC1的通道1,PA3 --ADC1的通道3
![](https://img-blog.csdn.net/2018021912092918?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzczODkxMzM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
GPIOMODE 为 GPIO_Mode_AIN 模拟输入!
这里进行ADC配置,同样的这里有些东西非常讲究! ADC模式我们就采用独立模式ADC_Mode_Independent,接下来我们会看到是否使用扫描模式ADC_ScanConvMode,是否使用连续模式ADC_ContinuousConvMode,在多通道的时候,我们会考虑扫描模式,就是多通道按照顺序一个个扫描过来,一般的我们会结合DMA一起使用,连续模式就是,在触发一次后是否进行连续读取ADC的值。这里我们都不使能,相关的使用内容,在后面DMA例子中说明。ADC_DataAlign_Right是指数据对其方式:
比如说AD转换后数字量保存在ADCH,ADCL两个寄存器中
左对齐就是AD值的最高位就是ADCH的最高位了,ADCL的低位就会有的用不到,读出来就为0
右对齐就是AD值的最低位是ADCL的最低位,而ADCH的高位就会有的用不到,读出来也为0
左对齐:11111111 11110000
MSB LSB
右对齐:00001111 11111111
MSB LSB这里一般的我们选择右对齐! 左对齐的话,由于ADC采样为12位,最大为0x0FFF,所以左对齐 得到X>>4才是真实的值。
这里我们都是采用的软件的触发方式,所以,外部触发就不使用,就是ADC_ExternalTrigConv_None
这里使能ADC1, 同时的还有必要操作,就是ADC的校准,先复位后校准!这里配置函数依据结束!接下来为读取函数:
float getADC_Val(uint8_t channel){
uint16_t tempdata;
float out_val;
ADC_RegularChannelConfig(ADC1,channel,1,ADC_SampleTime_55Cycles5);
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); //等待读取结束
tempdata = ADC_GetConversionValue(ADC1);
out_val =tempdata*3.3/0xfff;
return out_val;
}
参数:
![](https://img-blog.csdn.net/20180219131103696?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzczODkxMzM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
这里由于我们不扫面,也不连续读取,要得时候在读取,所以每次读取都要初始化通道,并且软件触发一下:
ADC_RegularChannelConfig 规则组初始化,第三个参数为规则组的排序号,最后的参数为采样周期55.5:计算采样时间为(周期+12.5)/(72M/分频) = 时间 ,这里为 (55.5+12.5)/(72/6)=5.667usADC_SoftwareStartConvCmd 这里软件触发ADC_GetConversionValue读取相应的值out_val =tempdata*3.3/0xfff;
这里的转化为固定格式,12位ADC读取电压0~3.3V ,很好理解。
以上为多通道的非DMA模式,接下来是DMA模式://@作者:junwencui
这里使用DMA模式,更具32手册,得到 ADC1对应DMA1的通道1:
![](https://img-blog.csdn.net/20180219132249513?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzczODkxMzM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
也会发现,现在我们使用的都是扫描模式,和连续触发模式。工作时,就自动的按照规则组的排序一个个读取过来,并且重复此工作,不占用CMU,
规则组排序读取配置:
ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1,ADC_Channel_3,2,ADC_SampleTime_55Cycles5);对于DMA的使用这里不在阐述。可以看手册和结构体含义理解使用方式!!!!
写到这里,就差不多了!
对于ADC的使用,有很多小技巧,需要平时留意!
欢迎大家指正,互相学习,祝大家学习愉快!!
ADC采样,说白了就是采集电压,这个功能是极其重要的,通常的我们的都是对各种传感器采集电压,来进行判断,开环闭环控制,今天,向大家介绍ADC的多通道采样,和DMA的采样方式。DMA的采样方式,可有效节省CMU在ADC的运行时间,提高效率,尤其是在系统构建的时候,必须要考虑好,你的效率问题。
这里我用的开发板时正点原子的MiniSTM32,芯片型号为STM32F103RCT6. This is easy, so you can do that very easily![objc] view plain copy ***REMENBER STM32 is you! :)
我们在这里进行通俗的讲解,详细的内容,可以在以后再去看STM32手册。
了解ADC:
有 18 个通道,可测量 16 个外部和 2 个内部信号源。各通道的 A/D 转换可以单次、连续、扫描或间断模式执行 ;ADC的结果可以左对齐或右
eef7
对齐方式存储在 16 位数据寄存器中 ;模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高 / 低阈值。
接下来让我们分析两种方式(注意这里我们这里的代码是连续的):第一种:
void adc_Config(void){ ADC_InitTypeDef ADC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); //这里ADC分频,ADC工作频率最高不超过14M
这里我们使用ADC1 ,相应的打开时钟,最后一步很重要,就是要给ADC分频,有个要求就是ADC工作频率不能超过14MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_InitStructure.GPIO_Pin =GPIO_Pin_1; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_InitStructure.GPIO_Pin =GPIO_Pin_3; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure);
以上初始化使到的Pin,有PA1 --ADC1的通道1,PA3 --ADC1的通道3
GPIOMODE 为 GPIO_Mode_AIN 模拟输入!
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_ExternalTrigConv= ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1,&ADC_InitStructure);
这里进行ADC配置,同样的这里有些东西非常讲究! ADC模式我们就采用独立模式ADC_Mode_Independent,接下来我们会看到是否使用扫描模式ADC_ScanConvMode,是否使用连续模式ADC_ContinuousConvMode,在多通道的时候,我们会考虑扫描模式,就是多通道按照顺序一个个扫描过来,一般的我们会结合DMA一起使用,连续模式就是,在触发一次后是否进行连续读取ADC的值。这里我们都不使能,相关的使用内容,在后面DMA例子中说明。ADC_DataAlign_Right是指数据对其方式:
比如说AD转换后数字量保存在ADCH,ADCL两个寄存器中
左对齐就是AD值的最高位就是ADCH的最高位了,ADCL的低位就会有的用不到,读出来就为0
右对齐就是AD值的最低位是ADCL的最低位,而ADCH的高位就会有的用不到,读出来也为0
左对齐:11111111 11110000
MSB LSB
右对齐:00001111 11111111
MSB LSB这里一般的我们选择右对齐! 左对齐的话,由于ADC采样为12位,最大为0x0FFF,所以左对齐 得到X>>4才是真实的值。
这里我们都是采用的软件的触发方式,所以,外部触发就不使用,就是ADC_ExternalTrigConv_None
ADC_Cmd(ADC1,ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); }
这里使能ADC1, 同时的还有必要操作,就是ADC的校准,先复位后校准!这里配置函数依据结束!接下来为读取函数:
float getADC_Val(uint8_t channel){
uint16_t tempdata;
float out_val;
ADC_RegularChannelConfig(ADC1,channel,1,ADC_SampleTime_55Cycles5);
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); //等待读取结束
tempdata = ADC_GetConversionValue(ADC1);
out_val =tempdata*3.3/0xfff;
return out_val;
}
参数:
这里由于我们不扫面,也不连续读取,要得时候在读取,所以每次读取都要初始化通道,并且软件触发一下:
ADC_RegularChannelConfig 规则组初始化,第三个参数为规则组的排序号,最后的参数为采样周期55.5:计算采样时间为(周期+12.5)/(72M/分频) = 时间 ,这里为 (55.5+12.5)/(72/6)=5.667usADC_SoftwareStartConvCmd 这里软件触发ADC_GetConversionValue读取相应的值out_val =tempdata*3.3/0xfff;
这里的转化为固定格式,12位ADC读取电压0~3.3V ,很好理解。
以上为多通道的非DMA模式,接下来是DMA模式://@作者:junwencui
//@weather:sunny
__IO uint16_t ADC_GetValue[2]={0,0}; void pADCInit(uint8_t length){ DMA_InitTypeDef DMA_InitStructure; ADC_InitTypeDef ADC_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); DMA_DeInit(DMA1_Channel1); DMA_InitStructure.DMA_PeripheralBaseAddr= (u32)(&(ADC1->DR)); DMA_InitStructure.DMA_MemoryBaseAddr=(u32)ADC_GetValue; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = length; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel1,&DMA_InitStructure); DMA_Cmd(DMA1_Channel1,ENABLE); ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = ENABLE; ADC_InitStructure.ADC_ContinuousConvMode =ENABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel=length; ADC_Init(ADC1,&ADC_InitStructure); RCC_ADCCLKConfig(RCC_PCLK2_Div6); ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1,ADC_Channel_3,2,ADC_SampleTime_55Cycles5); ADC_DMACmd(ADC1,ENABLE); ADC_Cmd(ADC1,ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); ADC_SoftwareStartConvCmd(ADC1,ENABLE); }
这里使用DMA模式,更具32手册,得到 ADC1对应DMA1的通道1:
也会发现,现在我们使用的都是扫描模式,和连续触发模式。工作时,就自动的按照规则组的排序一个个读取过来,并且重复此工作,不占用CMU,
规则组排序读取配置:
ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1,ADC_Channel_3,2,ADC_SampleTime_55Cycles5);对于DMA的使用这里不在阐述。可以看手册和结构体含义理解使用方式!!!!
val = (float)ADC_GetValue[channel]/4096*3.3;DMA数据会存储在ADC_GetValue 中,使用的时候输入01234等ADC_GetValue数组的序号,就可以方便读取!
写到这里,就差不多了!
对于ADC的使用,有很多小技巧,需要平时留意!
欢迎大家指正,互相学习,祝大家学习愉快!!
年过的差不多了,又要回学校上班了。;)
相关文章推荐
- STM32F10x_ADC三通道DMA连续转换(3通道、软件单次触发)
- STM32 ADC DMA 中断模式多通道读取ADC转换值
- 记STM32F030多通道ADC DMA读取乱序问题
- STM32F10x_ADC三通道DMA连续转换(3通道、软件单次触发)
- STM32开发板基础教程(七) - ADC with DMA
- STM32 多通道ADC采样,采用Timer1进行采样率控制,利用DMA进行传输
- STM32F4系列单片机ADC多通道DMA程序,注意DMA配置一定要先于DAC的配置
- STM32 ADC单通道与多通道_DMA学习笔记
- 【STM32】用DMA实现多路ADC通道数据采集
- lucene3.6.1 经典案例 入门教程 (包含从文件中读取content)
- [置顶] STM32的ADC1采集多条通道,可以不使用DMA功能吗?
- STM32之ADC 一个8通道DMA程序
- STM32F407IG多通道ADC-DMA采样
- STM32F10x_ADC三通道逐次转换(单次、单通道软件触发)
- stm32ADC非DMA模式的多通道采集与注入通道的采集
- STM32 ADC单通道与多通道_DMA学习笔记 百度搜索
- STM32F10x_ADC三通道逐次转换(单次、单通道软件触发)
- STM32通过TIM,ADC,DMA的配合使用实现双通道数据采样
- STM32之ADC 一个8通道DMA程序
- STM8L051之ADC+DMA两通道数据采样错位问题