Inzicht Arduino code

blackdog

Golden Member

Hi,

Om mijn mini oven die ik aan het ontwerpen ben heb ik een sensor nodig met voldoende hoge resolutie en welke niet afhankelijk is van bedradings eigenschappen.

Op het ogenblik gebruik ik hier meet NTC's voor die bij 25C 5K zijn.
Deze zou ik 4 draads kunnen uitvoeren om het wat beter te doe, maardat geeft ook weer meer draden naar buiten met natuurlijk energie lek.

Dus ik ben in mijn Temperatuur sensorbak gedoken en heb er een STM172 uit gehaald waarmee het mogelijk is redelijk snel een hoge resolutie temperatuur meting te doen.
De uitkomst wil ik dan middelen voor een wat stabielere uitlezing.
Deze sensor is een digitaal model, zodat bedradings weerstand geen rol speeld.

Het probleem is dat ik de code die ik hieronder laat zien niet goed begrijp, het zal echt iets in de basis zijn, maar ik begrijp de opset niet goed, waarom dit zo gedaan is.
Ik gebruik een stukje Arduino code die in een Library zit die voor de Arduino is gemaakt voor de STM172 Sensor.

Laat ik eerst even de code zien en dan ga ik verder met mijn vraag.

c code:


/*
 Demo sketch for the SMT172 library. 
 This sketch is intended for the ATmega328P (Uno, Nano, Pro Mini etc.)
 There is no timer2 on the ATmega32U4 (Pro Micro)
 The ICP1 pin is not exposed on the Mega2560R3 board so timer4 or timer5 must be
 used requiring a modification of the SMT172 library. This board also uses
 different pins for timer2.
 This sketch will output to serial.
 Connect the output of the SMT172 to pin 8 (Input Capture Pin of timer 1)
 Timer 2 is set up in phase correct PWM and output a duty cycle of
 10.98% ~-45.06 C on pin 3 and a duty cycle of 92.94% ~139.58 C on pin 11
 Connect pin 8 to pin 3 or pin 11 to check the working if no SMT172 is available
*/
#include <arduino.h>
#include <SMT172.h>
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C  lcd(0x3F,2,1,0,4,5,6,7); // 0x3F is the I2C bus address for an unmodified backpack of a PCF8574A

uint32_t LastSensorUpdate;



void setup() {
  // activate LCD module
  lcd.begin (16,2);                                // for 16 x 2 LCD module
  lcd.setBacklightPin(3,POSITIVE);
  lcd.setBacklight(HIGH);
  lcd.clear();
  
  Wire.begin();
  
	Serial.begin(115200);
	pinMode(8, INPUT);
	pinMode(12, OUTPUT);

//	The following code fragment sets up phase-correct PWM on pins 3 and 11 (Timer 2).
//	The waveform generation mode bits WGM are set to to 001 for phase-correct PWM.
//	The other bits are the same as for fast PWM.

	pinMode(3, OUTPUT);
	pinMode(11, OUTPUT);
	TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM20);
	// TCCR2B = _BV(CS22); // Output frequency: 16 MHz / 64 / 255 / 2 =  490.196 Hz
	TCCR2B = _BV(CS21); // Output frequency: 16 MHz /  8 / 255 / 2 = 3921.569 Hz
	OCR2A = 237; // Output A duty cycle: 237 / 255 = 92.94%	= 129.58 C	on pin 11
	OCR2B = 28;	 // Output B duty cycle:  28 / 255 = 10.98%	= -45.06 C	on pin 3
}



void loop() {

	// read the sensor every 250 millisecond
	if ((unsigned long) (millis() - LastSensorUpdate) >= 250) {
		LastSensorUpdate = millis();

		SMT172::startTemperature(0.001);

		repeat:
		switch (SMT172::getStatus()) {
		case 0: goto repeat; // O Dijkstra, be merciful onto me, for I have sinned against you :)
		case 1: Serial.print(F("Measuring time   [ms]: "));
				Serial.println(SMT172::getTime() * 1e3, 2); // convert to milliseconds
				Serial.print(F("Sensor frequency [Hz]: "));
				Serial.println(SMT172::getFrequency(), 2);
				Serial.print(F("Duty cycle        [%]: "));
				Serial.println(SMT172::getDutyCycle() * 100, 2);
				Serial.print(F("Temperature       [C]: "));
				Serial.println(SMT172::getTemperature(), 4);
				Serial.print(F("Error            [mK]: "));
				Serial.println(SMT172::getError() * 1000, 2);
				Serial.println();
				
 
// Bram frutsel om temperatuur op het LCD te krijgen
    lcd.clear();
    lcd.home();                // set cursor to 0,0
    lcd.setCursor (0,0);
    lcd.print("SMT172 "); 
    lcd.print(SMT172::getTemperature(), 4);
    lcd.print(" C"); 
// Bram frutsel om temperatuur op het LCD te krijgen				
				
				break;
		case 2: Serial.println(F("**** Sensor disconnected ****"));
				Serial.println();


   delay(10);        // delay in between reads for stability

   		}
	}
}

