Hallo,
ich weiss selber nicht so ganz genau, was ich von dieser Frage halten
soll. Auf jeden Fall aber hat Sie mich gestern mind. 4 Std. Fehlersuche
gekostet unbd ich steh halt immer noch genauso dumm da wie vorher??
Kann mir also bitte Jemand das Mysteruim dieser Funktion erklären, die
ein zwölftastites Tastenfeld (Matrix) ausließt, indem man immer eine
Reihe auf Null zieht und dann schaut ob in irgendeiner Spalte
irgendetwas auf Null gezogen ist. Aus dem "Schnittpunkt" ergibt sich
halt die Taste, wenn denn eine gedrückt wurde. Das funzt soweit auch
vorzüglich, nur wenn ich jetzt die Bits in PORTB einzeln setze, wie in
den Kommentaren angemerkt, dann gehts gar nicht mehr. Was dumm ist, denn
das Tastenfeld braucht nur sieben Pins und ich würde halt gerne den
achten (PB7) auch noch verwenden, was halt nicht geht, wenn ich den PORT
gesamt setze.
Ich weiss nicht ob man für diese Frage noch mehr Infos braucht, aber
Fakt ist halt dass, es in der "PORT="-Version geht und in der
"PORTB|="-Version nicht...(im Prgramm benutze ich selbstverständlich
immer nur eine Version des ganzen).
Ach ja, und entprellt ist das ganze auch, aber als komplette Funktion im
Stile von: Funktion()...warte soundsolange... Funktion()
vielen Dank für eure Hilfe
ich bin mit meinem Latein am Ende
Jakob
[c]
//init von PORTB:
//PORTB=0b11111111;
//DDRB= 0b11111000;
char scan_taste() {
uint8_t C =0;
/* PORTB setzen einzeln */
PORTB |= (1<<PB6) | (1<<PB5) | (1<<PB4) | (1<<PB2) | (1<<PB1) |
(1<<PB0);
PORTB &= ~(1<<PB3) &~(1<<PB7);
/* PORTB setzen gesamt */
PORTB=0b01110111;
//PIND0-2= Pullup_aktiv
//PIND3= log.0
//PIND4-6= log.1
C = PINB | 0b11111000; //um die drei letzten bits zu vergl.
switch(C) {
case 0b11111111 : break; //nix in R0 gedrückt, nix Passiert
case 0b11111011 : return 10;
case 0b11111101 : return 11;
case 0b11111110 : return 12;
}
/* PORTB setzen einzeln */
PORTB |= (1<<PB6) | (1<<PB3) | (1<<PB5) | (1<<PB2) | (1<<PB1) |
(1<<PB0);
PORTB &= ~(1<<PB4) &~(1<<PB7);
/* PORTB setzen gesamt */
PORTB=0b01101111; //PIND4= log.1 --->R1=5V, andere Rs=0V
//PIND5-6 und PIND3= log.0
C= PINB | 0b11111000;
switch(C) {
case 0b11111111 : break; //nix gedrückt in R1, nix Passiert
case 0b11111011 : return 1;
case 0b11111101 : return 2;
case 0b11111110 : return 3;
}
/* PORTB setzen einzeln */
PORTB |= (1<<PB6) | (1<<PB3) | (1<<PB4) | (1<<PB2) | (1<<PB1) |
(1<<PB0);
PORTB &= ~(1<<PB5) &~(1<<PB7);
/* PORTB setzen gesamt */
PORTB=0b01011111;
//PIND5= log.1 --->R2=5V, andere Rs=0V
//PIND3-4 und PIND6= log.0
C= PINB | 0b11111000;
switch(C) {
case 0b11111111 : break; //nix gedrückt in R2, nix Passiert
case 0b11111011 : return 4;
case 0b11111101 : return 5;
case 0b11111110 : return 6;
}
/* PORTB setzen einzeln */
PORTB |= (1<<PB3) | (1<<PB5) | (1<<PB4) | (1<<PB2) | (1<<PB1) |
(1<<PB0);
PORTB &= ~(1<<PB6) &~(1<<PB7);
/* PORTB setzen gesamt */
PORTB=0b00111111;
//PIND6= log.1 --->R3=5V, andere Rs=0V
//PIND3-5= log.0
C= PINB | 0b11111000;
switch(C) {
case 0b11111111 : break ; //nix gedrückt in R3, nix Passiert
case 0b11111011 : return 7;
case 0b11111101 : return 8;
case 0b11111110 : return 9;
}
return 0;
}
[c]
@ Jakob M. (Firma Student) (jakkob)
>vorzüglich, nur wenn ich jetzt die Bits in PORTB einzeln setze, wie in>den Kommentaren angemerkt, dann gehts gar nicht mehr. Was dumm ist, denn
Hehe, böser Fehler. ;-) Dass es überhaupt geht ist schon fast ein
Wunder, liegt möglicherweise am mehrfachaufruf der Funktion. Denn!!!
zwischen der Ausgabe und dem Einlesen MUSS mindestens ein Takt Pause
sein. Der AVR ist ein RSIC Prozessor mit einstufiger Pipeline. Das ist
aber schon ein Hardcore Insiedertrick.
@ Jakob
Aus dem
// Problemcode #1
PORTB |= (1<<PB6) | (1<<PB5) | (1<<PB4) | (1<<PB2) | (1<<PB1) |
(1<<PB0);
PORTB &= ~(1<<PB3) &~(1<<PB7);
// Funktionsfähigem Code
PORTB=0b01011111;
und der Frage
> denn das Tastenfeld braucht nur sieben Pins und ich würde halt> gerne den achten (PB7) auch noch verwenden, was halt nicht geht,> wenn ich den PORT gesamt setze.
Würde ich den Code #1 so abändern (und an den anderes zwei Stellen
entsprechend):
PORTB = 0b01011111 | (PORTB & (1<<PB7));
Dadurch lässt du PB7 von PORTB in dieser Routine scan_taste()
wunschgemäß unverändert.
Zur Sicherheit muss man hier den erzeugten Assemblercode und das
Restprogramm ansehen:
Kann es passieren, dass sich PORTB.7 zwischen Auslesen (PORTB),
Maskieren mit (& (1<<PB7)) und Setzen (=) ändert?
Eine solche Änderung könnte z.B. durch eine aktive Interruptroutine
erfolgen. D.h. ggf. sind für diese Zeile eventuell freigegebene
Interrupts zu sperren.
@ Falk
Danke für diesen Hinweis! Das wäre einen Eintrag in der Checkliste oder
in den IO-Abschnitten der Tutorials wert (wenn es nicht schon drin
steht, habe noch nicht nachgesehen).
an besagte Stelle eingefügt (Zeit wird per ISR im msec-Takt hochgezählt,
sowohl Zeit als auch F sind volatile uint_32's; meine Funktion ist nicht
zeitkritisch).
Das sollte Taktmäßig ja absolut ausreichen. Leider funktioniert es
allerdings immer noch nicht, wenn ich die Bits in PORTB einzeln
setze..??? :-(
Weißt Du vielleicht noch mehr Rat?
@Stefan
...auch dieser Code funzt aus mir unbekannten Gründen nicht. Und ich
habe nur eine ISR, die Zeit++; macht und sonst nüscht...:-(
gruß und dank
jakob
@ Jakob M. (Firma Student) (jakkob)
>Taste_Zeit=Zeit; while (Taste_Zeit+1>Zeit) {wdt_reset();}>F=Zeit/1000;>an besagte Stelle eingefügt (Zeit wird per ISR im msec-Takt hochgezählt,>sowohl Zeit als auch F sind volatile uint_32's; meine Funktion ist nicht>zeitkritisch).
Volatile reicht nicht bei uint32_t! Die kann der AVR nicht atomar
verarbeiten! Da musst du mit
cli()
sei()
klammern!
Lass den Watchdog erstmal aussen vor.
>...auch dieser Code funzt aus mir unbekannten Gründen nicht. Und ich>habe nur eine ISR, die Zeit++; macht und sonst nüscht...:-(
Poste mal VOLLSTÄNDIGEN Code, als Anhang.
MfG
Falk
Hi,
hmm...volatile hat eigentlich immer gefunzt, auch bei Zeit, die ja
uint_32t ist...
.../* musss an dieser Stelle mal 1000 Küsse vergeben an die Leute, die
hier so fleißig Probleme lösen helfen */
danke
@ Jakob M. (Firma Student) (jakkob)
>hmm...volatile hat eigentlich immer gefunzt, auch bei Zeit, die ja>uint_32t ist...
Das kann aber schief gehen. In 1 von 1 Million Fällen. Es ist
nachweislich NICHT sicher! Und dann viel Spass bei Debuggen.
http://www.mikrocontroller.net/articles/Interrupt#Atomarer_Datenzugriff
Nun Zum Programm.
[c]
#ifndef avr_io_h
#define avr_io_h
#include <avr/io.h>
#endif
#ifndef _interrupt_h
#define _interrupt_h
#include <avr/interrupt.h>
#endif
#ifndef Funktionen_h
#define Funktionen_h
#include "Funktionen.h"
#endif
#ifndef avr_wdt_h
#define avr_wdt_h
#include <avr/wdt.h>
#endif
#ifndef Kontrollvabsis_h
#define Kontrollvabsis_h
#include "Kontrollvabsis.h"
#endif
[c]
Das ist Käse. Diese Dinger gehören nur IN die jeweiligen Headerfiles
rein.
Deine verkorksten Warteschleifen in scan_taste() sind auch Unsinn. So
eine Tastenabfrage läuft einmal komplett OHNE Warteschleifen durch und
wird zyklisch alle 2..20 ms im Timerinterrupt aufgerufen. NCIHT ander
herum! Duch die "langsame" Abtastung erreicht man schon eine gute
Entprellung. Zusätzlich kann man prüfen obe 2..X mal der gleiche
Tastencode geliefert wird, dann ist es absolut wasserdicht.
MFG
Falk
@ Falk
ja, die Wartesacxhleifen in scan_taste() sind Unsinn. Es gibt sie auch
erst seit ein paar Studen, da Du ja meintest es sollten ein paar Befehle
zwischen setzen und lesen der Ports. Und das mit den headerfiles, nun
ja, da hab oich mich wohl als totaler newbi geoutet :-) (habe das jetzt
aber auch behoben! Danke hierfür), aber das ändert doch nix an meinem
Problem...das ja irgendwie mit der Portzuweisung zu tun hat (scheinbar
zumindest). Und das scan_taste() nicht inner ISR aufgerufen wird, liegt
daran, dass sie nur in ganz bestimmten Zuständen gebraucht wird...
1
charscan_taste(){
2
//PORTB=0b11111111;
3
//DDRB= 0b11111000;
4
volatileuint8_tC=0;
5
// C wird an switch übergeben
6
//am Anfang ist R0 auf 5V
7
cli();
8
PORTB=(0b01110111|(PORTB&(1<<PB7)));
9
//geht leider immer noch nicht
10
//gehen würde verrückterweise aber
11
//PORTB= 0b01110111
12
13
14
C=234;//um irgendwas zu machen zwischen
15
//schreiben und lesen
16
C|=0xDD;
17
C=PINB|0b11111000;//um die drei letzten bits zu vergl.
18
sei();// wenn Pin0=Col.3 gedrückt--> PORTB: 0b01111110, wenn in R0
19
switch(C){
20
case0b11111111:break;//nix in R0 gedrückt, nix Passiert
21
case0b11111011:return10;
22
case0b11111101:return11;
23
case0b11111110:return12;
24
}
25
cli();
26
PORTB=(0b01101111|(PORTB&(1<<PB7)));
27
//PIND4= log.1 --->R1=5V, andere Rs=0V
28
//PIND5-6 und PIND3= log.0
29
C=234;
30
C|=0xDD;
31
C=PINB|0b11111000;
32
sei();//if (B==1){PORTB |= (1<<PB7);}
33
switch(C){
34
case0b11111111:break;//nix gedrückt in R1, nix Passiert
35
case0b11111011:return1;
36
case0b11111101:return2;
37
case0b11111110:return3;
38
}
39
40
cli();
41
PORTB=(0b01011111|(PORTB&(1<<PB7)));;
42
//PIND5= log.1 --->R2=5V, andere Rs=0V
43
//PIND3-4 und PIND6= log.0
44
C=234;
45
C|=0xDD;
46
C=PINB|0b11111000;
47
sei();
48
switch(C){
49
case0b11111111:break;//nix gedrückt in R2, nix Passiert
50
case0b11111011:return4;
51
case0b11111101:return5;
52
case0b11111110:return6;
53
}
54
cli();
55
PORTB=(0b00111111|(PORTB&(1<<PB7)));
56
//PIND6= log.1 --->R3=5V, andere Rs=0V
57
//PIND3-5= log.0
58
C=234;
59
C|=0xDD;
60
C=PINB|0b11111000;
61
sei();
62
switch(C){
63
case0b11111111:break;//nix gedrückt in R3, nix Passiert
@ Jakob M. (Firma Student) (jakkob)
>erst seit ein paar Studen, da Du ja meintest es sollten ein paar Befehle>zwischen setzen und lesen der Ports.
Naja, aber leider ist der Compiler "schlauer" als du, und optimiert ggf.
den Zugriff anders.
Das muss man ihm expizit verbieten, z.B. indem men per Inline Assembler
ein NOP einfügt. Hab aber im Moment nicht die Syntax im Kopf. Jörg?
Für
>Problem...das ja irgendwie mit der Portzuweisung zu tun hat (scheinbar>zumindest). Und das scan_taste() nicht inner ISR aufgerufen wird, liegt>daran, dass sie nur in ganz bestimmten Zuständen gebraucht wird...
Wie testest du denn überhaupt? teste mal nur die funktion, ohne
irgendwelches anderes Zeug.
1
charscan_taste(){
2
//PORTB=0b11111111;
3
//DDRB= 0b11111000;
4
volatileuint8_tC=0;
Sowas ist insinnig. Volatile ist nur für GLOLE Variablen nötig, die
SOWOHL im Interrupt als auch im normalen Prpgramm verwendet werden.
Das cli() und sei() ist jetzt natürlich auch sinnlos, weil du ja nicht
mehr auf solche variablen zugreifst.
1
PORTB=(0b01110111|(PORTB&(1<<PB7)));
2
//geht leider immer noch nicht
3
//gehen würde verrückterweise aber
4
//PORTB= 0b01110111
Verdrahtungsfehler?
Versuchs mal so
1
charscan_taste(){
2
uint8_tC=0;
3
// C wird an switch übergeben
4
//am Anfang ist R0 auf 5V
5
6
DDRB=0xFF;
7
PORTB=0xFF;// alles Ausgang, HIGH
8
DDRB=0b11111000;
9
PORTB=(0b01110111|(PORTB&(1<<PB7)));
10
11
C=PINB;// NICHT optimierbar, da PINC volatile ist
12
C=PINB&0b111;//um die drei letzten bits zu vergl.
13
14
// mit UND-Verknüpfung wird das einfacher und übersichtlicher!
15
16
switch(C){
17
case0b111:break;//nix in R0 gedrückt, nix Passiert
18
case0b011:return10;
19
case0b101:return11;
20
case0b110:return12;
21
}
22
23
DDRB=0xFF;
24
PORTB=0xFF;// alles Ausgang, HIGH
25
DDRB=0b11111000;
26
27
PORTB=(0b01101111|(PORTB&(1<<PB7)));
28
//PIND4= log.1 --->R1=5V, andere Rs=0V
29
//PIND5-6 und PIND3= log.0
30
C=PinB;
31
C=PINB&0b111;
32
33
switch(C){
34
case0b111:break;//nix gedrückt in R1, nix Passiert
35
case0b011:return1;
36
case0b101:return2;
37
case0b110:return3;
38
}
39
40
DDRB=0xFF;
41
PORTB=0xFF;// alles Ausgang, HIGH
42
DDRB=0b11111000;
43
44
PORTB=(0b01011111|(PORTB&(1<<PB7)));;
45
//PIND5= log.1 --->R2=5V, andere Rs=0V
46
//PIND3-4 und PIND6= log.0
47
C=PINB;
48
C=PINB|0b11111000;
49
50
switch(C){
51
case0b111:break;//nix gedrückt in R2, nix Passiert
52
case0b011:return4;
53
case0b101:return5;
54
case0b110:return6;
55
}
56
57
DDRB=0xFF;
58
PORTB=0xFF;// alles Ausgang, HIGH
59
DDRB=0b11111000;
60
61
PORTB=(0b00111111|(PORTB&(1<<PB7)));
62
//PIND6= log.1 --->R3=5V, andere Rs=0V
63
//PIND3-5= log.0
64
C=PINB;
65
C=PINB|0b11111000;
66
67
switch(C){
68
case0b111:break;//nix gedrückt in R3, nix Passiert