Interrupt i Arduino-kod

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Caniz
Inlägg: 41
Blev medlem: 22 oktober 2013, 22:18:44

Interrupt i Arduino-kod

Inlägg av Caniz »

Hej!
Jag håller på att pula ihop en liten blixljusmodul som jag fjärrstyr med en vanlig enkel fjärrkontroll som sänder på 433 MHz.
Arduinon tar emot koden och gör olika saker beroende på vilken knapp på kontrollen som har tryckts in.

Problemet som har uppstått är att Arduinon inte vill registrera datatrafik som kommer medan blixtfunktionerna körs, trots att jag har byggt om dem så att de jobbar i loop-funktionen med millis-jämförelse istället för delay, vilket gjordes just för att kunna styra enheten även mitt i ett blixtmönster.

Koden för loop ser nu ut såhär (vissa namn och värden är ändrade):

Kod: Markera allt

void loop() {
	currentMillis = millis();
	if (mySwitch.available()) {
		String button_code = String(mySwitch.getReceivedValue(), DEC);
		Serial.print("Received code is: ");
		Serial.println(button_code);
		Serial.print("Current blink pattern is: ");
		Serial.println(blink_pattern);
		if (button_code == "11111111") {
		  blink_state = 1;
		  previousMillis = 0;
		  counter = 0;
		}
		else if (button_code == "11111112") {
		  digitalWrite(led_pin_1, LOW);
		  digitalWrite(led_pin_2, LOW);
		  blink_state = 0;
		  previousMillis = 0;
		  counter = 0;
		}
		else if (button_code == "11111113") {
		  if (blink_pattern <= 3) {
		  blink_pattern++;
		  }
		  else {
			blink_pattern = 1;
		  }
		}
		else if (button_code == "11111114") {
		if (blink_pattern >= 3) {
		  blink_pattern--;
		  }
		  else {
			blink_pattern = 4;
		  }
		}
		mySwitch.resetAvailable();
		delay(50);
	}
	else {
	  switch(blink_pattern) {
	// Pattern 1
		case 1:
			if (blink_state == 1) {
				currentMillis = millis();
				if (counter == 0) {
					digitalWrite(led_pin_1, HIGH);
					digitalWrite(led_pin_2, HIGH);
					counter++;
					previousMillis = millis();
				}
				else if (currentMillis - previousMillis >= pattern_1_delay_1 && counter == 1) {
					digitalWrite(led_pin_1, LOW);
					digitalWrite(led_pin_2, LOW);
					counter++;
					previousMillis = millis();
				}
				else if (currentMillis - previousMillis >= pattern_1_delay_2 && counter == 2) {
					counter = 0;
					previousMillis = 0;
				}
			}
			break;
	// Pattern 2
		case 2:
			if (blink_state == 1) {
				if (counter == 0) {
					digitalWrite(led_pin_1, HIGH);
					digitalWrite(led_pin_2, HIGH);
					counter++;
					previousMillis = millis();
					next_state = 0;
				}
				else if (currentMillis - previousMillis >= pattern_2_delay_1  && counter <= 7) {
					previousMillis = millis();
					counter++;
					if (next_state == 1) {
						digitalWrite(led_pin_1, HIGH);
						digitalWrite(led_pin_2, HIGH);
						next_state = 0;
					}
					else if (next_state == 0) {
						digitalWrite(led_pin_1, LOW);
						digitalWrite(led_pin_2, LOW);
						next_state = 1;
					}
				}
				else if (currentMillis - previousMillis >= pattern_2_delay_2  && counter == 8) {
					counter = 0;
					previousMillis = 0;
				}
			}
			break;
		case 3:
		  // blink_3();
			break;
		case 4:
		  // blink_4();
			break;
	}
  }
}
Om jag aktiverar en interrupt på pin 2 så får jag konstant trigger på den, oavsett om jag sänder eller inte.
Någon som har en teori om hur jag kan komma förbi detta lilla hindret? Tacksam för svar. =)
Användarvisningsbild
hanpa
Utsparkad, på semester
Inlägg: 639
Blev medlem: 22 november 2016, 21:54:43
Ort: Hemort

Re: Interrupt i Arduino-kod

Inlägg av hanpa »

Svårt att förstå hur det är kopplat. Interrupt på pin 2, hur? Vad är kopplat till pin 2? Hur har du satt upp hanteringen av interruptet?

Hanteringen av previousMillis är f.ö. skum, varför sätter du den så ofta och till noll ibland? Koden är inte helt lätt att genomskåda.

mySwitch.available() blir sann när din hårdvara lyckats ta emot en kod?

Vidare har du ingen delay i else-grenen (när inte kod tagits emot). Vet inte vad du kör utanför loopen men utan delay så riskerar du att svälta ut annat som behöver köras. Normalt vill man ha någon delay alltid i huvudloopen, oavsett om man läser av millis eller inte, för att ev. administrativ hantering ska kunna köras paralllellt (vet inte hur din kod ser ut i övrigt).

