Hallo,
ich möchte mit 4 Potis 4 LEDs über PWM dimmen. Dafür habe ich mir mit
Hilfe des Datenblatts zum ATtiny84 und ein paar Codebeispielen aus dem
Internet ein Programm zusammengebaut. Leider Funktionier Garnichts. Die
LEDs an den PWM Ausgängen bleiben aus. Im Anhang ist mein Programm.
Vielleicht kann sich das ja mal einer genauer Anschauen. Bin für jede
Hilfe dankbar.
Gruß Felix
Hi
Passiert GAR NICHTS, oder irgend was, was Du so nicht erwartet hättest?
Hast Du schon Mal probiert, hier und da im Programm einen Ausgang zu
toggeln, damit man sieht, daß das Programm zumindest läuft?
Hatte mit den While-Schleifen Bedenken, sind aber in dem Beispiel:
http://rn-wissen.de/wiki/index.php/ADC_(Avr)
ebenso ausgeführt - wird's dann wohl nicht sein.
MfG
Hallo,
das mit der ist mir klar, hab ich mich wohl vertippt. Aber was in den
anderen Fehlerhaften Zeilen ist, weiß ich nicht genau worauf du hinaus
willst. Währe schön wenn du mir es mal erklären könntest.
Gruß Felix
Hallo Felix,
das ist ein grundsätzliches Problem, erst muss man C lernen, dann die
Bitmanipulation - um die geht es hier - beherrschen, dann kann man die
Vorgaben aus dem Datenblatt auch umsetzen.
Also:
a = b;
a |= c;
a &= ~(d);
a = (1<<2);
a = (a & ~(0b00001111)) | 0b00000011;
Dies sind einige Beispiele die Du aus dem "ff" beherrschen müsstest.
Damit will ich Dich nicht angreifen, nur die nächste Lernstufe
aufzeigen.
Wir habe alle mal von Null angefangen.
Mach weiter.
holger schrieb:> ADMUX = (0<<REFS1) | (1<<REFS0);> ADMUX = (1<<ADLAR);> ADMUX = (0<<MUX3) | (0<<MUX2) | (0<<MUX1) | (0<<MUX0);
Da du immer ein '=' schreibst, wird der jeweils vorherige Zustand
überschrieben. Das gilt nicht nur für ADMUX, sondern auch für deine
anderen Registermanipulationen.
Du solltest also verODERn.
Karl M. schrieb:> das ist ein grundsätzliches Problem, erst muss man C lernen...
Naja, nicht unbedingt. Man kann auch eine Sprache verwenden, die mittels
des Befehls "Bits" nur die Bits im entsprechenden Register setzt, die
gesetzt werden sollen und die anderen in Ruhe läßt. Ohne VerOderungen
und/oder VerUndungen oder VerRenkungen.
$regfile = "attiny84.dat"
Admux = Bits(refs0 , Adlar)
Adcsra = Bits(aden , Adps2 , Adps1)
Do
nop
Loop
C tut weh schrieb:> Naja, nicht unbedingt. Man kann auch eine Sprache verwenden, die mittels> des Befehls "Bits" nur die Bits im entsprechenden Register setzt, die> gesetzt werden sollen und die anderen in Ruhe läßt. Ohne VerOderungen> und/oder VerUndungen oder VerRenkungen.
wenn du BASCOM meinst, das kenne ich zwar nicht wirklich, aber auch da
sind Veroderungen nötig (aus
http://www.roboternetz.de/community/threads/45591-Wie-Mehrere-Bits-in-Register-setzen):
Gicr = Gicr Or Bits(int1) -> Setzt Bit7 in Register GICR
Bascom macht daraus:
IN R16,0x3B In from I/O location
PUSH R16 Push register on stack
LDI R24,0x80 Load immediate
MOV R20,R24 Copy register
POP R16 Pop register from stack
OR R16,R20 Logical OR
OUT 0x3B,R16 Out to I/O location
und so richtig optimaler Code scheint das auch nicht
S. Landolt schrieb:> Nach der Argumentation von 'C tut weh' wären bei dieser anderen> Programmiersprache nach ADCSRA = Bits(ADEN)> ADCSRA = Bits(ADPS2,ADPS1)> in ADCSRA alle drei Bits ADEN, ADPS2 und ADPS1 gesetzt! ? - Sehr> interessant, um welche Sprache handelt es sich?
Es handelt sich um Bascom. Der Befehl "Bits" setzt die Bits in der
Klammer in dem jeweiligen Register. Alle Anderen (nicht genannten)
bleiben, wie sie vorher waren. Als Gegenstück gibt es dann "NBits", der
alle Bits in der Klammer löscht.
Natürlich ist es auch wichtig, die Bitmanipulationsbefehle zu kennen und
richtig benutzen zu können -wenn man sie braucht. Wenn man sie aber
NICHT braucht, dann kann man dadurch Fehlerquellen eliminieren und man
sieht auf einen Blick, was los ist.
(Ich habe nicht geprüft, ob die gesetzten Bits aus der Frage des TO den
von ihm gewünschten Effekt erzielen -ich habe es nur so übernommen, wie
er es stehen hatte.)
C tut weh schrieb:> Es handelt sich um Bascom. Der Befehl "Bits" setzt die Bits in der> Klammer in dem jeweiligen Register. Alle Anderen (nicht genannten)> bleiben, wie sie vorher waren.
Das stimmt nicht! Es muß genauso verodert werden, wenn schon gesetzte
Bits im Ziel nicht verändert werden sollen.
> ...Es muß genauso verodert werden...
Genauso sehe ich das nämlich auch. Und Felix hat ja nicht nach einer
kürzeren oder eleganteren Schreibweise gefragt, er sucht Fehler im
Programm.
Aber nach Argumentation und Wortspielen den Autor ahnend, möchte ich
mich an dieser Stelle verabschieden. Einen schönen Abend allerseits!
Guten Abend,
immer diese Mutmaßungen, die Onlinehilfe ist doch zu Var = Bits(b1
[,bn]) eindeutig.
https://avrhelp.mcselec.com/index.html?bits.htm
Man muss bei weiterem Zugriff auf das selbe Register dieses auch sich
selbst (ODER) beziehen.
Als Beispiel sind die unten gezeigten Zeilen ok.
C tut weh schrieb:> Karl M. schrieb:>> das ist ein grundsätzliches Problem, erst muss man C lernen...>> Naja, nicht unbedingt. Man kann auch eine Sprache verwenden, die mittels> des Befehls "Bits" nur die Bits im entsprechenden Register setzt, die> gesetzt werden sollen und die anderen in Ruhe läßt. Ohne VerOderungen> und/oder VerUndungen oder VerRenkungen.>> $regfile = "attiny84.dat">> Admux = Bits(refs0 , Adlar)> Adcsra = Bits(aden , Adps2 , Adps1)>> Do> nop> Loop
C tut weh schrieb:> manmanman schrieb:>> Das stimmt nicht!>> Natürlich stimmt das. Probiers aus und verwirre die Leser nicht!
Dann gib mir mal ein Beispiel zum probieren. Unten stehendes eignet sich
nicht, da nicht bekannt ist, was in Admux oder Adcsra zu Beginn steht.
Im Zweifel sind alle "0" (Tipp: Probier es erstmal selber aus)
C tut weh schrieb:> Naja, nicht unbedingt. Man kann auch eine Sprache verwenden, die mittels> des Befehls "Bits" nur die Bits im entsprechenden Register setzt, die> gesetzt werden sollen und die anderen in Ruhe läßt. Ohne VerOderungen> und/oder VerUndungen oder VerRenkungen.>> $regfile = "attiny84.dat">> Admux = Bits(refs0 , Adlar)> Adcsra = Bits(aden , Adps2 , Adps1)>> Do> nop> Loop
manmanman schrieb:> Unten stehendes eignet sich> nicht, da nicht bekannt ist, was in Admux oder Adcsra zu Beginn steht.> Im Zweifel sind alle "0" (Tipp: Probier es erstmal selber aus)
Natürlich ist das bekannt: Der Initialwert der Bits des Registers steht
im Datenblatt. (Siehe Anhang) Da hinein muß man sowieso sehen, um die
gewünschte Betriebsart einstellen zu können.
C tut weh schrieb:> manmanman schrieb:>> Im Zweifel sind alle "0" (Tipp: Probier es erstmal selber aus)>> Natürlich ist das bekannt: Der Initialwert der Bits des Registers steht> im Datenblatt. (Siehe Anhang) Da hinein muß man sowieso sehen, um die> gewünschte Betriebsart einstellen zu können.
Und? Weiter? Was soll ich nun probieren?
manmanman schrieb:> Und? Weiter? Was soll ich nun probieren?
Das weiß ich doch nicht, was Du probieren sollst. Du mußt doch selbst
wissen, welche Betriebsart Du einstellen willst. Da das Register initial
mit Null gefüllt ist, mußt Du nachsehen, welche Bits gesetzt werden
sollen.
Das kann ich doch nicht für Dich entscheiden.
C tut weh schrieb:> manmanman schrieb:>> Und? Weiter? Was soll ich nun probieren?>> Das weiß ich doch nicht, was Du probieren sollst.
Viel Glück bei deiner Interpretation des BITS Befehls in Bascom. Das
wirst du brauchen.
Hallo,
danke erst mal für die ganzen Antworten. Um nochmal auf das Thema
zurückzukommen: Ich habe mich da noch mal eingelesen und mein Programm
überarbeitet. Das auslesen vom ADC funktioniert jetzt. ABER: Egal an
welchem ADC-Kanal ich das Signal auslese und einem der PWM-Kanäle
zuordne, es wird immer an den Kanal OC1B (PB5) ausgegeben. Muss ich die
einzelnen ADC-Kanäle speziell auslesen oder ist der Befehl ADCH in
dieser Situation richtig? Gibt es irgend eine Seite, die man empfehlen
kann wenn es um Code-Beispiele für den AVR in C gibt?
Danke schon mal für jede weitere Hilfe!!
Gruß Felix
Und warum programmierst Du nicht weiter funktional ?
1
uint16_treadADC_Channel(uint8_tchannel)
2
{
3
uint16_tresult=0;
4
// adc Kanal auswählen
5
...
6
// adc Messung starten
7
...
8
// adc Warte auf das Ende der Messung
9
...
10
// das Ergebnis auslesen
11
...
12
// und zurückliefern
13
returnresult;
14
}
Dann solltest Du dich mit den DIDRn Digital Input Disable Register
beschäftigen.
Wenn Du mal nicht Vcc als Referenz verwenden möchtest
ADMUX - REFS[1:0] = 00 : "Vcc used as analog reference, disconnected
from PA0 (AREF)"
Dann würde mann bei deinem Vorgehen immer die REFS[1:0] Bits in ADMUX
überschreiben.
Im Modus Single Ended Input sind nicht alle MUX[5:0] Bits von
Bedeutung, den man hat nur ADC0 bis ADC7 als Auswahl.
Also sind nur MUX[2:0] betroffen.
Besser ist es dann den Kanal wie folgt neu zu setzten:
1
ADMUX=(ADMUX&~(0b000111))|(channel&0b000111);
Die Atmel Entwickler habe zum Glück für den single ended input die
MUX[2:0] Bits passend belegt.
Hallo Felix,
noch etwas, wenn man eine ADC-Wandlung anwirft, muss man sie auch
auslesen und kann sie dann das Ergebnis verwerfen.
[c]void adc_init(void)
{
...
//Messung starten
ADCSRA |= (1 << ADSC);
//Warten auf Ergebnis
while (ADCSRA & (1 << ADSC));
// und nun noch den ADC auslesen und den Wert verwerfen.
...
}
Karl M. schrieb:> // und nun noch den ADC auslesen und den Wert verwerfen.
... aber nur, wenn das ganze an einem Freitag, den 13. stattfindet indem
gleichzeitig Neumond ist. Sonst sollte man zur Sicherheit die ersten 42
Werte verwerfen.
Man könnte das aber auch einfach sein lassen.
Oliver
Hallo,
ich bin's nochmal. Ich habe sowohl den ADC als auch die PWM Ausgänge zum
laufen bekommen (Habe bei RN-Wissen was zu dem ADC gefunden). Ich habe
aber noch 2 Probleme:
1. Ich muss mein ADC Ergebnis durch 4 Teilen, um auf einen maximalen
wert von 255 zu kommen.
2. Ich kann immer nur einen Kanal der beiden PWM Timer verwenden. Damit
meine ich, entweder OC1A oder OC1B. Beide gleichzeitig bekomme ich
einfach nicht hin.
Währe sehr schön wenn ihr nochmal über meinen Code schauen könntet.
1
#define F_CPU 8000000UL //Interner Oszilator mit 8MHz
2
3
#include<avr/io.h>
4
#include<inttypes.h>
5
6
7
uint16_treadADC(uint8_tchannel){
8
uint16_tergebnis=0;
9
uint8_ti;
10
11
//ADC aktivieren und Prescaler einstellen (64)
12
ADCSRA|=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1);
13
14
//Multiplexer Kanal auswählen und Referenzspannung auswählen
15
ADMUX|=channel|(0<<REFS1)|(0<<REFS0);
16
17
//ADC initialisieren und Dummyreadout machen
18
ADCSRA|=(1<<ADSC);
19
while(ADCSRA&(1<<ADSC));
20
21
//3x Spannung auslesen und Mittelwert bilden
22
for(i=0;i<3;i++){
23
//Wandlung durchführen und auf Ergebnis warten
24
ADCSRA|=(1<<ADSC);
25
while(ADCSRA&(1<<ADSC));
26
27
ergebnis+=ADCW;
28
}
29
30
//ADC deaktivieren
31
ADCSRA&=~(1<<ADEN);
32
33
ergebnis/=3;
34
35
returnergebnis;
36
}
37
38
voidpwm_init(){
39
40
//Ausgänge setzen
41
DDRA|=(1<<PA6)|(1<<PA7)|(1<<PA5);
42
DDRB|=(1<<PB2);
43
44
//Timer 0 (8 Bit)
45
//Löschen von Bits: OC0A/OC0B Bit 7 + 6
46
//Art der Wellenform erzeugung: PWM, Phase Correct
47
TCCR0A|=(1<<COM0A1)|
48
(1<<COM0B0)|
49
(0<<WGM02)|
50
(0<<WGM01)|
51
(1<<WGM00);
52
53
//Prescaler auf 256 einstellen
54
TCCR0B|=(1<<CS02)|
55
(0<<CS01)|
56
(0<<CS00);
57
58
//Timer 1 (16 Bit)
59
//Löschen von Bits: OC0A/OC0B Bit 7 + 6
60
//Art der Wellenform erzeugung: PWM, Phase Correct
> ADMUX |= channel | (0 << REFS1) | (0 << REFS0);
Das alte Missverständnis, wieder verodert.
Und es ist pures Glück, dass WGM0_ und WGM1_ bzw. CS0_ und CS1_ dieselbe
Wertigkeit haben.
S. Landolt schrieb:> Und es ist pures Glück, dass WGM0_ und WGM1_ bzw. CS0_ und CS1_ dieselbe> Wertigkeit haben.
Und dass WGMx2 Null sein soll und es daher nicht stört, dass es im
falschen Register nicht gesetzt wird.
meinereiner schrieb
> Das alte Missverständnis
Pardon, das war wohl irgendwo anders.
Also, mit
> ADMUX |= channel | (0 << REFS1) | (0 << REFS0);
"sammeln" sich die Kanäle in ADMUX an, nach
> OCR1B = readADC(3) / 4;
ist und bleibt der Kanal auf 3 stehen.
Hallo,
ich habe jetzt eine Lösung gefunden. Ich stelle den funktionierenden
Code noch mal hier rein, falls es jemanden interessiert oder den
gleichen Fehler hat. Danke an alle, die mir geholfen haben!
Gruß Felix
1
#define F_CPU 8000000UL //Interner Oszilator mit 8MHz
2
3
#include<avr/io.h>
4
#include<inttypes.h>
5
6
7
uint16_treadADC(uint8_tchannel){
8
uint16_tergebnis=0;
9
uint8_ti;
10
11
//ADC aktivieren und Prescaler einstellen (64)
12
ADCSRA|=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1);
13
14
//Multiplexer Kanal auswählen und Referenzspannung auswählen
15
ADMUX=channel|(0<<REFS1)|(0<<REFS0);
16
17
//ADC initialisieren und Dummyreadout machen
18
ADCSRA|=(1<<ADSC);
19
while(ADCSRA&(1<<ADSC));
20
21
//3x Spannung auslesen und Mittelwert bilden
22
for(i=0;i<3;i++){
23
//Wandlung durchführen und auf Ergebnis warten
24
ADCSRA|=(1<<ADSC);
25
while(ADCSRA&(1<<ADSC));
26
27
ergebnis+=ADCW;
28
}
29
30
//ADC deaktivieren
31
ADCSRA&=~(1<<ADEN);
32
33
ergebnis/=3;
34
35
returnergebnis;
36
}
37
38
voidpwm_init(){
39
40
//Ausgänge setzen
41
DDRA|=(1<<PA6)|(1<<PA7)|(1<<PA5);
42
DDRB|=(1<<PB2);
43
44
//Inerups für Timer setzen
45
//TIMSK0 = (1 << TOIE0);
46
//TIMSK1 = (1 << TOIE0);
47
48
//Timer 0 (8 Bit)
49
//Löschen von Bits: OC0A/OC0B Bit 7 + 6
50
//Art der Wellenform erzeugung: PWM, Phase Correct
51
TCCR0A|=(0<<COM0A1)|
52
(0<<COM0A0)|
53
(0<<COM0B1)|
54
(0<<COM0B0)|
55
(0<<WGM02)|
56
(0<<WGM01)|
57
(1<<WGM00);
58
59
//Prescaler auf 256 einstellen
60
TCCR0B|=(0<<WGM02)|
61
(0<<FOC0A)|
62
(0<<FOC0B)|
63
(0<<CS02)|
64
(0<<CS01)|
65
(1<<CS00);
66
67
//Timer 1 (16 Bit)
68
//Löschen von Bits: OC0A/OC0B Bit 7 + 6
69
//Art der Wellenform erzeugung: PWM, Phase Correct
Wie Stefan Ernst bereits schrieb, steht WGM12 nicht in TCCR1A, auch wenn
es, da 0, diesmal keinen Fehler verursacht.
Unklar ist mir, weshalb die PWM-Kanäle ständig aus- und wieder
eingeschaltet werden.
S. Landolt schrieb:> meinereiner schrieb>> Das alte Missverständnis> Pardon, das war wohl irgendwo anders.
Ach?!
> Also, mit>> ADMUX |= channel | (0 << REFS1) | (0 << REFS0);> "sammeln" sich die Kanäle in ADMUX an, nach>> OCR1B = readADC(3) / 4;> ist und bleibt der Kanal auf 3 stehen.
Das sieht nicht so aus...
S. Landolt schrieb:> Unklar ist mir, weshalb die PWM-Kanäle ständig aus- und wieder> eingeschaltet werden.
Vielleicht deshalb:
Felix schrieb:> ich möchte mit 4 Potis 4 LEDs über PWM dimmen.
Wolltest Du nicht längst nach Diktat verreist sein?
S. Landolt schrieb:> Aber nach Argumentation und Wortspielen den Autor ahnend, möchte ich> mich an dieser Stelle verabschieden. Einen schönen Abend allerseits!