LED auf Tastendruck

Hi,

Das Poti dient als Spannungsteiler, die geteilte Spannung greife ich an dem Mittelabgriff vom Poti der mit dem Port UPOT verbunden ist. Diese Spannung lege ich über ein Kabel an einen der ADC Ports und vergleiche dann im Prinzip zwei Spannungen miteinander? Das Ergebnis des Vergleichs wird danach weiterverarbeitet um den Timer1 der mir mein PWM Signal ausgibt damit die Pulsweite zu geben? Somit kann ich dann meine LEDs mit dem Poti regeln?

Die Spannung liegt am ADC-Eingang. Soweit OK. Der ADC hat eine Referenzspannung die im Atmel geändert werden kann (intern, extern, AVcc, ...) Der ADC teilt diese Referenzspannung in 1024 Teile und testet mit welchem Wert dieser Einteilung die Spannung am Eingang am besten übereinstimmt. Diese Nummer des Teils gibt er aus. Wenn du also als Referenz 5V verwendest und am Eingang 2,5V anliegen, dann gibt er 512 als Wert aus (die Hälfte von 1024 da ja auch 2,5V die Hälfte deiner 5V-Referenz ist). Der Dreisatz aus der Mathestunde läßt grüßen :p

Gruß
Dino
 
Ja.
Da die "Enden" des Onboard-Potis auf Vcc und Gnd liegen, stellst Du folglich auch an Upot (und somit auch am Pin des µC) eine Spannung zwischen Vcc und Gnd ein. Beim Mega8 sind alle ADC-Eingänge single ended, und "auf Gnd bezogen". Folglich ist Vcc als Referenzspannung am sinnigsten. Mein Vorschlag zielte auf die Kopplung eines 8-Bit-Timers (mit 8-bit-PWM) an den ADC mit 8-bit-Results.
Wobei ein weiterer Timer (Überlauf-ISR) den ADC triggert, und der ADC (Hab-fertig-ISR) den PWM-dutycycle ändert.
Wenn Dir das mit der AD-Conversion bzw das Ergebnis unklar ist, sag Bescheid. Im Prinzip hast Du (Mathe Klasse 6 oder so) einen Dreisatz /Verhältnisgleichung vor Dir.

erstmal
danach könnte man dann anderes ausprobieren:
-ADC im Dauerlauf
-10-Bit-PWM (frequenzkorrekt)
-Phasenkorrekte PWM (in Verbindung mit dem Oszi vom Foto vielleicht interessant, wenn man den anderen Kanal mit einem anderen Timer im Fastpwm laufen läßt (und diesen dann Triggern))

Edit: Dino war mal wieder schneller...
 
:confused: Immer diese ganzen Bits :confused:

Wie macht ihr das bloß, da wird man ja voll verrückt, ich finde den ADC ziemlich schwer, es wird hier von Channels gesprochen, damit sind doch sicherlich die Pins gemeint, die an den MUX angeschlossen sind :confused:

Was ist "Sample & Hold" in Kapitel ADC (S.195-196) Abschnitt "Prescaling and Conversion Timing"?
 
Hi,

Was ist "Sample & Hold" in Kapitel ADC (S.195-196) Abschnitt "Prescaling and Conversion Timing"?

stell dir mal vor du möchtest die Länge eines Stabes messen. Du legst einen Zollstock an aber dauernd zieht einer den Stab hin und her. Da wird es schwer die richtige Länge abzulesen. Genauso geht es dem ADC. Die Eingangsspannung am ADC-Kanal (Eingangspin) ist ja nicht total stabil. Sie ändert sich ja dauernd. Wenn du zB eine Wechselspannung oder einen Temperatursensor da anschließt. Also wird der Wert mit einem Sample&Hold für die Meßzeit "festgehalten". Der Eingang wird auf einen Kondensator geschaltet. Der Kondensator lädt sich auf die Spannung dieses Eingangs auf (Sample). Dann wird der Eingang abgetrennt (Hold) und die Spannung des Kondensators gemessen. Die verändert sich dann während der Meßzeit nicht da der Eingang ja abgetrennt ist.

Gruß
Dino
 
Dankeschön, das war sehr gut erklärt, jetzt hab ich's verstanden :)

Brauche ich den Noise Canceler des ADC?
Sonst würde ich den jetzt einfach überspringen und erstmal schauen, das ich "den" so zum laufen bekomme ;)

Ich benutzte als Referenzspannung Vcc?
 