Kompletta koden hade varit intressant att se.
Caniz
Inlägg: 41
Blev medlem: 22 oktober 2013, 22:18:44

Re: Interrupt i Arduino-kod

Inlägg av Caniz »

Jag sätter den till noll varje gång det blinkmönstret har genomgått en full cykel så att jag kan börja om från noll igen när nästa cykel ska börja (om den ska börja).
Koden kraffsade jag ihop lite snabbt för att se hur det fungerade, så den är inte riktigt så välgjord som den kommer att bli.

Såhär är det kopplat (inte exakt samma mottagarmodul som min men det spelar ingen roll i sammanhanget):
Bild

Själva mönsterfunktionerna fungerar som de ska, och loopen körs och kollar millis varje gång, därför tycker jag att det är konstigt att det inte registreras några mottagna värden "mitt i" en blixtfunktion. Jag hade en delay i loop innan men den måste ha försvunnit i samband med att jag gjorde om koden från funktioner med delay till millisjämförelse.
Användarvisningsbild
hanpa
Utsparkad, på semester
Inlägg: 639
Blev medlem: 22 november 2016, 21:54:43
Ort: Hemort

Re: Interrupt i Arduino-kod

Inlägg av hanpa »

Antar att du kör något bibliotek för "mySwitch" som tar emot koder?
Den lär inte få något gjort utan delay i else-grenen.
Alltså använd både delay och millis.

Delay för att vara snäll mot annat som behöver köras, även i else-grenen. Eller lägg in den först eller sist så den gäller för hela loopen oavsett vad som körs i den.

Millis ovanpå detta för att ha koll på hur lång tid som gått sedan något hände. Delay behöver inte vara så lång i varje varv i loopen men se till att den alltid körs.
Mr Andersson
Inlägg: 1394
Blev medlem: 29 januari 2011, 21:06:30
Ort: Lapplandet

Re: Interrupt i Arduino-kod

Inlägg av Mr Andersson »

Hur tänkte du nu? Arduino är varken flerkärnig eller flertrådig. Det finns ingenting som kan köras parallellt. Är radioavläsningen interruptstyrd så spelar det ingen roll om man har delay eller inte, den kommer köras andå. Är den inte interruptstyrd så spelar det heller ingen roll med delay eller inte för den kommer aldrig att köras.

Men som vanligt när folk vill ha kodhjälp här på forumet så är allt så jävla hemligt. Problem med interrupts? Jaha, det skrivs ingenting om vilken hårdvara eller libraries som används till radion eller hur interruptrutinen ser ut.
Användarvisningsbild
hanpa
Utsparkad, på semester
Inlägg: 639
Blev medlem: 22 november 2016, 21:54:43
Ort: Hemort

Re: Interrupt i Arduino-kod

Inlägg av hanpa »

Du har nog rätt. Tänker i termer av ESP8266 och inte Arduino.

Vad gäller parallell körning förresten så räknar jag även in multi-tasking och det kan man ha även utan en processer med olika kärnor eller hårdvarustöd för trådar. Men det är säkert inte applicerbart på normal användning av Arduino. Vanliga delay() i Arduino är tydligen blocking men det finns de som gör egna non blocking-varianter av delay() av det skälet.

Men jag tycker också att det är lite tunt med information så därför kan man gissa fel. Vilken hårdvara har man. Hur är den inkopplad, vilka bibliotek använder man etc.
Borre
Inlägg: 4566
Blev medlem: 14 juni 2007, 15:43:50
Ort: Hälsingland

Re: Interrupt i Arduino-kod

Inlägg av Borre »

Skulle delay vara annat för ESP8266 menar du? Vad för program programmerar du med då?

En "vanlig" delay är normalt vad det låter som, en fördröjning där processorn står "still" och väntar på att tiden ska löpa ut innan den fortsätter med resten.
SeniorLemuren
Inlägg: 7779
Blev medlem: 26 maj 2009, 12:20:37
Ort: Kristinehamn

Re: Interrupt i Arduino-kod

Inlägg av SeniorLemuren »

Arduino är ju rätt och slätt inte "bara Arduino" Arduino förekommer ju med flera olika processorer. Arduino Duo t.ex med Atmel SAM3X8E ARM Cortex-M3 32 bit CPU kan man i databladet läsa:
The SAM3X/A architecture is specifically designed to sustain high speed data transfers. It
includes a multi-layer bus matrix as well as multiple SRAM banks, PDC and DMA channels that
enable it to run tasks in parallel and maximize data throughput.
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43152
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Interrupt i Arduino-kod

Inlägg av sodjan »

> that enable it to run tasks in parallel

Men i det fallet syftar "task" nog inte på att det körs normal programkod
utan ett "task" kan vara att en I/O enhet självständigt skriver till minne
via någon DMA funktion. För ren parallellkörning av kod behövs det mer
än en kärna. Sen så upplever ju en vanlig "human" användare att det
körs "samtidigt" även om det byter task varje 10 ms eller så... :-)

