Arduino och läsa av tecken från serieporten
Arduino och läsa av tecken från serieporten
Jag är fortfarande nybörjare på Arduino men håller på att lära mig mer och mer.
Jag har nu problem med att läsa av information som jag skicka till Arduinon via serieport.
Koden fungerar, men om jag får in något annat tecken än de som jag behöver så fungerar det inte. Jag vet att jag i koden läser av ".startsWith" och det är här som det blir fel.
Jag har inte lyckats knäcka hur jag ska lösa detta.
Det som kommer in är 1 - många tecken och det finns vissa strängar som slutar med ett unikt tecken x04 eller "Enter". I andra fall är det bara 1, 2 eller 3 tecken långt utan speciellt avslutstecken.
Här nedan kommer koden som jag har just nu.
Finns det någon som kan hjälpa mig med en kod som kan fungera?
På något vis måste bufferten nollställas om det kommer in tecken som jag inte vill ha.
// Anropas mellan varje huvudloop
// Kolla av serieporten
void serialEvent() {
while (Serial.available()) {
// Hämta nästa tecken
char inChar = (char)Serial.read();
// Kolla och det är ett säkert avslutningstecken if ((inChar == '\x04') or (inChar == '\r')){
SerialInputString += inChar;
// Hoppa till "kolla vad den innehåller"
OnSerialString();
}
// Kolla om det är A, B, C and D som kommando -// fast bara om insträngen är tom.
//Det kommer inte fler tecken efter dessa
else if (SerialInputString == "") {
if ((inChar == 'A') || (inChar == 'B') || (inChar == 'C') || (inChar == 'D')) {
SerialInputString += inChar;
// Hoppa till "kolla vad den innehåller"
OnSerialString();
}
else {
// Annars lägg till tecknet för senare användning
SerialInputString += inChar;
}
}
// Annars lägg till tecknet i buffert för senare
// användning
else {
SerialInputString += inChar;
}
// Om buffert innehåller "PS" eller "GSI", inga fler
// tecken än dessa kommer
if ((SerialInputString == "PS") || (SerialInputString == "GSI")) {
// Hoppa till "kolla vad den innehåller"
OnSerialString();
}
}
}
// Här ligger all koll av vad som ligger i bufferten för seriedatat
void OnSerialString() {
// Bort med mellanslagen
SerialInputString.trim();
Kolla om bufferten startar med "SRV"
if (SerialInputString.startsWith("SRV") == true) {
// Kommando SRV - Set klocka vid uppstart av PC-program
// Hoppa till nästa rutinen
OnSerialSetTimeStart();
}
// Kommando GSI - Hämtar bla. versionsnumret i kretsen
else if (SerialInputString.startsWith("GSI") == true) {
// Command GSI - GetSystemInfo
// Hoppa till nästa rutinen
OnSerialGetSystemInfo();
}
// Kommando PS - Stoppa klocka vid nerstängning av pc-programmet
else if (SerialInputString.startsWith("PS") == true) {
// Hoppa till nästa rutinen
OnSerialStopClock();
}
// kolla de enstaka tecknen A-D
else if (SerialInputString.startsWith("A") == true) {
// Hoppa till nästa rutinen
SendTrigger('A');
}
else if (SerialInputString.startsWith("B") == true) {
// Hoppa till nästa rutinen
SendTrigger('B');
}
else if (SerialInputString.startsWith("C") == true) {
// Hoppa till nästa rutinen
SendTrigger('C');
}
else if (SerialInputString.startsWith("D") == true) {
// Hoppa till nästa rutinen
SendTrigger('D');
}
// Nollställ bufferten
SerialInputString = "";
}
Jag har nu problem med att läsa av information som jag skicka till Arduinon via serieport.
Koden fungerar, men om jag får in något annat tecken än de som jag behöver så fungerar det inte. Jag vet att jag i koden läser av ".startsWith" och det är här som det blir fel.
Jag har inte lyckats knäcka hur jag ska lösa detta.
Det som kommer in är 1 - många tecken och det finns vissa strängar som slutar med ett unikt tecken x04 eller "Enter". I andra fall är det bara 1, 2 eller 3 tecken långt utan speciellt avslutstecken.
Här nedan kommer koden som jag har just nu.
Finns det någon som kan hjälpa mig med en kod som kan fungera?
På något vis måste bufferten nollställas om det kommer in tecken som jag inte vill ha.
// Anropas mellan varje huvudloop
// Kolla av serieporten
void serialEvent() {
while (Serial.available()) {
// Hämta nästa tecken
char inChar = (char)Serial.read();
// Kolla och det är ett säkert avslutningstecken if ((inChar == '\x04') or (inChar == '\r')){
SerialInputString += inChar;
// Hoppa till "kolla vad den innehåller"
OnSerialString();
}
// Kolla om det är A, B, C and D som kommando -// fast bara om insträngen är tom.
//Det kommer inte fler tecken efter dessa
else if (SerialInputString == "") {
if ((inChar == 'A') || (inChar == 'B') || (inChar == 'C') || (inChar == 'D')) {
SerialInputString += inChar;
// Hoppa till "kolla vad den innehåller"
OnSerialString();
}
else {
// Annars lägg till tecknet för senare användning
SerialInputString += inChar;
}
}
// Annars lägg till tecknet i buffert för senare
// användning
else {
SerialInputString += inChar;
}
// Om buffert innehåller "PS" eller "GSI", inga fler
// tecken än dessa kommer
if ((SerialInputString == "PS") || (SerialInputString == "GSI")) {
// Hoppa till "kolla vad den innehåller"
OnSerialString();
}
}
}
// Här ligger all koll av vad som ligger i bufferten för seriedatat
void OnSerialString() {
// Bort med mellanslagen
SerialInputString.trim();
Kolla om bufferten startar med "SRV"
if (SerialInputString.startsWith("SRV") == true) {
// Kommando SRV - Set klocka vid uppstart av PC-program
// Hoppa till nästa rutinen
OnSerialSetTimeStart();
}
// Kommando GSI - Hämtar bla. versionsnumret i kretsen
else if (SerialInputString.startsWith("GSI") == true) {
// Command GSI - GetSystemInfo
// Hoppa till nästa rutinen
OnSerialGetSystemInfo();
}
// Kommando PS - Stoppa klocka vid nerstängning av pc-programmet
else if (SerialInputString.startsWith("PS") == true) {
// Hoppa till nästa rutinen
OnSerialStopClock();
}
// kolla de enstaka tecknen A-D
else if (SerialInputString.startsWith("A") == true) {
// Hoppa till nästa rutinen
SendTrigger('A');
}
else if (SerialInputString.startsWith("B") == true) {
// Hoppa till nästa rutinen
SendTrigger('B');
}
else if (SerialInputString.startsWith("C") == true) {
// Hoppa till nästa rutinen
SendTrigger('C');
}
else if (SerialInputString.startsWith("D") == true) {
// Hoppa till nästa rutinen
SendTrigger('D');
}
// Nollställ bufferten
SerialInputString = "";
}
Re: Arduino och läsa av tecken från serieporten
Om du använder code-taggarna så blir koden även läsbar.
Det underlättar nog för de som vill kolla...
[/code]
Det underlättar nog för de som vill kolla...