Om dus de temperatuur op het display te krijgen moet ik het stukje code "Bram Frutsel" binne het "Repeat" deel zetten.
Ik krijg de waarde (SMT172::getTemperature(), 4) niet buiten deze Repeat functie.
Dus wat zal de rede zijn dat de Library/Code maker dit zo heeft uitgevoerd en hoe kan ik de temperatuur functie buiten die Repeat functie krijgen voor andere functies zoals
status LED aansturing en het middelen dat ik wil gaan doen?

Twee van de vijf 2x 16 LCD die ik op voorraad had werkte er maar, ik dacht dat ik gek werd gisteren avond, had ook nog een nieuwe i2c printje en een nieuwe LCD display Bingo en het werkte.
Natuurlijk had ik met een i2c scanner het adres van het conversie printje achterhaald, daar zat het niet in, wel een beetje vreemd, maar nu geen probleem meer, het werkt met het nieuwe spul.
En ja, natuurlijk ook de contrast instelling gecontroleerd en bij display wissel een power cycle gedaan.

Plaatje van de simpele test setup, hier wordt de plastic TO92 versie gebruikt, ik heb hem ook nog in "metal can" die een wat hogere nauwkeurigheid heeft.
https://www.bramcam.nl/NA/NA-Mini-Oven/STM172-Breadboad-01.png

Ik hoor graag van jullie hoe ik de temperatuur gewoon in de loop kan gebruiken voor verdere bewerking.

Dank vast en groet,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.
Lucky Luke

Golden Member