Men när det gäller grundfrågan i denna tråd så kanske ett "test-case"
vore på plats. Alltså en nerbantad version av koden till det minsta
praktiska som fortfarande uppvisar problemen. Sannolikheten är
dessutom stor att man under tiden löser problemet... :-)
Användarvisningsbild
hanpa
Utsparkad, på semester
Inlägg: 639
Blev medlem: 22 november 2016, 21:54:43
Ort: Hemort

Re: Interrupt i Arduino-kod

Inlägg av hanpa »

Borre skrev:Skulle delay vara annat för ESP8266 menar du? Vad för program programmerar du med då?

En "vanlig" delay är normalt vad det låter som, en fördröjning där processorn står "still" och väntar på att tiden ska löpa ut innan den fortsätter med resten.
Som jag har förstått det så är delay() vid "standard Arduino" helt blockerande, dvs inget annat kan köras då man exekverar delay().
Då menar jag inbyggda delay(), det finns andra varianter att tillgå.

Kör man ESP8266 via Arduino-miljön så har man oftast annat som kan köras under delay(), eller alternativt via yield()

Exempel på annat som kan köras på ESP8266 är hantering av webbserver, ftp, mqtt eller vad man nu använder WLAN-delen till. Så även om huvudloopen inte gör något annat än väntar under delay() så kan andra delar få köra. Diverse bibliotek bygger på att de får köra när inget annat körs i huvudloopen, anrop av delay() eller yield() är helt nödvändigt.
Användarvisningsbild
hanpa
Utsparkad, på semester
Inlägg: 639
Blev medlem: 22 november 2016, 21:54:43
Ort: Hemort

Re: Interrupt i Arduino-kod

Inlägg av hanpa »

Det är inte helt lätt att tränga igenom exakt hur det fungerar med delay, yield osv på Arduino eller ESP8266. Undantag finns även för Arduino angående att inget annat körs vid delay.
Certain things do go on while the delay() function is controlling the Atmega chip however, because the delay function does not disable interrupts. Serial communication that appears at the RX pin is recorded, PWM (analogWrite) values and pin states are maintained, and interrupts will work as they should.
https://www.arduino.cc/en/Reference/Delay
Mr Andersson
Inlägg: 1394
Blev medlem: 29 januari 2011, 21:06:30
Ort: Lapplandet

Re: Interrupt i Arduino-kod

Inlägg av Mr Andersson »

Ja interrupts har alltid högre prioritet än "vanlig" kod. Det är ju det som är hela poängen med interrupts, att de 'avbryter' nuvarande kod för någonting som är viktigare. Har ingenting med delay att göra. Inte heller DMA som nämndes tidigare.

Att det skulle vara svårt att se vad delay gör håller jag inte med om. Det är ju öppen kod.

Kod: Markera allt

void delay(unsigned long ms)
{
	uint32_t start = micros();

	while (ms > 0) {
		yield();
		while ( ms > 0 && (micros() - start) >= 1000) {
			ms--;
			start += 1000;
		}
	}
}

static void __empty() {
	// Empty
}
void yield(void) __attribute__ ((weak, alias("__empty")));
Det går alltså att överlagra yield eftersom det är ett svagt alias, men då TS inte nämnt någonting om det så antar jag att så inte skett.
Användarvisningsbild
hanpa
Utsparkad, på semester
Inlägg: 639
Blev medlem: 22 november 2016, 21:54:43
Ort: Hemort

Re: Interrupt i Arduino-kod

Inlägg av hanpa »

Att koden är öppen och kan läsas innebär inte att det är lätt för alla att förstå eftersom:
1. Man måste hitta koden
2. Man måste förstå vad den gör (kräver viss erfarenhet och den är dessutom utan kommentarer)

Sen behöver man förstå omgivningen, micros, att förstå syftet med yield och veta om den är överlagrad eller inte. Etc. Många användare av "Arduino" kopierar kod och det är då inte lätt att veta vad som händer, vad olika bibliotek gör etc. I aktuella tråden har vi fortfarande bara fått fragment av information om vad som görs i koden.
Användarvisningsbild
hawkan
Inlägg: 2586
Blev medlem: 14 augusti 2011, 10:27:40

Re: Interrupt i Arduino-kod

Inlägg av hawkan »

RCSwitch används eller? Tycker mej se det efter en snabb googling.
Undrar om det inte har med den att göra. Du skriver att det händer saker om du enablar interrupt på 2.
Hur har du satt upp RCSwitch och hur används den?
Användarvisningsbild
Synesthesia
Inlägg: 574
Blev medlem: 22 januari 2010, 19:14:10
Ort: Mellan Göteborg och Kungsbacka

Re: Interrupt i Arduino-kod

Inlägg av Synesthesia »

Det som är "events" (t.ex serialEvent()) är inte interrupt, utan det anropas från main och använder man delay eller gör något annat tidsödande i loop() så stannar också events.
Vet inte hur det är med AVR (eller vad det är för Arduino-variant du har) men på många microcontroller måste man nollställa en interruptflagga när man tagit emot interrupt (åtminstone för vissa interrupt), se datablad om det är något sådant som behöver göras på interruptet du enablade.
Skriv svar