Problem with mils not working with max6675 library.

Post here first, or if you can't find a relevant section!
Ciceron
Posts: 5
Joined: Wed Sep 27, 2023 1:21 am

Problem with mils not working with max6675 library.

Post by Ciceron »

Hi all.
I encountered a problem on the bluepill board, the max6675 library with a mils delay refuses to work correctly.
For the library itself to work, a delay of 250 or more is required, but since the sketch uses a PID, such delays lead to unstable operation.

When using classic milis processing
if ((millis()-timer ) >= 500)
{
temp1 = thermocouple.readCelsius();
Serial.println(thermocouple.readCelsius());
timer = millis();
}
The sensor is polled only at startup. The processing itself works correctly because printing into the serial comes with the required timings.
I also used an SPI display in the project, but the max6675 refused to work on the same bus. started using the second SPI for MAX.

Used libraries
#include <Wire.h>
#include <TFT_eSPI.h>
#include <SPI.h>
#include <STM32RTC.h>
#include <RotaryEncoder.h>
#include <max6675.h>
#include <PID_v1.h>

Could you please tell me how to get rid of delay. or perhaps there are alternatives?
ozcar
Posts: 143
Joined: Wed Apr 29, 2020 9:07 pm
Answers: 5

Re: Problem with mils not working with max6675 library.

Post by ozcar »

Ciceron wrote: Wed Sep 27, 2023 1:37 am
When using classic milis processing

Code: Select all

 if ((millis()-timer ) >= 500)
           {
        temp1 = thermocouple.readCelsius();
        Serial.println(thermocouple.readCelsius());
        timer = millis();
         }
Maybe you need to explain more as to what the problem actually is. Does the code as you showed work OK, but stops working if you reduce the 500ms? Or the value you get in temp1 and/or the value as displayed is not as expected? Or ?????

What sort of thermocouple are you using and what response time are you expecting the thermocouple itself to have? What I know about thermocouples could fit on the back of a postage stamp without even needing a small font, but uncle G suggests response times of several seconds are not unusual.

The MAX6675 data sheet says that the conversion time is “typically” 170ms but can be up to 220ms. It also says that taking /CS low (which is required to read a result from it) will stop any conversion in progress, and then a new conversion will start when /CS goes high again. That means that you could prevent it from ever completing a conversion if you try to read from it too frequently.

The data sheet does not seem to say exactly what you get if you do try to read it before a conversion completes, and I don’t have one to test. If it returns the last successfully converted result, then maybe the code you showed would display a correct result every 500ms (assuming you keep calling it). On the other hand, if the MAX6675 returns some partially converted result when you try to read from it when a conversion is in progress, then temp1 might get a correct value but what you display there would be rubbish, as a new conversion would be started by temp1 = thermocouple.readCelsius() and there would certainly not be enough time for that to complete by the time you call thermocouple.readCelsius() again to display the result.

BTW, I took a quick look at the Adafruit MAX6675 library (I guess that is what you are using) and it uses only digitalWrite(), digitalRead(), and delayMicroseconds(), so you are not constrained to use only SPI capable pins.
Ciceron
Posts: 5
Joined: Wed Sep 27, 2023 1:21 am

Re: Problem with mils not working with max6675 library.

Post by Ciceron »

The code that I presented works but the sensor readings are not menud. are read only once at startup.

I use a standard K type thermocouple. I also know that it is not read quickly. The problem is that it is not read when calling millis, but only when delay.

Yes, I know about the problem of reading too often, that’s why I wanted to use Milis, but it didn’t work.

Yes Adafruit MAX6675 library.

Here's my sketch, maybe I'm missing something?

Code: Select all

#include <Arduino.h>
#include <Wire.h>
#include <TFT_eSPI.h> // Hardware-specific library
#include <SPI.h>

#define TFT_GREY 0x5AEB

TFT_eSPI tft = TFT_eSPI();       // Invoke custom library

uint32_t targetTime = 0;                    // for next 1 second timeout

static uint8_t conv2d(const char* p); // Forward declaration needed for IDE 1.6.x

int hh = 0, mm = 0, ss = 0; // Get H, M, S from compile time

byte omm = 99, oss = 99;
byte xcolon = 0, xsecs = 0;
unsigned int colour = 0;

/////////
#include <STM32RTC.h>
STM32RTC& rtc = STM32RTC::getInstance();
const byte seconds = 0;
const byte minutes = 0;
const byte hours = 0;

///////////////
int pinPID_out = PA8;
int piddata = 50;

//////////////////////
unsigned long timer;
unsigned long timing1;

/////////////
#include <RotaryEncoder.h>
#define PIN_A   PB4 //ky-040 clk pin, add 100nF/0.1uF capacitors between pin & ground!!!
#define PIN_B   PB3 //ky-040 dt  pin, add 100nF/0.1uF capacitors between pin & ground!!!
#define BUTTON  PB5 //ky-040 sw  pin, add 100nF/0.1uF capacitors between pin & ground!!!
uint8_t position = 0;
RotaryEncoder encoder(PIN_A, PIN_B, BUTTON);