In plaat van die goto repeat kan daar toch gewoon een break? En die delay(10) zit ‘m toch al in de if(milis() comstructie?

Afgezien daarvan: je zou in die elke-250-ms de temperatuur kunnen lezen en in een (globale) variabele kunnen stoppen, en die variabele dan daarbuiten kunnen lezen.

Nu lees je de temperatuur 2x uit. Die kan dus verschillen tussen je serial.print en de print-naar-lcd.

Ik zit nu niet achter een ‘echt’ toetsenbord, anders had ik het in de code zelf gezet.

Eluke.nl | De mens onderscheid zich van (andere) dieren door o.a. complexe gereedschappen en bouwwerken te maken. Mens zijn is nerd zijn. Blijf Maken. (Of wordt, bijvoorbeeld, cultuurhistoricus)

De SMT172 interface is asynchroon. Je kunt een conversie starten dmv startTemperature(..), en vervolgens moet je wachten tot de status 1 wordt voordat je de gegevens kunt uitlezen. Uitlezen tijdens conversie geeft foute resultaten.

Wel een rare construktie in dat voorbeeld. Erg onhandig met die repeat. Je programma zit vast gedurende de hele conversie.

Je kunt de variabelen uitlezen en vastleggen in een set variabelen. Dan kun je er mee doen wat je wilt.
Bijv zo (niet getest want ik heb geen SMT172:

code:


/*
 Demo sketch for the SMT172 library. 
 This sketch is intended for the ATmega328P (Uno, Nano, Pro Mini etc.)
 There is no timer2 on the ATmega32U4 (Pro Micro)
 The ICP1 pin is not exposed on the Mega2560R3 board so timer4 or timer5 must be
 used requiring a modification of the SMT172 library. This board also uses
 different pins for timer2.
 This sketch will output to serial.
 Connect the output of the SMT172 to pin 8 (Input Capture Pin of timer 1)
 Timer 2 is set up in phase correct PWM and output a duty cycle of
 10.98% ~-45.06 C on pin 3 and a duty cycle of 92.94% ~139.58 C on pin 11
 Connect pin 8 to pin 3 or pin 11 to check the working if no SMT172 is available
*/
// #include <arduino.h>
#include <SMT172.h>
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C  lcd(0x3F,2,1,0,4,5,6,7); // 0x3F is the I2C bus address for an unmodified backpack of a PCF8574A

uint32_t LastSensorUpdate;


void setup() 
{
  // activate LCD module
  lcd.begin (16,2);                                // for 16 x 2 LCD module
  lcd.setBacklightPin(3,POSITIVE);
  lcd.setBacklight(HIGH);
  lcd.clear();
  
  Wire.begin();
  
  Serial.begin(115200);
  pinMode(8, INPUT);
  pinMode(12, OUTPUT);

  //  The following code fragment sets up phase-correct PWM on pins 3 and 11 (Timer 2).
  //  The waveform generation mode bits WGM are set to to 001 for phase-correct PWM.
  //  The other bits are the same as for fast PWM.

  pinMode(3, OUTPUT);
  pinMode(11, OUTPUT);
  TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM20);
  // TCCR2B = _BV(CS22); // Output frequency: 16 MHz / 64 / 255 / 2 =  490.196 Hz
  TCCR2B = _BV(CS21); // Output frequency: 16 MHz /  8 / 255 / 2 = 3921.569 Hz
  OCR2A = 237; // Output A duty cycle: 237 / 255 = 92.94% = 129.58 C  on pin 11
  OCR2B = 28;  // Output B duty cycle:  28 / 255 = 10.98% = -45.06 C  on pin 3
}




float SMT172_Temperature = 0.0;
float SMT172_Time        = 0.0;
float SMT172_Frequency   = 0.0;
float SMT172_DutyCycle   = 0.0;
float SMT172_Error       = 0.0;

bool  SMT172_HasChanged  = false;
bool  SMT172_Busy        = false;

void loop() 
{

  if(SMT172_Busy == false) 
  {  // Read the sensor every 250 millisecond
     if ((unsigned long) (millis() - LastSensorUpdate) >= 250) 
     {
       LastSensorUpdate = millis();
  
       SMT172::startTemperature(0.001);
       SMT172_Busy = true;
     }
  }
  else 
  {  switch (SMT172::getStatus()) 
     {
        case 0: 
        {  // Conversion busy. Just wait 
           break;
        }
        
        case 1:
        {  SMT172_Busy = false;

           SMT172_Time        = SMT172::getTime();
           SMT172_Frequency   = SMT172::getFrequency();
           SMT172_DutyCycle   = SMT172::getDutyCycle();
           SMT172_Temperature = SMT172::getTemperature();
           SMT172_Error       = SMT172::getError();
           SMT172_HasChanged  = true;
           break;
        }
        
        case 2: 
        {  Serial.println(F("**** Sensor disconnected ****"));
           Serial.println();
           SMT172_Busy = false;
           break;
        }
     }
  }

  if(SMT172_HasChanged)
  {  
     SMT172_HasChanged = false;

     Serial.print(F("Measuring time   [ms]: "));
     Serial.println(SMT172_Time * 1e3, 2); // convert to milliseconds
     Serial.print(F("Sensor frequency [Hz]: "));
     Serial.println(SMT172_Frequency, 2);
     Serial.print(F("Duty cycle        [%]: "));
     Serial.println(SMT172_DutyCycle * 100, 2);
     Serial.print(F("Temperature       [C]: "));
     Serial.println(SMT172_Temperature, 4);
     Serial.print(F("Error            [mK]: "));
     Serial.println(SMT172_Error * 1000, 2);
     Serial.println();

// Bram frutsel om temperatuur op het LCD te krijgen
     lcd.clear();
     lcd.home();                // set cursor to 0,0
     lcd.setCursor (0,0);
     lcd.print("SMT172 "); 
     lcd.print(SMT172_Temperature, 4);
     lcd.print(" C"); 
// Bram frutsel om temperatuur op het LCD te krijgen        
  }
}

blackdog

Golden Member

Hi,

Lucky Luke
De uitlezing via de serial interface is tijdelijk, die wordt er later uit ge-edit.

deKees
Ik heb je code in een nieuwe sketch geplakt en er komt een eror melding betreffende Busy dat deze niet gedeclareerd is, zie de error melding hieronder:

c code:


C:\Users\BlahBla\Documents\Arduino\SMT172-deKees-01\SMT172-deKees-01.ino: In function 'void loop()':
SMT172-deKees-01:86:12: error: 'Busy' was not declared in this scope
         {  Busy = false;
            ^~~~
SMT172-deKees-01:100:12: error: 'busy' was not declared in this scope
            busy = false;
            ^~~~
SMT172-deKees-01:111:21: error: 'SMT172_Time' was not declared in this scope
      Serial.println(SMT172_Time * 1e3, 2); // convert to milliseconds
                     ^~~~~~~~~~~
C:\Users\BlahBla\Documents\Arduino\SMT172-deKees-01\SMT172-deKees-01.ino:111:21: note: suggested alternative: 'STM172_Time'
      Serial.println(SMT172_Time * 1e3, 2); // convert to milliseconds
                     ^~~~~~~~~~~
                     STM172_Time
SMT172-deKees-01:113:21: error: 'SMT172_Frequency' was not declared in this scope
      Serial.println(SMT172_Frequency, 2);
                     ^~~~~~~~~~~~~~~~
C:\Users\BlahBla\Documents\Arduino\SMT172-deKees-01\SMT172-deKees-01.ino:113:21: note: suggested alternative: 'STM172_Frequency'
      Serial.println(SMT172_Frequency, 2);
                     ^~~~~~~~~~~~~~~~
                     STM172_Frequency
SMT172-deKees-01:115:21: error: 'SMT172_DutyCycle' was not declared in this scope
      Serial.println(SMT172_DutyCycle * 100, 2);
                     ^~~~~~~~~~~~~~~~
C:\Users\BlahBla\Documents\Arduino\SMT172-deKees-01\SMT172-deKees-01.ino:115:21: note: suggested alternative: 'STM172_DutyCycle'
      Serial.println(SMT172_DutyCycle * 100, 2);
                     ^~~~~~~~~~~~~~~~
                     STM172_DutyCycle
SMT172-deKees-01:117:21: error: 'SMT172_Temperature' was not declared in this scope
      Serial.println(SMT172_Temperature, 4);
                     ^~~~~~~~~~~~~~~~~~
C:\Users\BlahBla\Documents\Arduino\SMT172-deKees-01\SMT172-deKees-01.ino:117:21: note: suggested alternative: 'STM172_Temperature'
      Serial.println(SMT172_Temperature, 4);
                     ^~~~~~~~~~~~~~~~~~
                     STM172_Temperature
SMT172-deKees-01:119:21: error: 'SMT172_Error' was not declared in this scope
      Serial.println(SMT172_Error * 1000, 2);
                     ^~~~~~~~~~~~
C:\Users\BlahBla\Documents\Arduino\SMT172-deKees-01\SMT172-deKees-01.ino:119:21: note: suggested alternative: 'STM172_Error'
      Serial.println(SMT172_Error * 1000, 2);
                     ^~~~~~~~~~~~
                     STM172_Error
Meerdere bibliotheken gevonden voor "Wire.h"
Gebruikt: C:\Users\BlahBla\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.6\libraries\Wire
Niet gebruikt: C:\Users\BlahBla\Documents\Arduino\libraries\Wire-master
exit status 1
'Busy' was not declared in this scope

Ik vind in de setup wel dit: bool STM172_Busy = false;

Maar in de loop komt ook dit voor: { Busy = false;

Is dit een type fooutje?

Dank en groet,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.

Inderdaad, last-minute change, en kan niet testen. Gaat alijd fout.
Ik zal de bovenstaande code wel nakijken.

blackdog

Golden Member

Hi,

deKees, no problemo, ik leer iedere keer weer meer als je antwoordt geeft, en je bent net als ik en anderen, een "fooutje?"zit in een klein hoeje, ;-)

Groet,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.

En ook een paar keer SMT172.. ipv STM172..
Dat gaat ook fout natuurlijk.

Zou nu goed moeten zijn.

Alhoewel,
De sensor is dus een SMT172, dus nu is het overal fout. Al zal het wel werken met die foute naam. Zolang je aar consequent blijft. 8)7

Dus toch maar even aangepast. Nu overal SMT...

blackdog

Golden Member

Hi,

dekees je ene typefout zat er nog steeds in, ik heb die zelf even bijgewerkt en de code werkt nu.
Ik moet er nog wel mee spelen om te ijken of ik nu kan doen wat noodzakelijk is, zoals controle op de temperatuur waarden voor "Oven OK", Still Heating" enz en ook een over temperatuur meting.
Verder gaat de software ook wat voedinspanningen meten, allemaal niet zo spannend.

Dit is wat achtergrond info waar de code voor is.
Dit is een meting die loopt, kijk naar de resolutie die door de meters wordt weergegeven...
Vooral van de bovenste meter denk ik dat een groot deel de variatie, eigenlijk in de DMM zelf zit.
Dat een DMM zeer veel resolutie kan tonen, heeft niet zo veel te maken met zijn stabiliteit.
Vooral omdat de NTC van 5K twee draads gemeten is en je de Referentie stabiliteit hebt in de DMM, zijn range weerstanden en de stabiliteit van de gebruikte stroombron in de DMM.

https://www.bramcam.nl/NA/NA-Mini-Oven/2xKeithley-Temp-01.png

Dit is de output van de Serial Monitor
https://www.bramcam.nl/NA/NA-Mini-Oven/STM172-Breadboad-02.png

De bovenste meter wil ik eigenlijk zo even laten en dat ik de STM172 er gewoon bij monteer, dit om te zien of er veel variatie tussen de twee meetsystemen zit, dat is de bovenste KeithLey en de STM172 sensor.

Ik kan dan een punt in de tijd nemen en de waarde op papier noteren van beide meetmethode om te zien hoeveel beide sensoren uit elkaar driften.
Zal er eerst nog wat middeling op de temperatuur moeten gaan toepassen, het veranderd allemaal traag en het zal weer uren moeten aan staan voor het na een verandering weer zijn equilibrium bereikt heeft.

Mijn dank is weer GROOT.

PS
deKees, is de code nu nog steeds blokkerend?

Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.

Nee, de code blokkeert niet meer.

De beide vlaggetjes sturen nu een soort van State machine.
De loop() blijft steeds herhalen in de Arduino.

Als SMT172_Busy laag is wordt er een nieuwe meting gestart, als het tijd is tenminste. Als je wilt kun je de delay weglaten, dan krijg je sneller samples. Als ik het goed zie duurt een meting 76 milliseconden, dus je zou 3 keer zoveel samples kunnen krijgen.

Vervolgens wordt de SMT172 Status uitgelezen, en alle variabelen zodra die beschikbaar zijn.

Tijdens het wachten op de start timer, en tijdens conversie gebeurt er niks. Maar de loop() blijft wel draaien.

De temperatuur uit SMT127_Temperature kun je zo vaak gebruiken als je wilt. Het vlaggetje SMT172_Changed wordt gezet als er een nieuwe sample is uitgelezen, dus daarmee kun je je filter sturen.

PS, ik weet niet wat de meters laten zien zo. 0.000170 C lijkt me wel erg koud, maar dat zal wel een delta zijn tov een eerdere meting?

Arco

Special Member

Voor dit soort periodieke taken heeft men de interrupt uitgevonden... ;)

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
blackdog

