Hallo, ich habe ein Problem mit meinem Programm und komme nach mehreren
Stunden rumprobieren nicht auf die Lösung. Es geht darum, dass der
Controller bei gedrückthalten der Taste immer wieder den selben Befehl
per IR-Diode sendet. Funktioniert auch wunderbar.
Wird die Taste aber nochmal gedrückt soll das Signal etwas abgeändert
werden. Es soll das dritte Startbit getoggelt werden. Das passiert
allerdings nicht. Es wird immer dasselbe Signal gesendet. Der Controller
toggelt die Variable state nicht. Woran kann das liegen?
Taster ist mit einem Pulldown-Widerstand auf GND gezogen, parallel dazu
ein Kondensator.
1
5V
2
__ |
3
| /-
4
µC | |
5
| |
6
|-------------
7
| | |
8
| | | _|_
9
| |R| _C_
10
| | |
11
|______|
12
|
13
GND
1
#include<avr/io.h>
2
#define F_CPU 8000000UL
3
#include<util/delay.h>
4
5
6
intmain(void)
7
{
8
9
volatileuint8_tstate=0;
10
11
DDRB=(1<<PORTB1);// PB1 als Ausgang
12
DDRC&=~(1<<PC5);// PC5 als Eingang
13
DDRC&=~(1<<PC4);// PC4 als Eingang
14
DDRC&=~(1<<PC3);// PC3 als Eingang
15
16
17
TCCR1A|=(1<<WGM12)|(1<<WGM11);// Fast-PWM mit ICR1 als TOP
18
TCCR1B|=(1<<CS10)|(1<<WGM13);// Prescaler = 1
19
20
// ICR1 = F_CPU/(2*Prescaler*(F_PWM+1)
21
ICR1=108;// Periode PWM => 38kHz
22
OCR1A=27;// ICRI/4 => 25% PWM
23
24
while(1){
25
26
if(PINC&(1<<PINC5)){// wenn Taste gedrückt:
27
if(state==1)state=0;// toggle state
28
elseif(state==0)state=1;
29
30
while((PINC&(1<<PINC5))){// solange Taste 1 gedrückt: bleibe in Schleife
31
if(state==1){sendStartSeq1();}// wenn state == 1 => Startsequenz = 1 1 1
32
elseif(state==0){sendStartSeq0();}// wenn state == 0 => Startsequenz = 1 1 0
Hi,
da fallen mir mehrere Themen auf:
1) Entprellung?
2) Warum die 2 Abfragen mit dem while, irgendwie haengt er dann auch
In der 2. Scleife.
3) Der Vergleich mit 1<<PC5 sieht seltsam aus, da bin ich mir nicht
sicher, schau dir dass nochmal an.
//hufnala
Hallo,
der Kondensator war eigentlich zum Entprellen gedacht.
Es wird erst in die if-Abfrage gesprungen, wenn die Taste 1 tatsächlich
gedrückt ist. Erst dann soll das state getoggelt werden. Wenn getoggelt
wurde soll das Programm solange in der While-Schleife hängen wie die
Taste gedrückt ist (permanenten Senden der gleichen Sequenz). Beim
loslassen soll das Programm aus der while-Schleife raus, zurück in die
main. Wird die Taste jetzt nochmal betätigt sollte die Variable state
getoggelt werden, sodass eine andere Startsequenz als beim letzten
drücken gesendet wird, jedoch passiert dies nicht.
Der auskommentierte Bereich ist nicht so von Interesse, es wurde viel
ausprobiert... Der komplette Code ist:
1
#include<avr/io.h>
2
#define F_CPU 8000000UL
3
#include<util/delay.h>
4
#include<stdbool.h>
5
6
7
8
9
intmain(void)
10
{
11
12
13
volatileintstate=0;
14
15
DDRB=(1<<PORTB1);// PB1 als Ausgang
16
DDRC&=~(1<<PC5);// PC5 als Eingang
17
18
19
DDRC&=~(1<<PC4);// PC4 als Eingang
20
DDRC&=~(1<<PC3);// PC3 als Eingang
21
22
23
TCCR1A|=(1<<WGM12)|(1<<WGM11);
24
// Fast-PWM mit ICR1 als TOP
25
TCCR1B|=(1<<CS10)|(1<<WGM13);// Prescaler = 1
26
27
28
// ICR1 = F_CPU/(2*Prescaler*(F_PWM+1)
29
ICR1=108;// Periode PWM => 38kHz
30
OCR1A=27;// ICRI/4 => 25% PWM
31
32
while(1){
33
34
35
36
if(PINC&(1<<PINC5)){
37
if(state==1)state=0;
38
elseif(state==0)state=1;
39
40
while((PINC&(1<<PINC5))){// solange Taste 1 gedrückt: bleibe in Schleife
41
if(state==1){sendStartSeq1();}// wenn i == 1 => Startsequenz = 1 1 1
42
if(state==0){sendStartSeq0();}// wenn i == 0 => Startsequenz = 1 1 0
Deine Entprellung erinnert mich doch sehr an die Entprellung auf dem
Pollin Board
http://www.mikrocontroller.net/articles/Diskussion:Pollin_ATMEL_Evaluations-Board
die dazu führen kann, dass der µC bei einem Tastendruck abschmiert. Was
so ganz nebenbei und zwanglos dein Nicht-Toggeln erklären würde. Denn
nach einem Reset geht alles wieder von vorne los.
Würde es was bringen einen Widerstand direkt hinter den Schalter zu
klemmen um den Strom zu begrenzen?
Ich dachte eigentlich, dass der Eingang an sich schon ziemlich hochohmig
ist und nicht viel hineinfließt.
Die Entprellschaltung besteht aus dem Pulldown von 10k und dem 22nF.
Opto, was ist denn nun mit der Klammer?
Der Code compiliert so nicht, und wie du vielleicht siehst, steht
"return 0;"
in der while-schleife.
Was sollen also alle weiteren Fragen?
Hallo,
Opto schrieb:> Die Entprellschaltung besteht aus dem Pulldown von 10k und dem 22nF.
nein das ist falsch !
Eine R-C Entprellung besteht aus einem Tiefpass, das ist etwas anderes.
Uwe S. schrieb:>> Die Entprellschaltung besteht aus dem Pulldown von 10k und dem 22nF.>> nein das ist falsch !
Na, geht schon so.
Der Kondesator lädt schnell auf, und wird langsam entladen.
Ein Serienwiderstand von 100R würde dem Schaltkontakt allerdings ein
längeres Leben bescheren.
Problem ist aber nach wie vor der Code... und ich höre nicht auf zu
quengeln ;-)
Easylife schrieb:> Uwe S. schrieb:>>> Die Entprellschaltung besteht aus dem Pulldown von 10k und dem 22nF.>>>> nein das ist falsch !>> Na, geht schon so.> Der Kondesator lädt schnell auf
Das Problem ist, dass er zu schnell auflädt!
De facto schaltet man mit dem Taster einen kurz anliegenden Kurzschluss.
Die Leute, die das original Pollin Board mit genau dieser
Hardware-Entprellung haben, bauen die nicht ohne Grund um.
Easylife schrieb:> deswegen ja 100R in serie zum C...
Ah. Den hab ich bei dir überlesen.
Ja klar. Der würde helfen
1
Vcc
2
|
3
/
4
|
5
----+--+---+
6
| |
7
10k 100
8
| |
9
| C
10
| |
11
-------+---+---- GND
(oder so ähnlich. Auf jeden Fall nicht den C per Taster direkt an Vcc
schalten lassen)
Abgesehen von der Klammer, was hast du im Code sonst noch entdeckt? Ein
paar Sachen könnte man einfacher schreiben, aber im grossen und ganzen
sollte das funktionieren. D.h. wenn dann irgendwann mal der µC nicht bei
einem Tastendruck abschmiert.
Karl Heinz schrieb:> Abgesehen von der Klammer,
die natürlich an der richtigen Stelle eingefügt werden muss.
Was wiederrum den Wert von sauberen Einrückungen mehr als deutlich
unterstreicht!
Okay, also hier nochmal der gesamte Code, ohne Klammerfehler (compiliert
bei mir zumindest ohne Probleme) und hoffentlich besserer Formatierung.
Wo würde der µC-Eingang sein? Kann es wirklich am C ohne Vorwiderstand
liegen, dass der Controller abschmiert und sich resettet?
Vcc
|
/
|
µC--+--+---+
hier? | |
10k 100
| |
| C
| |
-------+---+---- GND
Danke schonmal :)
1
#include<avr/io.h>
2
#define F_CPU 8000000UL
3
#include<util/delay.h>
4
5
6
voidsendOne(void);
7
voidsendNull(void);
8
voidsendStartSeq1(void);
9
voidsendStartSeq0(void);
10
voidsendDevAddr(void);
11
voidsendData1(void);
12
13
14
15
intmain(void)
16
{
17
volatileintstate=0;
18
19
DDRB=(1<<PORTB1);// PB1 als Ausgang
20
DDRC&=~(1<<PC5);// PC5 als Eingang
21
DDRC&=~(1<<PC4);// PC4 als Eingang
22
DDRC&=~(1<<PC3);// PC3 als Eingang
23
24
25
TCCR1A|=(1<<WGM12)|(1<<WGM11);// Fast-PWM mit ICR1 als TOP
26
27
TCCR1B|=(1<<CS10)|(1<<WGM13);// Prescaler = 1
28
29
// ICR1 = F_CPU/(2*Prescaler*(F_PWM+1)
30
ICR1=108;// Periode PWM => 38kHz
31
OCR1A=27;// ICRI/4 => 25% PWM
32
33
while(1)
34
{
35
36
if(PINC&(1<<PINC5))
37
{
38
if(state==1){state=0;}
39
elseif(state==0){state=1;}
40
41
while((PINC&(1<<PINC5)))// solange Taste 1 gedrückt: bleibe in Schleife
42
{
43
if(state==1){sendStartSeq1();}// wenn i == 0xff => Startsequenz = 1 1 1
44
if(state==0){sendStartSeq0();}// wenn i = 0x00 => Startsequenz = 1 1 0
Opto schrieb:> Wo würde der µC-Eingang sein? Kann es wirklich am C ohne Vorwiderstand> liegen, dass der Controller abschmiert und sich resettet?
Du kannst es ja mal ausprobieren. Mit einer anderen LED (aber nicht
Infrarot), bei der du auch was siehst.
1
>intmain(void)
2
>{
3
>volatileintstate=0;
4
>
5
>DDRB=(1<<PORTB1);// PB1 als Ausgang
6
7
DDRB|=(1<<PB2);
8
9
PORTB|=(1<<PB2);
10
_delay_ms(500);
11
PORTB&=~(1<<PB2);
12
_delay_ms(500);
13
PORTB|=(1<<PB2);
14
_delay_ms(500);
15
16
>DDRC&=~(1<<PC5);// PC5 als Eingang
17
....
schliess eine LED an PB2 an (oder ändere um auf einen anderen noch
freien Pin) und beobachte die LED. Wenn sie bei einem Tastendruck
flackert, dann ist dein µC abgeschmiert und hat sich gerade resettet.
Mit so einer LED kann man ganz leicht Dinge sichtbar machen :-)
Opto schrieb:> Wo würde der µC-Eingang sein? Kann es wirklich am C ohne Vorwiderstand> liegen, dass der Controller abschmiert und sich resettet?
Die Beschaltung des uC mit Taster ist OK so.
Dass "der Controller abschmiert und sich resettet" ist jetzt aber neu,
oder?
Ursprünglich sagtest du:
Opto schrieb:> Das passiert> allerdings nicht. Es wird immer dasselbe Signal gesendet. Der Controller> toggelt die Variable state nicht. Woran kann das liegen?
Poste bitte mal den Schaltplan und das Layout.
Ich vermute, dass du hier mit elektrischen Problemen kämpfst.
Den Code könnte man zwar optimieren, er müsste aber funktionieren.
Hallo, ihrlagt mit der Vermutung, der µC würde sich permanent resetten
goldrichtig. Vielen Danke für den Tipp! Habe dann wie empfohlen einen
390Ohm Widerstand (war kein anderer kleiner R da) in Reihe mit dem
Kondensator gehängt und siehe da, es funktioniert genau wie es soll.
Jemand sagte man könnte noch optimieren. Wie genau? Es läuft zwar, aber
muss auch demnächst mal präsentiert werden :)
Opto schrieb:> Jemand sagte man könnte noch optimieren.
Na ja.
'Optimieren' ist das falsche Wort. 'Weniger umständlich' trifft es eher.
Die Variable 'state' kann bei dir nur 2 Werte haben. Entweder sie ist 0
oder sie ist 1.
Dann kannst du aber zb das hier
1
if(state==1)state=0;// toggle state
2
elseif(state==0)state=1;
durch das hier ersetzen
1
state=1-state;
hat state den Wert 0, denn ergibt 1 - 0 den neuen Wert 1. Hat state den
Wert 1, dann ergibt 1 - 1 den neuen Wert 0. Aus 0 wird 1, aus 1 wird 0.
Genau wie gefordert.
Das hier
1
if(state==1){sendStartSeq1();}
2
if(state==0){sendStartSeq0();}
state kann nur 0 oder 1 sein. Wenn es nicht den Wert 1 hat, dann muss
daher state den Wert 0 haben.
1
if(state==1)
2
sendStartSeq1();
3
else
4
sendStartSeq0();
gewöhn dir schnell an, mit 'else' zu arbeiten. Du machst dir (und dem
Prozessor) sonst eine Menge Mehrarbeit für nichts und wieder nichts
Gewieftere C Programmierer beherzigen auch, dass in C oft weniger gleich
mehr ist und nutzen aus, dass in C ein Wert ungleich 0 (und 1 ist
zweifellos ungleich 0) automatisch als logisch wahr gilt. D.h man muss
gar nicht drauf bestehen, dass state den Wert 1 haben muss. Irgendein
Wert ungleich 0 (und 1 ist das zweifellos) tut es auch
1
if(state)
2
sendStartSeq1();
3
else
4
sendStartSeq0();
Der Hintergrund ist der, dass man sich nämlich mit derart expliziten,
unnötigen, Vergleichen oft ganz schön ins Knie schiessen kann, ohne es
zu merken.
Verlangt man hier nicht mehr explizit den Wert 1, dann geht die
Umschaltung in den anderen Zustand noch einfacher
1
state=!state;
Eventuell könnte man beim Funktionsaufruf auch an den Einsatz des
ternären Operators denken.
Zudem ist 'state' so ein herrlich nichtssagender Variablenname. Das
Programm ist in einem Zustand. Ja. Und? Weiter! Was ist das füe ein
Zustand, was beschreibt er, was hat es damit auf sich. All das spiegelt
sich in einem gut gewählten Variablennamen wieder.
1
if(state==1){sendStartSeq1();}// wenn i == 0xff => Startsequenz = 1 1 1
fällt dir was auf?
Genau. Im Code steht die Abfrage auf 'state'. Im Kommentar ist da
plötzlich von einem i die Rede. Im Code steht ein Verlgeich auf 1, im
Kommentar steht ein Vergleich auf 0xFF
Grundregel: Ehe du einen derartigen Kommentar schreibst, überlege, wie
du Variablen bzw. Funktionsnamen so umbenennen kannst, dass du den
Kommentar ÜBERHAUPT NICHT BRAUCHST!
Der ideale Kommentar ist derjenige, der wegfallen kann, weil alles was
mir der Kommentar erzählen könnte, bereits im Code selber steht. Denn so
ein (weggefallener) Kommentar kann nie falsch sein.
Karl Heinz schrieb:> Der ideale Kommentar ist derjenige, der wegfallen kann, weil alles was> mir der Kommentar erzählen könnte, bereits im Code selber steht. Denn so> ein (weggefallener) Kommentar kann nie falsch sein.
Der hier zum Bleistift
1
ICR1=108;// Periode PWM => 38kHz
2
OCR1A=27;// ICRI/4 => 25% PWM
ZUm einen: Warum stehen da die 108 direkt im Code?
Was ist, wenn sich die Taktfrequenz des Controllers ändert. oder die
geforderte PWM Frequenz. WIllst du dann wirklich selber den neuen Wert
ausrechnen? Händisch?
Du hast einen COmpiler. Und dein Compiler kann rechnen! WIe bist du auf
die 108 gekommen? Genau die gleiche Berechnung kann auch der Compiler
für dich übernehmen.
1
#define PWM_PERIOD_VALUE ........... Berechnungsvorschrift für den TOP Wert .....
Und warum stellst du dann in OCR1A ein Viertel von diesem Wert wieder
selbst händisch ausgerechnet rein
1
ICR1=PWM_PERIOD_VALUE;
2
OCR1A=PWM_PERIOD_VALUE/4;// 25%
Der springende Punkt ist, dass sich bei einer notwendigen Änderung von
Werten nur noch 1 Wert ändert. Den anderen passt der Compiler für dich
an.
Die 25% im Kommentar lass ich dir, denn heutzutage ist das ja nicht mehr
selbstverständlich, dass Leute 1 Viertel mit 25 Prozent assozieren
können.
bist du dir da sicher?
Warum 2*prescaler?
Und die +1 sind auch fraglich.
IMHO müsstes du am Ausgang mit deinen 108 eigentlich eine Frequenz von
rund 73.3kHz haben. Hast du nachgemessen?
d.h. sofern die hier
Jetzt geht's hier aber zur Sache.
Wegen dem i=0xFF. Wie gesagt, es wurde viel rumprobiert und nach
mehreren Stunden ist man eben verzweifelt ;) Irgendwann wurde aus i
state und aus i=~(i); diese blöden if-Abfragen. Wobei i natürlich auch
nicht so vielsagend ist.
Der TOP Wert wurde ehrlich gesagt experimentell bestimmt. Die 8MHz
passen, da die 889µs delays gut hinkommen (mit Oszi nachgemessen).
Zur Formatierung des Quelltextes: Im Atmel Studio sieht das ganz anders
und ordentlich aus. Die Boardsoftware scheint die Kommentare aber
irgendwie nicht zu mögen.
Das mit dem PWM_PERIOD_VALUE war mir eigentlich auch klar, dass man das
oben einmal #defined und dann nicht mehr mit absoluten Werten arbeitet,
aber das stammt noch aus den ersten Stunden, die in das Projekt
geflossen sind. Habs jetzt überarbeitet.
Opto schrieb:> Jetzt geht's hier aber zur Sache.>> Wegen dem i=0xFF. Wie gesagt, es wurde viel rumprobiert und nach> mehreren Stunden ist man eben verzweifelt ;) Irgendwann wurde aus i> state und aus i=~(i); diese blöden if-Abfragen. Wobei i natürlich auch> nicht so vielsagend ist.
Ja, das kennen wir alle.
Und genau deshalb sind derartige Kommentare gelinde gesagt scheisse.
Sie werden in guter Absicht geschrieben und nach 2 Stunden stimmen sie
schon nicht mehr mit dem Code überein.
Genau deswegen ist es die beste Strategie, wenn der Code so geschrieben
ist, dass er sein eigener Kommentar ist und man keinen expliziten
Kommentar mehr braucht. Je mehr Kommentare du NICHT brauchst, desto
besser wird dein Code.
Opto schrieb:> Der TOP Wert wurde ehrlich gesagt experimentell bestimmt.
Tja. rein rechnerisch kommt da aber eine Frequenz von rund 73kHz raus.
Denn in einem PWM Durchgang, wird der Ausgangspin ja von 0 auf 1 und von
1 auf 0 gesetzt. D.h. in einem PWM Durchgang hast du einen kompletten
Wellenzug. Pro Sekunde finden bei deinen Werten aber 73tausend - 3
hundert - und irgendwas PWM Durchgänge statt. Von den versprochenen
38kHz weit entfernt.
TCCR1A|=(1<<WGM12)|(1<<WGM11);// Fast-PWM mit ICR1 als TOP
2
3
TCCR1B|=(1<<CS10)|(1<<WGM13);// Prescaler = 1
WGM12 ist beim Mega8 nicht im Register TCR1A sondern im Register TCR1B.
Du hast in Wirklichkeit eine Phase Correct PWM eingestellt. Und dann
sind deine Werte wieder plausibel.
Du musst noch viel sorgfältiger werden!