参考:
mcu型号:stm32l0系列,
采样通道:采样ADC_CHANNEL_1和ADC_CHANNEL_VREFINT多个通道,后者在电源电压变化时,比如电池供电,准确测量当前采样通道ADC_CHANNEL_xxx电压时会用到。
1.初始化配置项说明:
ADC_ChannelConfTypeDef sConfig = {0};
以下列代码为例进行说明:
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc.Instance = ADC1;
hadc.Init.OversamplingMode = DISABLE; //过采样是否使能
hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; //ADC采用同步时钟PCLK分频系数
hadc.Init.Resolution = ADC_RESOLUTION_12B; //12位转换
hadc.Init.SamplingTime = ADC_SAMPLETIME_160CYCLES_5; //采样时间
hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ContinuousConvMode = DISABLE;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc.Init.DMAContinuousRequests = DISABLE;
hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc.Init.LowPowerAutoWait = DISABLE;
hadc.Init.LowPowerFrequencyMode = DISABLE;
hadc.Init.LowPowerAutoPowerOff = DISABLE;
if (HAL_ADC_Init(&hadc) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_1; //Ñ¡ÔñͨµÀ
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_VREFINT;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
这里注意说明几个需要解释的配置:
1)ScanConvMode :对应操作ADC_CFGR1寄存器 SCANDIR位,用于在我们使用多通道采样时,同来配置扫描顺序,比如使用了通道1、通道2、通道4,是用来配置1-2-4的采样顺序还是4-2-1的采样顺序。这里我们举例ADC_SCAN_DIRECTION_FORWARD,即采样顺序由小到大来说明。
2)下面的ContinuousConvMode和DiscontinuousConvMode需要放在一起讲:
ContinuousConvMode :对应操作ADC_CFGR1寄存器 CONT位,使能表示其置1。
DiscontinuousConvMode :对应ADC_CFGR1 寄存器中的 DISCEN 位,使能表示其置1
当CONT =0,DISCEN =0时,当我们调用一次HAL_ADC_Start(&hadc)开启ADC转换后,那么实际上你使用的通道1,2,4都会依次自动进行AD采样,每次AD转换结束会EOC置1。注意你这里只开启了一次ADC,但实际上根据你使用的n个通道,进行了n次AD转换。所有通道AD转换1轮结束后结束。
当CONT =0,DISCEN =1时,那么当我们调用一次HAL_ADC_Start(&hadc)开启ADC转换后,会对通道1进行AD采样,并在AD转换结束会EOC置1。如果你想获得下个信道2的值,需要再开启一次ADC转换(再调用一次HAL_ADC_Start(&hadc))。即每开启一次ADC,执行一次通道转换。开启ADC->转换通道1->开启ADC->转换通道2->开启ADC->转换通道4->开启ADC->转换通道1->开启ADC->转换通道2....顺序执行,这种方式我们如果轮训接收的话,优点是不会错过对应的通道采集数据。
当CONT =1,DISCEN =0时,,当我们调用一次HAL_ADC_Start(&hadc)开启ADC转换后,那么实际上你使用的通道1,2,4都会依次自动进行AD采样,并且所有通道AD转换1轮后会继续下一轮转换。
CONT =1,DISCEN =1参考手册明确说明不支持这么操作。
3)LowPowerAutoWait和LowPowerAutoPowerOff:这两个使能后都是可以实现降低功耗的配置,LowPowerAutoWait配置的是ADC_CFGR1 寄存器中的 WAIT位,置 1,则仅当之前的数据已进行处理、 ADC_DR 寄存器已读取或者 EOC 位已清零后,才会开始新的转换。比如CONT =0或1,DISCEN =0,我们开启ADC转换后不是各个通道会自动转换嘛,我们可以将该位使能,那么只有当我们读取ADC_DR 寄存器即一个通道的数据后,才会自动采样下一个通道,这样,如果我们的代码是轮训,就不怕错过哪个信道采样了我们没来的及读取导致无法确定当前采样到底是哪个通道的数据了。
LowPowerAutoPowerOff:也称为自动关闭模式,将 ADC_CFGR1 寄存器中的 AUTOFF位置 1 可使能此模式。使能后,当ADC未进行转换时,会自动关闭ADC,实现降低功耗的目的。并且,当我们重新开始采集时,并不会将采集通道的顺序进行复位。比如说我们通道1-2-4,刚采集了1通道,再次开启后,会从2采集,再次开启,会采集4.而不是复位到1重新开始。
下面两种示例均可实现依次获取AD通道的数据。
代码:CONT =0,DISCEN =1时代码示例如下:
初始化:
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC_Init 1 */
/* USER CODE END ADC_Init 1 */
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc.Instance = ADC1;
hadc.Init.OversamplingMode = DISABLE;
hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
hadc.Init.Resolution = ADC_RESOLUTION_12B;
hadc.Init.SamplingTime = ADC_SAMPLETIME_79CYCLES_5;
hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ContinuousConvMode = DISABLE;//DISABLE;
hadc.Init.DiscontinuousConvMode = ENABLE;//ENABLE;// DISABLE;//
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc.Init.DMAContinuousRequests = DISABLE;
hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc.Init.LowPowerAutoWait = ENABLE;//DISABLE;
hadc.Init.LowPowerFrequencyMode = DISABLE;
hadc.Init.LowPowerAutoPowerOff = ENABLE;
if (HAL_ADC_Init(&hadc) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_1; //Ñ¡ÔñͨµÀ
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_VREFINT;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
轮询:
u8 data[10] ={1,2,6,0,0,0,7};
HAL_ADCEx_Calibration_Start(&hadc, ADC_SINGLE_ENDED); //校准
while (1)
{
// /* USER CODE END WHILE */
HAL_ADC_Start(&hadc);
u8 ret = HAL_ADC_PollForConversion(&hadc, 100); //等待转换完毕
if(HAL_OK == ret){
u16 num = HAL_ADC_GetValue(&hadc); //依次获得通道1和参考电压通道的值
data[3] = num>>8&0xff;
data[4] = num&0xff;
data[5] = tmp++;
HAL_UART_Transmit(&huart2, data, 6, 2000);
}
}
代码:
CONT =1,DISCEN =0时,示例代码:
hadc.Init.LowPowerAutoWait = ENABLE;
hadc.Init.LowPowerFrequencyMode = DISABLE;
hadc.Init.LowPowerAutoPowerOff = ENABLE;
轮询:
HAL_ADC_Start(&hadc); //只需要开启一次
while (1)
{
/* USER CODE END WHILE */
u8 ret = HAL_ADC_PollForConversion(&hadc, 100);
if(HAL_OK == ret){
u16 num = HAL_ADC_GetValue(&hadc); //自动等待使能,只有读取后才会开启下一通道采集
data[3] = num>>8&0xff;
data[4] = num&0xff;
data[5] = tmp++;
HAL_UART_Transmit(&huart2, data, 6, 2000);
}
}