0
votes

I'm using the ADC channels (12-bit resolution) of a STM32F0 microcontroller to read voltage values in three different points of a board. What I want to do is to read the values every 2 seconds (I have 2 seconds to read the values in the three points) and send them by the UART interface. In order to select which ADC channel I'm reading I'm implementing the voltage reading functions as follows:

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;
}

This is the function for scanning one ADC channel. For reading the other two ADC channels I'm using the same procedure just changing the value of n in the line chConfig.Channel = ADC_CHANNEL_n; where n is the channel number. Note that chConfig is of the same type of sConfig declared in MX_ADC_Init() function, but chConfig is a global variable, should it be declared as a local variable within each function?

The problem I have is that readv1 function reads a constant voltage (I have checked it with a voltimeter) but the numbers showed in the terminal via UART change a lot, between 120 and 2400. I'm not sure if using the line chConfig.Channel = ADC_CHANNEL_1; for selecting a channel is good or if there is any other procedure to follow. How could I properly read the values of each ADC?

In order to do the scan the ADC every two seconds I'm using a 8 MHz timer as follows:

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);
    }
}

This is the main function where I initialize the periphericals:

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)
  {

  }
}

And below are the initialization functions for the timer and the 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();
  }

}
1
volt1 = readv1(); readv2(volt1); readv3(volt1); Why raeadv2() and readv3() take parameter volt1 but readv1() does not? You said "For reading the other two ADC channels I'm using the same procedure just changing the value of n in the line chConfig.Channel = ADC_CHANNEL_n; where n is the channel number." Try to add "volatile" for volt1 variable.Zhifei

1 Answers

0
votes

I solved the problem by modifying the functions as follows:

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;
}

I added the lines I mentioned in the three functions reading the ADC channels. Actually, as I'm using the same procedure for reading all the ADC channels I created a function which receives as parameter the channel number.