Hallo,
ich möchte auf einem Tiny13 alle vier ADC Eingänge kontinuierlich
nacheinander abfragen.
Dazu habe ich mir gedacht den ADC im free running Modus laufen zu lassen
und dann folgende ISR:
1
//Analog inputs
2
ISR(ADC_vect)
3
{
4
if(uADCChange<4)
5
{
6
//vier mal einlesen
7
uADCChange++;
8
//jeweiliger Wert des ADC-Pins ins Input-Array
9
uInputs[ADMUX]=ADCL;
10
}
11
else
12
{
13
uADCChange=0;
14
//ADC Pins weiterschalten
15
ADMUX++%3;
16
}
17
}
Kann ich mit den Registern so wie mit Variablen arbeiten ?
Oder muß ich jeweils händisch die Werte in eine Zwischenvariable holen ?
Weil so wär's mir am liebsten ;-)
Danke.
Ja das sollte gehen. Aber:
- ADCMUX++%3 macht nicht ganz das, was du wahrscheinlich denkst: Die
Erhoehung findet erst nach dem modulo statt.
- %3 ? Du willst vier mal erhoehen, also %4 => moegliche Werte (0,1,2,3)
- Du schaltest den MUX ja waehrend einer Messung um, also kannst du das
naechste Ergebnis nach jedem Umschalten nicht gebrauchen.
- Du brauchst die zusaetzliche Zaehlvariable gar nicht: Du kannst direkt
den Wert aus ADCMUX verwenden.
Jan M. wrote:
> - Du schaltest den MUX ja waehrend einer Messung um, also kannst du das> naechste Ergebnis nach jedem Umschalten nicht gebrauchen.
Stimmt so nicht. Die Umschaltung erfolgt halt nur nach dem Ende der
laufenden Messung.
Danke für die schnelle Antwort.
Da ich sowieso vier mal hintereinander den selben Pin Abfrage (daher die
Zählvariable), sollte das mit dem Umschalten während der Messung nicht
ins Gewicht fallen.
Das Modulo vor dem Inkrement ausgeführt wird wußte ich gar nicht.
Und typischer Denkfehler 3%3 ist 0, Danke X-D
Also müsste das so OK sein:
1
//Analog inputs
2
ISR(ADC_vect)
3
{
4
if(uADCChange<4)
5
{
6
//vier mal selben Pin einlesen
7
uADCChange++;
8
//jeweiliger Wert des ADC-Pins ins Input-Array
9
uInputs[ADMUX]=ADCL;
10
}
11
else
12
{
13
uADCChange=0;
14
//ADC Pins weiterschalten
15
(ADMUX++)%4;
16
}
17
}
Weitere Frage:
Da ich ja den RESET Pin nehmen muß, um vier analoge Eingänge zu haben,
wie kann ich den Tiny13 dann neu programmieren ?
ISP funktioniert dann ja nicht ?
Im Datenblatt steht was über High-Voltage Serial Programming.
Kann ich einfach 12V an RESET geben und dann mit einem üblichen ISP
programmieren, oder brauche ich da zusätzliche Hard-/Software ?
Ich verwende den aktuellen WinAVR und den billisgten Parport-ISP mit
avrdude.
Danke nochmal.
> uInputs[ADMUX]=ADCL;
So wird das nichts. Es muss auf jeden Fall auch (oder nur) ADCH gelesen
werden. Das alleinige Lesen von ADCL ist nicht nur ziemlich sinnfrei, es
sorgt auch dafür, dass sich der Wert in den Ergebnisregistern nicht mehr
ändern kann. Wenn Du nur 8 Bit Auflösung brauchst, dann setze das
ADLAR-Bit im ADMUX und lies nur das ADCH aus.
Nein. Ist nach C Standard immer noch undefiniert. Ganz abgesehen
davon, dass das Ergebnis der Modulo Division nirgends benutzt wird :-)
Was ist so schlimm an
1
ADMUX=(ADMUX+1)%4;
PS: Dir ist schon klar, dass dadurch alle anderen Bits in ADMUX,
so denn welche gesetzt sein sollten, auf 0 gesetzt werden?
@ Johannes M.
Dann habe ich das mit dem ADLAR Bit falsch verstanden.
Stimmt, hätte mal auf der nächsten Seite weiterlesen sollen X-D
@ Karl heinz Buchegger
Schreibfaulheit X-D
Ja das alle anderen auf 0 gesetzt werden ist klar, deswegen ja ADCL
statt ADCH.
OK kann ich dann sowas tun:
1
//Analog inputs
2
ISR(ADC_vect)
3
{
4
if(uADCChange<4)
5
{
6
//vier mal selben Pin einlesen
7
uADCChange++;
8
//jeweiliger Wert des ADC-Pins ins Input-Array
9
uInputs[ADMUX]=ADCL;
10
ADCL=ADCH;
11
}
12
else
13
{
14
uADCChange=0;
15
//ADC Pins weiterschalten
16
ADMUX=(ADMUX+1)%4;
17
}
18
}
Oder habe ich da jetzt wegen dem ADLAR unbrauchbare Werte ?
Sah vorhin noch so einfach aus ...
Danke.
> ADCL=ADCH;
ADCL und ADCH sind read-only... Macht aber auch ansonsten nicht viel
Sinn... Was Du da genau machen willst, verstehe ich immer noch nicht
ganz. Warum nur die letzten 8 Bit? Das macht keinen Sinn. Die laufen
im Wertebereich insgesamt dreimal über.
@ Johannes M.
Schade, hab' gerade gepeilt das ich das mit dem ADLAR total falsch
verstanden hatte :-(
Also nochmal:
1
//Analog inputs
2
ISR(ADC_vect)
3
{
4
if(uADCChange<4)
5
{
6
//vier mal selben Pin einlesen
7
uADCChange++;
8
//jeweiliger Wert des ADC-Pins ins Input-Array
9
uInputs[ADMUX]=ADCH;
10
}
11
else
12
{
13
uADCChange=0;
14
//ADC Pins weiterschalten
15
ADMUX=(ADMUX+1)%4;
16
ADMUX|=(1<<ADLAR);
17
}
18
}
Stimmt's jetzt ?
Um nochmal auf meine Frage wegen dem RESET Pin zurück zu kommen:
Geht das wie ich meine mit einem normalen ISP, nur das dann RESET statt
auf GND auf +12V gesetzt wird ?
Danke.
Neuer wrote:
> @ Johannes M.> Schade, hab' gerade gepeilt das ich das mit dem ADLAR total falsch> verstanden hatte :-(> Also nochmal:> [...]> Stimmt's jetzt ?
Sieht gut aus...
> Um nochmal auf meine Frage wegen dem RESET Pin zurück zu kommen:> Geht das wie ich meine mit einem normalen ISP, nur das dann RESET statt> auf GND auf +12V gesetzt wird ?
Nein, das geht nicht. Da muss eine bestimmte Sequenz eingehalten werden.
> ADMUX = (ADMUX + 1)%4;> ADMUX |= (1<<ADLAR);
Das kannste auch in einem Abwasch machen
1
ADMUX=((ADMUX+1)%4)|(1<<ADLAR);
Dann ist es nur ein Schreibzugriff auf ADMUX. Ich weiß nämlich nicht,
was passiert, wenn das ADLAR während einer laufenden Wandlung gelöscht
und dann wieder gesetzt wird...
OK,
schade das ich nicht meinen ISP nehmen kann zum HV-Programmieren :-(
Nun zum nächsten Problem:
Mit den ausgelesenen Potis soll eine in Frequenz (0-250 Hz) und
Tastverhältnis (0-100%) PWM ausgegeben werden.
Soweit ich das im Datenblatt verstanden habe wird die Frequenz durch die
CPU-Frequenz/Prescaler vorgegeben und ich kann im PWM Modus über das
OCRx Register das Tastverhältnis setzen.
Nur wie bekomme ich nun eine Frequenz von weniger als CLK/256 hin ?
Sorry wenn ich nerve aber ich stehe gerade ziemlich auf dem Schlauch.
Danke.
Neuer wrote:
> Mit den ausgelesenen Potis soll eine in Frequenz (0-250 Hz) und> Tastverhältnis (0-100%) PWM ausgegeben werden.
Also 0 Hz ist meist ein bisschen schwierig, v.a. bei einer PWM...
Du willst also ein PWM-Signal erzeugen und sowohl die Frequenz
(Periodendauer) als auch das Tastverhältnis ändern können?
> Soweit ich das im Datenblatt verstanden habe wird die Frequenz durch die> CPU-Frequenz/Prescaler vorgegeben und ich kann im PWM Modus über das> OCRx Register das Tastverhältnis setzen.
CPU-Frequenz/Prescaler ist die Frequenz, mit der der Timer getaktet
wird. Der wiederum läuft im Normalfall nach 256 Takten über, man kann im
CTC- bzw. Fast-PWM-Modus aber über eines der beiden Compare-Register
auch andere Werte vorgeben ==> Datenblatt...
> Nur wie bekomme ich nun eine Frequenz von weniger als CLK/256 hin ?
Im PWM-Modus 7 kannst Du über OCR0A die Periodendauer und über OCR0B das
Tastverhältnis ändern. Allerdings muss das Tastverhältnis natürlich
jeweils an die Periodendauer angepasst werden. Bei höheren Frequenzen
geht die Auflösung in den Keller. Abgesehen davon kann man aber über den
Prescaler auch andere Bereiche einstellen (der kann ja nicht nur durch
256, sondern auch durch 64, durch 8 und durch 1 teilen)...
Neuer wrote:
> Da ich ja den RESET Pin nehmen muß, um vier analoge Eingänge zu haben,> wie kann ich den Tiny13 dann neu programmieren ?> ISP funktioniert dann ja nicht ?
Stimmt.
Das ist dann ein Fall für den Bootloader-Man.
Peter
@ Johannes M.
Sorry da ist die 1 nicht mitgekommen 10-250 Hz :-)
Und 0 geht auch, Timer abschalten fällt mir so spontan ein (gut ist dann
keine PWM mehr).
Also ich lese jetzt schon länger die Timer Beschreibungen durch, OCRB
wird da irgendwie nie so richtig erklärt.
Ich denke das ist identisch zu OCRA ?
Wenn ich Dich jetzt richtig verstanden habe kann ich durch die beiden
Register den Timer so beeinflussen, das er einmal wenn OCRA erreicht
wird einen Output mit dem eingestellten Wert macht (Tastverhältnis) und
wenn OCRB erreicht wird der Timer von vorne anfängt und ich dadurch die
Frequenz ändern kann und umgekehrt ?
OK, dann muß ich je nach dem wie groß der Wert von OCRB ist OCRA
proportional daran anpassen, damit das Tastverhältnis identisch bleibt
wenn sich die PWM Frequenz ändert.
Ich denke mal das ich jetzt erstmal ein Bier trinke und mein Projekt
Projekt sein lasse.
Mal sehen ob ich's morgen kapiere ;-)
Danke für die Hilfestellung !
Neuer wrote:
> @ Johannes M.> Sorry da ist die 1 nicht mitgekommen 10-250 Hz :-)> Und 0 geht auch, Timer abschalten fällt mir so spontan ein (gut ist dann> keine PWM mehr).
Genau das ist das Problem...
> Also ich lese jetzt schon länger die Timer Beschreibungen durch, OCRB> wird da irgendwie nie so richtig erklärt.> Ich denke das ist identisch zu OCRA ?
Der µC hat zwei Compare-Einheiten, die in ihrer Grundfunktion identisch
sind und deshalb nicht gesondert erwähnt werden (in den
Registerbeschreibungen im Datenblatt steht dann OCR0x, wobei x für A
oder B stehen kann). Bei einer PWM mit fester Frequenz (8-Bit-PWM) kann
man mit beiden Compare-Einheiten zwei PWM-Kanäle mit der selben
Frequenz, aber unabhängig voneinander einstellbaren Tastverhältnissen
implementieren.
Wenn man die Frequenz verändern will, wird eins der beiden
Compare-Register "zweckentfremdet" und nimmt den Überlaufwert auf
(ähnlich wie bei CTC, nur dass im PWM-Betrieb noch ein paar zusätzliche
Dinge automatisch gemacht werden, wie z.B. Synchronisation der
Register). Das andere Compare-Register kann dann den Wert für das
Tastverhältnis aufnehmen und am dazugehörigen Ausgangspin steht dann das
PWM-Signal zur Verfügung.
> Wenn ich Dich jetzt richtig verstanden habe kann ich durch die beiden> Register den Timer so beeinflussen, das er einmal wenn OCRA erreicht> wird einen Output mit dem eingestellten Wert macht (Tastverhältnis) und> wenn OCRB erreicht wird der Timer von vorne anfängt und ich dadurch die> Frequenz ändern kann und umgekehrt ?
Naja, so ungefähr...
> OK, dann muß ich je nach dem wie groß der Wert von OCRB ist OCRA> proportional daran anpassen, damit das Tastverhältnis identisch bleibt> wenn sich die PWM Frequenz ändert.
Ja. Und das geht nicht stufenlos (OK, so richtig stufenlos geht es
sowieso nicht, weil digital und sowieso nur 8 Bit).
> Ich denke mal das ich jetzt erstmal ein Bier trinke und mein Projekt> Projekt sein lasse.
Bier ist meist ne gute Idee...
> Mal sehen ob ich's morgen kapiere ;-)
Wird schon...
Matthias Lipinsky wrote:
> Leute...>> Ihr wollt von 0 bis 3 zählen!>> Zu dessen Begrenzung nimmt man doch kein Modulo!>>
1
>ADMUX=(ADMUX+1)&0x03;
2
>
Was, lieber Matthias, glaubst Du, was der Compiler wohl aus dem "%4"
macht? OK, über die Schreibweise an sich kann man streiten, aber der
generierte Code dürfte (müsste) identisch sein. Einen Compiler, der es
nicht packt, aus "x % 2^n" ein "x & 2^n-1" zu machen, musste mir noch
zeigen...
OK,
also jetzt denke ich das mit dem Modus 7 verstanden zu haben.
Ich setze Timer0 mit Prescaler 256, dann schreibe ich 16 ins OCR0A und
bekomme statt den 4,6 kHz 292 Hz als PWM Grundfrequenz und bei 256 ca.
18 Hz.
Der Tiny läuft mit 1,2 MHz internem Takt.
Dann trage ich in OCR1A das Tastverhältnis ein, welches ich vorher durch
den OCR0A Wert teile und behalte so bei einer Frequenzänderung das
Tastverhältnis.
Wäre dann so etwas:
1
voidsetFreq(unsignedcharFreq)
2
{
3
OCR0A=Freq;
4
}
5
6
voidsetTast(unsignedcharTast)
7
{
8
OCR1A=Tast>>OCR0A;
9
}
Welcher PWM Pin wird dann genutzt, OCR1A ?
Oder hab ich's wieder nicht richtig verstanden ?
@ Peter Dannegger:
Was ist denn der "Bootloader-Man" ?
Danke.
Neuer wrote:
> OK,> also jetzt denke ich das mit dem Modus 7 verstanden zu haben.> Ich setze Timer0 mit Prescaler 256, dann schreibe ich 16 ins OCR0A und> bekomme statt den 4,6 kHz 292 Hz als PWM Grundfrequenz und bei 256 ca.> 18 Hz.
Fast
> Der Tiny läuft mit 1,2 MHz internem Takt.> Dann trage ich in OCR1A das Tastverhältnis ein, welches ich vorher durch> den OCR0A Wert teile und behalte so bei einer Frequenzänderung das> Tastverhältnis.
Der Tiny13 hat nur einen Timer, und das ist Timer 0. Dementsprechend
gibt es kein OCR1A. Die beiden Compare-Register heißen OCR0A und OCR0B,
wie oben schon mal erwähnt. OCR0A definiert die Frequenz, OCR0B das
Tastverhältnis, das PWM-Signal wird an OC0B ausgegeben.
> Wäre dann so etwas:> [...]> Welcher PWM Pin wird dann genutzt, OCR1A ?> Oder hab ich's wieder nicht richtig verstanden ?
Siehe oben...
Problem ist bei der genannten Konfiguration mit OCR0A = 16, dass das
Tastverhältnis auch nur noch in 16 Stufen einstellbar ist.
Ich sehe grad, dass in der Timer-Betriebsarten-Tabelle (Tabelle 32 im
Datenblatt) das Compare-Register irreführend mit OCRA angegeben ist. Es
muss OCR0A heißen.
EDIT:
Übrigens, damit das Signal auch ausgegeben wird, müssen natürlich die
COM-Bits im TCCR0A entsprechend gesetzt werden.
Was mir auch noch aufgefallen ist: Im Datenblatt wird für Fast-PWM mit
OCR0A als TOP keine explizite Formel für die Berechnung der Frequenz
anhand des Compare-Wertes angegeben. Die lautet
Neuer wrote:
> Danke das war's ;)> Noch eine Frage, ist das normal das das .hex größer ist als was gcc> anzeigt ?
Ja das ist normal.
gcc rechnet die Programmgröße in Bytes. Im HexFile wird aber
jedes Byte durch 2 Zeichen dargestellt (Ein Hex File ist ja
auch nur ein Textfile. Wenn du willst kannst du ja mal reinschauen).
Dazu dann noch ein paar Steuerinformationen, wie Startadresse,
Checksumme und dgl. und schon ist das HexFile rund 3 mal so groß
wie die eigentliche 'Nutzinformation' gemessen in Byte.