如何在STM32 MCU中每n秒每通道读取多个ADC接口?
How to read several ADCs interfaces every n seconds per channel in STM32 MCU?
我正在使用 STM32F0 微控制器的 ADC 通道(12 位分辨率)读取板上三个不同点的电压值。我想做的是每2秒读取一次值(我有2秒读取三个点中的值)并通过UART接口发送。为了 select 我正在读取哪个 ADC 通道,我正在按如下方式实现电压读取功能:
uint16_t readv1(void){
//Here I try to read ADC_CHANNEL_1
//chConfig and txtbuff are global variables:
//ADC_ChannelConfTypeDef chConfig;
//char txtbuff[64];
chConfig.Channel = ADC_CHANNEL_1;
HAL_ADC_ConfigChannel(&hadc, &chConfig);
uint32_t vref = HAL_ADC_GetValue(&hadc);
uint16_t vref2 = (uint16_t) vref;
sprintf(TextBuffer, "%u\n", vref2);
HAL_UART_Transmit(&huart4, (uint8_t*)txtbuff, strlen(txtbuff), 0xFFFFFFFF);
return vref2;
}
这是扫描一个ADC通道的功能。为了读取其他两个 ADC 通道,我使用相同的程序,只是更改 chConfig.Channel = ADC_CHANNEL_n;
行中 n
的值,其中 n
是通道编号。注意chConfig
和MX_ADC_Init()
函数中声明的sConfig
是同一类型,但是chConfig
是一个全局变量,是否应该在每个函数中都声明为局部变量?
我遇到的问题是 readv1
函数读取恒定电压(我已经用电压表检查过)但是通过 UART 在终端中显示的数字变化很大,在 120 到 2400 之间。我'我不确定使用 chConfig.Channel = ADC_CHANNEL_1;
行来 selecting 频道是否好,或者是否有任何其他程序可以遵循。我怎样才能正确读取每个 ADC 的值?
为了每两秒扫描一次 ADC,我使用了一个 8 MHz 定时器,如下所示:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if (htim->Instance==TIM3){
//Here I call the functions which read the voltage values of different ADC channels
volt1 = readv1();
readv2(volt1);
readv3(volt1);
}
}
这是我初始化外围设备的主要功能:
int main(void)
{
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART4_UART_Init();
MX_ADC_Init();
MX_TIM3_Init();
/* USER CODE BEGIN 2 */
HAL_ADC_Start_IT(&hadc);
HAL_TIM_Base_Start_IT(&htim3);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
}
}
下面是定时器和ADC的初始化函数:
/* TIM3 init function */
static void MX_TIM3_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
htim3.Instance = TIM3;
htim3.Init.Prescaler = 8000;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 1999;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
}
/* ADC init function */
static void MX_ADC_Init(void)
{
ADC_ChannelConfTypeDef sConfig;
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc.Instance = ADC1;
hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc.Init.Resolution = ADC_RESOLUTION_12B;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc.Init.LowPowerAutoWait = DISABLE;
hadc.Init.LowPowerAutoPowerOff = DISABLE;
hadc.Init.ContinuousConvMode = ENABLE;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc.Init.DMAContinuousRequests = DISABLE;
hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
if (HAL_ADC_Init(&hadc) != HAL_OK)
{
Error_Handler();
}
/**Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/**Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_1;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/**Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_2;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/**Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_4;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
我通过如下修改函数解决了问题:
uint16_t readv1(void){
chConfig.Channel = ADC_CHANNEL_1;
// I added these two lines after the ADC channel selection
chConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
chConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
// The first one will configure the ADC channel as enabled
// The second one is the sampling time (1.5)
HAL_ADC_ConfigChannel(&hadc, &chConfig);
// Then I added these two instructions:
HAL_ADC_Start_IT(&hadc);
HAL_ADCEx_Calibration_Start(&hadc);
// The first one starts the ADC in interruption mode
// The second one calls the calibration function
uint32_t vref = HAL_ADC_GetValue(&hadc);
// Finally I added these three last instructions:
HAL_ADC_Stop_IT(&hadc);
chConfig.Rank = ADC_RANK_NONE;
HAL_ADC_ConfigChannel(&hadc, &chConfig);
// The first one stops the ADC
// The second one will configure the ADC channel as disabled
// The third one sets the channel with the new parameters
uint16_t vref2 = (uint16_t) vref;
sprintf(TextBuffer, "%u\n", vref2);
HAL_UART_Transmit(&huart4, (uint8_t*)txtbuff, strlen(txtbuff), 0xFFFFFFFF);
return vref2;
}
我添加了我在读取 ADC 通道的三个函数中提到的行。实际上,由于我使用相同的程序读取所有 ADC 通道,因此我创建了一个函数,该函数接收通道号作为参数。
我正在使用 STM32F0 微控制器的 ADC 通道(12 位分辨率)读取板上三个不同点的电压值。我想做的是每2秒读取一次值(我有2秒读取三个点中的值)并通过UART接口发送。为了 select 我正在读取哪个 ADC 通道,我正在按如下方式实现电压读取功能:
uint16_t readv1(void){
//Here I try to read ADC_CHANNEL_1
//chConfig and txtbuff are global variables:
//ADC_ChannelConfTypeDef chConfig;
//char txtbuff[64];
chConfig.Channel = ADC_CHANNEL_1;
HAL_ADC_ConfigChannel(&hadc, &chConfig);
uint32_t vref = HAL_ADC_GetValue(&hadc);
uint16_t vref2 = (uint16_t) vref;
sprintf(TextBuffer, "%u\n", vref2);
HAL_UART_Transmit(&huart4, (uint8_t*)txtbuff, strlen(txtbuff), 0xFFFFFFFF);
return vref2;
}
这是扫描一个ADC通道的功能。为了读取其他两个 ADC 通道,我使用相同的程序,只是更改 chConfig.Channel = ADC_CHANNEL_n;
行中 n
的值,其中 n
是通道编号。注意chConfig
和MX_ADC_Init()
函数中声明的sConfig
是同一类型,但是chConfig
是一个全局变量,是否应该在每个函数中都声明为局部变量?
我遇到的问题是 readv1
函数读取恒定电压(我已经用电压表检查过)但是通过 UART 在终端中显示的数字变化很大,在 120 到 2400 之间。我'我不确定使用 chConfig.Channel = ADC_CHANNEL_1;
行来 selecting 频道是否好,或者是否有任何其他程序可以遵循。我怎样才能正确读取每个 ADC 的值?
为了每两秒扫描一次 ADC,我使用了一个 8 MHz 定时器,如下所示:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if (htim->Instance==TIM3){
//Here I call the functions which read the voltage values of different ADC channels
volt1 = readv1();
readv2(volt1);
readv3(volt1);
}
}
这是我初始化外围设备的主要功能:
int main(void)
{
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART4_UART_Init();
MX_ADC_Init();
MX_TIM3_Init();
/* USER CODE BEGIN 2 */
HAL_ADC_Start_IT(&hadc);
HAL_TIM_Base_Start_IT(&htim3);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
}
}
下面是定时器和ADC的初始化函数:
/* TIM3 init function */
static void MX_TIM3_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
htim3.Instance = TIM3;
htim3.Init.Prescaler = 8000;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 1999;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
}
/* ADC init function */
static void MX_ADC_Init(void)
{
ADC_ChannelConfTypeDef sConfig;
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc.Instance = ADC1;
hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc.Init.Resolution = ADC_RESOLUTION_12B;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc.Init.LowPowerAutoWait = DISABLE;
hadc.Init.LowPowerAutoPowerOff = DISABLE;
hadc.Init.ContinuousConvMode = ENABLE;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc.Init.DMAContinuousRequests = DISABLE;
hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
if (HAL_ADC_Init(&hadc) != HAL_OK)
{
Error_Handler();
}
/**Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/**Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_1;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/**Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_2;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
/**Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_4;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
我通过如下修改函数解决了问题:
uint16_t readv1(void){
chConfig.Channel = ADC_CHANNEL_1;
// I added these two lines after the ADC channel selection
chConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
chConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
// The first one will configure the ADC channel as enabled
// The second one is the sampling time (1.5)
HAL_ADC_ConfigChannel(&hadc, &chConfig);
// Then I added these two instructions:
HAL_ADC_Start_IT(&hadc);
HAL_ADCEx_Calibration_Start(&hadc);
// The first one starts the ADC in interruption mode
// The second one calls the calibration function
uint32_t vref = HAL_ADC_GetValue(&hadc);
// Finally I added these three last instructions:
HAL_ADC_Stop_IT(&hadc);
chConfig.Rank = ADC_RANK_NONE;
HAL_ADC_ConfigChannel(&hadc, &chConfig);
// The first one stops the ADC
// The second one will configure the ADC channel as disabled
// The third one sets the channel with the new parameters
uint16_t vref2 = (uint16_t) vref;
sprintf(TextBuffer, "%u\n", vref2);
HAL_UART_Transmit(&huart4, (uint8_t*)txtbuff, strlen(txtbuff), 0xFFFFFFFF);
return vref2;
}
我添加了我在读取 ADC 通道的三个函数中提到的行。实际上,由于我使用相同的程序读取所有 ADC 通道,因此我创建了一个函数,该函数接收通道号作为参数。