Ergebnis von A/D-Umsetzung falsch

In dieses Forum gehören all deine Fragen rund um die Elektrotechnik und im Speziellen zum Bereich der Mikrocontrollertechnik.

Re: Ergebnis von A/D-Umsetzung falsch

#11

Ungelesener Beitrag Nico » 17. Apr 2019, 09:41

Hallo Sebbl,

also gut, du hast den AD-Umsetzer mit ADCON0 = 0b10000000; auf VDD (5V) für die Referenz gesetzt. Der Umsetzer arbeitet mit 10 Bit, demnach ist dein ULSB = 4,88mV. In deinem Programm fragst du verschiedene Bereiche ab:

Code: Alles auswählen

while (Modus == 1) // 2,1A-Modus
{ 
	if ((Wert3 > 50) && (Wert3 < 200))
	{
		Ausgang = 0;
	}
	else 
	{  
		Ausgang = 1;
	}
}    
while (Modus == 0) // 2,4A-Modus (Punkt)
{ 
	if ((Wert3 > 200) && (Wert3 < 300))
	{ 
		Ausgang = 0;
	}
	else
	{  
		Ausgang = 1;
	}
} 
Hieraus würde ich lesen, dass Ausgang aka GPIO5 gelöscht wird, wenn die Spannung an AN0 im Bereich von ca. 0,25 bis 0,976V liegt (etwas gerundet) und Modus aka GPIO2 ein high sieht. Wenn jedoch ein low an Modus anliegt, ändert sich der Spannungsbereich in dem Ausgang gelöscht wird auf 0,976V bis 1,47V (erneut gerundet).

Anmerkung(en) an dieser Stelle:
  • #defines werden üblicherweise immer in Großbuchstaben geschrieben.
  • Variablen werden üblicherweise mit einem Kleinbuchstaben begonnen.
Demnach würde ich empfehlen deine zwei #defines entsprechend zu ändern (englische Begriffe habe ich mir jetzt mal verkniffen ;-) ):

Code: Alles auswählen

#define MODUS		GPIO2
#define AUSGANG		GPIO5
Des Weiteren die Änderung deiner (globalen) Variablen:

Code: Alles auswählen

int wert;
Richtig, nur noch eine statt drei (nicht notwendig, siehe später). Ein weiterer Hinweis: Globale Variablen sollten wenn möglich immer vermieden werden. Aber das soll uns an dieser Stelle jetzt erstmal nicht weiter kümmern.
pic18 hat geschrieben:
3. Apr 2019, 11:57
[..] Außerdem sollte man im Interrupt keine Zeitschleifen machen!
Da hat er recht. Mach es lieber so: Wenn ein Interrupt auftritt, setzt ein Flag für dieses aufgetretene Ereignis (einfach ein Bit / Variable setzen). In der Hauptschleife kannst du dieses Flag überprüfen und entsprechend reagieren.
pic18 hat geschrieben:
3. Apr 2019, 11:57
wie wird denn hier der Interrupt ausgelöst?
Da er in initPIC() das Bit T0IE in INTCON setzt, vermute ich, dass der Timer0 einen kontinuierlichen Interrupt auslösen soll. Konfiguriert hat er diesen über OPTION_REG = 0b00000111;. Somit sollte der Timer mit 4Mhz / (4*256) ~ 3,9kHz laufen (sofern ich nichts übersehen habe). Bei 8 bit ergibt das also einen Interrupt alle ~66ms.



Ich habe mir mal erlaubt deine main.c etwas umzuschreiben (siehe Anhang). Man könnte sicherlich noch mehr verbessern aber lassen wir es erstmal dabei. Ich wollte auch nicht zu viel verändern. Also was habe ich gemacht?

Im Grunde nicht sehr viel .. Ich habe die Anmerkungen (siehe oben) umgesetzt, etwas überflüssige Variablen entfernt und allem voran die Interrupt Service Routine aufgeräumt: In der Routine wird nun nur noch ein Flag gesetzt (flag_tmr0). Dieses Flag wird in der Hauptschleife geprüft und entsprechend die Messung gestartet (ausgelagert in die Funktion readAN0() um es etwas übersichtlicher zu gestalten).

Frage: Mit welchem Compiler arbeitest du? Ich musste die ISR umbenennen, da mein Compiler (XC8) es in diesem Format haben möchte. Das ganze Programm habe ich mit dem Simulator durchgespielt (Funktion wie erwartet).

PS: Die Widerstände sollten die hohe Last vertragen können. Normale 0815 Drahtwiderstände haben oftmals nur 125..250 mW als Belastungsgrenze. Bei den im Quellcode genannten 2,4A sind das dann aber schon >5W! Das möchte ich dann nicht mehr mit nackten Fingern anfassen. Wie wäre es die Last nur kurzzeitig zu schalten (Einschaltdauer je nach Belastungsverhalten/Erprobung der Lader)?
Dateianhänge
main.c
(1.85 KiB) 20-mal heruntergeladen