ADC外设做为沟通数字电路与模拟电路的桥梁,其作用不言而喻。在大多数项目应用中,ADC采样均为周期采样。比如温度每5秒采样一次,电流采样可能10ms一次,1000ms一次等。这样,不仅便于滤波,而且更便于反映真实的模拟世界的情况。下面,我们就在STM32F407上实现ADC的软件方式触发周期采样。
STM32F407在实现软件触发ADC采样都是分为两部分,第一部分是ADC外设的初始化;第二部分是软件周期触发。第一部分的ADC外设初始化是标准的,流程的,必须按照手册来执行
/* ADC handle declaration */
ADC_HandleTypeDef hadc1;
/**
* @brief ADC1 Initialization Function
* @param None
* @retval None
*/
void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
/* 1. Enable ADC1 Clock */
__HAL_RCC_ADC1_CLK_ENABLE();
/* 2. Configure ADC Global Parameters */
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; /* ADC clock <= 36MHz */
hadc1.Init.Resolution = ADC_RESOLUTION_12B; /* 12-bit resolution */
hadc1.Init.ScanConvMode = DISABLE; /* Single channel, no scan */
hadc1.Init.ContinuousConvMode = DISABLE; /* Single conversion mode */
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; /* Software trigger */
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; /* Right alignment */
hadc1.Init.NbrOfConversion = 1; /* 1 conversion in sequence */
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
/* 3. Configure ADC Channel 0 (PA0) */
sConfig.Channel = ADC_CHANNEL_0; /* Select Channel 0 */
sConfig.Rank = 1; /* Rank 1 in regular sequence */
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES; /* Longest sampling time for stability */
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
/* Configuration Error */
Error_Handler();
}
}
/**
* @brief ADC MSP Initialization
* This function configures the hardware resources used in this example:
* - Peripheral's clock enable
* - Peripheral's GPIO Configuration
* @param hadc: ADC handle pointer
* @retval None
*/
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(hadc->Instance == ADC1)
{
/* 1. Enable GPIOA Clock */
__HAL_RCC_GPIOA_CLK_ENABLE();
/* 2. Configure PA0 as Analog Input */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
}第二部分就是软件周期触发。这里我常用两种方式来实现,一种是通过systick计时,并在while(1)检查是否溢出;
while(1)
{
if(adc_tick_cnt == 0)
{
/* Start ADC Conversion */
if (HAL_ADC_Start(&hadc1) != HAL_OK)
{
return 0; /* Return 0 if start failed */
}
/* Wait for End Of Conversion (with timeout) */
if (HAL_ADC_PollForConversion(&hadc1, 100) != HAL_OK)
{
return 0; /* Return 0 if timeout or error */
}
/* Get ADC Converted Value */
adc_value = HAL_ADC_GetValue(&hadc1);
/* Stop ADC to save power (optional for single shot) */
HAL_ADC_Stop(&hadc1);
}
}另一种是通过RTOS的delay()函数来实现的周期触发;
void adc_sample_task(void)
{
vTaskDelay(100);
adc_volt_get(&volt_buf[0]);
}ADC软件触发流程简单,代码清晰,检查起来也非常方便。但由于ADC软件触发的周期性并不严格,所以对于一些实时性强要求的应用来说,软件触发的时间偏差不是被允许的。下一期,我们一起使用定时器来实现严格的周期采样。
我要赚赏金