Hallo Twister,

ein paar Beiträge zuvor hatte ich dir ein kleines ADC-Beispiel geschrieben. Probierte das vielleicht erst einmal aus. Es sind effektiv vielleicht 5 Zeilen code.

Gruss,
Dirk
 
Folgende vorgehensweise habe ich mir für's Programmieren überlegt: (ich hoffe Ihr könnt das lesen)

Foto(1).jpg

EDIT: Werde ich machen, hatte die Seite nicht aktualisiert, deswegen hatte ich jetzt erstmal meinen Beitrag gemacht ;)

EDIT: Programm probiert, allerdings habe ich nur die Zustände AN/AUS, was ich erstmal auch schon nicht so schlecht finde ;)
 
:confused: Immer diese ganzen Bits :confused:

Wie macht ihr das bloß, da wird man ja voll verrückt...
Nur eine Frage der Übung... und immer die Datenblätter hinzuziehen - einerseits die Block-Diagramme der Hardware, andererseits die entsprechenden Register-Beschreibungen helfen enorm. Insbesondere, wenn man die Register- und Bitnamen versucht auszusprechen (also die Abkürzungen).
...es wird hier von Channels gesprochen, damit sind doch sicherlich die Pins gemeint, die an den MUX angeschlossen sind...
Genau, Du hast mehrere mögliche (analog)Eingänge, aber nur einen AnalogDigitalConverter, folglich mußt Du dafür sorgen, daß der gewünschte Eingang auf den ADC geschaltet wird. Intern wird das über einen Multiplexer realisiert, den Du über das ADC-Multiplexer-Selection-Register (ADMUX) steuerst. (Den Ausgang des Multiplexers kannst Du übrigens stattdessen (wenn der ADC nicht enabled ist) auch auf den negativen Eingang des Analog Comperators schalten (ACME in SFIOR))
Was ist "Sample & Hold" in Kapitel ADC (S.195-196) Abschnitt "Prescaling and Conversion Timing"?
Hat Dino ja mal wieder sehr schön "blumig" erklärt... typisch Dino halt...;)
...Brauche ich den Noise Canceler des ADC?
Sonst würde ich den jetzt einfach überspringen und erstmal schauen, das ich "den" so zum laufen bekomme ;) ...
Brauchst Du erstmal nicht. Was ist das überhaupt?
So'n Controller erzeugt als schnell und viel schaltendes Digital-IC natürlich auch 'ne Menge EM-Störungen, die sich dann auch auf die eigene analoge Meß-Genauigkeit auswirken.
Andererseits hat man ja (auch um Strom zu sparen) bereits unterschiedliche Sleep-Modi (bei denen unterschiedliche Bereiche (mehr oder weniger) des Controllers angehalten/eingefroren/abgeschaltet werden können - und natürlich durch unterschiedliche Quellen (IRQs) wieder aufgeweckt (sonst macht das ja keinen Sinn)).
Das NoiseCancelling ist also eigentlich nur ein Sleep-Mode, bei dem der ADC aktiv bleiben darf, ein Teil des restlichen Controllers aber einfach mal die Klappe hält (Siehe auch Table 14 auf Seite 35 im Datenblatt zu den unterschiedlichen Sleep-Modi, den dann aktiven/inaktiven Bereichen, und den Weck-Möglichkeiten).
Ich benutzte als Referenzspannung Vcc?
Macht hier wie gesagt den meisten Sinn, allerdings nicht über den Aref-Pin, sondern intern verschaltet (Reference Selection Bits in ADMUX).

Folgende vorgehensweise habe ich mir für's Programmieren überlegt: (ich hoffe Ihr könnt das lesen)...
geht schon. Zur Frage, was in der while-Schleife zu tun ist: Nix - das auswerten des ADC-Ergebnisses, und beschreiben des OCRegisters für den PWM kannst Du bereits in der ISR des ADC erledigen. Ansonsten kann man natürlich vor der main einen entsprechenden Sleep-Modus vorbereiten, und den Controller in der main schlafen schicken - dann hast Du auch Dein "Noise Cancelling" (sofern man das bei aktivem PWM so nennen kann;))
@nur an/aus: stell mal den Code ein...
 
Hallo zusammen,

zum Entwurf der Programmstruktur: Im Freerunning Mode kann man den ADC durch bestimmte Ereignisse triggern lassen (also neu starten), u.a. auch durch die ADC-ISR. Man muss hier also nicht selber erneut starten.

