0
\$\begingroup\$

I am working on a simple microcontroller based proportional controller to regulate the temperature of a heater cartridge using a feedback thermistor. I'm using the 'black pill' STM32F103C8T6 and have the controller working however I would like to send out time stamp and temperature readings over UART so that I can plot a graph of the temperature output vs time and use the Ziegler-Nichols method to obtain integral and derivative values (by obtaining the ultimate period of oscillation and ultimate gain).

I played around with DMA mode and ADC but had a lot of troubles so ended up using the simple polling method mentioned in the answer here:

The controller works in the main loop:

 /* USER CODE BEGIN 2 */
  usart_send_string("READY");
  HAL_ADC_Start(&hadc1);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {

     if (HAL_ADC_PollForConversion(&hadc1, 1000000) == HAL_OK){
         waxThermistor = HAL_ADC_GetValue(&hadc1);
         temperatureInDegrees = read_temp(waxThermistor); //Calculates the value in degrees using a look up table
     }

     if(heater==1){
         HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1); //PWM for heater element
         heater = 0;
     }

     int currentTemperature = temperatureInDegrees;
     int pi = PI(30,currentTemperature,50,0); //returns the controller value P + I
     int actuate = limitActuation(pi,0,500); //Limits the actuation range between 0% and 50% duty cycle
     htim3.Instance->CCR1 = actuate; //Sets the duty cycle
     sendTemperature(currentTemperature); //transmits the temperature over UART
    /* USER CODE END WHILE */  

I would like to be able to send out a time value along with the temperature. I tried removing the polling and placing waxThermistor = HAL_ADC_GetValue(&hadc1);in the interrupt routine for a 20ms timer (using OC mode) however I no longer get any PWM output as the ADC value is just returning 0 all the time. Could anyone recommend a better method for ADC sampling at a regular known interval rather than polling like this?

One possible solution I thought of would be to setup the ADC to trigger conversion on a timer and then read the sample in the conversion complete callback function. The time elapsed would then be the time between triggers + time taken for conversion to complete which can be calculated through the formulas given here. Would this be a viable solution?

For example if sampling every 20ms, the data sent out over UART would look like:

0ms;25c\n
20ms;27c\n
40ms;35c\n
\$\endgroup\$
1
  • 1
    \$\begingroup\$ You should configure the Timer & ADC such that the Timer directly triggers the ADC to perform a conversion, and then use the ADC's Conversion-Complete interrupt to read the result. You shouldn't need to use the TImer's interrupt and write code to start the ADC there. \$\endgroup\$ – brhans Sep 27 '20 at 19:17
1
\$\begingroup\$

Prepend an external sample&hold circuit to the ADC input. Create some hardware-based pacer (oscillator->counter) whose edge will disengage the S&H from its signal source and trigger an interrupt in the MCU. The ISR latency in the MCU can then be somewhat relaxed, as the sampling point in time will be hardwired from the HW-based pacer... Remember to re-engage the S&H by the MCU program, after an AD conversion has happend.

EDIT: the comment by @brhans is likely more to the point and more HW-specific than my general response.

I mean: modern-day ADC's (certainly those doing successive approximation) typically have an S&H stage integrated, otherwise they wouldn't be much use (would require external components) = if there's an on-chip periodic timer/counter in the MCU that can trigger the on-chip AD conversion, it likely also disengages the S&H as the very first step in the AD conversion process. If that's the case, indeed all you need to do is wait for the "conversion completed" interrupt.

Just in case you wanted a timestamp of the "S&H disengaged" event, you would possibly need the timer (pacer) to give you a timestamp of the event... if at all possible. Or you could just increment the timestamp based on your knowledge of some initial time and the number of samples taken/elapsed. Not sure how precise a timestamp you can take intially, but the relative temporal precision of the isochronous / evenly spaced sampling points can be pretty good. The question then is, if your "system wall clock" runs along the same reference as the pacer clock = if they can deviate / wander against each other etc. The devil's in the details :-)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.