Golden Member

Hi deKees,

Dat klopt, de meters laten een Delta waarde zien, dat is makkelijk om drift signalen beter weer te geven.
De tempeartuur in het oventje is rond de 44,1 C°

Maar als het een "oventje" wat gestuurd met een Peltier element, dan zou "0C°" natuurlijk ook kunnen, maar zou het dan og een oventje heten, of een koelkastje? :+

Groet,
Bram

PS,
Het jammere van de Keithley meters is dat als je de NULL functie gebruikt, dat ze niet de eigenlijke waarde ook in beeld zetten, bij de Keysight meters is dat b.v. wel zo.

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.

Op 4 maart 2023 15:22:44 schreef Arco:
Voor dit soort periodieke taken heeft men de interrupt uitgevonden... ;)

Klopt, die wordt ook gebruikt binnen de SMT172 library. Als je dan een event wilt doorsturen naar de main loop moet je toch weer gaan pollen zoals hier, of anders een OS installeren zoals freeRTOS, maar dat gaat me wat ver.

Je kunt ook de filtering in de interrupt handler inbouwen, maar dan moet je de library gaan ombouwen..

Kortom mogelijkheden genoeg en elke methode heeft zijn voor- en nadelen. :)

En voor Bram die nog niet veel ervaring heeft met arduino is bijvoorbeeld "interrupts" nog even te hoog gegrepen. Arduino code met een mainloop prima.