Allgemein:
Ich würde erst mal "sample+hold", "noise cancelling" und sowas "Zur Seite legen". ADC-ISR ist natürlich elegant, wenn man das Compare-Register ändern möchte. Ich denke gut wäre es, wenn in der while Schleife von main() einfach mal eine simple ADC-Messung gemacht wird, das Ergebnis kann man über einen Port ausgeben (zB. LEDs ansteuern) oder eben das Compare Register ändern.
Danach erst weitere Schritte machen:
  • ggf. Messungen summieren und Mittelwert bilden,
  • dann ADC-ISR verwenden mit free running mode
  • dann ggf. in der ADC-ISR Mittelwertbildung realisieren


@Twister: Manchmal editierst und ergänzt du vergangene Beiträge, das übersieht man eventuell. Bei deinem letzten Beitrag weiss ich nicht genau, auf was oder wen du dich beziehst (bei den EDITs), bitte ab und zu auch mal zitieren.

Dirk :ciao:
 
@Twister: Manchmal editierst und ergänzt du vergangene Beiträge, das übersieht man eventuell. Bei deinem letzten Beitrag weiss ich nicht genau, auf was oder wen du dich beziehst (bei den EDITs), bitte ab und zu auch mal zitieren.
aber bitte nicht einfach den gesamten Beitrag zitieren. Wenn man einfach auf "zitieren" geht und einen langen Beitrag des Vorredners so stehen läßt, dann bläht sich das unnötig auf und wird etwas nervig ;)

Gruß
Dino
 
Nunja, Freerunning und so hat er ja bisher auch noch nicht in Angriff genommen. Daß die Begriffe mal deutlich erklärt werden, finde ich eigentlich auch ganz gut (mich hat das "sample&hold" im Datenblatt damals auch verwirrt ("Äh... was muß ich jetzt damit machen??"... nix eben;)).
Aber ok, vielleicht sollte man wirklich mal ganz unten anfangen.
Also nach dem init alles in der Hauptschleife abarbeiten lassen. Das sichere Abwarten einer kompletten Wandlung ist ja in einer Hochsprache kein Problem - dafür gibts sicher einen wait/delay/was-auch-immer-Befehl (unter ASM ist es einfacher, dann auf ein Flag zu warten).
Also... Level 1:
  • Initialisierung
  • while-Schleife
    • singleConversion starten
    • Pause (bis die Messung sicher fertig ist)
    • Ergebnis verarbeiten und ausgeben (LEDs/PWM/Display...)
    • ggf weitere Pause
  • while-Ende
Level 2:
  • Initialisierung
  • while-Schleife
    • singleConversion starten
    • Auf das ADC-hat-Conversion-fertig-Flag warten (ADIF in ADCSRA)
    • Ergebnis verarbeiten und ausgeben (LEDs/PWM/Display...)
    • ggf weitere Pause
  • while-Ende
Anmerkung: ADIF ist danach zu Fuß zu löschen, da wir ja keine IRQs vewenden. Da sich aber auch das ADC-Start-Conversion-Bit (ADSC) in ADCSRA befindet, sollte sich das zusammen beim Start der Conversion erledigen lassen.

Level 3:
  • Initialisierung (inklusive einem Timer mit Überlauf-IRQ, der länger braucht, als der ADC)
  • eine singleConversion anstoßen
  • leere while-Schleife
  • Timer-ISR
    • ADC-Ergebnis auslesen/verarbeiten/ausgeben
    • neue Conversion anstoßen
  • ISR-Ende
Level 4:
fällt mir grad nix konkretes ein...
 
Mein aktueller Code:

Code:
#include <avr/io.h>      

#include <stdlib.h>
#include <avr/interrupt.h>


#define F_CPU 1000000UL
#include <util/delay.h> 



int main(void)
{

	//	Timer/Counter initialisieren

	TIMSK = (1<<OCIE1A) | (1<<TOIE1);
	TCCR1A = (1<<WGM10) | (1<<COM1A1) | (1<<COM1A0);
	TCCR1B = (1<<CS11);
	OCR1A = 0;
	
	ADMUX |= (1<<REFS0);
	ADCSRA |= (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // ADEN: Enable ADC, ADSC: Start Conv., Prescaler: 128
	

	//	Register initialisieren

	DDRB = 0xFF;
	PORTB = 0xFF;									// Zuerst alle LEDs ausschalten


	sei();											//	Globale Interrupts ein

	//	Hauptprogramm

	while(1)
	{
		ADCSRA |= (1<< ADSC);
		_delay_ms(100);
	}
}

Ich komme einfach gerade nicht vorwärts.... Wie kann man denn das Ergebnis weiterverarbeiten? Hab ich bis hierhin Fehler gemacht?

Referenzspannung: Vcc an AREF
Prescaler 128: 7k und ein paar zerquetschte Hertz ;)
 