//////////
#include <max6675.h>
int temp1 = 0;
int thermoDO = PB14;
int thermoCS = PA15;
int thermoCLK = PB13;
MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);

/////////////////
#include <PID_v1.h>
double Setpoint, Input_pid, Output_pid;
double Kp=20, Ki=0.1, Kd=2;
PID myPID(&Input_pid, &Output_pid, &Setpoint, Kp, Ki, Kd, DIRECT);


///////////////
void encoderISR()
{
  encoder.readAB();
}
void encoderButtonISR()
{
  encoder.readPushButton();
}


void setup(void) {
  Serial.begin(9600);
  Serial.println("Serial start."); 
  
  tft.init();
  tft.setRotation(1);
  tft.fillScreen(TFT_BLACK);
  tft.setTextSize(1);
  tft.setTextColor(TFT_YELLOW, TFT_BLACK);

  rtc.setClockSource(STM32RTC::LSE_CLOCK);
  rtc.begin(); // initialize RTC 24H format
  // Set the time
  rtc.setHours(hh);
  rtc.setMinutes(mm);
  rtc.setSeconds(ss);

  /////////////////////

  encoder.begin();                                                           //set encoders pins as input & enable built-in pullup resistors
  attachInterrupt(digitalPinToInterrupt(PIN_A),  encoderISR,       CHANGE);  //call encoderISR()    every high->low or low->high changes
  attachInterrupt(digitalPinToInterrupt(BUTTON), encoderButtonISR, FALLING); //call pushButtonISR() every high->low              changes

  ///////
  myPID.SetMode(AUTOMATIC);
 delay(500);
}

