
Jag la på LIB efter LIB, allt funkade.
Sen använder jag också xTaskCreatePinnedToCore vilket inte behöver nåt LIB, utan bör följa med IDEn eller höra till boards?
När jag la till den så började jag få enstaka -127..
Detta alltså i ett väldigt bantat testprojekt, i skarpt projekt blir det bara -127 hela tiden.
Tipset om ChatGPT var ett bra tips. Det finns förstås väldigt mycket info på nätet om ardunio och esp32 mm, så den har ju mycket att gå på.
Så jag gav ChatGPT mitt program och frågade efter eventuella problem.
Utan fördröjning (sinnessjukt hur snabbt den analyserar allt) så fick jag en rad tips och åtgärder i mitt program, men inget som direkt pekade på mitt problem. Bara på ytan om timing och sånt.
Så jag förtydligade mitt problem, och då kom tipsen kring det, och mycket handlar om timing.
Slutligen la jag till [vTaskDelay(pdMS_TO_TICKS(500));] i min task, och vips, funkar klockrent!
För den som orkar läsa så är här hela min konversation med ChatGPT:
Kod: Markera allt
Jag har problem med en kod till en esp32 som är programmerad i arduino ide.
Kan du titta på koden och se om du hittar något fel?
ChatGPT sade:
Självklart! Skicka koden så kan jag hjälpa dig att hitta eventuella fel och föreslå förbättringar. 😊
Du sade:
#include <SPI.h> //För OLED
//#include <Wire.h> //vene..
#include <Adafruit_SSD1306.h> //För OLED
#include <ModbusRTU.h> //Modbushanteringen
#include <OneWire.h> //Onewiredriver
#include <DallasTemperature.h> //Interface DS-givare
#include <Preferences.h> //Persistent variabler
#include <FastLED.h> //För LED
Preferences persistent; //Skapa en minnesyta för persistent
OneWire oneWire(19); //OneWire på GPIO19
DallasTemperature sensors(&oneWire); //Starta motorn
Adafruit_SSD1306 display(128, 64, &Wire, 4); //Width, height, vene, RST-pin (anv. ej på disp, men låt stå
byte SLAVE_ID = 1; //Håller ID - Ändras senare med persistent
byte readSLAVE_ID = 1; //Läst ID från modbus
int ROOM = 0; //Håller Rumsnummer - Ändras senare med persistent
int readROOM = 0; //Läst Rumsnummer från modbus
byte mbSLAVE_ID = 0; //MB-ID på register 0 / 40001
byte mbROOM = 1; //Rumsnummer på register 1 / 40002
byte mbCORR = 2; //Korrfaktor på register 2 / 40003
byte mbLEDRED = 3; //Röd RGB på register 3 / 40004
byte mbLEDGREEN = 4; //Grön RGB på register 4 / 40005
byte mbLEDBLUE = 5; //Blå RGB på register 5 / 40006
byte mbLDR = 6; //LDR på register 6 / 40007
byte mbROOMTEMP = 7; //Rumstemp på register 7 / 40008
byte mbOUTTEMP = 8; //Utetemp på register 8 / 40009
byte mbLARM = 9; //Larm på register 9 / 40010
byte mbSTATUS = 10; //Status på register 10 / 40011
byte mbWDOG = 11; //Watchdog på register 11 / 40012
byte mbGN301 = 12; //Närvarogivare på register 12 / 40013
byte mbOLEDto = 13; //Timeout-tid för OLED 13 / 40014
byte mbLillaRad1FirstChar = 19; //Förtsa tecken av 21 för lilla rad 1 / 40020 .. 40040
byte mbLillaRad2FirstChar = 40; //Förtsa tecken av 21 för lilla rad 2 / 40041 .. 40061
CRGB leds[1]; //Hur många LEDs i serie
uint16_t iRed;
uint16_t iGreen;
uint16_t iBlue;
float fRoomTemp, fOutTemp;
uint16_t uModbusCorr;
uint16_t uCorr; //Unsigned korrfaktor för persistent
uint16_t uLDR; //Värde LDR på GPIO
uint16_t uOutTemp;
int16_t iCorr;
float fCorr;
int iRoomTemp, iOutTemp;
int iStatTextTimeout; //För statustextradtimeout
unsigned long OLED_timeout; //Millisekunderräknare för släckning OLED
uint16_t OLED_timeout_set = 20; //Sekunder för släckning OLED, default 20
uint16_t OLED_timeout_set_Read = 20; //Sekunder för släckning OLED, läst från modbus
char cLillaRad1[21] = { 0 }; //Lilla rad 1 på OLED
char cLillaRad2[21] = { 0 }; //Lilla rad 2 på OLED
int iCharLoop = 0; //För charloop
int iWDOG = 0; //För Watchdog, ska vara under 5 för kom=ok. Ökas med 1 1ggn per Task1-loop, DHC sätter till 0.
int iWDOGloop = 0;
String sLillaRad1; //Lilla rad 1 på OLED
String sLillaRad2; //Lilla rad 2 på OLED
ModbusRTU mb; //Starta modbus mb
TaskHandle_t Task1; //För att köra DS-läsning på Core 0 (det andra på default Core 1)
void setup() {
xTaskCreatePinnedToCore(
Task1code, /* Task function. */
"Task1", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&Task1, /* Task handle to keep track of created task */
1); /* pin task to core 0 */
persistent.begin("MBID", false); // Starta variabel "MBID", false = RW-mode
SLAVE_ID = persistent.getUInt("MBID", 1); //Hämta värdet, default 1 om det inte finns
persistent.begin("corr", false); // Starta variabel "corr", false = RW-mode
uCorr = persistent.getUInt("corr", 0); //Hämta värdet, default 0 om det inte finns
persistent.begin("ROOM", false); // Starta variabel "ROOM", false = RW-mode
ROOM = persistent.getUInt("ROOM", 0); //Hämta värdet, default 0 om det inte finns
persistent.begin("OLEDto", false); // Starta variabel "OLEDto", false = RW-mode
OLED_timeout_set = persistent.getUInt("OLEDto", 20); //Hämta värdet, default 0 om det inte finns
Serial2.begin(9600, SERIAL_8N1, 16, 17); //Starta serial 2 för modbus. GPIO 16+17 för Tx Rx
//Serial.begin(9600); //debugger
mb.begin(&Serial2); //mb på serial 2
mb.slave(SLAVE_ID); //md ID
for (int iRegs = 0; iRegs <= 70; iRegs++) {
mb.addHreg(iRegs); //Sätt upp holding 70st
}
mb.Hreg(mbCORR, uCorr); //Sätt persistent corr till holding
mb.Hreg(mbSLAVE_ID, SLAVE_ID); //Sätt persistent slavID till holding
mb.Hreg(mbROOM, ROOM); //Sätt persistent rumsnummer till holding
mb.Hreg(mbOLEDto, OLED_timeout_set); //Sätt persistent OLED TimeOut till holding
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //starta OLED, adress 0x3C
display.display(); //visa bild (splash)
sensors.begin(); //Starta läsning OW
FastLED.addLeds<APA102, 12, 14, BGR>(leds, 1); //Modell, data-pin, clock-pin, RGB-följd, antal LEDs i serie
pinMode(36, INPUT); //LDR
pinMode(35, INPUT); //Sensor närvaro
}
void loop() {
//Sätt RGB-värde till LED, begränsa med LDR
iRed = constrain(mb.Hreg(mbLEDRED), 0, uLDR);
iGreen = constrain(mb.Hreg(mbLEDGREEN), 0, uLDR);
iBlue = constrain(mb.Hreg(mbLEDBLUE), 0, uLDR);
leds[0] = CRGB(iRed, iGreen, iBlue);
FastLED.show();
//Om närvaro aktiv = sätt tid för OLED-aktivering.
if (digitalRead(35)) {
OLED_timeout = millis();
OLED_timeout = OLED_timeout + (OLED_timeout_set * 1000); //Default 20sekunder
}
mb.task(); //gör modbussaker
yield(); //vene
}
void UpdatePersistent() {
readSLAVE_ID = mb.Hreg(mbSLAVE_ID);
if (readSLAVE_ID != SLAVE_ID) { //är modbus-ID ändrat mot persistent?
persistent.putUInt("MBID", readSLAVE_ID); //Sätt nytt värde i persistent
ESP.restart(); //Starta om så nya MBID gäller
}
readROOM = mb.Hreg(mbROOM);
if (readROOM != ROOM) { //är ROOM ändrat mot persistent?
persistent.putUInt("ROOM", readROOM); //Sätt nytt värde i persistent
ROOM = readROOM;
}
uModbusCorr = mb.Hreg(mbCORR); //läs av holding för corr
if (uModbusCorr != uCorr) { //är holding 11 ändrat mot persistent?
persistent.putUInt("corr", uModbusCorr); //Sätt nytt värde i persistent
uCorr = uModbusCorr; //sätt nytt corr till vidare funktioner
}
OLED_timeout_set_Read = mb.Hreg(mbOLEDto); //läs av holding för OLED TimeOut
if (OLED_timeout_set_Read != OLED_timeout_set) { //är holding ändrat mot persistent?
persistent.putUInt("OLEDto", OLED_timeout_set_Read); //Sätt nytt värde i persistent
OLED_timeout_set = OLED_timeout_set_Read; //sätt nytt OLED TimeOut till vidare funktioner
}
}
void Task1code(void* pvParameters) {
for (;;) {
uOutTemp = mb.Hreg(mbOUTTEMP);
iOutTemp = *(int16_t*)&uOutTemp; //konv unsigned till signed
fOutTemp = (float)iOutTemp / 10.0;
sensors.requestTemperatures(); //läs in DS-givarna
fRoomTemp = sensors.getTempCByIndex(0); //lägg temp här - float - ÄNDRA VARNAMN
iCorr = *(int16_t*)&uCorr; //konv unsigned till signed
fCorr = (float)iCorr / 10.0; //skapa float av int
fRoomTemp = fRoomTemp + fCorr; //Korrigering
iRoomTemp = fRoomTemp * 10; //Konvertera till int x10
mb.Hreg(mbROOMTEMP, iRoomTemp); //Sätt rumstemp i holding
mb.Hreg(mbGN301, digitalRead(35)); //Sätt närvaro i holding
uLDR = analogRead(36); //Läs LDR på GPIO36
uLDR = map(uLDR, 0, 3000, 0, 255); //Mappad för att passa rumsljus bättre (går mellan 0-4095 annars)
uLDR = constrain(uLDR, 1, 255); //Håll inom 1-255
mb.Hreg(mbLDR, uLDR); //Lägg värde på reg 3
UpdatePersistent(); //Kolla om persistent ska uppdateras.
UpdateTwoRows(); //Updatera textrader på OLED
visa(fRoomTemp, fOutTemp); //visa temp på OLED
iWDOG = mb.Hreg(mbWDOG); //Läs in från DHC, skriv > 0 för att visa att vi har kontakt
iWDOGloop ++;
if (iWDOGloop > 5){
if (iWDOG > 0){
iWDOG --;
mb.Hreg(mbWDOG, iWDOG); //Skriv WDOG till modbus, så den uppdaterar sig
iWDOGloop = 0;
}
}
}
}
void visa(float fIn, float fUt) {
if (OLED_timeout > millis()) {
display.clearDisplay();
display.setTextSize(3);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0); // Start at top-left corner
display.setTextSize(1);
display.print("IN:");
display.setTextSize(3);
if (fIn >= 0) display.print("+");
display.print(fIn, 1);
display.setTextSize(1);
display.print("o");
display.setTextSize(2);
display.println("C");
display.setCursor(0, 24); // rad 2
display.setTextSize(1);
display.print("UT:");
display.setTextSize(3);
if (fUt >= 0) display.print("+");
display.print(fUt, 1);
display.setTextSize(1);
display.print("o");
display.setTextSize(2);
display.println("C");
display.setCursor(0, 48); // rad 3
display.setTextSize(1);
display.println(sLillaRad1);
if (iStatTextTimeout < 10) {
iStatTextTimeout = iStatTextTimeout + 1;
display.println("Rum:" + String(ROOM) + " - nodID:" + String(SLAVE_ID));
} else {
display.println(sLillaRad2);
}
display.display();
} else {
display.clearDisplay();
display.display();
iStatTextTimeout = 0;
}
}
void UpdateTwoRows() {
sLillaRad1 = "";
sLillaRad2 = "";
if (iWDOG == 0) {
sLillaRad1 = "Kommunikationsfel!";
mb.Hreg(mbLEDRED, 255);
mb.Hreg(mbLEDGREEN, 0);
mb.Hreg(mbLEDBLUE, 0);
} else {
for (int iCharLoop = 0; iCharLoop <= 20; iCharLoop++) {
cLillaRad1[iCharLoop] = mb.Hreg(iCharLoop + 19);
cLillaRad2[iCharLoop] = mb.Hreg(iCharLoop + 40);
sLillaRad1 = sLillaRad1 + String(cLillaRad1[iCharLoop]);
sLillaRad2 = sLillaRad2 + String(cLillaRad2[iCharLoop]);
}
}
}
ChatGPT sade:
Jag har gått igenom din kod och ser att den är välstrukturerad, men det finns några potentiella problem och förbättringsmöjligheter. Här är några saker du kan kolla på:
1. Möjligt problem med OLED timeout i loop()
Du använder:
cpp
Kopiera
Redigera
if (digitalRead(35)) {
OLED_timeout = millis();
OLED_timeout = OLED_timeout + (OLED_timeout_set * 1000);
}
Problem:
Detta kan leda till att OLED aldrig släcks om digitalRead(35) ofta är HIGH. En bättre lösning vore att endast uppdatera timeout när en förändring upptäcks.
2. UpdatePersistent() kallas för ofta
I Task1code() anropas UpdatePersistent() varje loop, vilket kan leda till onödiga skrivningar till flashminnet. Flashminnet i ESP32 har begränsat antal skrivningar.
Lösning:
Lägg till en flagga som endast uppdaterar Preferences när ett värde faktiskt ändras.
3. visa() kan orsaka att OLED flimrar
Funktionen display.clearDisplay(); i visa() kallas varje gång OLED ska ritas om, vilket kan ge ett flimrande intryck.
Lösning:
Använd istället en flagga för att bara uppdatera skärmen när något ändras.
4. Möjlig heap overflow med String
Du använder String-konkatenering här:
cpp
Kopiera
Redigera
sLillaRad1 = sLillaRad1 + String(cLillaRad1[iCharLoop]);
Problem:
ESP32 har begränsat RAM, och String kan orsaka fragmentering. För längre strängar är char-arrayer bättre.
Lösning:
Byt ut String mot char[] och strcat().
5. pinMode() bör specificera INPUT_PULLUP för knappar
cpp
Kopiera
Redigera
pinMode(36, INPUT);
pinMode(35, INPUT);
Om du har knappar på dessa, överväg att använda INPUT_PULLUP för att undvika svävande ingångar.
6. OLED_timeout logiken kan vara inkorrekt
I visa():
cpp
Kopiera
Redigera
if (OLED_timeout > millis()) { ... }
Detta kan ge problem vid millis()-överspill (efter ~49 dagar). En säkrare lösning är:
cpp
Kopiera
Redigera
if (millis() - OLED_timeout < OLED_timeout_set * 1000) { ... }
7. Task1code() kan bli blockerande
Den har en oändlig loop utan delay(), vilket kan skapa problem.
Lösning:
Lägg till en liten delay:
cpp
Kopiera
Redigera
vTaskDelay(pdMS_TO_TICKS(500)); // Vänta 500 ms
Dessa är några potentiella förbättringar och fixar. Vill du att jag ändrar koden direkt åt dig? 😊
Du sade:
Nej tack.
Jag för problem med att sensors.getTempCByIndex(0) returnerar -127.
Detta när xTaskCreatePinnedToCore används.
Delar DallasTemperature.h och xTaskCreatePinnedToCore några timers?
ChatGPT sade:
Ja, problemet du stöter på – att sensors.getTempCByIndex(0) returnerar -127 – beror ofta på att ESP32:s FreeRTOS hantering av trådar (Tasks) påverkar kommunikationen med OneWire-bussen. xTaskCreatePinnedToCore() kan påverka hur ESP32 hanterar timers, vilket i sin tur kan störa OneWire-protokollet.
Varför händer detta?
Timers och OneWire-protokollet
DallasTemperature-biblioteket använder delayMicroseconds() som kan påverkas av hur FreeRTOS schemalägger tasks. Om Task1code() körs på en annan kärna kan den blockera eller störa OneWire-läsningen.
GPIO och kärnkonflikter
OneWire (DallasTemperature) kräver exakt timing och fungerar bäst när det körs på samma kärna som huvudloopen (loop()).
Prioritetsproblem
Din Task1 har priority = 1, men det kan vara för lågt eller för högt beroende på vad som körs på den andra kärnan.
Lösningar att testa
1. Flytta OneWire-läsningen tillbaka till loop()
En snabb test är att flytta all temperaturavläsning till loop() istället för att köra den i Task1code().
Testa att ändra loop() till något sånt här:
cpp
Kopiera
Redigera
void loop() {
sensors.requestTemperatures(); // Läs in DS-givarna
float temp = sensors.getTempCByIndex(0);
if (temp != -127.0) {
fRoomTemp = temp;
} else {
Serial.println("Fel: Kunde inte läsa temperatur.");
}
delay(1000); // Vänta lite innan nästa läsning
}
Om temperaturen fungerar i loop(), då är problemet troligtvis xTaskCreatePinnedToCore().
2. Pin tasken till samma kärna som loop()
Om du måste ha temperaturavläsningen i Task1code(), prova att köra den på Core 1, samma som loop():
cpp
Kopiera
Redigera
xTaskCreatePinnedToCore(
Task1code,
"Task1",
10000,
NULL,
1,
&Task1,
1 // Ändra till 1 istället för 0
);
3. Lägg till vTaskDelay() i Task1
Eftersom OneWire kan störas av FreeRTOS, lägg till en liten paus i tasken för att undvika att den låser systemet:
cpp
Kopiera
Redigera
void Task1code(void* pvParameters) {
for (;;) {
sensors.requestTemperatures();
float temp = sensors.getTempCByIndex(0);
if (temp != -127.0) {
fRoomTemp = temp;
} else {
Serial.println("Fel: Temp returnerade -127.");
}
vTaskDelay(pdMS_TO_TICKS(2000)); // Vänta 2 sekunder mellan läsningar
}
}
Detta ger mer utrymme åt ESP32 att hantera OneWire-protokollet korrekt.
4. Använd taskENTER_CRITICAL() och taskEXIT_CRITICAL()
Om FreeRTOS stör OneWire kan du testa att köra OneWire-läsningen i en kritisk sektion:
cpp
Kopiera
Redigera
taskENTER_CRITICAL();
sensors.requestTemperatures();
float temp = sensors.getTempCByIndex(0);
taskEXIT_CRITICAL();
Men detta kan påverka prestanda, så testa andra lösningar först.
Slutsats
Det mest sannolika är att xTaskCreatePinnedToCore() påverkar timers och GPIO på ett sätt som stör OneWire-kommunikationen. Prova att flytta temperaturavläsningen till loop() eller att köra Task1 på samma kärna som loop().
Testa och se om det löser problemet! 😊
Du sade:
Att lägga till vTaskDelay(pdMS_TO_TICKS(500)); i Task1 löste problemet!
Har någon uppdatering i något bibliotek skapat detta problem som inte fanns innan?
ChatGPT sade:
Bra att vTaskDelay(pdMS_TO_TICKS(500)); löste problemet! 🎉
Har en uppdatering i något bibliotek orsakat detta problem?
Ja, det är möjligt att en uppdatering i DallasTemperature, OneWire, eller Arduino ESP32 Core har förändrat hur OneWire hanteras i förhållande till FreeRTOS och multitasking på ESP32. Några möjliga orsaker:
ESP32 Arduino Core har ändrats
Nya versioner av ESP32 Arduino Core har förbättrad multitasking och schemaläggning, vilket kan ha ändrat tidshanteringen i FreeRTOS.
ESP32 har också fått förbättrade GPIO-drivrutiner som kan påverka timing-känsliga protokoll som OneWire.
Äldre versioner kanske var mer förlåtande mot dålig timing i en FreeRTOS-task.
OneWire-biblioteket kan ha ändrats
OneWire-protokollet är extremt känsligt för exakta tidsfördröjningar. Om en uppdatering har ändrat hur delayMicroseconds() eller GPIO-hanteringen fungerar, kan det påverka stabiliteten.
DallasTemperature-biblioteket kan ha fått uppdateringar
Om biblioteket nu använder en annan metod för att kommunicera med OneWire kan det kräva striktare timing och störas av FreeRTOS-task-switching.
Hur kan du testa om en uppdatering orsakade problemet?
Om du vill testa om en äldre version fungerade bättre, kan du nedgradera biblioteken:
Kolla vilken version av ESP32 Core du har
I Arduino IDE, gå till Tools → Board → Boards Manager
Sök på ESP32
Testa att nedgradera till en äldre version, t.ex. 2.0.5 eller 2.0.3
Testa en äldre version av OneWire och DallasTemperature
I Arduino IDE, gå till Sketch → Inkludera bibliotek → Hantera bibliotek
Sök på DallasTemperature och OneWire
Prova att installera en äldre version (t.ex. 3.x istället för 4.x)
Slutsats
Ja, en uppdatering kan ha ändrat timing-hanteringen i FreeRTOS, OneWire eller ESP32 Core, vilket gör att problemet uppstod nu men inte tidigare. Att lägga till vTaskDelay() hjälper eftersom det låter FreeRTOS schemalägga uppgifterna mer effektivt utan att blockera andra viktiga systemprocesser.
Om du vill fördjupa dig kan du testa äldre versioner av biblioteken för att bekräfta vilken ändring som skapade problemet. 😊