Hallo,
ich habe soeben ein Programm für den Atmega8 geschrieben, mit welchem
ich die Eingabe von einer 4*4 Tastenmatrix ausgeben möchte.
Dabei wird von dem uC eine Zeile nach der anderen auf high gelegt und
dann der Zustand der Spalten abgefragt. Ein Timer sorgt dafür, dass die
gesamte Matrix innerhalb von 0,01s abgefragt wird.
Leider klappt das nicht so, wie ich es mir vorstelle, auf dem LCD wird
zwar "Eingabe:" ausgegeben (hier liegt also kein Fehler), aber bei
Tastendruck ändert sich nichts. Findet einer von euch meinen Fehler?
Führe das Programm mit einem Debugger aus oder gib zwischendurch
Log-Meldungen aus, um den Fehler einzukreisen.
In so vielen Zeilen Code den Fehler durch Sichtkontrolle zu suchen,
halte ich für die falsche Herangehensweise.
Die Art, wie du dort die Interruptroutine verwendest, kommt mir arg
seltsam vor. Kannst mal erklären, wie dieses Programm funktionieren
soll? Ein Ablaufdiagramm wäre hilfreich.
Danke für die schnelle Antwort!
Die Interruptroutine soll die 1, welche zu Beginn in PinD4 steht, immer
um eins nach links schieben, um eine Zeile nach der anderen abzufragen.
Dabei soll PORTD0...3 unangetastet bleiben, weil diese Pins den Eingang
für die Spalten darstellen.
Das ist doch sinnlos, wenn dein Hauptprogramm am Ende darauf wartet,
dass alle Zeilen durchlaufen wurden. Das kannst du dann auch gleich in
der lesematrix() Funktion machen, dann ist es auch viel einfacher zu
debuggen.
Mir ist gerade was aufgefallen: Ich sehe keinen Code, der Timer startet
und auch keinen Code, der die Interrupts aktiviert.
Stefan U. schrieb:> Mir ist gerade was aufgefallen: Ich sehe keinen Code, der Timer startet> und auch keinen Code, der die Interrupts aktiviert.
Ich bis gerade auch nicht! Der Fehler ist behoben, leider bleibt PORTD =
0, wenn ich ihn mir auf dem LCD anzeigen lasse,obwohl sich eigentlich
die höherwertigen Bits ändern müssten...
Habe folgendes für den Timer hinzugefügt:
Wie gesagt, baue Log-Meldungen ein. Und gebe sie auch einem Bildschirm
aus, auf dem man sie vernünftige lesen kann. Bei mir heißt das: Serielle
Verbindung zum PC und dort läuft das Hammer Terminal.
PS: Du hast recht, dass man das alles eigtl. auch ohne Interrupt gut
realisieren kann. Da ich jetzt diesen Ansatz gewählt habe, möchte ich
den aber auch gerne zu Ende bringen, einfach aus Prinzip (oder Trotz :-/
)
>> Wo ist der Code, der den Timer startet?> Ganz doof gefragt, wird der nicht mit Einstellen des> Prescalers gestartet?
Nein
> Da ich jetzt diesen Ansatz gewählt habe, möchte ich> den aber auch gerne zu Ende bringen, einfach aus Prinzip
Dann mache nicht zwei Fässer gleichzeitig auf!
Starte einen Timer und schalte eine LED über dessen OCR Ausgang an/aus.
Als nächsten Schritt fügst du eine Interruptroutine hinzu und schaltest
die LED stattdessen per Software um.
Danach erst bringst du deine Matrix ein.
Stefan U. schrieb:> Starte einen Timer und schalte eine LED über dessen OCR Ausgang an/aus.> Als nächsten Schritt fügst du eine Interruptroutine hinzu und schaltest> die LED stattdessen per Software um.
Das habe ich schon gemacht, auch schon mit dem ADC um die Helligkeit
einstellen zu können. Da gab es eben keine Probleme!
Und da bei den Prescaler select Bits im Datenblatt ausdrücklich steht
"No clock source (Timer/Counter stopped)" wenn alle besagten Bits = 0
sind, war ich davon ausgegangen, dass bei allen anderen Prescaler
Einstellungen der Timer gestartet wird.
Stefan U. schrieb:>>> Wo ist der Code, der den Timer startet?>> Ganz doof gefragt, wird der nicht mit Einstellen des>> Prescalers gestartet?>> Nein
Hier habe ich in das AVR-GCC-Tutorial geschaut, da wird auch nichts
weiter gemacht, als den prescaler setzen, die Timer-Interrupts erlauben
und globale Interrupts erlauben:
1
// Timer 0 konfigurieren
2
TCCR0=(1<<CS01);// Prescaler 8
3
4
// Overflow Interrupt erlauben
5
TIMSK|=(1<<TOIE0);
6
7
// Global Interrupts aktivieren
8
sei();
Ich bin dankbar für jede Hilfe, bloß hier erkenne ich wirklich nicht,
was ich noch hätte ändern müssen, um den Timer zu starten.
Hi doodle,
warum liest Du nicht das spezielle und richtige Datenblatt zu deinem
Atmel AVR?
Ein AVR-GCC-Tutorial mal als Blick hinter die Kulissen reichen, aber den
real verwendeten Atmel AVR kann man nur korrekt über sein Datenblatt
ansprechen.
Hi,
was Stefan U. wahrscheinlich meint, ist, dass außer dem Timer Overflow
Modus 0, alle weiteren Modi konfiguriert werden müssen.
Wir kennen ja deinen verwenden Atmel AVR nicht.
Wenn die µC mit 1MHz läuft, der Timer0 Prescaler 1/32 beträgt und alle
256 Ticks ein Interrupt Overflow erfolgt, dann wird die ISR alle ~122Hz
ausgeführt.
Das liegt dann daran, dass im Mode 0 der Zähler TCNT0 von 0 bis 255
läuft und bei Überlauf von 255->0 eine Timer0 Interrupt Request
generiert wird.
Wie geschrieben, das steht alles sehr genau im Datenblatt.
Karl M. schrieb:> warum liest Du nicht das spezielle und richtige Datenblatt zu deinem> Atmel AVR?
Natürlich richte ich mich nach dem (richtigen) Datenblatt. Ich habe mir
dazu die "modes of operation" durchgelesen und bin zu dem Schluss
gekommen, den Timer im "normal mode" mit einem prescaler von 32 zu
nutzen. Daraufhin bin ich Bit für Bit alle Timer/Counter2-Register mit
Blick auf meine Anwendung durchgegangen und habe die notwendigen Bits
gesetzt.
Ich weiß, dass die Ratschläge, die einzelnen "Einheiten" eines
Programmes voneinander getrennt zu erlernen, gut gemeint sind;
allerdings habe ich eben schon Versuche mit den Timern, PWM etc.
gemacht.
Karl M. schrieb:> Wenn die µC mit 1MHz läuft, der Timer0 Prescaler 1/32 beträgt und alle> 256 Ticks ein Interrupt Overflow erfolgt, dann wird die ISR alle ~122Hz> ausgeführt.
Ich betreibe den Avr mit 8MHz, ein prescaler von 32 ergibt somit eine
Frequenz von 980Hz, das ist mir schon klar.
Ok, es sieht ganz danach aus, als ob ich den Fehler in meinem Programm
mithilfe von trial and error finden muss; wenn ich damit nicht weiter
komme, probiere ich halt etwas anderes aus.
Ich möchte euch trotzdem für eure Hilfe danken!
Sorry Stefan Us,
er lass deine Beiträge wohl nur oberflächlich.
Ich verweise auf Beitrag von Peter Dannegger, er hat einen sehr schönen
und effiziente Code geschrieben.
Beitrag "Re: Tastenmatrix 3x4 Problem"
Aber Achtung auch dieses Taster prellen und man muss noch jede erkannte
Taste entprellen!
Ich nutze dieses Basiscode auch zur Erledigung der Aufgabe, es werden
DTMF Codes eingegeben und über ein Soundmodul (AVR PWM) ausgegeben.
'---------------------------------------
' Der Einfachheit halber wird angenommen,
' dass ein Keypad an einem Port
' angeschlossen wurde.
'---------------------------------------
'
' Col0 Col1 Col2
' | | |
' D6 ---x----x----x--Row0 (1, 2, 3)
' D5 ---x----x----x--Row1 (4, 5, 6)
' D4 ---x----x----x--Row2 (7, 8, 9)
' D3 ---x----x----x--Row3 (*, 0, #)
' | | |
' | | |
' D2 ---+ | |
' D1 --------+ |
' D0 -------------+
'
' Legende.
' x : Taster
' -,+,| : Leitung
'---------------------------------------
Hallo,
üblicher Weise hängt man Col-0, Col-1 und Col-2 über einen Widerstand
(z.b. 10k) nach VCC. Über Row-0 bis Row-3 wird dann eine Low ausgegeben
die dann bei einem Tastendruck an D0 bis D2 gelesen wird.
Danke Karl für den Link!
Wie oben schon geschrieben habe ich wohl am meisten Erfolg, wenn ich
hier bei mir vor Ort herumprobiere, das Programm ist wirklich etwas zu
unübersichtlich, als dass man sich da mal eben hineinarbeiten kann.
Wenigstens ist in diesem Thread nie das Wort "Glaskugel" gefallen, davor
hatte ich am meisten Angst, haha :'D
Hans schrieb:> üblicher Weise hängt man Col-0, Col-1 und Col-2 über einen Widerstand> (z.b. 10k) nach VCC. Über Row-0 bis Row-3 wird dann eine Low ausgegeben> die dann bei einem Tastendruck an D0 bis D2 gelesen wird.>
Ja, einen ähnlichen Ansatz hatte ich auch verfolgt, nur dass nicht ein
low, sondern ein high erkannt werden sollte.
> es sieht ganz danach aus, als ob ich den Fehler in meinem Programm> mithilfe von trial and error finden muss
Warum übergehst du meinen Ratschlag bezüglich der Log Meldungen oder
Debugger? Wenn du unbedingt trial & error willst, dann mach das. Aber
dann bitte hier nicht um Hilfe.
Wenn das jetzt die Initialisierung für deinen ATmega8 ist, dann ist sie
in ordnung, soweit ich das auf die schnelle beurteilen kann:
> TCCR2 |= (1<<CS21) | (1<<CS20); //prescaler 32> TIMSK |= (1<<TOIE2);> sei();
Wenn du zur Kontrolle in der ISR eine LED einschaltest, müsste sie
gleich nach dem Programmstart an gehen. Tut sie das?
Was machen denn deine Zeilen-Ausgäge? Werden die nacheinander auf High
geschaltet, oder nicht? Werden sie überhaupt geschaltet?
Dazu könntest du dort mal LED's anschließen. Oder die Spannung messen.
An einem Pin der ein Rechteck-Signal führt müsste ein normales
Multimeter den Mittelwert der Spannung messen, als knapp über 1 Volt (da
1/4 der Zeit auf High).
Der Code ist wirklich sehr komplex und schwer zu durchschauen.
Ich sehr nirgends, wo die Inputs abgefragt werden.
Und mal wird PORTC, mal PORTD benutzt.
Zeig mal den Schaltplan.
Was liefert dir die Funktion greytonormal als Rückgabewert wenn
eingabe nicht 0, 1, 2, 4 oder 8 ist?
Welche Wert kriegt die Variable zeile in der Funktion lesematrix?