Ich komme einfach gerade nicht vorwärts.... Wie kann man denn das Ergebnis weiterverarbeiten? Hab ich bis hierhin Fehler gemacht?

Referenzspannung: Vcc an AREF
Prescaler 128: 7k und ein paar zerquetschte Hertz ;)

Ich habe dir in diesem Beitrag ein einfaches Beispiel geschrieben. Schau dir das mal an, damit solltest du eigentlich zurecht kommen.

Dirk :ciao:
 
Hey Dirk,

danke nochmal für den Link, ich hatte es mir schon angekuckt, benutzt und hatte mich gewundert warum es nicht funktioniert, allerdings funktioniert es doch, ich dachte das Programm regeltdie Helligkeit, aber eigetnlich kann man da über das Poti die Anzahl der leuchtenden LEDs einstellen.

Was hat es mit dem uint16_t auf sich? Ich komme mit diesem Typ noch nicht ganz klar, genauso wie mit uint8_t...

du hast mit der Zeile

adc_result = ADCW;

das Ergebnis der Unwandlung in deiner Variable gespeichert, was bedeutet das W in ADCW?
 
Ich kann jetzt im aktuellen Code mit dem Poti die LED über PWM EIN/AUS-schalten, theoretisch müsste ich jetzt nur noch viele Stufen einbauen, um somit die LED feiner regeln zu können oder?

Hier mein Code:

Code:
#include <avr/io.h>      
#include <stdlib.h>
#include <avr/interrupt.h>

int main(void)
{

	uint16_t adc_result;

	//	Timer/Counter initialisieren

	TIMSK = (1<<OCIE1A) | (1<<TOIE1);
	TCCR1A = (1<<WGM10) | (1<<COM1A1) | (1<<COM1A0);
	TCCR1B = (1<<CS11);
	OCR1A = 0;
	
	ADMUX |= (1<<REFS0);
	ADCSRA |= (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // ADEN: Enable ADC, ADSC: Start Conv., Prescaler: 128
	

	//	Register initialisieren

	DDRB = 0xFF;
	PORTB = 0xFF;									// Zuerst alle LEDs ausschalten


	sei();											//	Globale Interrupts ein

	//	Hauptprogramm

	while(1)
	{
		ADCSRA |= (1<< ADSC);						// Start single conversion
		while ( ADCSRA & (1<<ADSC) ) { }
		
		adc_result = ADCW;
		
		if(adc_result < 512)
		{
			OCR1A = 0;
		} else
		{
			OCR1A = 255;
		}
	}
}
 
Hi Twister,

ich habe jetzt leider nicht so viel Zeit, deshalb mal kurz ...
Was hat es mit dem uint16_t auf sich? Ich komme mit diesem Typ noch nicht ganz klar, genauso wie mit uint8_t...

Hier legst du die Größe der Variable im SRAM fest. uint16_t ist eine 16bit Variable ohne Vorzeichen, uint8_t entsprechend 8Bit.
du hast mit der Zeile

adc_result = ADCW;

das Ergebnis der Unwandlung in deiner Variable gespeichert, was bedeutet das W in ADCW?

ADCW ist das Ergebnisregister. Genau genommen gibts das Register ADCW nicht, es gibt ADCL und ADCH (beides 8bit). Der Compiler kann aber über ADCW richtig auf die Ergebnisregister zugreifen und behandelt das Ergebnis als 16Bit Register, also uint16_t oder WORD (deshalb auch das W).

Ich kann jetzt im aktuellen Code mit dem Poti die LED über PWM EIN/AUS-schalten, theoretisch müsste ich jetzt nur noch viele Stufen einbauen, um somit die LED feiner regeln zu können oder?

Mach doch mal folgendes, wenn du ein 8bit Compare-Wert benötigst und 10bit ADC Ergebnis hast:

Code:
adc_result = ADC_result >> 2; // rechts shiften um 2 Bits entspricht Division durch 4 -> Wertebereich also 0..255
OCR1A = adc_result;

Dirk :ciao:
 
Hey Dirk,

danke für den Tipp, dass ist sehr viel eleganter, als 500.... if-Schleifen zu machen :)

