Hallo Leute!
Nachdem mir bei meinem anderen Thread im µC-Forum keiner weiterhelfen
kann, womöglich wegen der argen Komplexität meiner Probleme, poste ich
am besten hier nochmal eine "reduzierte" Fragestellung.
Ausgangslage:
Ich versuche an meinem AT90USBKEY mit AT90USB1287 eine Folientastatur
mit 2 Spalten und 5 Zeilen zu betreiben.
Später soll die Tasteneingabe per USB an den PC übermittelt werden, aber
das ist jetzt nicht das Ziel.
Hier im Forum hab ich eine Ansteuerung von einer Tastenmatrix gefunden
und sie entsprechend angepasst (s. Anhang).
Da ich noch relativ neu bin in µC-Programmierung, verstehe ich aber
manche Teile des Codes nicht ganz und würde euch gerne darum bitte, sie
mir zu erläutern.
Da ich das Ergebnis der Tastenabfrage gerne in einer Variable o.ä.
speichern würde, um diese dann per USB-Tast an den PC zu übermitteln,
komme ich v.a. mit dem letzten Teil des Codes nicht so klar:
1
PORTA=0xFF;
2
DDRA=0xFF;
3
for(;;){
4
if(get_key_press(1<<8))// "1"
5
PORTA^=1<<0;// toggle
6
if(get_key_press(1<<4))// "2"
7
PORTA^=1<<1;
8
if(get_key_press(1<<0))// "3"
9
PORTA^=1<<2;
10
if(get_key_press(1<<9))// "4"
11
PORTA^=1<<3;
12
if(get_key_press(1<<5))// "5"
13
PORTA^=1<<4;
14
if(get_key_press(1<<1))// "6"
15
PORTA^=1<<5;
16
if(get_key_press(1<<10))// "7"
17
PORTA^=1<<6;
18
if(get_key_press(1<<6))// "8"
19
PORTA^=1<<7;
20
if(get_key_press(1<<11))// "#"
21
PORTA=0;// all on
22
if(get_key_press(1<<3))// "*"
23
PORTA=0xFF;// all off
24
}
Sie is es richtig, dass das Scanergebnis an den PortA "übermittelt"
wird?
Was wird v.a. bei folgendem Codeteil gemacht?
1
if(get_key_press(1<<4))// "2"
2
PORTA^=1<<1;
Wie gesagt, ich würde gerne den Tastendruck einlesen und an den USB-Task
weitergeben. Das Drücken und Erkennen von zwei Tasten gleichzeitig wäre
auch nicht schlecht für meine Anforderung.
Bevor ich aber die Daten per USB schicke, würde ich gerne sicher gehen,
dass der Code der Tastenmatrix funktioniert und beim Drücken einer
Taste, z.B. der in der Matrix oben links, eine LED auf dem USBKEY auf
"grün" schalten. Pin 5 von PORTD muss dazu auf "high" geschaltet werden.
Tut mir Leid für meine Anfängerfragen, aber ich komm im Moment einfach
nicht wirklich weiter, hab schon AVR-GCC Tutorial durchgeforstet und zig
Threads gelesen, aber ohne hier zu posten komm ich wohl nicht aus.
Ich bin für jede Hilfe dankbar!
Andreas R. wrote:
> Sie is es richtig, dass das Scanergebnis an den PortA "übermittelt"> wird?
Grundsätzlich ja. PORTA ist auf Ausgabe geschaltet (DDRA = 0xFF;) und am
Anfang sind alle Pins LOW (PORTA = 0xFF;). Je nach Tastendruck
(get_key_press(...)) wird ein Pin von PORTA mittels XOR Bitverknüpfung
umgeschaltet (PORTA ^= ...). Das kann z.B. LEDs an/aus Schalten.
> Bevor ich aber die Daten per USB schicke, würde ich gerne sicher gehen,> dass der Code der Tastenmatrix funktioniert und beim Drücken einer> Taste, z.B. der in der Matrix oben links, eine LED auf dem USBKEY auf> "grün" schalten.
"in der Matrix oben links" ist welche Spalte und welche Zeile? Hast du
einen Schaltplan?
> Pin 5 von PORTD muss dazu auf "high" geschaltet werden.
// Pin 5 an PORT D auf Ausgang schalten
DDRD = (1<<PD5);
// dann HIGH schalten
PORTD = (1<<PD5);
// oder LOW schalten
PORTD &= ~(1<<PD5);
Danke für deine Antwort Stefan!
Stefan "stefb" B. wrote:
> Andreas R. wrote:>>> Sie is es richtig, dass das Scanergebnis an den PortA "übermittelt">> wird?>> Grundsätzlich ja. PORTA ist auf Ausgabe geschaltet (DDRA = 0xFF;) und am> Anfang sind alle Pins LOW (PORTA = 0xFF;). Je nach Tastendruck> (get_key_press(...)) wird ein Pin von PORTA mittels XOR Bitverknüpfung> umgeschaltet (PORTA ^= ...). Das kann z.B. LEDs an/aus Schalten.
Genau so hab ichs mir schon gedacht, war mir nur nicht sicher.
>> Bevor ich aber die Daten per USB schicke, würde ich gerne sicher gehen,>> dass der Code der Tastenmatrix funktioniert und beim Drücken einer>> Taste, z.B. der in der Matrix oben links, eine LED auf dem USBKEY auf>> "grün" schalten.>> "in der Matrix oben links" ist welche Spalte und welche Zeile? Hast du> einen Schaltplan?
Digital hab ich leider gerade keinen Schaltplan hier, aber es die erste
Taste ist quasi Zeile 1, Spalte 1.
Hier mal schematisch die Matrix mit der Pinbelegung am Flachbandkabel
und somit von 0-6 am AVR (mit T meine ich die einzelnen Tasten):
PIN 1 PIN2
PIN3 T1 T2
PIN4 T3 T4
PIN5 T5 T6
PIN6 T7 T8
PIN7 T9 T10
>> Pin 5 von PORTD muss dazu auf "high" geschaltet werden.>> // Pin 5 an PORT D auf Ausgang schalten> DDRD = (1<<PD5);>> // dann HIGH schalten> PORTD = (1<<PD5);>> // oder LOW schalten> PORTD &= ~(1<<PD5);
OK, danke, ich werde es mal versuchen, ob sich ich den den ersten Erfolg
an der LED sichtbar machen kann ;-)
Vorausgesetzt ich hab den Rest des Codes richtig angepasst bzw. meine
PINs und PORTs richtig angepasst..
> // Pin 5 an PORT D auf Ausgang schalten> DDRD = (1<<PD5);>> // dann HIGH schalten> PORTD = (1<<PD5);
Mist. Flüchtigkeitsfehler und | vergessen. Obiges geht zwar, aber du
änderst andere Pins ebenfalls. Man sollte das mit einem ODER machen:
// Pin 5 an PORT D auf Ausgang schalten
DDRD |= (1<<PD5);
// dann HIGH schalten
PORTD |= (1<<PD5);
>> Sieht gut aus. Sehr gut sähe es aus, wenn KEY_COL0 und KEY_COL1 auch> definiert wären ;-)
Hab ich mir auch schon gedacht, als ich den Code gefunden hab. Aber
sollte ja auch so gehn oder?
>>
1
>
2
>staticinline
3
>u16key_scan(void)
4
>{
5
>u16keys=0;
6
>u8i;
7
>
8
>KEY_DDR=1<<KEY_ROW0;
9
>for(i=5;i;i--){
10
>keys=(keys<<4)|(KEY_PIN&0x0F);
11
>KEY_DDR<<=1;
12
>}
13
>return~keys;
14
>}
15
>
16
>
>> Passt nicht. Das ist für eine 4x4 Matrix.
Dachte ich mir schon, weiß nur nicht, wie ich den Teil abändern muss.
i=5 stand vorher auf 3, also hab ichs auf i=5 gesetzt, da 5 outputs.
Habe vorhin den Bereich abgeändert damit man mit Zeile 1, Spalte 1 die
LED auf grün schalten kann. Getan hat sich aber auf dem Controller
nichts. Liegt wohl auch am obigen Fehler, dass der Codeteil für ne 4x4
Matrix ist oder?
Annahme: Bei Taste 10 soll im Ergbnis Bit 10 gelöscht sein (damit es zum
Rest des Codes passt mit dem Interrrupt etc.), bei Taste 9 Bit 9 usw..
Was nicht passt ist der Kommentar in main - dort ist eine andere
Zuordnung. Mit dem Code unten ist die Bitnummer in der Abfrage gleich
der Tastennummer.
COL0 COL1
PIN 1 PIN2
PIN3 T1 T2 ROW0
PIN4 T3 T4 ROW1
PIN5 T5 T6 ROW2
PIN6 T7 T8 ROW3
PIN7 T9 T10 ROW4
Stefan "stefb" B. wrote:
> Annahme: Bei Taste 10 soll im Ergbnis Bit 10 gelöscht sein (damit es zum> Rest des Codes passt mit dem Interrrupt etc.), bei Taste 9 Bit 9 usw..> Was nicht passt ist der Kommentar in main - dort ist eine andere> Zuordnung. Mit dem Code unten ist die Bitnummer in der Abfrage gleich> der Tastennummer.>> COL0 COL1> PIN 1 PIN2> PIN3 T1 T2 ROW0> PIN4 T3 T4 ROW1> PIN5 T5 T6 ROW2> PIN6 T7 T8 ROW3> PIN7 T9 T10 ROW4>
Stimmt, die andere Zuordnung hat mich auch verwirrt bei dem Abschnitt im
Code...
So habs mal geändert, jetzt leuchtet allerdings die LED sofort, schon
vor dem Tastendruck... Hab wie du oben erklärt hast folgendes drinnen
stehn:
Andreas R. wrote:
> if( get_key_press( 1<<0 ))
^
1<<0 geht sowieso nicht. Die erste Taste ist Bit 1 also 1<<1 bis Taste
10 und das wäre Bit 10 also 1<<10. Wenn es mit anderen Werten als 1<<0
auch nicht klappt, melde dich noch mal.
Den neuen Code müsste ich mir im Debugger/Simulator schrittweise
ansehen, denn im Kopp habe ich im Moment Probleme, das alles
nachzuvollziehen.
Leider gehts auch mit Bit 1 nicht.
Vielleicht war es ein bißchen mißverständlich, aber Pin 1 des
Flachbandkabels der Folientastatur hängt eigentlich an Pin 0 von Port B.
Also wär doch dann Taste 1 schon Bit 0 oder?
Mir ist auch noch aufgefallen, dass
1
KEY_PORT=0x0F;
doch auch nicht stimmen kann oder? Für die Pullups für die Inputs
müsste doch in meinem Fall
1
KEY_PORT=0x03;
benutzt werden oder? Für Pin 0 und Pin 1 der Spalten...
Wär super wenn du den Code mal debuggen/simulieren könntest. Unter Linux
kann ich den AT90USB1287 nämlich leider nicht simulieren. Und nen AVR
Dragon oder so hab ich grad ned zur Verfügung...
Schon mal ein riesen Danke!
Ja, da war noch ein Mix von Problemen im Code. Teilweise Änderungen von
mir (KEY_ROW4 statt KEY_ROW0) in deiner neuen Version nicht drin. Dann
die von dir schon gefundene, zerstückelte Initialisierung in key_scan()
und in main(). Und die Zurodnung der Bits zur Taste...
folgendes funktioniert im Simulator. Die Initialisierung wird nur in
key_Scan gemacht.
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
#include<avr/pgmspace.h>
4
5
6
typedefunsignedcharu8;
7
typedefunsignedshortu16;
8
9
10
#define XTAL 8e6 // 8MHz
11
12
#define KEY_PIN PINB // B1..0 = inputs
13
#define KEY_PORT PORTB
14
#define KEY_DDR DDRB
15
#define KEY_COL0 PORTB0
16
#define KEY_COL1 PORTB1
17
#define KEY_ROW0 PORTB2 // B6..2 = outputs
18
#define KEY_ROW1 PORTB3
19
#define KEY_ROW2 PORTB4
20
#define KEY_ROW3 PORTB5
21
#define KEY_ROW4 PORTB6
22
23
staticinline
24
u16key_scan(void)
25
{
26
u16keys=0;
27
u8i;
28
u8old_ddr=KEY_DDR;
29
u8old_port=KEY_PORT;
30
31
KEY_PORT=(1<<KEY_ROW4);
32
KEY_DDR=(1<<KEY_ROW4);
33
34
i=5;
35
do
36
{
37
keys|=(KEY_PIN&((1<<KEY_COL1)|(1<<KEY_COL0)))<<1;
38
i-=1;
39
if(i)
40
{
41
keys<<=2;
42
KEY_DDR>>=1;
43
KEY_PORT>>=1;
44
}
45
}
46
while(i);
47
48
KEY_DDR=old_ddr;
49
KEY_PORT=old_port;
50
51
return~keys;
52
}
53
54
55
u16key_state;// debounced key state:
56
// bit = 1: key pressed
57
u16key_press;// key press detect
58
59
60
ISR(TIMER0_OVF_vect)
61
{
62
staticu16ct0,ct1;
63
u16i;
64
65
TCNT0=(u16)(256-XTAL/1024/100);// 100Hz (10ms)
66
67
i=key_state^key_scan();// key changed ?
68
ct0=~(ct0&i);// reset or count ct0
69
ct1=ct0^(ct1&i);// reset or count ct1
70
i&=ct0&ct1;// count until roll over ?
71
key_state^=i;// then toggle debounced state
72
key_press|=key_state&i;// 0->1: key press detect
73
}
74
75
76
u16get_key_press(u16key_mask)
77
{
78
cli();
79
key_mask&=key_press;// read key(s)
80
key_press^=key_mask;// clear key(s)
81
sei();
82
returnkey_mask;
83
}
84
85
86
intmain(void)
87
{
88
TCCR0B=(1<<CS02)|(1<<CS00);// XTAL / 1024
89
TIMSK0=1<<TOIE0;
90
91
sei();
92
93
DDRD|=(1<<PD5);
94
95
for(;;)
96
{
97
if(get_key_press(1<<10))// "Taste 10"
98
PORTD|=(1<<PD5);
99
//else
100
// PORTD &= ~(1<<PD5);
101
}
102
}
wo stammt der ursprüngliche Code mit der Entprellung eigentlich her? Ist
das ein Beispiel von Atmel?
Danke für deine Mühe, aber leider funktioniert der Code immer noch
nicht.
Benutze ich
1
if(get_key_press(1<<10))// "Taste 10"
2
PORTD|=(1<<PD5);
3
//else
4
// PORTD &= ~(1<<PD5);
Dann leuchtet die LED wieder permanent. Mach ich das "else" mit rein,
blinkt die LED eeeextrem kurz auf, wenn ich die Taste drücke.
Sollte Taste 10 nicht eigentlich Bit 9 sein?
Der Code zur Entprellung wie der Rest auch, stammt aus dem Forum hier.
Ist ähnlich der Entprellroutine der Tastenmatrix über 2 Leitungen aus
der Codesammlung.
Ich habe dabei auch
1
TCCR0=1<<CS02^1<<CS00;// XTAL / 1024
2
TIMSK=1<<TOIE0;
auf
1
TCCR0B=(1<<CS02)|(1<<CS00);// XTAL / 1024
2
TIMSK0=1<<TOIE0;
Angepasst, weil die Bezeichnungen TCCR0 und TIMSK0 beim AT90USB1287 so
nicht vorkommen.
Vielleicht liegt es daran??
Im Anhang ist übrigens der Original-Code, so wie ich ihn hier gefunden
habe.
Andreas R. wrote:
> Im Anhang ist übrigens der Original-Code, so wie ich ihn hier gefunden> habe.
Ah vom Peter ist der Code! Lass unbedingt solche Hinweise in den Sourcen
drin, die du von ausserhalb hast. Änderungen kann man dann leichter
verfolgen. Plus: Ehre wem Ehre gebührt.
Ich schaue mir das Thema heute abend im Debugger/Simulator bzw. kann es
auf einem kleinerem AVR auch live austesten.
Taste 10 ist Bit 10, weil ich es oben mal so beschrieben habe, Wenn dich
das stört weil du dir 10 = 9 besser merken kannst, ändere diese Zeile
;-)
keys |= (KEY_PIN & ((1<<KEY_COL1) | (1<<KEY_COL0))) /* << 1 */;
^^^^^^^^^^
Zwischen
TCCR0 = 1<<CS02^1<<CS00; // XTAL / 1024
und
TCCR0B = (1<<CS02)|(1<<CS00); // XTAL / 1024
Sind mehrere Änderungen. Die Änderung ^ zu | muss ich mir auch in Ruhe
zu Gemüte führen.
Das Dauerleuchten der LED ohne Tastendruck am Anfang kann daran hängen,
dass die LEDlow-active angeschlossen ist (AVR Tutorial IO). Hast du
Unterlagen zur Hardware? Dementsprechend ist auch das if/else
anzupassen. Einfachmal die Statements tauschen.
Das kurze Aufblitzen (oder eher Verdunkeln?) ist doch gut. Das zeigt,
dass der Code arbeitet. get_key_press löscht ja den Tastendruck beim
Auslesen (read keys + clear keys...). Und dein AVR rennt mit einer
Endlos-For und einem mickrigen if ziemlich schnell ;-)
Jap, zu dem AT90USBKEY hab ich ein Datenblatt, dort steht bezüglich der
LEDs:
"The AT90USBKey includes 2 bi-color LEDs (green/red) implemented on one
line. They are connected to the high nibble of “Port D” of AT90USB
(PORTD[4..7]).
To light on a LED, the corresponding port pin must drive a high level.
To light off a LED, the corresponding port pin must drive a low level."
Im Anhang ist die ganze PDF.
Zum AT90USB1287 selbst gibts natürlich auf der Atmelseite auch ein
Datenblatt...
Hoffentlich wird das noch was mit der Matrix, ist nämlich ein Teil
meiner Abschlussarbeit ;-)
Nein, bin nicht dazu gekommen. Gestern habe ich die Fahrtmesser-Anzeige
der F16 aus Falcon 4.0: Allied Force auf meine 7-Segment-Anzeige legen
müssen ;-)
Gibt es auch ein Datenblatt von der Tastatur oder ist die selbstgebaut
(wie geschaltet?)
Die LEDs sind also high-active angeschlossen. Vielleicht benutzt du mal
diesen Code zum Ausprobieren. Es sind brutale Delays drin, und beide
LEDs werden benutzt damit was sichtbares und erklärbares passiert. Taste
10 wirkt per Programm als Ein-/Ausschalter.
1
#inlude <util/delay.h>
2
3
4
intmain(void)
5
{
6
u16taste;
7
8
TCCR0B=(1<<CS02)|(1<<CS00);// XTAL / 1024
9
TIMSK0=1<<TOIE0;
10
11
sei();
12
13
DDRD|=(1<<PD4)|(1<<PD5)|(1<<PD6)|(1<<PD7);
14
PORTD=(PORTD&0x0F)|((1<<PD4)|(1<<PD7));// D2-R D5-G beide dauer
15
_delay_ms(5000);
16
17
for(;;)
18
{
19
if(get_key_press(1<<10))// "Taste 10" merken
20
taste^=(1<<10);
21
22
if((taste&(1<<10)))
23
{
24
PORTD&=~(1<<PD4);
25
PORTD^=(1<<PD5);// D2-G 0.5s Blinken
26
_delay_ms(500);
27
}
28
else
29
{
30
PORTD&=~(1<<PD7);
31
PORTD^=(1<<PD6);// D5-R 2s Blinken
32
_delay_ms(2000);
33
}
34
}
35
}
RESET machen, 10 Sek warten. Welche LEDs leuchten wie? Ändert sich das
Leuchten nach ca. 5s? Mit Taste 10 spielen. Welche LEDs ändern sich wie?
Kommen die Blinkfrequenzen hin, d.h. läuft der Timer richtig oder
wesentlich schneller/langsamer?
Hi, People
Want to share with you the results of my work. I've discovered that
these 3 programs solved my
security problems by using them simultaneously.
1. XoftSpy-SE (the biggest base of detected spyware programs) +
Web-site: http://xoftspyse.repairandsecure.com/
2. Netcom Internet Security (complete protection from viruses including
firewall) +
Found it here:
http://securityandprivacy.triedtool.com/product.php?id=netcominternetsecuritysuiteregistryandadwarespywarecleaner
3. SpyBot Search and Destroy (the only freeware anti-spyware program!)
Web-site: http://www.safer-networking.org/
These programs are from the the different manufacturers and they do have
different threats definitions bases but in a complex they cover 99.8%!
of all known threats. These numbers are taken from the direct comparison
of the 18 popular antivirus programs so it can be trusted.
Keep your computers safe! Good luck ;)
Regards,
Mark
> Gibt es auch ein Datenblatt von der Tastatur oder ist die selbstgebaut> (wie geschaltet?)
Also die Folientastatur ist wie im Bild im Anhang geschaltet.
Wobei ich Pin 1 der Anschlussfahne auf Pin 0 von Port B gelegt hab. Pin
2 auf Pin 1. Da Pin3 der Fahne nicht belegt ist, habe ich Pin 4 auf Pin
2 von Port B gelegt usw.
Pin 9 und 10 der Fahne sind für einen Powerbutton und Pin 9 ist nur aus
praktischen Gründen im Flachbandkabel zum Controller enthalten und läuft
dort auf VCC (Pin 10 ist nicht mehr drauf durch das Entfernen der Ader
vom nicht belegten Pin 3 - aus dem Flachbandkabel entfernt). Kann es
sein, dass ich durch versehentliches Drücken des Powerbuttons einen
Kurzschluss verursacht habe und dadurch irgendwas geschossen hab?!?
Ich habe nun folgenden Code benutzt:
1
#ifndef F_CPU
2
#define F_CPU 8000000UL /* Quarz mit 8 Mhz */
3
#endif
4
#include<avr/io.h>
5
#include<avr/interrupt.h>
6
#include<avr/pgmspace.h>
7
#include<util/delay.h>
8
9
typedefunsignedcharu8;
10
typedefunsignedshortu16;
11
12
13
#define XTAL 8e6 // 8MHz
14
15
#define KEY_PIN PINB // B1..0 = inputs
16
#define KEY_PORT PORTB
17
#define KEY_DDR DDRB
18
#define KEY_COL0 PORTB0
19
#define KEY_COL1 PORTB1
20
#define KEY_ROW0 PORTB2 // B6..2 = outputs
21
#define KEY_ROW1 PORTB3
22
#define KEY_ROW2 PORTB4
23
#define KEY_ROW3 PORTB5
24
#define KEY_ROW4 PORTB6
25
26
staticinline
27
u16key_scan(void)
28
{
29
u16keys=0;
30
u8i;
31
u8old_ddr=KEY_DDR;
32
u8old_port=KEY_PORT;
33
34
KEY_PORT=(1<<KEY_ROW4);
35
KEY_DDR=(1<<KEY_ROW4);
36
37
i=5;
38
do
39
{
40
keys|=(KEY_PIN&((1<<KEY_COL1)|(1<<KEY_COL0)))<<1;
41
i-=1;
42
if(i)
43
{
44
keys<<=2;
45
KEY_DDR>>=1;
46
KEY_PORT>>=1;
47
}
48
}
49
while(i);
50
51
KEY_DDR=old_ddr;
52
KEY_PORT=old_port;
53
54
return~keys;
55
}
56
57
58
u16key_state;// debounced key state:
59
// bit = 1: key pressed
60
u16key_press;// key press detect
61
62
63
ISR(TIMER0_OVF_vect)
64
{
65
staticu16ct0,ct1;
66
u16i;
67
68
TCNT0=(u16)(256-XTAL/1024/100);// 100Hz (10ms)
69
70
i=key_state^key_scan();// key changed ?
71
ct0=~(ct0&i);// reset or count ct0
72
ct1=ct0^(ct1&i);// reset or count ct1
73
i&=ct0&ct1;// count until roll over ?
74
key_state^=i;// then toggle debounced state
75
key_press|=key_state&i;// 0->1: key press detect
76
}
77
78
79
u16get_key_press(u16key_mask)
80
{
81
cli();
82
key_mask&=key_press;// read key(s)
83
key_press^=key_mask;// clear key(s)
84
sei();
85
returnkey_mask;
86
}
87
88
89
intmain(void)
90
{
91
u16taste;
92
93
TCCR0B=(1<<CS02)|(1<<CS00);// XTAL / 1024
94
TIMSK0=1<<TOIE0;
95
96
sei();
97
98
DDRD|=(1<<PD4)|(1<<PD5)|(1<<PD6)|(1<<PD7);
99
PORTD=(PORTD&0x0F)|((1<<PD4)|(1<<PD7));// D2-R D5-G beide dauer
100
_delay_ms(5000);
101
102
for(;;)
103
{
104
if(get_key_press(1<<10))// "Taste 10" merken
105
taste^=(1<<10);
106
107
if((taste&(1<<10)))
108
{
109
PORTD&=~(1<<PD4);
110
PORTD^=(1<<PD5);// D2-G 0.5s Blinken
111
_delay_ms(500);
112
}
113
else
114
{
115
PORTD&=~(1<<PD7);
116
PORTD^=(1<<PD6);// D5-R 2s Blinken
117
_delay_ms(2000);
118
}
119
}
120
}
Diesen habe ich mit einer Make-File kompiliert, weil ich mit dem Befehl
avr-gcc -mmcu=at90usb1287 keymatrix.c -Os keymatrix.elf
Fehlermeldungen erhalten habe...
> RESET machen, 10 Sek warten. Welche LEDs leuchten wie? Ändert sich das> Leuchten nach ca. 5s? Mit Taste 10 spielen. Welche LEDs ändern sich wie?> Kommen die Blinkfrequenzen hin, d.h. läuft der Timer richtig oder> wesentlich schneller/langsamer?
Tja und jetzt kommt das Tolle:
Nach Drücken der RST-Taste auf dem USBKEY leuchten beide LEDs ROT für 40
Sekunden, danach schaltet D2 auf GRÜN und schaltet in 4
Sekunden-Abständen an bzw. aus. Drücke ich Taste 10 also auf der
Folientastatur die Taste F5 passiert rein gar nichts...
Was ich allerdings feststellen musste:
Wenn ich erneut einen RESET mache kommt es manchmal vor, dass nach 40
Sekunden statt D2 auf einmal D5 GRÜN leuchtet und im 4 Sekunden-Abstand
blinkt, aber bei einem anderen RESET-Versuch in 16 Sekunden-Abstand
blinkt.
Also schön langsam versteh ich die (AVR-)Welt nicht mehr...
Die Verzweiflung ist nahe...
Bei den Blinkfrequenzen bin ich mir noch nicht sicher, ob dein Board
korrekt mit 8 MHz läuft. Das wäre aber nichts Kritisches (#).
Jetzt zum Kern! Ich denke es ist ein Hardwareproblem. Deshalb bin ich
vom Simulator weg und habe es auf einem echten AVR laufen lassen.
Dazu habe ich mangels AT90USBKEY ein [[Pollin
Funk-AVR-Evaluationsboard]] verwendet. Die Umschaltung PFA und
AT90USBKEY geschieht mit dem Makro SBTEST (s. Codeanfang). Mein PFA hat
im Moment aber nicht genug Pins frei, um deine komplette Tastatur
nachzustellen und ich habe nur eine Taste 10 emuliert. Die Emulation
besteht in einem SMD-Tasterchen in Serie mit einem 1K5 Widerstand (##)
zwischen PD2 und PD3. Aufbau auf Steckbrett und angeschlossen mit ca. 50
cm langen Klingeldrähten.
Desweiteren musste ich die Diagnose etwas abgespecken, weil auf dem PFA
nur zwei rote LEDs sind. Das funktioniert so auch auf deinem Board. Als
Diagnose blinkt eine LED je nach Taste 10 schnell/langsam und eine LED
leuchtet, so lange wie ein Tastendruck entdeckt wird.
Du wirst diese Zeile mit einer Pause entdecken:
_delay_us(10); // Übersprechen bei langen Leitungen abwarten
Ich denke das ist die Lösung für das Kernproblem. Ich habe die externe
Taste ja mit fliegender Verdrahtung und rel. langen Leitungen (50 cm
2x0,6mm Klingeldraht) angeschlossen. Bei meinem Aufbau gibt es ein
kurzes Übersprechen zwischen der Ausgabeleitung (ROW-Leitung, Screenshot
Spur 01) und der Abfrageleitung (COL-Leitung, Spur 00).
Ohne Pause führt das dazu, dass immer "1" eingelesen wird. Mit der
Pause wird nach dem Übersprechen abgefragt.
Die Länge der Pause kann durch Versuche ermittelt werden - zuerst ein
kurzer Wert genommen (1) und dann solange erhöht, bis die Diagnose-LED
an PD6 nicht ständig leuchtet sondern nur bei Tastendruck. Oder mit
Logikanalysator oder Oszi, kann man den Wert aus der Messung ermitteln
(Zeit von Trigger bis X 4,8 us + Sicherheitsaufschlag)
Jetzt beim Testen besonders darauf achten, ob es gelingt beim
Tastendruck ein eindeutiges Signal an der LED an PD6 zu bekommen (bei
dir D5-Grün).
Das Blinken an D2-Grün ist dann davon abhängig, ob der Code die
eingelesene Taste an die richtige Bitposition schiebt. Ich denke, dass
da kein Fehler im Code ist, aber mal abwarten.
// Externer Taster in Serie mit R=1K5 zwischen PD2 und PD3
3
// On-Board LEDs an PD5 und PD6 aktiv-high geschaltet
4
// Auskommentieren bei AT90USBKEY !
5
#define SBTEST
6
7
#ifndef F_CPU
8
#define F_CPU 8000000UL /* Quarz mit 8 Mhz */
9
#endif
10
#include<avr/io.h>
11
#include<avr/interrupt.h>
12
#include<avr/pgmspace.h>
13
#include<util/delay.h>
14
15
typedefunsignedcharu8;
16
typedefunsignedshortu16;
17
18
#ifdef SBTEST
19
#define XTAL F_CPU
20
#define KEY_PIN PIND // B1..0 = inputs
21
#define KEY_PORT PORTD
22
#define KEY_DDR DDRD
23
#define KEY_COL0 PORTD2
24
#define KEY_ROW4 PORTD3
25
#else
26
#define XTAL 8e6 // 8MHz
27
#define KEY_PIN PINB // B1..0 = inputs
28
#define KEY_PORT PORTB
29
#define KEY_DDR DDRB
30
#define KEY_COL0 PORTB0
31
#define KEY_COL1 PORTB1
32
#define KEY_ROW0 PORTB2 // B6..2 = outputs
33
#define KEY_ROW1 PORTB3
34
#define KEY_ROW2 PORTB4
35
#define KEY_ROW3 PORTB5
36
#define KEY_ROW4 PORTB6
37
#endif
38
39
staticinline
40
u16key_scan(void)
41
{
42
u16keys=0;
43
u8i;
44
u8old_ddr=KEY_DDR;
45
u8old_port=KEY_PORT;
46
47
KEY_PORT=(1<<KEY_ROW4);
48
KEY_DDR=(1<<KEY_ROW4);
49
50
#ifdef SBTEST
51
i=1;
52
do
53
{
54
_delay_us(10);// Übersprechen bei langen Leitungen abwarten
55
keys|=(KEY_PIN&(1<<KEY_COL0))<<(10-KEY_COL0);
56
i-=1;
57
}
58
while(i);
59
#else
60
i=5;
61
do
62
{
63
_delay_us(10);// Übersprechen bei langen Leitungen abwarten
64
keys|=(KEY_PIN&((1<<KEY_COL1)|(1<<KEY_COL0)))<<1;
65
i-=1;
66
if(i)
67
{
68
keys<<=2;
69
KEY_DDR>>=1;
70
KEY_PORT>>=1;
71
}
72
}
73
while(i);
74
#endif
75
76
KEY_DDR=old_ddr;
77
KEY_PORT=old_port;
78
79
// DIAGNOSE
80
if(keys)
81
PORTD|=(1<<PD6);
82
else
83
PORTD&=~(1<<PD6);
84
85
return~keys;
86
}
87
88
u16key_state;// debounced key state:
89
// bit = 1: key pressed
90
u16key_press;// key press detect
91
92
93
ISR(TIMER0_OVF_vect)
94
{
95
staticu16ct0,ct1;
96
u16i;
97
98
TCNT0=(u16)(256-XTAL/1024/100);// 100Hz (10ms)
99
100
i=key_state^key_scan();// key changed ?
101
ct0=~(ct0&i);// reset or count ct0
102
ct1=ct0^(ct1&i);// reset or count ct1
103
i&=ct0&ct1;// count until roll over ?
104
key_state^=i;// then toggle debounced state
105
key_press|=key_state&i;// 0->1: key press detect
106
}
107
108
109
u16get_key_press(u16key_mask)
110
{
111
cli();
112
key_mask&=key_press;// read key(s)
113
key_press^=key_mask;// clear key(s)
114
sei();
115
returnkey_mask;
116
}
117
118
119
intmain(void)
120
{
121
u16taste;
122
123
#ifdef SBTEST
124
// ATmega8
125
TCCR0=(1<<CS02)|(1<<CS00);// XTAL / 1024
126
TIMSK=1<<TOIE0;
127
#else
128
TCCR0B=(1<<CS02)|(1<<CS00);// XTAL / 1024
129
TIMSK0=1<<TOIE0;
130
#endif
131
132
sei();
133
134
// DIAGNOSE
135
DDRD|=(1<<PD5)|(1<<PD6);
136
137
for(;;)
138
{
139
if(get_key_press(1<<10))// "Taste 10" merken
140
taste^=(1<<10);
141
142
// DIAGNOSE
143
if((taste&(1<<10)))
144
{
145
PORTD^=(1<<PD5);// 0.5s Blinken
146
_delay_ms(500);
147
}
148
else
149
{
150
PORTD^=(1<<PD5);// 2s Blinken
151
_delay_ms(2000);
152
}
153
}
154
}
(#) Eine Fehleinstellung (insb. 1 MHz intern statt 8 MHz extern) könnte
bei der Diagnose nerven (8-fache Blinkzeiten) und beim Entprellen etwas
längere Tastendrücke (80ms statt 10ms Entprellzeit) erforderlich machen.
Wenn RS232 ins Spiel kommt, muss das aber passen.
(##) Bei Gelegenheit solltest du auch mal deine Tastatur mit dem
Multimeter durchmessen, welcher Widerstand bei geöffneter Taste und
welcher bei geschlossener Taste vorhanden ist. Wenn irgendwo nahe 0 Ohm
gemessen werden, würde ich die Tastatur über Serienwiderstände
anschliessen, um aus den AVR Ports nicht zu viel Strom zu saugen.
Vielen Dank Stefan für deine erneute Hilfe, ich werde mir das ganze aber
erst morgen Abend ansehn können. Ich meld mich wieder, wennn ich
Resultate habe. Danke!
Wenn du schon dabei bist, die Tastatur auszumessen, hier vielleicht noch
ein paar Überlegungen zum Anschliessen über Widerstände.
Man kann die Störungszeit der Einleseleitung verkürzen, wenn man sie bei
der Abfrage nicht floaten lässt, sondern sie mit einem
Pulldown-Widerstand auf einem LOW Pegel hält, der durch den Tastendruck
auf HIGH gezogen wird.
Im Anhang ein paar Versuche dazu mit Pulldown-Widerständen von
"Unendlich" (s. vorheriger Anhang) und fallenden Werten von 33 KOhm bis
470 Ohm.
Gemessen wurde die Dauer der Störung auf der COL Leitung, wenn die ROW
Leitung mit Spannung beaufschlagt wird, um den Taster reaktionsfähig zu
machen. Der Taster wurde offen gelassen. Es ist also nicht das
Tastendrücken oder ein eventuelles Prellen dargestellt!
Weniger als 470 Ohm wollte ich nicht austesten, weil es dann schon in
die Richtung max. zulässige Stromabgabe eines Portpins geht, wenn der
Portpin zufällig mal als Ausgabe HIGH arbeitet.
Rechnet man für die Taktrate mit 12 MHz 83 ns für einen AVR Befehl (1
Takt Befehl), würde man die Störung bei 470 Ohm Pulldown im worst-case
Fall (1 Takt zwischen Umschalten und Einlesen) nicht mehr mitbekommen,
selbst wenn das _delay_us weggelassen wird. Bei einem langsameren Takt
könnte der Pulldown grösser werden (8 MHz 125 ns => 1+ KOhm).
Ein Takt zwischen Spannung aufgeben und Ergebnis auslesen sollte man
aber sowieso nicht benutzen (s.
[[AVR-Tutorial:_IO-Grundlagen#Stolperfalle_bei_Matrixtastaturen_etc.]]),
so dass man grössere Pulldowns verwenden kann.
So, ich habe gerade ein paar Tests mit den Delay-Zeiten gefahren und
sehe LED-Blinken am Ende des Tunnels ;-)
Wenn auch noch gestört, aber es kommt etwas an.
Aber nun zu meinen Beobachtungen:
Delay = 10µs:
Beide LEDs leuchten, danach Blinken von D2 mit etwa 4s und D5 leuchtet.
Delay = 100µs:
D2 blinkt mit 4s.
D5 blinkt mit kurzem Abstand
Taste 10 gedrückt gehalten: D5 leuchtet permanent, nach Auslassen blinkt
D5 (nicht immer) weiter.
Abgesteckte Tastatur bei 100µs: D2 blinkt, D5 aus(!)
Delay = 90µs:
D2 blinkt mit 4s.
D5 an
Tastendruck (kurz): D5 blinkt mit kurzem Abstand
erneuter Tastendruck: D5 wieder an
Hier das selbe, steck ich die Tastatur ab, blinkt D2 und D5 ist aus.
Anscheinend registriert der AVR bereits bei angesteckter Tastatur ohne
Tastendruck etwas.
Genauso habe ich beobachtet, dass bei gewisser Position des USBKEYs auf
dem Tisch D5 leuchtet ohne Tastatur.
Da ich diese ewig kleinen Anschlüsse für die Ports mit Zusatzplatinen (
http://www.wizbangdesigns.com/10017_PCB.html ) nach außen geführt habe,
um vernünftige Stecker anschließen zu können, könnte die ein oder andere
Lötstelle nicht sauber sein.
Ich schau mir das morgen mal unterm Mikroskop an und werde dann auch die
Tastatur durchmessen. Heute bin ich leider nicht in Reichweite der
Geräte ;-)
Ist ja schon mal ein Lichtblick, dass ich bei 90µs einen Effekt erzielen
konnte mit Tastendruck.
Hallo Peter!
Ich habe gerade den Code getestet, kann aber durch Drücken der Taste 10
keine Reaktion der LED D5 hervorrufen.
Hab ich etwas übersehen oder muss ich noch andere Codestellen ändern,
außer die obige?
Mein jetziger Code ist im Anhang...
Danke!
Hm, hab mal die Bitnummern auf deinen Code angepasst.
Selbst mit folgendem Code lässt sich bei Drücken der Taste 10 kein
LED-Blinken erzielen... Ich steh wohl gerade wieder mal auf der Leitung
;-)
Andreas R. wrote:
> Hm, hab mal die Bitnummern auf deinen Code angepasst.>> Selbst mit folgendem Code lässt sich bei Drücken der Taste 10 kein> LED-Blinken erzielen...
Blinken muß doch immer was, egal ob gedrückt oder nicht.
Peter
Peter Dannegger wrote:
> Andreas R. wrote:>> Hm, hab mal die Bitnummern auf deinen Code angepasst.>>>> Selbst mit folgendem Code lässt sich bei Drücken der Taste 10 kein>> LED-Blinken erzielen...>> Blinken muß doch immer was, egal ob gedrückt oder nicht.>>>> Peter
Stimmt, hab mich wohl falsch ausgedrückt:
Das Blinken ändert sich mit Tastendruck nicht (kein schnelleres
Blinken).
Und LED5 leuchtet auch bei Tastendruck nicht auf, was ja eigentlich
passieren sollte.
@ Andreas
Messe die Tastatur durch. Das ist mit einem Multimeter, Bleistift,
Papier und Geduld bei einer Tasse Kaffee erledigt. Wir müssen
ausschliessen, dass ein Kurzschluss vorliegt. Mach ein Quadrat,
unterteile es in so viele Spalten und Zeilen, wiel Leitungen vorhanden
sind. Dann messe den widerstand jeder Leitung gegen alle anderen
Leitungen. Das Ganze für keine Taste gedrückt. Wenn du einen grossen
Pott Kaffee hast, dann auch paar Widerstandsmessungen mit gedrückten
Tasten.
> Beide LEDs leuchten, danach Blinken von D2 mit etwa 4s und D5 leuchtet.> ...steck ich die Tastatur ab, blinkt D2 und D5 ist aus.
ist doch extrem verdächtig.
> Das Blinken ändert sich mit Tastendruck nicht (kein schnelleres> Blinken). Und LED5 leuchtet auch bei Tastendruck nicht auf, was ja> eigentlich passieren sollte.
Wenn du den neuen Code von Peter 1:1 übernommen hast, kann D5 nicht mehr
leuchten, wenn eine beliebige Taste gedrückt wird. Es fehlt der DIAGNOSE
Teil in key_scan.
Stefan "stefb" B. wrote:
> @ Andreas>> Messe die Tastatur durch. Das ist mit einem Multimeter, Bleistift,> Papier und Geduld bei einer Tasse Kaffee erledigt. Wir müssen> ausschliessen, dass ein Kurzschluss vorliegt.
Werd ich jetzt auch machen, nachdem ich die Lötstellen kontrolliert habe
und mir noch schnell einen Kaffee machen werde ;-)
>> Beide LEDs leuchten, danach Blinken von D2 mit etwa 4s und D5 leuchtet.>> ...steck ich die Tastatur ab, blinkt D2 und D5 ist aus.>> ist doch extrem verdächtig.>>> Das Blinken ändert sich mit Tastendruck nicht (kein schnelleres>> Blinken). Und LED5 leuchtet auch bei Tastendruck nicht auf, was ja>> eigentlich passieren sollte.>> Wenn du den neuen Code von Peter 1:1 übernommen hast, kann D5 nicht mehr> leuchten, wenn eine beliebige Taste gedrückt wird. Es fehlt der DIAGNOSE> Teil in key_scan.
Aber schneller blinken müsste die LED trotzdem, wenn der Code
funktionieren würde oder?
Also, hab gerade die Tastatur durchgemessen:
Kein Kurzschluss bei offenem Taster/Button.
Hier mal die Widerstandswerte bei geschlossenem Taster:
Tastennr: Widerstand [Ohm]:
1 1,6
2 1,7
3 1,0
4 1,5
5 0,9
6 1,5
7 0,7
8 1,4
9 1,0
10 1,1
Das ganze habe ich direkt an der Anschlussfahne gemessen, ohne das
Flachbandkabel, das zum Controller führt.
Andreas R. wrote:
> Aber schneller blinken müsste die LED trotzdem, wenn der Code> funktionieren würde oder?
Nur wenn die Taktrate stimmt. Ich hatte ja schon mal Zweifel angemeldet.
Das schnelle 0.5s-AN/0,5s-AUS Blinken bei 8 Mhz gäbe ein langsames
4s-AN/4s-AUS Blinken bei 1 MHz. Das langsame 2s-AN/2s-AUS Blinken bei 8
Mhz gäbe ein schnarchlangsames 16s-AN/16s-AUS Blinken bei 1 MHz. Mit
einer Angabe zu den Fuses-Einstellungen (Screenshot o.ä.) könnte man
überprüfen, auf welche Taktquelle dein AVR eingestellt ist.
Eine Unsicherheit liegt ausserdem bei deiner Toolchain. Da weiss ich
noch nicht, was du verwendest. Erkl.: Die langen Delay-Zeiten 500ms und
2000ms und deren Exaktheit sind davon abhängig, dass eine avr-libc ab
Version 1.6 verwendet wird, F_CPU und Fuses zur Taktquelle passen sowie
mit -Os übersetzt wurde. Die Version ab 1.6 ist ab dem WinAVR vom
letzten Dezember vorhanden. Wenn du ein #lteres WinAVR hast, musst du
kleiner Delays (z.B. 25ms) entsprechend oft ausführen (Schleife).
Sorry, dass ich da ohne Nachdenken von meiner Version (WinAVR Dez. 2007)
ausgegangen bin und meine selbstverständliche Benutzung der
Delayfunktion und deren Voraussetzungen dir als µC-Neuling nicht näher
beschrieben habe.
Stefan "stefb" B. wrote:
> Andreas R. wrote:>>> Aber schneller blinken müsste die LED trotzdem, wenn der Code>> funktionieren würde oder?>> Nur wenn die Taktrate stimmt. Ich hatte ja schon mal Zweifel angemeldet.> Das schnelle 0.5s-AN/0,5s-AUS Blinken bei 8 Mhz gäbe ein langsames> 4s-AN/4s-AUS Blinken bei 1 MHz. Das langsame 2s-AN/2s-AUS Blinken bei 8> Mhz gäbe ein schnarchlangsames 16s-AN/16s-AUS Blinken bei 1 MHz. Mit> einer Angabe zu den Fuses-Einstellungen (Screenshot o.ä.) könnte man> überprüfen, auf welche Taktquelle dein AVR eingestellt ist.
Hm, stimmt, habe ich schon mal irgendwo gelesen, dass beim AT90USB1287
das Fusebit für den Takt oft falsch gesetzt wurde "ab Werk".
Da ich unter Linux arbeite, muss ich allerdings erstmal nachsehn, wie
ich die Fuses auslesen kann. Zum Programmieren benutz ich den
dfu-programmer, weil der über USB recht gut funktioniert. Aber ich
glaube, der kann die Fuses nicht auslesen...
> Eine Unsicherheit liegt ausserdem bei deiner Toolchain. Da weiss ich> noch nicht, was du verwendest. Erkl.: Die langen Delay-Zeiten 500ms und> 2000ms und deren Exaktheit sind davon abhängig, dass eine avr-libc ab> Version 1.6 verwendet wird, F_CPU und Fuses zur Taktquelle passen sowie> mit -Os übersetzt wurde. Die Version ab 1.6 ist ab dem WinAVR vom> letzten Dezember vorhanden. Wenn du ein #lteres WinAVR hast, musst du> kleiner Delays (z.B. 25ms) entsprechend oft ausführen (Schleife).>> Sorry, dass ich da ohne Nachdenken von meiner Version (WinAVR Dez. 2007)> ausgegangen bin und meine selbstverständliche Benutzung der> Delayfunktion und deren Voraussetzungen dir als µC-Neuling nicht näher> beschrieben habe.
Kein Problem, das mit der Delayfunktion habe ich schon verstanden und
die arg abweichenden Zeiten kamen wir auch spanisch vor. Da ich aber,
wie gesagt, unter Linux arbeite, kann ich kein WinAVR anbieten, nur die
Versionen von avr-gcc und avr-libc ;-)
avr-gcc: Version 4.2.2
avr-libc: 1.6.1
Wenn Fuses-Auslesen nicht so einfach geht, dann programmiere dir ein 1s
Blinken vor der For-Schleife. Wenn dein AVR dann keinen 60er Ruhepuls
hat, ist er krank ;-)
1
// DIAGNOSE
2
DDRD|=(1<<PD5)|(1<<PD6);
3
// Puls fühlen: 10 s lang mit 1 Hz Blinken
4
{
5
inti=20;// 10 AN Phasen + 10 AUS Phasen zu je 500 ms
So jetzt hab ich mit Hilfe eines schnell aufgetriebenen AVR Dragon
herausgefunden, dass der interne Teiler durch 8 eingestellt war.
Jedenfalls ist der nun weg und mein AVR lässt die LED jetzt im
Sekundentakt blinken! Na endlich...
Wobei ich nach wie vor per Tastendruck und Peters Code die LED nicht zum
schnelleren Blinken bewegen kann.
> Wobei ich nach wie vor per Tastendruck und Peters Code die LED nicht zum> schnelleren Blinken bewegen kann.
Schneller? Du kannst das Binken nur verlangsamen...
Angenommen Von dir wird nie eine Taste gedrückt. Bei #1 (for 1. if) ist
taste = 0. Es gab ein 0,5s AN/0,5s AUS Blinken (30x LED an in einer
Minute), d.h. die Taktrate des AVRs stimmt jetzt.
1/ Wenn #2 (1. if) nie einen Tastendruck erkennt/erhält, bleibt taste
0. d.h. #4 (else vom 2. if) wird ausgeführt. d.h. das Blinken wechselt
in der for-schleife zu 2s AN/2s AUS. 15x LED an in einer Minute. Das
wäre korrekt, wenn du keine Taste drückst.
2/ Wenn #2 immer fehlerhaft einen nicht gegebenen Tastendruck erkennt,
toggelt die Variable taste durch das if, d.h. wechselweise wird #3
(statement im 2. if) und #4 ausgeführt. d.h. 0,5s AN/2s AUS Blinken. In
1 Minute. In einer Minute: 24x LED an.
3/ Wenn sich wie von dir beschrieben das Blinken aus #1 nicht ändert und
bei 0,5/0,5 bleibt (30x an in 1 Minute) Wird die for schleife nicht bis
zur if-Abfrage ausgeführt.
Nicht ausgeführt kann eigentlich nur heissen, der AVR geht in den RESET
und fängt immer von vorne an. Ein Indiz wäre auch, wenn es eine
Gedenkpause alle 10 Blinker gibt.
So ein RESET könnte von einer absackenden Spannung und dem ansprechen
der Brownouterkennung kommen (wie steht die Brownout-Fuse?). Das Wäre
mir aber ein Ratsel, denn Peters neuer Code mit den internen Pullups
sollte hier robust genug sein sein, um da nichts anbrennen zu lassen.
Robuster jedenfalls als die allererste, direkte Verbindung ROW/COL ohne
nennenswerte Serienwiderstände.
Bist du schon weiter mit der Inspektion der Anschlüsse? Keine
Kurzschlüsse zwischen den Portpins?
Ich bin auch mal in die Beschreibung des Boards rein - PORTB wird für
verschiedene On board Bauelemente benutzt (Joystick, Dataflash Memory)
und ich sehe im Schaltplan nicht, dass man die deaktivieren kann. Ich
würde es mal auf einem anderen, freien Port (C oder F) probieren.
http://www.atmel.com/dyn/resources/prod_documents/doc7627.pdf
Stefan "stefb" B. wrote:
>> Wobei ich nach wie vor per Tastendruck und Peters Code die LED nicht zum>> schnelleren Blinken bewegen kann.>> Schneller? Du kannst das Binken nur verlangsamen...>> Angenommen Von dir wird nie eine Taste gedrückt. Bei #1 (for 1. if) ist> taste = 0. Es gab ein 0,5s AN/0,5s AUS Blinken (30x LED an in einer> Minute), d.h. die Taktrate des AVRs stimmt jetzt.>> 1/ Wenn #2 (1. if) nie einen Tastendruck erkennt/erhält, bleibt taste> 0. d.h. #4 (else vom 2. if) wird ausgeführt. d.h. das Blinken wechselt> in der for-schleife zu 2s AN/2s AUS. 15x LED an in einer Minute. Das> wäre korrekt, wenn du keine Taste drückst.>> 2/ Wenn #2 immer fehlerhaft einen nicht gegebenen Tastendruck erkennt,> toggelt die Variable taste durch das if, d.h. wechselweise wird #3> (statement im 2. if) und #4 ausgeführt. d.h. 0,5s AN/2s AUS Blinken. In> 1 Minute. In einer Minute: 24x LED an.>> 3/ Wenn sich wie von dir beschrieben das Blinken aus #1 nicht ändert und> bei 0,5/0,5 bleibt (30x an in 1 Minute) Wird die for schleife nicht bis> zur if-Abfrage ausgeführt.>> Nicht ausgeführt kann eigentlich nur heissen, der AVR geht in den RESET> und fängt immer von vorne an. Ein Indiz wäre auch, wenn es eine> Gedenkpause alle 10 Blinker gibt.
Eine solche "Gedenkpause" kann ich nicht erkennen, allerdings blinkt die
LED bei Entfernen des 0,5s Blink-Codes sehr schnell, kaum sichtbar,
anscheinend hervorgerufen, durch die Bicolor-LED, die länger an sein
muss um wirklich "hell" zu sein.
> So ein RESET könnte von einer absackenden Spannung und dem ansprechen> der Brownouterkennung kommen (wie steht die Brownout-Fuse?). Das Wäre> mir aber ein Ratsel, denn Peters neuer Code mit den internen Pullups> sollte hier robust genug sein sein, um da nichts anbrennen zu lassen.> Robuster jedenfalls als die allererste, direkte Verbindung ROW/COL ohne> nennenswerte Serienwiderstände.
Brownout-Fuse kann ich erst wieder nachsehn, wenn ich den Dragon hab,
das kann noch ein bißchen dauern.
Wobei ich die ersten Tests jetzt ohne Tastatur gemacht hab um eine
Veränderung rein durchs anstecken erkennbar zu machen.
> Bist du schon weiter mit der Inspektion der Anschlüsse? Keine> Kurzschlüsse zwischen den Portpins?
Nicht, dass ich etwas erkennen könnte unterm Mikroskop. Hab sogar manche
Lötstellen neu gemacht. Genauso wie der Übergang von der Fahne der
Tastatur auf einen 10 Pin Steckanschluss... Nichts zu finden...
> Ich bin auch mal in die Beschreibung des Boards rein - PORTB wird für> verschiedene On board Bauelemente benutzt (Joystick, Dataflash Memory)> und ich sehe im Schaltplan nicht, dass man die deaktivieren kann. Ich> würde es mal auf einem anderen, freien Port (C oder F) probieren.>> http://www.atmel.com/dyn/resources/prod_documents/doc7627.pdf
Das ist mir auch schon in den Sinn gekommen, werde das mal als nächstes
Versuchen und einen der freien Ports benutzen.
Also selbst nach Entfernen des "Pulsblinkens" blinkt die LED im 1s-Takt
weiter...
Tastendruck egal, selbst bei einem anderen Port (PortF).
Ich finde es schon etwas sonderlich, denn heute Nachmittag konnte ich
deutlich beobachten, wie der AVR nach den 10 Phasen des "Pulsblinken"
auf das 2s Blinken gewechselt ist.
Nach dem Umstellen des 8-Teilers bin ich mir nicht sicher, ob ich dann
das Wechseln noch gesehen habe, aber ich bilde es mir ein. Erst seit den
letzten Versuchen geht er nicht mehr auf das 2s Blinken...
Nachtrag: Schön langsam wirds gruslig.
Ich hab den angehängten Code ausgeführt und die LED blinkt sehr schnell,
also wahrscheinlich mit 0.5s nach einem Reset.
Dann hab ich den KEY abgesteckt vom USB und wieder an und die LED blinkt
langsam.
Tastendruck bewirkt nichts...
Peter Dannegger wrote:
> Gib Dir dochmal key_state über die UART aus.>> Debuggen nur mit LEDs ist etwas mühselig.>>>> Peter
Geht so einfach nicht, der AT90USBKEY hat nur USB-Anschluss und mein
Laptop keinen seriellen Anschluss mehr...
Oder gibts noch andere Möglichkeiten?
Andreas R. wrote:
> Geht so einfach nicht, der AT90USBKEY hat nur USB-Anschluss und mein> Laptop keinen seriellen Anschluss mehr...
Dann mal prüfen, ob das USB nicht nur ne getunnelte UART ist.
Oder nen USB-RS232 Umsetzer kaufen (~10,-€).
Peter
Naja der USB ist ein echter USB, weil der Controller AT90USB1287 einen
eigenen USB-Controller onboard hat, mit sämtlichen USB-Funktionen, wie
HID etc. Allerdings sind diese Funktionen in meinem USB-Library, das ich
eigentlich erst in einem weiteren Schritt einbinden will.
Hintergrund ist es, dass die Tastatur als HID-Tastatur an den Rechner
angeschlossen werden soll um eben Funktionen wie F1 etc zu
ermöglichen...
Da wird für den TIMER0 berechnet, wo der Hardwarezähler anfangen soll
pro Takt ein Einerschritten zu zählen. Der 8-Bit Timer0 löst dann beim
255 + 1 = 0 Überlaufen den Interrupt aus.
Hier soll mit dem eingestellten Prescaler 1024 (=> TCCR0B) und der
verwendeten Taktrate (=> F_CPU bzw. XTAL) ungefähr 10ms zwischen den
Interrupts vergehen. Ungefähr, weil 8000000 1024 100 keine ganze
Zahl ergeben.
8000000/1024/100 = 78,125 Takte genau
8000000 Hz/1024 Prescaler = 0,128ms pro Takt
0,128ms * 78 ganzzahlige Takte = 9,984ms
Die Initialisierung von TIMER0 für den normal mode (in Peters Code ist
ein manueller RELOAD von TCNT0 enthalten, d.h. normal mode) müsste laut
Datenblattstudium so aussehen:
TCCR0A = 0; // optional
TCCR0B = (1<<CS02) | (1<<CS00); // Prescaler 1024
TCNT0 = (u16)(256 - XTAL 1024 100); // Startwert
TIMSK0 = (1<<TOIE0); // Timer0 Overflow enable
TIFR0 |= (1<<TOV0); // optional
Das entspricht dem Code oben.
Den Vorschlag von Peter mit dem serielle Debuganschluss würde ich an
deiner Stelle unbedingt aufgreifen. Hardwareseitig hast du an PORTD die
RX/TX Pins dafür frei und kannst die USART unabhängig vom USB Anschluss
benutzen.
Du brauchst nur einen 3,3V fähigen TTL-RS232 Pegelwandler und einen
RS232-USB Konverter. Unter Windows hätte ich ein günstiges USB-RS232
Handydatenkabel mit gängigem Chipsatz dafür geschlachtet und hätte dann
beides zusammen. Linux muss ich schauen, ob es RS232-USB Konverter gibt
und ob vielleicht das Datenkabel aus meiner Grabbelkiste funktioniert.
Welches Linux hast du?
Spätestens wenn es an die USB Codeteile geht, wirst du dem Herrn auf
Knien für das unabhängige Terminal danken!
> Welches Linux hast du?>
Kubuntu Linux 7.10
Aber normalerweise sollte das auch unter Linux hinhaun. Wenn ich ein CDC
auf dem Controller laufen lasse, also quasi einen virtuellen Com-Port
über USB, dann kann ich über /dev/ttyACM0 Daten auslesen per cat
/dev/ttyACM0...
Stefan "stefb" B. wrote:
> UART Teil im AVR-GCC-Tutorial lesen und die erste Antwort in der> FAQ ;-)
Alles klar, danke.
Die nötige Hardware besorg ich mir die Tage...
Ich habe gerade wieder ein bisschen "gespielt" und die Diagnosefunktion
des Tastendruck in den Code wieder aufgenommen:
1
if(keys)
2
PORTD|=(1<<PD6);
3
else
4
PORTD&=~(1<<PD6);
Dabei leutet D5 konstant, als würde ein Tastendruck registriert werden
(ohne angesteckte Tastatur).
D2 blinkt dabei allerdings im 2 Sekundentakt.
Der gesamte Code ist im Anhang...
Ein weiterer Diagnoseversuch mit dem Code für key_state auf D5 mit rotem
Blinken ergab, dass sowohl D2 (grün), als auch D5 (rot) im Sekundentakt
blinken.
Allerdings ist das Blinken von der Lichtstärke her relativ schwach
(woran liegt das??).
1
if(1<<key_state)
2
{
3
PORTD^=(1<<PD7);// 0.5s Blinken ROT
4
_delay_ms(500);
5
}
Der gesamte Code ist wieder im Anhang (der Kommentar zum Blinken der
roten LED ist dort leider falsch ;-) ).
Anscheinend wird wiederum ein Tastendruck ohne angesteckter Tastatur
registriert, denn das key_state Bit ist anscheinend 1.
Oder liege ich mit meiner Schlussfolgerung falsch?
> if(1<<key_state)
Diese Diagnose ergibt für mich keinen Sinn. key_state ist eine Bitmaske
und diese Bedingung ist immer irgendwie wahr.
Ich komme zum letzten Mal auf den Hardwareanschluss zurück. Denn ich
weiss immer noch nicht genau, wie die Schaltung aussieht.
Bei der Widerstandsmessung hast du den Teil zwischen Tastatur und AVR
ausgelassen und bist auch nicht auf die angefragte Matrix mit den
Leitungen eingegangen, sondern hast die Werte auf die Tasten bezogen.
Aber das Programm fragt nur indirekt Tasten ab, direkt fragt es Pegel
auf Leitungen ab, die zuvor auf anderen Leitungen angelegt wurden.
Zu den Leitungen vom Flachbandkabel habe ich nur Infos, welche Leitung
an welchem Pin vom AVR hängt (damals beim PORTB).
Wie die Leitungsnummer mit der Taste zusammenhängt - grosses
Fragezeichen. Da gibt es nur die Definition der Makros im Programm. Und
die muss ja nicht mit der Hardware am anderen Ende des Kabels
zusammenpassen.
Man sollte endlich sicherstellen, dass die richtigen Leitungen abgefragt
werden.
Wie messen? Ohmmeter zwischen Leitung A und Leitung B und eintragen, bei
welcher Taste ein geringer widerstand messbar ist. Es sollte etwas in
der Art rauskommen (10 = 0). An dem Ende messen, das später an den AVR
kommt, nicht direkt an der Tastatur, denn das Kabel ist ja verändert.
A
-------------------------------------
1 2 3 4 5 6 7 8 9 0
|1 - T1 T2 T3...
|2 T1 - oo...
|3 T2 öö -
|4
|5
B |6
|7
|8
|9
|0
- Messung nicht möglich, 2x gleiche Leitungsnummer
oo Widerstand immer unendlich, keine Reaktion auf Tastendrücken
In obigen Bild wäre die Leitung 1 COL und 2,3,4 ROW Leitungen.
> Bei der Widerstandsmessung hast du den Teil zwischen Tastatur und AVR> ausgelassen und bist auch nicht auf die angefragte Matrix mit den> Leitungen eingegangen, sondern hast die Werte auf die Tasten bezogen.
OK, ich habe zwar den Teil zwischen Tastatur und AVR ausgelassen, ihn
aber bereits vorher schon einmal auf Kurzschlüsse geprüft.
Ich verstehe nicht ganz, was du damit meinst, dass ich nicht auf die
angefragte Matrix eingegangen bin.
> Aber das Programm fragt nur indirekt Tasten ab, direkt fragt es Pegel> auf Leitungen ab, die zuvor auf anderen Leitungen angelegt wurden.>> Zu den Leitungen vom Flachbandkabel habe ich nur Infos, welche Leitung> an welchem Pin vom AVR hängt (damals beim PORTB).>> Wie die Leitungsnummer mit der Taste zusammenhängt - grosses> Fragezeichen.
Wieso? Das habe ich doch durchgemessen und auch in der einen Grafik
mitgeteilt. Drückt man Taste 1, schließt man die Verbindung von Pin1 und
Pin4 des Flachbandkabels und damit entsprechend am AVR die Pins.
Deswegen habe ich auch die nur immer die entpsrechenden Widerstandswerte
der Pins für eine bestimmte Taste angegeben, weil bei allen anderen
Messpunkten der Widerstand erwartungsgemäß undendlich war.
Tastatur messen schön und recht, aber wenn der Diagnose Code die LED nur
auf grün schalten soll, wenn er einen Tastendruck registriert, die
Tastatur aber gar nicht angeschlossen ist, dann liegt es wohl auch in
diesem Fall weniger an der Tastatur.
> Man sollte endlich sicherstellen, dass die richtigen Leitungen abgefragt> werden.>> Wie messen? Ohmmeter zwischen Leitung A und Leitung B und eintragen, bei> welcher Taste ein geringer widerstand messbar ist. Es sollte etwas in> der Art rauskommen (10 = 0). An dem Ende messen, das später an den AVR> kommt, nicht direkt an der Tastatur, denn das Kabel ist ja verändert.>> A> -------------------------------------> 1 2 3 4 5 6 7 8 9 0> |1 - T1 T2 T3...> |2 T1 - oo...> |3 T2 öö -> |4> |5> B |6> |7> |8> |9> |0>> - Messung nicht möglich, 2x gleiche Leitungsnummer> oo Widerstand immer unendlich, keine Reaktion auf Tastendrücken>> In obigen Bild wäre die Leitung 1 COL und 2,3,4 ROW Leitungen.
Dass die Grafik
(http://www.mikrocontroller.net/attachment/34178/tasten.jpg) schon ein
durchgemessenes Ergebnis war, habe ich nicht gewusst. Sorry.
Ich schlage folgende Änderungen vor:
1/ Einlesen über eine Maske. Nur die als Eingang geschalteten ROW-Pins
dürfen in keys gelangen.
2/ Casten des eingelesenen Wertes auf u16 vor der Schieberei
3/ Schieben an die bestimmte Bitpositionen (s. Kommentare)
4/ Einlesen beider Spalten in einem Aufruf von key_scan und
nicht in zwei getrennten Aufrufen.
5/ Umdrehen der Logik im Diagnosecode (~keys) und maskieren der Bits
10..1 für die Tasten 1..10. Beseitigt Dauerleuchten ohne Tastatur.
Peters Code arbeitet mit Pullups, d.h. Ruhezustand HIGH an Pins
und nicht wie angenommen mit Ruhezustand LOW an den Pins.
Vielen Dank für deine Antwort Stefan, ich werde es später versuchen.
Hab übrigens die Tastatur heute nochmal stichprobenweise duchrgemessen,
um wirklich sicher zu gehen, dass bei Tastendruck auch die richtigen
Pins geschalten werden am AVR.
Ergebnis war, dass die Tastatur richtig angeschlossen ist und der
Gesamtwiderstand z.B. bei Taste 1 nur unwesentlich höher ist, als direkt
an der Tastatur (0,1 Ohm höher, wenn überhaupt ein Unterschied
feststellbar war).
So, hab mal den neuen Code eingefügt und getestet.
Bei Tastendruck leuchtet die LED D5 jetzt auf. Das funktioniert bei
jeder Taste :-)
Jedoch blinkt die LED D2 weiterhin im Sekundentakt.
Habe für Taste 1 das Bit 1 zum Test in die if Schleife eingefügt:
1
for(;;)
2
{
3
if(get_key_press(1<<1))// "Taste 10" merken
4
taste^=(1<<1);
5
6
// DIAGNOSE
7
if((taste&(1<<1)))
8
{
9
PORTD^=(1<<PD5);// 0.5s Blinken
10
_delay_ms(500);
11
}
12
else
13
{
14
PORTD^=(1<<PD5);// 2s Blinken
15
_delay_ms(2000);
16
}
Anscheinend stimmt mit dem get_key_press noch irgendwas nicht.
Ich bin dir echt dankbar für deine Hilfe und hoffe, dass wir "den Rest"
auch noch hinbekommen, dass die LED D2 nur im Sekundentakt blinkt, wenn
eine bestimmte Taste betätigt wird.
Ich bin mit meinem Latein fast am Ende ;-(
Auf meiner Ersatz-Hardware funktioniert nämlich alles perfekt. Ich kann
dir jetzt noch zwei Sachen anbieten:
Meinen Testsourcecode mit eingebautem UART-Debugging (Anhang). Du
brauchst für den optionalen UART-Teil wie gesagt eine Zusatzhardware
(TTL (=> RS232) => USB). Die geringen Anpassarbeiten ATmega8 =>
AT90USB1287 sind im Code beschrieben.
Und ich kann dein automatisch erzeugtes Assemblerlistung (Datei mit
Endung .lss) kontrollieren, ob ein Übersetzungsproblem vorliegt. Aber
dynamische Hardwareprobleme zur Laufzeit finde ich so nicht. Wenn du so
eine LSS Datei nicht hast, muss man das Makefile anpassen, damit diese
Datei erzeugt wird.
Danke, ich schau mir deinen Code mal an nachher.
Ich hab mal meine Makefile und die keymatrix.lss in einem Zip-Archiv in
den Anhang getan.
Die Grundlage für die makefile ist die, die im MyUSB Library enthalten
ist, ich hab die damals angepasst.
Die erzeugte keymatrix.elf wandle ich dann immer in eine *.a90 um:
avr-objcopy -R .eeprom -O ihex keymatrix.elf keymatrix.a90
Vielleicht liegt darin der Fehler?
Lass mal diese Zeile in main drin:
DDRD |= (1<<PD5) | (1<<PD6);
Im Moment fehlt diese Zeile, weil du sie mit dem "Pulsschlag"
auskommentiert hast. Dadurch arbeiten die D2 und D5 an dem als EINGANG
geschalteten Port D. Dass die LEDs überhaupt leuchten, ist nur der
Tatsache zu verdanken, dass die internen Pullups manipuliert werden. Das
Leuchten an sich müsste ziemlich schwach sein, weil über die Pullups nur
~0,1mA Strom kommen! Hier auf meiner Hardware mit fetten 20mA LEDs statt
Low-Current-LEDs sehe ich nur im ganz dunklen Raum ein Glimmen!
Sonst ist im LSS nichts Auffälliges. An dem a90 Format hängt es bestimmt
auch nicht, denn du kannst ja alle bisherigen Source Änderungen in den
AVR rein programmieren.
Mache ich gleich mal...
An der Makefile an sich kann es nicht liegen?
Könntest du mal mit entsprechendem mcu=at90usb1287 die keymatrix.c von
mir kompilieren und eine hex oder a90 erzeugen?
Vielleicht liegts ja doch an meiner Toolchain bzw. der Makefile...
So, hab mal die Zeile für die LEDs wieder reingemacht.
Jetzt blinken/leuchten die LEDs wieder heller ;-)
Eine Auffälligkeit stelle ich übrigens fest:
Flashe ich den frischen kompilierten Code und drücke die RESET-Taste am
USBKEY, dann blinkt D2 im Sekundentakt, also wie wenn ein Tastendruck
der Taste 1 festgestellt werden würde.
Erst nach Trennen und wieder Anschließen des USBKEYS an die
Spannungsversorgung (über USB) blinkt die LED D2 im 2-Sekundentakt.
Bei Drücken der Taste 1 (Taste +) leuchtet zwar D5, aber die
Blinkgeschwindigkeit von D5 ändert sich nicht :-(
Habe gerade eine andere Makefile benutzt.
Als Vorlage diente die Makefile von Herrn Salewski, der sich ebenfalls
mit dem AT90USB1287 beschäftigt und seine Daten auf seiner Homepage
veröffentlicht.
Ich habe diese Makefile an meine keymatrix.c angepasst:
http://www.ssalewski.de/USB-Sources/Makefile
Danach mit make all kompiliert.
Bei diesem Vorgang erhalte ich eine Warnung:
keymatrix.c: In function 'main':
keymatrix.c:92: warning: 'taste' may be used uninitialized in this
function
Nochmal ein RIIIESEN Dankeschön für deine äußerst geduldige Hilfe!
Jetzt gehts erst mal weiter aus dem Tastendruck ein vernünftiges
Resultat am PC hervorzurufen ;-)
Voraussichtlich werde ich mich sicher wieder melden müssen ;-)
Und plötzlich platzt der Knoten. Glückwunsch zu einem funktionierenden
System! Das war ja eine lange Sitzung. Ich bin auch sehr froh, dass es
jetzt klappt.
Andreas R. wrote:
> Ich glaubs nicht!! ES GEHT!>> Ich habe>>
1
>u16taste;
2
>
>> auf>>
1
>u16taste=0;
2
>
Ja, so ist das eben, wenn man die Warnungen des Compilers in den Wind
schlägt:
C_TAST.C:102: warning: 'taste' may be used uninitialized in this
function
Peter