De huidige opzet is weer een klein beetje "ingewikkeld" doordat de boel non-blocking is gemaakt. Veel van dat soort arduino libraries hebben dan ook een "SMT_get_temperature_blocking" functie die gewoon de "zet hem aan het werk", "wacht tot ie klaar is" en "haal de waarde op" combineert. Kost dus enige tijd, maar in deze toepassing helemaal geen probleem.

Voor de overzichtelijkheid had dat denk ik hier beter geweest. Maar... het werkt!, niet meer aankomen. :-)

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Arco

Special Member

Is een beetje een eigenaardig ding die SMT172... (met een PWM output)

Ik heb liever een 'all digital' versie zoals de MCP9800. Nu moet de sensor eerst temperatuur in duty-cycle omzetten, en de micr weer van duty naar een temperatuurwaarde.
Komt de eenvoud en precisie niet echt ten goede.

Libraries gebruik ik zo min mogelijk. Ze zijn vaak onnodig groot en meestal is het een 'black box' zonder sourcecode, zodat je niet weet wat er allemaal gebeurt...

Arco - "Simplicity is a prerequisite for reliability" - hard-, firm-, en software ontwikkeling: www.arcovox.com
blackdog

Golden Member

Hi Arco,

De STM172 is een speciale sensor die zeer nauwkeurig is, een MCP9800 is niet te vergelijken er mee.
Dat de code wat meer tijd vergt maakt het geen slechte sensor.

De STM172 is beter dan 0,1% tussen -20 en +60C en heeft een zeer lage ruis van 0,0002C°
En zeer laag eigen verbruik.
Er zijn er maar weinig andere sensoren die hier bij in de buurt kunnen komen.

Ik zoek trouwens niet naar de temepratuur nauwkeurigheid, dan zou ik de De STM172 sensor nemen met het metalen huisje,
maar het gaat mij meer om de resolutie/ruis van deze sensor die zeer goed is.
Vele gebruikers die een temperatuur sensor nodig hebben is dit allemaal veel te mooi en te duur.

Een moderne ook heel goede sensor die een stuk goedkoper is, is b.v. de TI TMP116 met een 16 Bit ADC, resolutie is 0,0078C°
Heeft ook een zeer laag eigen verbruik en de interface is i2c.

Groet,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.
blackdog

Golden Member

Hi,

Het middelen is me gelukt na diefstal van wat code van Felix Donkers, ;) deze gebuikt een lopend filter dat weinig processorkracht gebruikt.
Alleen de opbouw van het filter bij gebruik van 128 samples duurt wat lang, maar dit is een 1x vulling van het filter, daar deze LAB referentie waar dit software/oventje in komt, gaat 24/7/365 aan staan.
Dus het vullen van het filter is geen probleem.
Wel ben ik al een beetje aan het stoeien geweest met het LCD display update tijd, ik doe dit nu als test met het meten van milis en na 500mSec ververs ik het scherm.
De testen worden nu dus gedaan met het twee regelig LCD schermpje, dat wordt waarschijnlijk een klein OLED schempje dat ik na een bepaalde tijd dim, dit moet ik nog verder uitzoeken.
Het kan ook nog een klein TFT schermpje worden, hangt ook af van in welke cassette is het display in bouw van het 19Inch rekje waar alles in komt.

De looptijd heb ik ook gemeten en zonder de SerialPrint commando's duur het met de Nano ongeveer 32mSec, netjes dus.
Door de functie lcd.clear uit te zetten flikkert het LCD display niet meer, gaat hier goed omdat ik de posities van de temperatuur waarde steeds overschrijf,
Bij bepaalde OLED en TFT scherpjes werkt dat vaak niet, krijg je last van overblijfselen van de vorige geplaatste karakters, puntje voor mij om rekening mee te houden.

Brams Frutsel code die voor de test nu goed genoeg werkt, als het meezit plaats ik vanavond nog de STM172 in het oventje.

c code:


