开发背景:
- 编译工具:MDK5
- 代码生成工具:CubeMX(veision5.6.1)
- 芯片:STM32F302RC
使用CubeMX配置时钟、ADC、DMA
- 配置时钟在此不做说明,后续补上链接
- 使用PA6、PA7进行ADC数据采集,PA6/7分别对应ADC2的Channel_3/4
在CubeMX软件左侧找到ADC2(Categories->Analog或A->Z中直接点开ADC2),找到IN3,IN4对应的就是PA6/7引脚,由于这两个引脚都是对应在同一个ADC2上面,我们下拉选择INx Single-ended,设置完成后,对下面的Parameter Settings进行参数设定,如下图:
相关参数设置说明:
mode:independent mode 独立模式(只是用了ADC2)
Clock Prescale:synchronous clock mode divided by 4 //ADC时钟的4分频 72/4=18MHz
resolution:ADC 12-bit resolution(采集分辨率最高12位)
data alignment:Right alignment(采集数据有效位是16位,也就是有4位空余,左/右对齐根据你的需求,这里选择右对齐方式)
scan conversion mode:Enable 使能扫描模式(多个channel且连续转换时循环扫描)
continuous conversion mode:Enable 使能连续转换
Discontinuous conversion mode:Disable
DMA continuous requests:enable 使用DMA请求数据
end of conversion selection:end of single conversion 单个转换或顺序转换
overrun behavior:overrun data preserved 溢出数据保存
low Power Auto wait:Disable 低功耗自动等待关闭
enable regular conversion:enable 使能规则转换
number of conversion edge:2 转换的数量(PA6/7)
external trigger conversion source:这里使用软件触发转换方式
external trigger conversion edge :None 使用软件转换就 不使用其他的
rank :设置通道的相关信息
这里需要说明的就是sample time:采集周期19.5个周期,计算总的转换时间,公式如下:
Tconv = (采样周期+12个周期)x (1/ADCClk) = (19.5+12)* 72/4 = 1.75 (单位:us)
4:Clock Prescale我们设置成4分频
72MHz:AHB时钟也就是ADC的时钟频率
ADC_injected_conversionMode 注入方式设置了软件转换方式就设置成disable
最后在project manager 中设置工程名以及编译工具及版本信息,相关设置在此不做说明
相关设置点详细说明
1.ADC时钟注意事项
ADC时钟频率不是越高越好
M3:确保ADC时钟不要超过14MHz
M4/M7:确保ADC时钟不要超过36MHz
2.ADC 采样时间
总转换时间计算公式:
Tconv = (采样时间+12个周期)x (1/ADCClk)
M4内核,ADCClk=APB2CLK/prescale=30MHz且采样的时间=3个周期时,
Tconv = (3+12 = 15周期) /30MHz = 0.5us
3.数据对齐方式(左右对齐)
数据位存储至CR2 32位寄存器中,实际存储数据的只有16位,而STM32最大读取只能是12位分辨率
所以在存储数据的时候采用左、右对齐方式供用户进行使用,一般使用右对齐方式存储数据,当然
也可以使用左对齐的方式只是我们寄存器数据的时候需要将数据进行右移4位
4.单次转换与连续转换
两个转换都是针对单个通道进行,比如channal_1,单次转换顾名思义就是对channal_1只转换一次就
结束了,连续转换就是对channal_1转换完成一次之后,立即对channal_1开启下一次转换
5.扫描模式:
针对多个通道扫描的方式进行转换,比如有15个通道,会将这15个通道依次进行转换,如果同时也开
启了连续转换的话,会再次从通道一开始依次转换(故多通道可以开启连续转换+扫描模式)
main中生成如下代码并修改
static void MX_ADC2_Init(void)
{
/* USER CODE BEGIN ADC2_Init 0 */
/* USER CODE END ADC2_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC2_Init 1 */
/* USER CODE END ADC2_Init 1 */
/** Common config
*/
hadc2.Instance = ADC2;
hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc2.Init.Resolution = ADC_RESOLUTION_12B;
hadc2.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc2.Init.ContinuousConvMode = ENABLE;
hadc2.Init.DiscontinuousConvMode = DISABLE;
hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc2.Init.NbrOfConversion = 2;
hadc2.Init.DMAContinuousRequests = ENABLE;
hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc2.Init.LowPowerAutoWait = DISABLE;
hadc2.Init.Overrun = ADC_OVR_DATA_PRESERVED;
if (HAL_ADC_Init(&hadc2) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_3;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.SamplingTime = ADC_SAMPLETIME_19CYCLES_5;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_4;
sConfig.Rank = ADC_REGULAR_RANK_2;
if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC2_Init 2 */
//添加如下代码,开启ADC+DMA 并将数据存储至ADC_DMA_ConvertedValue中
(定义:volatile uint16_t ADC_DMA_ConvertedValue[2];)
HAL_ADC_Start_DMA(&hadc2,(uint32_t*)ADC_DMA_ConvertedValue,2);
/* USER CODE END ADC2_Init 2 */
}
main文件中增加这个转换成电压的函数,while循环中调用,获取的数据的时候有必要延时一下
static void Get_Data(float *temp,uint8_t times){
uint32_t temp_val[2]={0};
uint8_t t=0;
for(t=0;t<times;t++)
{
HAL_ADC_Start_DMA(&hadc2,(uint32_t*)&ADC_DMA_ConvertedValue,4);
temp_val[0]+=ADC_DMA_ConvertedValue[0];
temp_val[1]+=ADC_DMA_ConvertedValue[1];
// delay_ms(5);
}
temp[0]=(float)temp_val[0]/times*3.3/4096;
temp[1]=(float)temp_val[1]/times*3.3/4096;
}