Forum: Compiler & IDEs 2x5 Tastenmatrix an AT90USB1287


von Andreas R. (imrazor)


Angehängte Dateien:

Lesenswert?

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!

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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);

von Andreas R. (imrazor)


Lesenswert?

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..

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Halb.
1
#define KEY_PIN   PINB      // B1..0 = inputs
2
#define KEY_PORT  PORTB
3
#define KEY_DDR   DDRB
4
#define KEY_ROW0  PORTB2    // B6..2 = outputs
5
#define KEY_ROW1  PORTB3
6
#define KEY_ROW2  PORTB4
7
#define KEY_ROW3  PORTB5
8
#define KEY_ROW4  PORTB6

Sieht gut aus. Sehr gut sähe es aus, wenn KEY_COL0 und KEY_COL1 auch 
definiert wären ;-)
1
static inline
2
u16 key_scan( void )
3
{
4
  u16 keys = 0;
5
  u8 i;
6
7
  KEY_DDR = 1<<KEY_ROW0;  
8
  for( i = 5; i; i-- ){
9
    keys = (keys << 4) | (KEY_PIN & 0x0F);
10
    KEY_DDR <<= 1;
11
  }
12
  return ~keys;
13
}

Passt nicht. Das ist für eine 4x4 Matrix.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

>   // 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);

von Andreas R. (imrazor)


Lesenswert?