/*
 Demo sketch for the SMT172 library. 
 This sketch is intended for the ATmega328P (Uno, Nano, Pro Mini etc.)
 There is no timer2 on the ATmega32U4 (Pro Micro)
 The ICP1 pin is not exposed on the Mega2560R3 board so timer4 or timer5 must be
 used requiring a modification of the SMT172 library. This board also uses
 different pins for timer2.
 This sketch will output to serial.
 Connect the output of the SMT172 to pin 8 (Input Capture Pin of timer 1)
 Timer 2 is set up in phase correct PWM and output a duty cycle of
 10.98% ~-45.06 C on pin 3 and a duty cycle of 92.94% ~139.58 C on pin 11
 Connect pin 8 to pin 3 or pin 11 to check the working if no SMT172 is available
*/
// #include <arduino.h>
#include <SMT172.h>
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
#include "Timer.h"

LiquidCrystal_I2C  lcd(0x3F,2,1,0,4,5,6,7); // 0x3F is the I2C bus address for an unmodified backpack of a PCF8574A

uint32_t LastSensorUpdate;



//Middelen Variabelen door Felix Donkers
const int N = 128;         // Aantal te middelen meetwaarden
float meetwaardes[N];       // Opslag van individuele meerwaarden
float filtersom = 0;        // Optelsom van alle individuele meetwaardes
int i = 0;                // Meetwaarde teller
float filterwaarde = 0;
//Middelen Variabelen

long previousMillis = 0;
long interval = 500; 


void setup() 
{
  // activate LCD module
  lcd.begin (16,2);                                // for 16 x 2 LCD module
  lcd.setBacklightPin(3,POSITIVE);
  lcd.setBacklight(HIGH);
  lcd.clear();
  
  Wire.begin();


  
  Serial.begin(115200);
  pinMode(8, INPUT);
  pinMode(12, OUTPUT);

  //  The following code fragment sets up phase-correct PWM on pins 3 and 11 (Timer 2).
  //  The waveform generation mode bits WGM are set to to 001 for phase-correct PWM.
  //  The other bits are the same as for fast PWM.

  pinMode(3, OUTPUT);
  pinMode(11, OUTPUT);
  TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM20);
  // TCCR2B = _BV(CS22); // Output frequency: 16 MHz / 64 / 255 / 2 =  490.196 Hz
  TCCR2B = _BV(CS21); // Output frequency: 16 MHz /  8 / 255 / 2 = 3921.569 Hz
  OCR2A = 237; // Output A duty cycle: 237 / 255 = 92.94% = 129.58 C  on pin 11
  OCR2B = 28;  // Output B duty cycle:  28 / 255 = 10.98% = -45.06 C  on pin 3
}


float STM172_Temperature = 0.0;
float STM172_Time        = 0.0;
float STM172_Frequency   = 0.0;
float STM172_DutyCycle   = 0.0;
float STM172_Error       = 0.0;

bool  STM172_HasChanged  = false;
bool  STM172_Busy        = false;



void loop() 
{
  if(STM172_Busy == false) 
  {  // Read the sensor every 250 millisecond
     if ((unsigned long) (millis() - LastSensorUpdate) >= 100) 
     {
       LastSensorUpdate = millis();
  
       SMT172::startTemperature(0.001);
       STM172_Busy = true;
     }
  }
  else 
  {  switch (SMT172::getStatus()) 
     {
        case 0: 
        {  // Conversion busy. Just wait 
           break;
        }
        
        case 1:
        {  STM172_Busy = false;

           STM172_Time        = SMT172::getTime();
           STM172_Frequency   = SMT172::getFrequency();
           STM172_DutyCycle   = SMT172::getDutyCycle();
           STM172_Temperature = SMT172::getTemperature();
           STM172_Error       = SMT172::getError();
           STM172_HasChanged  = true;
           break;
        }
        
        case 2: 
        {  Serial.println(F("**** Sensor disconnected ****"));
           Serial.println();
           STM172_Busy = false;
           break;
        }
     }
  }

  if(STM172_HasChanged)
  {  
     STM172_HasChanged = false;

//     Serial.print(F("Measuring time   [ms]: "));
//     Serial.println(STM172_Time * 1e3, 2); // convert to milliseconds
//     Serial.print(F("Sensor frequency [Hz]: "));
//     Serial.println(STM172_Frequency, 2);
//     Serial.print(F("Duty cycle        [%]: "));
//     Serial.println(STM172_DutyCycle * 100, 2);
//     Serial.print(F("Temperature       [C]: "));
//     Serial.println(STM172_Temperature, 4);
//     Serial.print(F("Error            [mK]: "));
//     Serial.println(STM172_Error * 1000, 2);
//     Serial.println();

      // Midddel code Felix Donkers
      filtersom -= meetwaardes[i];                     // Vergeet oudste meetwaarde
      meetwaardes[i] = (STM172_Temperature);           // Bewaar nieuwe meetwaarde
      filtersom += meetwaardes[i];                     // Accumuleer nieuwste meetwaarde
      i++; i %= N;                                     // Teller loopt van 0 tot N-1

      filterwaarde - filtersom/N;                      // Bereken de gemiddelde waarde


// Bram frutsel om temperatuur op het LCD te krijgen
      unsigned long currentMillis = millis();
      if(currentMillis - previousMillis > interval) {
    // Sla de laatste keer op dat het Display is bijgewerkt
      previousMillis = currentMillis;   
  
 //    lcd.clear();
     lcd.home();                // set cursor to 0,0
     lcd.setCursor (0,0);
     lcd.print("STM172 "); 
     lcd.print(filtersom/N, 5);
     lcd.print(" C"); 
//     lcd.setCursor (0,1);
//     lcd.print("Looptime "); 
      }
// Bram frutsel om temperatuur op het LCD te krijgen        

}
}

