Hi, ich habe hier nen Code für die flankenberücksichtigende Auswertung
vom PinA des Mega32@4MHz entworfen. Bei Flankenwechsel wird ein Text
(später mit Uhrzeit von einer RTC über TWI) ausgegeben. Der
Übersichtlichkeit halber habe ich nur die steigende Flankenauswertung
und nur das nötigste gepostet. Jetzt ist die Frage an euch, ob der Code
rational genug geschrieben ist oder man vielleicht das "checke1(void);"
eleganter, vielleicht auch mit einer for-Schleife lösen kann.
MfG
spencer
1
chare1_text[15]="kein Text1";//usw..
2
inte1hi[8];// Array für Pins, welche auf High gegangen sind
3
inte1c=0;// Änderungsvariable = 0 wenn sich E1 (PINA) nicht geändert hat)
4
5
SIGNAL(SIG_OVERFLOW0){// Timer-Interruptroutine
6
7
inti;
8
for(i=0;i<8;i++){// Zustand der Eingänge 1 bis 8 vergleichen und an Array e1 weitergeben
9
10
if(!(PINA&(1<<i)==pina_last&(1<<i))){// Mindestens ein Pin auf E1 hat sich verändert, prüfen!!!
11
12
e1c=0xFF;// Benachrichtigungschar "E1 hat sich geändert!"
13
14
if(!(PINA&(1<<i))){
15
e1hi[i]=1;}
16
17
if((PINA&(1<<i))){
18
e1lo[i]=1;}
19
}
20
}
21
}
1
intmain(void){// Hauptschleife
2
...
3
sei();// IRQ einschalten
4
reade1();
5
6
while(1){
7
8
if(!(e1c==0))// Änderungschar für E1 prüfen
9
{
10
checke1();
11
}
12
}
13
return0;// nie erreicht
14
15
}
1
intchecke1(void){// E1 hat sich verändert, prüfe, welche Pins und drucke!
2
cli();// IRQ abschalten
3
inti;
4
5
for(i=0;i>8;i++){// steigende Flanke detektieren
6
7
if(!(e1hi[i]==0)){
8
9
if((i==0)){
10
uart_puts(e1_text);
11
get_high();
12
}
13
14
if((i==1)){
15
uart_puts(e2_text);
16
get_high();
17
}
18
....
19
if((i==7)){
20
uart_puts(e8_text);
21
get_high();
22
}
23
}
24
varres1();
25
reade1();
26
sei();// IRQ einschalten
27
}
1
intreade1(void){// E1 abgleichen
2
pina_last=PINA;
3
}
1
intvarres1(void){// Änderungsindex bzw. Statusarrays auf 0 setzen (E1)
2
inti;
3
4
for(i=0;i<8;i++){// Statusarray auf 0 setzen
5
e1hi[i]=0;
6
}
7
8
for(i=0;i<8;i++){// Statusarray auf 0 setzen
9
e1lo[i]=0;
10
}
11
e1c=0;// Änderungsindex E1 reseten
12
13
}
1
intget_high(void){// grafische Darstellung für steigende Flanke
Hallo spencer,
ich habe deinen Code nicht bis ins Detail angeschaut, dazu waren es dann
doch schon ein paar Glas Rotwein zuviel, jedoch kurz überflogen.
- Dir ist bewußt wie breit ein int in avr-gcc ist?
- Du weißt das das Makro SIGNAL obsolet ist?
- Schau dir mal Pin-Change Interrupts an.
- Das elhi Array, welches bei dir 128 Bit breit ist lässt sich
auf 8 Bit eindampfen wenn du ein Bitfeld draus machst:
1
struct{
2
unsigneda1:1;
3
unsigneda2:1;
4
unsigneda3:1;
5
unsigneda4:1;
6
unsigneda5:1;
7
unsigneda6:1;
8
unsigneda7:1;
9
unsigneda8:1;
10
}elhi;
Wenn du möchtest kann man da noch als union ein char drüberlegen,
meinetwegen "inport" um in einem Rutsch den Port einzulesen:
Hm stimmt... mein Fehler! Statt int werde ich char beim e1hi verwenden.
Ich dachte, beim Lesen von Eingängen ist es günstiger, nen Timer-IRQ zu
verwenden und zu pollen anstatt nen pinchange?
MfG
spencer
Wenn du nur wissen willst, ob sich irgendein Pin am PINA verändert
hat, dann musst du das nicht Einzelbitweise machen.
Vergleiche einfach den kompletten Portzustand mit dem kompletten
Portzustand unmittelbar davor.
1
uint8_tPrevPin;
2
3
ISR(TIMER0_OVF_vect)
4
{
5
uint8_ti;
6
uint8_tMask;
7
uint8_tPinNow=PINA;
8
9
if(PinNow!=PrevPin){
10
// ein Pin am Port A hat seinen Zustand geändert
11
12
e1c=0xFF;// Benachrichtigungschar "E1 hat sich geändert!"
13
PrevPin=PinNow;
14
15
// finde die momentane PinBelegung (Hi Lo raus)
16
Mask=0x01;
17
for(i=0;i<8;++i){
18
ello[0]=!(elhi[0]=(PinNow&Mask!=0));
19
Mask=Mask<<1;
20
}
21
}
22
}
Erhebt sich natürlich noch die Frage, wozu du das ello Array
überhaupt brauchst. Wenn ein Pin nicht High ist (also in elhi
an der entsprechenden Stelle eine 1 steht), dann kann er nur
Low sein (elhi muss dann an der Stelle 0 sein, dafür ist
ello an dieser Stelle 1)
Zwischen elhi und ello gibt es also einen Zusammenhang:
elhi[i] != ello[i];
wenn elhi[i] gleich 1 ist, dann muss ello[i] 0 sein und
umgekehrt. Damit kannst du aber ello eleminieren, da du
von elhi immer weist wie der Eintrag lauten muss.
Naja ich wollte, dass auf der UART nur der jeweilige pin ausgegeben
wird, der sich verändert hat. Deshalb E1HI und einmal E1LO. Wenn z.B.
E1HI 0b00000001 ist, weiß ich, dass PINA.0 (und NUR PINA.0) high wurde
(und vorher low war) --> jeweiligen Text ausgeben. Wenn also dasselbe 10
sek. später in E1LO steht, weiß ich, dass selbiger low geworden ist -->
Text ausgeben. Es geht eben um reine Pinauswertung, nicht nen kompletten
Port, sonst befürchte ich schaut mein Terminal bei jedem Pinwechsel so
aus:
PINA.0 hi --> low
PINA.1 low--> hi
PINA.2 hi --> low
PINA.3 low--> hi
PINA.4 hi --> low
PINA.5 hi --> low
PINA.6 low--> hi
PINA.7 hi --> low
(und das, obwohl nur PINA.0 low geworden wäre)
MfG
spencer wrote:
> Naja ich wollte, dass auf der UART nur der jeweilige pin ausgegeben> wird, der sich verändert hat.
OK. Das hab ich dann wohl missverstanden.
Mir kommen nur in deinem Code zuviele PIN Abfragen vor, sowie
etwas zu oft eine Schieberei von 1 mit einer Variablen.
Die häufigen PIN Abfragen sin dproblematisch, weil sich ja in
der Zeit von einer Abfrage zur nächsten der Zustand des
Eingangspins schon wieder verändert haben könnte.
zb hier
if (!(PINA&(1<<i))){
e1hi[i] = 1;}
if ((PINA&(1<<i))){
e1lo[i] = 1;}
}
Niemand kann dir garantieren, dass nicht tatsächlichj beide
Vergleiche false ergeben. Der PINA Wert bei der ersten Abfrage
hat ja nichts mit dem PINA der zweiten Abfrage zu tun. Und beide
wiederrum haben nichts mit der übergeordneten if-Bedingung zu tun,
die ebenfalls ihren eigenen PIN Wert benutzt.
Theroretisch könnte es dir also passieren, dass hier
1
if(!(PINA&(1<<i)==pina_last&(1<<i))){// Mindestens ein Pin auf E1 hat sich verändert, prüfen!!!
zwar ein Pin Change detektiert wird, aber die beiden nachfolgenden
Auswertungen weder Low noch High detektieren -> du hast die
Flanke verloren.
-> Das PINA Register nur einmal auslesen, und dann mit dem ausgelesenen
Komplett-Wert weitermachen.
Das andere sind die vielen 1 << i. Da der AVR das nicht in einer
Assemblerinstruktion machen kann. Wenn du Glück hast, dann hat sich
der Optimizer diese Berechnung vorgezogen und macht sie nur einmal.
Aber darauf würde ich so nicht vertrauen.
schreibe? Alles klar, werd ich ausprobieren. Ich konnte den Code leider
noch nicht testen, da ich unter Linux (KontrollerLab) code und für die
Zielschaltung das Board noch nicht fertig ist. Desweiteren kenne ich
unter Linux leider noch keinen Simulator für AVRs. Daher verläuft die
Entwicklung des Codes unter erschwerten Umständen, aber das ist ein
anderes Thema.
Danke für die bisherige Hilfe
MfG
spencer