void loop() {
  ////////////////////
   //Serial.println("loop"); 
      /////////RTС/////////////////////
   hh = rtc.getHours();
   mm = rtc.getMinutes();
   ss = rtc.getSeconds();
   
  /////////
    int xpos = 120;
    int ypos = 10;
    int ysecs = ypos + 24;
    tft.drawString("Job time", 10, 10,4);
  ////////////
      if (hh < 10)
      {
        xpos += tft.drawChar('0', xpos, ypos, 6);
      }
      xpos += tft.drawNumber(hh, xpos, ypos, 6);
      xpos += tft.drawChar(':', xpos, ypos - 4, 6);
      if (mm < 10)
      {
        xpos += tft.drawChar('0', xpos, ypos, 6);
      }
      xpos += tft.drawNumber(mm, xpos, ypos, 6); 
      xpos += tft.drawChar(':', xpos, ypos - 4, 6);
      if (ss < 10)
      {
         xpos += tft.drawChar('0', xpos, ypos, 6);
      }
      xpos += tft.drawNumber(ss, xpos, ypos, 6);  
/////////////
myPID.Compute();
Setpoint=position;
Input_pid=temp1;
position = encoder.getPosition();

int xpos1 = 120;
int ypos1 = 60;
tft.drawString("Set temp", 10, 70,4);
if (position <10)
    {
    xpos1 += tft.drawChar('0', xpos1, ypos1, 6);
    }
    if (position <100)
    {
      xpos1 += tft.drawChar('0', xpos1, ypos1, 6);
    }
tft.drawNumber (position, xpos1,ypos1, 6);
/////////
tft.drawString("Current temp", 10, 120,4);
int xpos2 = 160;
int ypos2 = 120;
        if (temp1 <10)
          {
          xpos2 += tft.drawChar('0', xpos2, ypos2, 6);
          }
        if (temp1 <100)
          {
          xpos2 += tft.drawChar('0', xpos2, ypos2, 6);
          }
    tft.drawNumber (temp1, xpos2,ypos2, 6);
    
    
  ///
    tft.drawString("Current PWM", 10, 180, 4);
    int xpos3 = 180;
    int ypos3 = 180;
    if (Output_pid < 10)
    {
    xpos3 += tft.drawChar('0', xpos3, ypos3, 6);
    }
    if (Output_pid < 100)
    {
    xpos3 += tft.drawChar('0', xpos3, ypos3, 6);
    }
    tft.drawNumber(Output_pid, xpos3, ypos3, 6);

//////
       // if ((millis()-timer ) >= 500)
       //   {     
       //  temp1 = thermocouple.readCelsius();
       //  ///Serial.println(thermocouple.readCelsius());
       //  timer  = millis();
       //   }
Serial.println(temp1);
temp1 = thermocouple.readCelsius();
analogWrite(pinPID_out, Output_pid); 
delay(1000);
it works unstable due to delay and PID library
and if you uncomment the millis block, the temperature is read only once.
ozcar
Posts: 143
Joined: Wed Apr 29, 2020 9:07 pm
Answers: 5

Re: Problem with mils not working with max6675 library.

Post by ozcar »

Not having all your hardware, I can’t lift up your whole program and try it. However I can pretend that I have a MAX6675 attached, and when I include this in the loop()

Code: Select all

if ((millis()-timer ) >= 500)
   {
     temp1 = thermocouple.readCelsius();
     Serial.println(temp1);
     timer = millis();
   }

delay(1000);

then it ticks over displaying “0” every second. If I change the last line to delay(1) it then prints out the “0” every 500ms (times as confirmed by turning on the timestamp in the Arduino serial monitor). Given it is reading from a floating input here instead of a MAX6675 I guess it could display any old rubbish, but there is certainly no indication of any problem with millis() or the logic that gets it to read and print the thermocouple.readCelsius() value.

I see you did not initialise “timer” before using it the first time, and so I also did not do that, but it ended up in zeroed storage so that did not cause any trouble for me. However, just to be sure about that you could either zero it or set it equal to millis() in setup(). Assuming that does not help, all I can suggest is to print millis() and timer in the loop and see where that gets you.
ag123
Posts: 1653
Joined: Thu Dec 19, 2019 5:30 am
Answers: 24

Re: Problem with mils not working with max6675 library.

Post by ag123 »

in setup() add

Code: Select all

timer = millis();
you forgot to initialize the variable. And use \[code\] blocks to enclose the code in posts here, that makes it much more readable.
(global) variables that are uninitialised takes an undefined value, not necessary 0 (zero). imagine that it is 0xffffff, then that loop is never run.
dannyf
Posts: 446
Joined: Sat Jul 04, 2020 7:46 pm

Re: Problem with mils not working with max6675 library.

Post by dannyf »

as others have mentioned, you need to help others to help you - a difficult spot to be in.

short of that, two observations:
1. whether that particular loop works depends on many factors, including the initial value of "timer" and its type.
2. unstable control loop is often due to too much gain, or incorrect polarity.
dannyf
Posts: 446
Joined: Sat Jul 04, 2020 7:46 pm

Re: Problem with mils not working with max6675 library.

Post by dannyf »

Here's my sketch, maybe I'm missing something?
maybe you want to change the way you write your code. I would do something like this.

Code: Select all

  //update the display
  if (millis() - timer_display > PR_DISPLAY) {
    timer_display += PR_DISPLAY; //advance to the next update point
    //update the display
    update_display();
  }
  
  //read the probe
  if (millis() - timer_temp > PR_TEMP) {
    timer_temp += PR_TEMP; //advance to the next update point
    //read the temp
    read_probe();
  }

  //update the pid
  if (millis() - timer_pid > PR_PID) {
    timer_pid += PR_PID; //advance to the next update point
    //update the pid
    pid_compute();
  }
  
  ...
this allows each function to be independently executed, at intervals you decide (PR_PID, PR_TEMP, PR_DISPLAY, ...)
Ciceron
Posts: 5
Joined: Wed Sep 27, 2023 1:21 am

Re: Problem with mils not working with max6675 library.

Post by Ciceron »

ag123 wrote: Thu Sep 28, 2023 6:15 am in setup() add

Code: Select all

timer = millis();
you forgot to initialize the variable. And use \[code\] blocks to enclose the code in posts here, that makes it much more readable.
(global) variables that are uninitialised takes an undefined value, not necessary 0 (zero). imagine that it is 0xffffff, then that loop is never run.
I'll try to add it this evening.
however, I thought it was enough -
unsigned long timer;
in the variables section

Edit:did not work
Last edited by Ciceron on Fri Sep 29, 2023 12:37 am, edited 1 time in total.
Ciceron
Posts: 5
Joined: Wed Sep 27, 2023 1:21 am

Re: Problem with mils not working with max6675 library.

Post by Ciceron »

dannyf wrote: Thu Sep 28, 2023 11:34 am
Here's my sketch, maybe I'm missing something?
maybe you want to change the way you write your code. I would do something like this.

Code: Select all

  //update the display
  if (millis() - timer_display > PR_DISPLAY) {
    timer_display += PR_DISPLAY; //advance to the next update point
    //update the display
    update_display();
  }
  
  //read the probe
  if (millis() - timer_temp > PR_TEMP) {
    timer_temp += PR_TEMP; //advance to the next update point
    //read the temp
    read_probe();
  }

  //update the pid
  if (millis() - timer_pid > PR_PID) {
    timer_pid += PR_PID; //advance to the next update point
    //update the pid
    pid_compute();
  }
  
  ...
this allows each function to be independently executed, at intervals you decide (PR_PID, PR_TEMP, PR_DISPLAY, ...)
Interesting solution. it really makes sense since there may be a conflict with delay or millis which are located in the PID or Encoder libraries.

I'll try and write back.
Ciceron
Posts: 5
Joined: Wed Sep 27, 2023 1:21 am

Re: Problem with mils not working with max6675 library.

Post by Ciceron »

Interesting. The data output has become clearly more correct.

If previously information was displayed mainly in integers 80,81,82, etc., now
113.50
113.00
113.25
113.25
113.50
112.50
112.00
but for some reason a bug remains - at one point the readings are not readable.
Log
65.25
65.25
65.25
65.25
65.25
65.25
65.25
103.75
103.75
106.00
105.75
Frozen and change from 65 to 105
Post Reply

Return to “General discussion”