Zo ziet de testsetup er uit, het blauwe Labello buisje dient er voor dat de sensor een beetje stabiele omgevings tempratuur ziet,
anders is niet goed in te schatten hoe goed het gebruikte filter werkt, met dit buisje geplaats zijn drie cijfers achter de comma stabiel als ik rustig blijf zitten...

Met deze hoge resolutie is het zichtbaar na een bepaalde tijd, dat er iemand langsloopt als de deur van de kamer open staat. :-)

https://www.bramcam.nl/NA/NA-Mini-Oven/STM172-Breadboad-03.png

Allen dank voor de input, het wordt gewaardeerd!

Groet,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.

Klein puntje

code:


filterwaarde - filtersom/N;                      // Bereken de gemiddelde waarde

Dit heeft geen effect. Niet erg omdat je filterwaarde niet gebruikt.

Maar een '=' teken ipv '-' helpt wel:

code:


filterwaarde = filtersom/N;                      // Bereken de gemiddelde waarde

PS: Als je sneller wilt samplen dan kan de code nog wel een stuk korter.

[Bericht gewijzigd door deKees op zaterdag 4 maart 2023 18:09:47 (11%)

blackdog

Golden Member

Hi deKees,

Foutje heb ik in ieder geval even aanegpast, dank.
Of het sneller moet, weet ik nog niet, misschien wordt de processor een Arduino Pro Micro op 3,3V dat komt beter uit met de 3,3V displays.
Dan mis ik wel wat snelheid, maar hopelijk is het nog voldoende dit omdat er geen snelle handelingen gewenst zijn.

Bijna alles is vrij statisch wat op het display gaat worden weergegeven, voeding spanningen en temperaturen of het geheel dus normaal werkt.
Alleen voor de test zal ik 5 cijfers achter de komma gebruiken, uiteindelijk worden dat er drie.

Eerst de rest even laten indalen, zit ook nog met voedings problemen, verbonden massa's wat in de gebruikte schakeling niet mag,
ik denk dat i2c galvanische scheiding ga gebruiken om dit op te lossen.

Groet,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.

De processor is hier niet de beperking. Maar het programma heeft een delay ingebouwd tussen de samples. Die is volgens mij niet nodig. Zonder delay krijg je meer samples en dus kun je dan beter filteren.

Wel zie ik dat de delay is ingekort naar 100 millis. Klopt dus niet meer met de commentaar-regel 8)7 :

code:


   // Read the sensor every 250 millisecond
   if ((unsigned long) (millis() - LastSensorUpdate) >= 100) 

Maar eigenlijk kan heel die delay weg.

blackdog

Golden Member

Hi deKees,

Je kan dan in ieder geval zien dat ik aan de code werk! :+

Wat ik nog niet goed begrijp is of die pause van belang is voor de eigen verwarming van de sensor.
Het kan zijn dat er niets aan de sensorkant veranderd, ik zal de scoop eens aan de uitgang van de sensor hangen.

Er schiet me nog iets te binnen, dit apparaat gaat maanden achter elkaar aan staan, kom ik dan niet in de problemen met de millis fucties?

Groet,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.

De sensor merkt het niet als je vaker meet.
De sensor genereert een PWM puls trein. De library meet de lengte van de puls. Ook als de library niet werkt dan blijft de sensor gewoon pulsen genereren.

En millis() gaat over de kop na 49.5 dagen (232 milliseconden).

Daarom moet je de juiste manier gebruiken om een timeout te testen:

code:


if ((unsigned long) (millis() - LastSensorUpdate) >= 100) 

Op deze manier gaat het altijd goed. Ook in geval van overflow.
Tenminste..
-- Je moet wel zorgen dat LastSensorUpdate en millis() allebei 32 bit unsigned integers zijn.
-- Op een 64-bit machine werkt het dus niet want LastSensorUpdate is gedefiniëerd als uint32_t en millis() wordt dan een 64-bit integer.

[Bericht gewijzigd door deKees op zaterdag 4 maart 2023 20:42:50 (20%)

blackdog

Golden Member

Hi,

deKees, uhm... een 64 bit machine? ik ga een Nano of een Pro Micro gebruiken, beide hebben zover ik weet een 328p controller.
Kijk dat er 1x in de 50 dagen een meting niet helemaal goed zo gaan, zal mij een zorg zijn, maar als de code daardoor uit de rails gaat is natuurlijk minder leuk.
Dus met unsigned long voor de variabelen die milis gebruiken zit ik veilig?

Ter afsluiting, want de code voor de STM172 werkt goed genoeg wat plaatjes hoe het is toegepast in het oventje, de rest van het oventje staat al in zijn eigen topic welke ik vanavond verder aanvul.

Dit is de variatie in LAB temperatuur gemeten door deze meter, een de ingang bussen zit een speciale 5K NTC voor meet doeleinden en de afwijking rond de menselijke temperatuur is een paar tiende van een %.
Eigenlijk niet zo van belang als je ziet hoeveel de temperatuur varieert, dat is hier ongeveer 3C°
Het zakje over de NTC heen is een soort filter, het middelt de metingen een beetje uit en het digitale filter in de DMM doet de rest.
Zonder het zakje is er veel meer "ruis" zichtbaar.
Mijn excuus voor de in verhouding slechte foto's, ik heb de netwerkverbindingen voor mijn nieuwe opzet nog niet afgehandeld.
Mijn Covid is nu bijna over en als het goed is heb ik de komende week weer extra energie. :-)