Kod: Markera allt
[code]
// Anropas mellan varje huvudloop
// Kolla av serieporten
void serialEvent() {
while (Serial.available()) {
// Hämta nästa tecken
char inChar = (char)Serial.read();
...
...
Re: Arduino och läsa av tecken från serieporten
RadioDJ: du har ingen avkänning av när ett block data är "gammalt". Därför kommer ditt program inte att "veta" när det blir skräpdata som bara kan rensas bort.
Och orsaken är i grunden nog att din struktur i det hela är usel.
Har du gjort klart för dig hur de olika data kan särskiljas? Alltså finns det tecken som avslutar varje datablock? Eller finns det en viss minimum tid mellan de olika block? Utan att ha denna särskiljning får du ha en helt annan avkänning av data, något som förvisso är ganska enkelt och mycket mer elegant än det du har nu.
Men utan att kunde rensa bort skräp kommer det förr eller senare att kollapsa.
Och orsaken är i grunden nog att din struktur i det hela är usel.
Har du gjort klart för dig hur de olika data kan särskiljas? Alltså finns det tecken som avslutar varje datablock? Eller finns det en viss minimum tid mellan de olika block? Utan att ha denna särskiljning får du ha en helt annan avkänning av data, något som förvisso är ganska enkelt och mycket mer elegant än det du har nu.
Men utan att kunde rensa bort skräp kommer det förr eller senare att kollapsa.
Re: Arduino och läsa av tecken från serieporten
Det som kommer på serieporten är det inte jag som har bestämt. Detta kommer från ett datorprogram som inte jag har gjort.
Jag vet att det är "skit". Hade jag gjort något själv hade det aldrig sett ut på detta viset.
Vi kan nog sätta en tid som återställer allt om inget nytt har kommit in.
Den längsta strängen som kommer in är på ca 20 tecken.
Allt sker i en hastighet på 9600.
Tiden mellan de olika strängarna som mottages kan vi säga ligger på minst 0,5 sek.
Kan det hjälp Er med att fixa till en kod som jag kan prova??
Jag vet att det är "skit". Hade jag gjort något själv hade det aldrig sett ut på detta viset.
Vi kan nog sätta en tid som återställer allt om inget nytt har kommit in.
Den längsta strängen som kommer in är på ca 20 tecken.
Allt sker i en hastighet på 9600.
Tiden mellan de olika strängarna som mottages kan vi säga ligger på minst 0,5 sek.
Kan det hjälp Er med att fixa till en kod som jag kan prova??
Re: Arduino och läsa av tecken från serieporten
Det man då gör är att om vi antar att tiden mellan varje "skur" är 500ms, då lägger man en timer till att räkna 300ms. För varje tecken som mottas startas timern om igen och när timern går ut ska data anses som värda att kolla och sedan spola.
Jag hade startat en timer-interrupt med en hastighet av t.ex. 30Hz. Då motsvarar 300ms 9 st sådana timer-interrupts.
Sedan hade jag lagt ett par variabler som räknades ner:
unsigned char Timer, Timeout;
och i Timer-ISR:
I main-loop ser man sedan till att dels sätta Timer till 9 varje gång det mottas en seriellt tecken och även att kolla Timeout. Är Timeout satt (if(Timeout)) ska inkommande buffer nollas OCH Timeout sättas till false.
Klart.
Självklart kan man lösa det mycket enklare om de olika värden som kommer har kända tecken på slutet, t.ex. 0x04, CR/LF eller liknande. Då kan man bara fånga dom.
Ett annat trick är att kolla om buffern fylls helt (den ska såklart vara lätt överdimensionerat), blir den helt full MÅSTE det ju vara skräp för att det inte är igenkänd.
Sedan är grundproblemet ju att det koll du har lagt in av de olika värden/texter är dåligt i sin grundutförande till att börja med. Men timeout-delen kan behövas i alla fall.
Själv har jag skapat en funktion som gör en sådan text-kontroll. Den scanner igenom mottagna SMS och jag har en tabell över ord som ska kännas igen samt vilka funktioner som ska utlösas av dessa ord. Skriver jag ord som inte finns med i tabellen kollas de såklart igenom också men stegas igenom, bokstav för bokstav.
Så om det t.ex. står "ge mig status på pannan" och "status" är ett nyckelord kommer rutinen att kolla:
* "ge mig" - inte "status"
* "e mig " - inte "status"
* " mig s" - inte "status"
* "mig st" - inte "status"
* "ig sta" - inte "status"
* "g stat" - inte "status"
* " statu" - inte "status"
* "status" - BINGO! "status"!
* "tatus " - inte "status"
* atus p" - inte "status"
osv. Längden på antal tecken som kollas beror på längden av ordet "status". Är det fler kommandon kommer kollen såklart att anpassas för varje textsträngs längd.
Nu är det inte bara ett ord men ett antal kommandon, utökar gör jag vid att fylla i tabellen, resten klarar mjukvaran automatisk när jag kompilerar. Jag använder det till att styra min pelletsbrännare, jag har "start", "start nu", "stopp", "stopp nu", "dusch", "status" som kommandon för tillfället. En viktig sak med det sätt jag kör är att "stopp nu" måste stå innan "stopp" i tabellen liksom att "start nu" måste stå före "start".
Om nyckelord upptäcks hoppar pekaren vidare till första bokstav efter kommandot och det fortsätts till all text i SMS-texten är slut. På det vis kan jag hitta och utföra fler kommandon i samma SMS, t.ex. "start status" som dels startar brännaren och får den att komponerar ett SMS med lite status i klartext. Ett exempel:
Pelletsbrännaren status:
Aktiv
Termostat: varm
Panntemp: 63'C
Pelletsräknaren: 174kg
Utomhus temp: 2'C
Att det används ' istället för ° är för att det senare tecken inte är med i SMS-teckentabellen.
Jag hade startat en timer-interrupt med en hastighet av t.ex. 30Hz. Då motsvarar 300ms 9 st sådana timer-interrupts.
Sedan hade jag lagt ett par variabler som räknades ner:
unsigned char Timer, Timeout;
och i Timer-ISR:
Kod: Markera allt
if(Timer)
{
if(!--Timer) Timeout = true;
}
Klart.
Självklart kan man lösa det mycket enklare om de olika värden som kommer har kända tecken på slutet, t.ex. 0x04, CR/LF eller liknande. Då kan man bara fånga dom.
Ett annat trick är att kolla om buffern fylls helt (den ska såklart vara lätt överdimensionerat), blir den helt full MÅSTE det ju vara skräp för att det inte är igenkänd.
Sedan är grundproblemet ju att det koll du har lagt in av de olika värden/texter är dåligt i sin grundutförande till att börja med. Men timeout-delen kan behövas i alla fall.
Själv har jag skapat en funktion som gör en sådan text-kontroll. Den scanner igenom mottagna SMS och jag har en tabell över ord som ska kännas igen samt vilka funktioner som ska utlösas av dessa ord. Skriver jag ord som inte finns med i tabellen kollas de såklart igenom också men stegas igenom, bokstav för bokstav.
Så om det t.ex. står "ge mig status på pannan" och "status" är ett nyckelord kommer rutinen att kolla:
* "ge mig" - inte "status"
* "e mig " - inte "status"
* " mig s" - inte "status"
* "mig st" - inte "status"
* "ig sta" - inte "status"
* "g stat" - inte "status"
* " statu" - inte "status"
* "status" - BINGO! "status"!
* "tatus " - inte "status"
* atus p" - inte "status"
osv. Längden på antal tecken som kollas beror på längden av ordet "status". Är det fler kommandon kommer kollen såklart att anpassas för varje textsträngs längd.
Nu är det inte bara ett ord men ett antal kommandon, utökar gör jag vid att fylla i tabellen, resten klarar mjukvaran automatisk när jag kompilerar. Jag använder det till att styra min pelletsbrännare, jag har "start", "start nu", "stopp", "stopp nu", "dusch", "status" som kommandon för tillfället. En viktig sak med det sätt jag kör är att "stopp nu" måste stå innan "stopp" i tabellen liksom att "start nu" måste stå före "start".
Om nyckelord upptäcks hoppar pekaren vidare till första bokstav efter kommandot och det fortsätts till all text i SMS-texten är slut. På det vis kan jag hitta och utföra fler kommandon i samma SMS, t.ex. "start status" som dels startar brännaren och får den att komponerar ett SMS med lite status i klartext. Ett exempel:
Pelletsbrännaren status:
Aktiv
Termostat: varm
Panntemp: 63'C
Pelletsräknaren: 174kg
Utomhus temp: 2'C
Att det används ' istället för ° är för att det senare tecken inte är med i SMS-teckentabellen.
Senast redigerad av Icecap 5 mars 2014, 13:36:33, redigerad totalt 1 gång.
Re: Arduino och läsa av tecken från serieporten
Tack för hjälpen, men nu kommer nästa problem och det är ditt "Klart".
Jag ber om överseende med det här med Timer har jag inte börjat att titta på än.
Jag vet att den koden som jag använder, använder Timer2 (stulen kod)
.
Skulle man kunna få lite mer ledtrådar att jobba efter.
Jag är som sagt ingen stjärna på Arduino än..... men försöker förstå och lära mig lite efterhand.
Jag ber om överseende med det här med Timer har jag inte börjat att titta på än.
Jag vet att den koden som jag använder, använder Timer2 (stulen kod)

Skulle man kunna få lite mer ledtrådar att jobba efter.
Jag är som sagt ingen stjärna på Arduino än..... men försöker förstå och lära mig lite efterhand.
Re: Arduino och läsa av tecken från serieporten
Du kanske vill titta lite på CmdMessenger libraryt.
Re: Arduino och läsa av tecken från serieporten
ToPNoTCH:
Jag blir inte klok på cmdMessager.
Jag läste in "read" exemplet i en Arduino och sedan skulle jag prova att tända och släcka lampan.
Detta gick inte så bra. Snarare inte alls.
Har du någon erfarenhet av cmdMessager?
Det jag provade med var att skicka kSetLed, 1 samt en massa andra varianter som jag kunde komma på som startade med kSetLed.
Jag blir inte klok på cmdMessager.
Jag läste in "read" exemplet i en Arduino och sedan skulle jag prova att tända och släcka lampan.
Detta gick inte så bra. Snarare inte alls.
Har du någon erfarenhet av cmdMessager?
Det jag provade med var att skicka kSetLed, 1 samt en massa andra varianter som jag kunde komma på som startade med kSetLed.