Stefan "stefb" B. wrote:
> Halb.
>
>
1
> 
2
> #define KEY_PIN   PINB      // B1..0 = inputs
3
> #define KEY_PORT  PORTB
4
> #define KEY_DDR   DDRB
5
> #define KEY_ROW0  PORTB2    // B6..2 = outputs
6
> #define KEY_ROW1  PORTB3
7
> #define KEY_ROW2  PORTB4
8
> #define KEY_ROW3  PORTB5
9
> #define KEY_ROW4  PORTB6
10
> 
11
>
>
> 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
> static inline
3
> u16 key_scan( void )
4
> {
5
>   u16 keys = 0;
6
>   u8 i;
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?
1
  PORTA = 0xFF;
2
  DDRA = 0xFF;
3
  DDRD |= (1<<PD5);
4
  for(;;){
5
    if( get_key_press( 1<<8 ))    // "1"
6
      PORTD |= (1<<PD5);//  toggle
7
    if( get_key_press( 1<<4 ))    // "2"
8
      PORTA ^= 1<<1;

von Andreas R. (imrazor)


Lesenswert?

Ach ja, das Ding war ursprünglich für ne 3x4 Matrix und nicht für ne 4x4 
fällt mir gerade ein...

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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
1
static inline
2
u16 key_scan( void )
3
{
4
  u16 keys = 0;
5
  u8 i;
6
7
  KEY_DDR = (1<<KEY_ROW4);
8
  for( i = 5; i; i-- )
9
  {
10
    keys <<= 2;
11
    keys |= ((KEY_PIN & (1<<KEY_COL1))<<2) | ((KEY_PIN & (1<<KEY_COL0))<<1);
12
    KEY_DDR >>= 1;
13
  }
14
  return ~keys;
15
}

von Andreas R. (imrazor)


Lesenswert?

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:
1
  PORTA = 0xFF;
2
  DDRA = 0xFF;
3
  DDRD |= (1<<PD5);
4
  for(;;){
5
    if( get_key_press( 1<<8 ))
6
      PORTD |= (1<<PD5)

von Andreas R. (imrazor)


Angehängte Dateien:

Lesenswert?

Also natürlich mit dem Code für Taste 1:
1
  PORTA = 0xFF;
2
  DDRA = 0xFF;
3
  DDRD |= (1<<PD5);
4
  for(;;){
5
    if( get_key_press( 1<<0 ))
6
      PORTD |= (1<<PD5)

Hab mal den kompletten neuen Code angehängt mit COL Definition etc. pp.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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.

von Andreas R. (imrazor)


Lesenswert?

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!

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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
typedef unsigned char  u8;
7
typedef unsigned short u16;
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
static inline
24
u16 key_scan( void )
25
{
26
  u16 keys = 0;
27
  u8 i;
28
  u8 old_ddr = KEY_DDR;
29
  u8 old_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
u16 key_state;        // debounced key state:
56
                      // bit = 1: key pressed
57
u16 key_press;        // key press detect
58
59
60
ISR(TIMER0_OVF_vect )
61
{
62
  static u16 ct0, ct1;
63
  u16 i;
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
u16 get_key_press( u16 key_mask )
77
{
78
  cli();
79
  key_mask &= key_press;    // read key(s)
80
  key_press ^= key_mask;    // clear key(s)
81
  sei();
82
  return key_mask;
83
}
84
85
86
int main( 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?

von Andreas R. (imrazor)


Angehängte Dateien:

Lesenswert?

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.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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 LED low-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 ;-)

von Andreas R. (imrazor)


Lesenswert?

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 ;-)

von Andreas R. (imrazor)


Lesenswert?

Ich will ja nicht quängeln, aber bist du schon dazu gekommen, dir den 
Code nochmal anzusehn?

Danke!

von Stefan B. (stefan) Benutzerseite


Angehängte Dateien:

Lesenswert?

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
int main( void )
5
{
6
  u16 taste;
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?

von spycrasher (Gast)


Lesenswert?

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

von Andreas R. (imrazor)


Angehängte Dateien:

Lesenswert?

> 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
typedef unsigned char  u8;
10
typedef unsigned short u16;
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
static inline
27
u16 key_scan( void )
28
{
29
  u16 keys = 0;
30
  u8 i;
31
  u8 old_ddr = KEY_DDR;
32
  u8 old_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
u16 key_state;        // debounced key state:
59
                      // bit = 1: key pressed
60
u16 key_press;        // key press detect
61
62
63
ISR(TIMER0_OVF_vect )
64
{
65
  static u16 ct0, ct1;
66
  u16 i;
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
u16 get_key_press( u16 key_mask )
80
{
81
  cli();
82
  key_mask &= key_press;    // read key(s)
83
  key_press ^= key_mask;    // clear key(s)
84
  sei();
85
  return key_mask;
86
}
87
88
89
int main( void )
90
{
91
  u16 taste;
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...

von Andreas R. (imrazor)


Lesenswert?

Ich meinte natürlich mit Taste 10 die F1 Taste und nicht F5...
Und vorsorglich hab ich alle mal gedrückt, ohne Effekt ;-)

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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.
1
// Testboard: Pollin Funk-AVR-Evaluationsboard v1.1, 12 MHz, ATmega 8)  
2
//            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
typedef unsigned char  u8;
16
typedef unsigned short u16;
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
static inline
40
u16 key_scan( void )
41
{
42
  u16 keys = 0;
43
  u8 i;
44
  u8 old_ddr = KEY_DDR;
45
  u8 old_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
u16 key_state;        // debounced key state:
89
                      // bit = 1: key pressed
90
u16 key_press;        // key press detect
91
92
93
ISR(TIMER0_OVF_vect )
94
{
95
  static u16 ct0, ct1;
96
  u16 i;
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
u16 get_key_press( u16 key_mask )
110
{
111
  cli();
112
  key_mask &= key_press;    // read key(s)
113
  key_press ^= key_mask;    // clear key(s)
114
  sei();
115
  return key_mask;
116
}
117
118
119
int main( void )
120
{
121
  u16 taste;
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.

von Stefan B. (stefan) Benutzerseite


Angehängte Dateien:

Lesenswert?

Nachtrag: Bild vom Übersprechen

von Andreas R. (imrazor)


Lesenswert?

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!

von Stefan B. (stefan) Benutzerseite


Angehängte Dateien:

Lesenswert?

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.

von Andreas R. (imrazor)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

Warum so komplizier?

Nimm die Spalten als Ausgänge, spart nen Haufen Arbeit.
1
u16 key_scan( void )
2
{
3
  u16 keys = 0;
4
5
  KEY_PORT = 1<<KEY_ROW0^1<<KEY_ROW1^1<<KEY_ROW2^1<<KEY_ROW3^1<<KEY_ROW4;
6
                                // row0..4 = pullup on
7
  keys = KEY_PIN;               // key 0..4 = bit 2..6
8
  KEY_DDR = 1<<KEY_COL1;        // col1 = low
9
  _delay_us( 10 );
10
  keys ^= KEY_PIN<<8;           // key 5..9 = bit 10..14
11
  KEY_DDR = 1<<KEY_COL0;        // col0 = low
12
  return ~keys;
13
}
Und laß alle Widerstände weg, sonst funktioniert es nicht.


Peter

von Andreas R. (imrazor)


Angehängte Dateien:

Lesenswert?

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!

von Andreas R. (imrazor)


Lesenswert?

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 
;-)
1
 for(;;)
2
  {
3
    if( get_key_press( 1<<14 ) )    // "Taste 10" merken
4
      taste ^= (1<<14);
5
6
    // DIAGNOSE
7
    if ( (taste & (1<<14)) )
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);

von Peter D. (peda)


Lesenswert?

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

von Andreas R. (imrazor)


Lesenswert?

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.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

@ 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.

von Andreas R. (imrazor)


Lesenswert?

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?

von Andreas R. (imrazor)


Lesenswert?

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.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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.

von Andreas R. (imrazor)


Lesenswert?

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

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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
     int i = 20;           // 10 AN Phasen + 10 AUS Phasen zu je 500 ms
6
     PORTD |= (1<<PD5);    // AN
7
     do 
8
     {
9
        _delay_ms(500);
10
        PORTD ^= (1<<PD5); // TOGGLE
11
        i -= 1;
12
     }
13
     while (i);
14
     PORTD &= ~(1<<PD5);   // AUS 
15
  }

von Andreas R. (imrazor)


Lesenswert?

Diagnose: Krank.

Er blinkt mit 4s AN und 4s AUS. Also insgesamt 8s...

von Andreas R. (imrazor)


Lesenswert?

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.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

> 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

von Andreas R. (imrazor)


Lesenswert?

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.

von Andreas R. (imrazor)


Lesenswert?

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...

von Andreas R. (imrazor)


Angehängte Dateien:

Lesenswert?

Code im Anhang...

Ach ja und er wechselt jetzt wieder vom 1s Pulsblinken auf das 2s 
Blinken.

von Peter D. (peda)


Lesenswert?

Gib Dir dochmal key_state über die UART aus.

Debuggen nur mit LEDs ist etwas mühselig.



Peter

von Andreas R. (imrazor)


Lesenswert?

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?

von Peter D. (peda)


Lesenswert?

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

von Andreas R. (imrazor)


Lesenswert?

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...

von Andreas R. (imrazor)


Lesenswert?

Mal ne Frage:

Was bedeutet diese Codezeile eigentlich genau? Außer die im Kommentar 
angegebene Frequenz...

1
 TCNT0 = (u16)(256 - XTAL / 1024 / 100);

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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!

von Andreas R. (imrazor)


Lesenswert?

> 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...

von Andreas R. (imrazor)


Lesenswert?

Schon mal vorweg: Wie übergebe ich dann am besten den key_state an den 
UART?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

UART Teil im AVR-GCC-Tutorial lesen und die erste Antwort in der 
FAQ ;-)

von Andreas R. (imrazor)


Lesenswert?

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...

von Andreas R. (imrazor)


Angehängte Dateien:

Lesenswert?

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...

von Andreas R. (imrazor)


Angehängte Dateien:

Lesenswert?

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?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

>     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.

von Andreas R. (imrazor)


Lesenswert?

> 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.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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.
1
#define ROWMASKE \
2
((1<<KEY_ROW0)|(1<<KEY_ROW1)|(1<<KEY_ROW2)|(1<<KEY_ROW3)|(1<<KEY_ROW4))
3
4
static inline
5
u16 key_scan( void )
6
{
7
  u16 keys = 0;
8
9
  // row0..4 = pullup on
10
  // col0..1 LOW wenn Ausgabe aktiv
11
  KEY_PORT = ROWMASKE;          
12
13
  // Die Tasten + = T1 bis FN = T5 
14
  KEY_DDR = 1<<KEY_COL0;        // col0 = low
15
  _delay_us(10);
16
  // setzen Bits 1..5 in keys
17
  keys = ((u16) (KEY_PIN & ROWMASKE)) >> 1;    
18
19
  // Tasten F6 = T6 bis F1 = T10
20
  KEY_DDR = 1<<KEY_COL1;        // col1 = low
21
  _delay_us(10);
22
  // setzen Bits 6..10 in keys
23
  keys ^= ((u16) (KEY_PIN & ROWMASKE)) << 4;
24
25
  //DIAGNOSE
26
  if ( ((~keys) & 0x07FE) )
27
    PORTD |= (1<<PD6);   // ja => D5 Grün AN
28
  else
29
    PORTD &= ~(1<<PD6);  // D5 Grün AUS
30
31
  return ~keys;
32
}

von Andreas R. (imrazor)


Lesenswert?

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).

von Andreas R. (imrazor)


Angehängte Dateien:

Lesenswert?

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.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Das ist doch ein Lichtblick. Den Rest schaue ich mir heute abend auf der 
Ersatz-Hardware an.

von Stefan B. (stefan) Benutzerseite


Angehängte Dateien:

Lesenswert?

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.

von Andreas R. (imrazor)


Angehängte Dateien:

Lesenswert?

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?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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.

von Andreas R. (imrazor)


Lesenswert?

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...

von Andreas R. (imrazor)


Lesenswert?

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 :-(

von Andreas R. (imrazor)


Lesenswert?

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

von Andreas R. (imrazor)


Lesenswert?

Ich glaubs nicht!! ES GEHT!

Ich habe
1
u16 taste;

auf
1
u16 taste=0;

geändert und jetzt blinkt die LED D2 bei Drücken der Taste 1 im 
Sekundentakt, bei erneutem Drücken im 2-Sekundentakt :-)

von Andreas R. (imrazor)


Lesenswert?

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 ;-)

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

Andreas R. wrote:
> Ich glaubs nicht!! ES GEHT!
>
> Ich habe
>
>
1
> u16 taste;
2
>
>
> auf
>
>
1
> u16 taste=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

von Andreas R. (imrazor)


Lesenswert?

Naja mit meiner alten Makefile kam die Warnung nur leider nicht ;-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.