I have an ADC with two channels on a Nucleo F401RE: one that reads values from a thermistor (channel 8, rank 1) and another that reads values from a potentiometer (channel 1, rank 2). Pressing the button on the microcontroller is supposed to switch between the channels, but I can only switch from channel 8 to channel 1
I tried to switch their ranks or give them the same rank but it does'n work.
void change_channel(uint32_t channel, uint32_t rank)
{ ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = channel;
sConfig.Rank = rank;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
global_channel=sConfig.Channel;
global_rank= sConfig.Rank;
}
I also tried to disable the other channel but it still doesn't work.(it will read values only from the potentiometer).When i try to give sConfig.Rank = 2 when i disable the channels i read a value around 1310 for the termistor and i don't know where it comes from.
void change_channel(uint32_t channel, uint32_t rank)
{
ADC_ChannelConfTypeDef sConfig = {0};
// Disable all channels
for (uint32_t ch = ADC_CHANNEL_0; ch <= ADC_CHANNEL_10; ch++) // Adjust range based on your MCU's ADC channels
{
sConfig.Channel = ch;
sConfig.Rank = 0; // Set rank to 0 to disable the channel (no valid rank)
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
// Enable the desired channel
sConfig.Channel = channel;
sConfig.Rank = rank; // Explicitly set the desired rank
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
// Store the global variables for tracking
global_channel = sConfig.Channel;
global_rank = sConfig.Rank;
}
I read the values in the second task(mod is a variable that changes between 0 and 1 when i press the button to help me select the channel, 0 means automatic mode and 1 means manual mode)text
void StartTask02(void *argument)
{
/* USER CODE BEGIN StartTask02 */
float readValue;
float voltage;
float d=3.3;
int mod1;
/* Infinite loop */
for(;;)
{osMessageQueueGet (mod_for_ADCHandle, &mod1, 0, 0);
if(mod1==0)//
{
change_channel(8,1);
HAL_ADC_Start(&hadc1);
if(HAL_ADC_PollForConversion(&hadc1,1000)==HAL_OK){
readValue=HAL_ADC_GetValue(&hadc1);
voltage=(float)readValue/(float)4095*d;
globalvoltage= voltage;
globalreadValue=readValue;
}
HAL_ADC_Stop(&hadc1);
osMessageQueuePut (queque_voltageHandle, &voltage, 0, 0);
osDelay(100);
}
if(mod1==1)//
{
change_channel(1,2);
HAL_ADC_Start(&hadc1);
if(HAL_ADC_PollForConversion(&hadc1,1000)==HAL_OK){
readValue=HAL_ADC_GetValue(&hadc1);
voltage=(float)readValue/(float)4095*d;
globalvoltage= voltage;
globalreadValue=readValue;
}
HAL_ADC_Stop(&hadc1);
osMessageQueuePut (queque_voltageHandle, &voltage, 0, 0);
osDelay(100);
}
}
/* USER CODE END StartTask02 */
}
ADC configuration
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = ENABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 2;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_8;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Rank = 2;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
I think you misunderstand how the ADC Scan Conversion Mode works.
With ScanConvMode
set to ENABLE and NbrOfConversion
set to 2 then the ADC will perform conversions on both channels after you call HAL_ADC_Start()
. First the ADC will select, sample, and convert the Rank 1 channel. Then the ADC will select, sample, and convert the Rank 2 channel. Your code should wait for and get the results of both conversions after calling HAL_ADC_Start()
. But now your code is only reading one conversion, which is the first or Rank 1.
You don't need to change the ADC configuration to "switch" channels with a button push. The ADC will sample and convert both channels each time you call HAL_ADC_Start()
. If you really want to output only one channel and switch that channel with a button push, then you only need to change which of the two conversions you output. But you should still wait for and get both conversions from the ADC.
If you really want to perform only one conversion at a time and switch the channel with a button push, then you should set NbrOfConversion
to 1, disable ScanConvMode
, and reconfigure which channel is Rank 1 before calling HAL_ADC_Start()
.