https://www.bramcam.nl/NA/NA-Mini-Oven/STM172-Breadboad-08.png

.
Hier is de STM172 code aan het werk, twee uur geleden stond de waarde op 44.87213 en nu is dat ongeveer 3mC° omhoog gegaan.
Ik zou nog wat meer middeling kunnen gebruiken in de code maar de 128x waar hij nu op staat is uiteindelijk goed genoeg, deze code met de STM172 geeft een iets stabielere uitlezing dan da DMM.
De laatst digit van de STM172 meter is de enig die beweegt door de meetruis en natuurlijk de temperatuur drift, de DMM met de meet NTC en de STM172 verschilde maar een paar honderste van een C°.
De resolutie op het LCD metertje zit wel in de PPM's :-)
Nauwkeurigheid, tot de LAB deur. *grin*
Oja, de waarde linksonder op het display is de spanningsmeting van de Arduino 5V voeding met een INA219 sensor, dient hier er alleen voor om te kijken of ik de INA219 goed ingesteld kreeg.
Dat heeft meer dan 1 uur gekost om het werkend te krijgen, de bereik omschakeling in de code werkte niet, dit wou ik hebben als instelling: ina219.setCalibration_32V_1A();
Uiteindelijk bleek het conflicterende Librarys te zijn, alles van de INA219 verwijderd en toen de laatste versie ge-installeert en BINGO.
https://www.bramcam.nl/NA/NA-Mini-Oven/STM172-Breadboad-07.png

.
Dit is een kijkje in het mini oventje, onderop het koperprintje zit de oven controller met een LM10 IC.
Onder het stukje Glastape van 3M zitten de 5K NTC en de STM172 sensor met wat 10 seconde lijm vastgezet.
Voor deze testen heb ik wel koelpasta gebruikt vor de deksel, maar niet de schroefjes in de deksel gedraaid, door de goede isolatie was dit voor nu niet direct noodzakelijk.
Het rode kader geeft de NTC aan en het groene kader de STM172.
https://www.bramcam.nl/NA/NA-Mini-Oven/STM172-Breadboad-06.png

.
Volgens de gegevens van de STM172 moet je het IC vlak bij ontkoppelen en dit heb ik zo uitgevoerd, 470nF en wat Teflon kousjes.
https://www.bramcam.nl/NA/NA-Mini-Oven/STM172-Breadboad-04.png

.
En hier als laatste een stukje krimpkous zodat er geen sluiting met het koperprintje gemaakt kan worden.
https://www.bramcam.nl/NA/NA-Mini-Oven/STM172-Breadboad-05.png

.
De ruimte boven het koperprintje in het oventje is voor de onderdelen die ik op temperatuur ga houden, welke onderdelen weet ik nog niet zeker.
Dit kunnen een paar hele mooie weerstanden zijn van b.v. Vishay of AE, maar ook een paar referentie IC's parallel voor b.v. 10V.
Het een en ander hangt af van hoeveel ruimte ik heb in mijn Grote oven, wat ik daar dus nog extra in kwijt kan.

Ik weet nu voldoende en daar wat testen te doen met varieerende voeding voor de oven, weet ik dat ik dit met deze opbouw niet goed genoeg krijg.
Als ik 1V zak in ovenvoeding dan duurd het vrij lang voor de STM172 weer de goede temperatuur aangeeft.
Dus als ik een "nood" accu aanbreng ter bescherming van spanningsuitval dan is het geheel te traag reagerend om op dalende accu spanning goed te kunnen reageren.

Test geslaagt, accu backup is hierbij afgeschoten. :-)

Groet,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.

Toch wel leuk om te zien allemaal. :)

Dus met unsigned long voor de variabelen die milis gebruiken zit ik veilig?

Niet helemaal. Die (unsigned long) doet hier niks. Die kun je net zo goed weglaten.

code:

if ((unsigned long) (millis() - LastSensorUpdate) >= 100)

millis() geeft een unsigned long terug. En LastSensorUpdate is een uint32_t. Probleem is dat 'unsigned long' van alles kan zijn. Terwijl uint32_t altijd 32 bit is.

Op een UNO is 'unsigned long' hetzelfde als een uint32_t, dus geen probleem.

Wat wel belangrijk is dat je eerst het verschil berekent en daarna pas vergelijkt. Bij ons op de zaak had iemand dat ooit omgedraaid:

code:

if ( millis() >= (LastSensorUpdate + 100)) 

Dat geeft de eerste 49 dagen hetzelfde resultaat, maar als je pech hebt kan het weer 49 dagen duren tot de volgende timeout.