jetzt werde ich mal an Version 2 von Lotadas Vorschlägen setzen!

EDIT: Ist der Free Running Mode nicht eigentlich viel sinvoller, wenn ich mit einem Mikrocontroller sowieso das Ziel verfolge, kontinuierlich bestimmte Werte umzuwandeln?

Es kam doch der Vorschlag die Abtastrate mit dem Timer 0 einzustellen, wenn ich den Free Running Mode benutzte, dann wird der Timer 0 aber nicht benutzt, d.h. die dadurch aufgerufene ISR braucht mein Hauptprogramm nicht unterbrechen um den ADC zu starten, welcher mir dann mit einem weiteren Interrupt wieder meine Schleife unterbrechen würde.
Ist der Free Running Mode für eine solche Aufgabe wo ich ständig auf bestimmte ext. Werte angewiesen bin besser?
 
Hallo Mr.Twister,

du hast mit der Zeile

adc_result = ADCW;

das Ergebnis der Unwandlung in deiner Variable gespeichert, was bedeutet das W in ADCW?

Im Datenblatt stehen auch die langen Namen der Register drin ...

ADC Multiplexer Selection Register – ADMUX

ADC Control and Status Register A – ADCSRA

Wenn du in einem Registernamen ein W findest, dann kann das "Working" oder aber auch "Word" (16Bit = 2 8Bit-Register zusammen) bedeuten. Da die ADC-Ergebnisregister ADCH und ADCL heißen und nur 8Bit haben, ist die Wahrscheinlichkeit für "Word" recht groß wenn im Programm das Ergebnis mit einem Befehl in eine Variable gelegt wird, wo doch das Ergebnis eigentlich in zwei 8Bit-Registern liegt. ADCW steht jetzt nicht im Datenblatt weil es keine 16Bit-Register gibt. Das ist eine Definition der Programmiersprache die das dann in die entsprechenden Einzelbefehle umsetzt. Also "eigentlich nur" logische Kombination der vorhandenen Fakten um auf die Erklärung zu kommen ;)

Gruß
Dino
 
...Ist der Free Running Mode nicht eigentlich viel sinvoller, wenn ich mit einem Mikrocontroller sowieso das Ziel verfolge, kontinuierlich bestimmte Werte umzuwandeln?

Es kam doch der Vorschlag die Abtastrate mit dem Timer 0 einzustellen, wenn ich den Free Running Mode benutzte, dann wird der Timer 0 aber nicht benutzt, d.h. die dadurch aufgerufene ISR braucht mein Hauptprogramm nicht unterbrechen um den ADC zu starten, welcher mir dann mit einem weiteren Interrupt wieder meine Schleife unterbrechen würde.
Ist der Free Running Mode für eine solche Aufgabe wo ich ständig auf bestimmte ext. Werte angewiesen bin besser?
Natürlich - aber ich wollte Dich ein wenig mit dem ganzen Kram spielen lassen...
Am besten ist es, wenn der ADC sich selbst triggert (also das setzen des ADIF eine neue Konversion startet. Beim Mega88 können auch andere Ereignisse den ADC automatisch triggern), und man die Verarbeitung in der entsprechenden ISR vornimmt (direkt, wenns schnell geht/nötig ist, indirekt (über ein Flag) im Hauptprogramm, wenns länger dauert).
Wie Dir inzwischen klar ist, handelt es sich um einen 10-Bit-ADC. Außerdem weißt Du, daß das 10-Bit-Ergebnis in 2 Registern abgelegt wird - ADCH und ADCL. Normalerweise stehen also in ADCL die unteren 8 bits, in ADCH sind die oberen 8 Bits null, in Bit 1 steht das MSB des Ergebnisses, in Bit 0 Bit 9 des Ergebnisses. Diese Einstellung heißt "right adjusted". Ist aber im ADMUX-Register das Bit ADLAR (ADC Left Adjusted Result) gesetzt, werden (oh welch Überraschung) die oberen 8 Bit des Ergebnisses in ADCH abgelegt, die untersten beiden Bits vom Ergebnis in Bit 7 und 6 von ADCL. Die 10 Ergebnisbits sind quasi linksbündig in das zusammengesetzte 16-Bit-ADC-(Ergebnis)-Register geschrieben, klar?!
Preisfrage: Was steht jetzt konkret in ADCH?
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)