Hallo,
ich habe zwei kurze Fragen zur Programmierung von meinem AVR Atmega8.
Ich habe vor, ihn in C zu programmieren. Daher nun zwei Fragen:
1.) Ist es Möglich, den Zählerstand eines Timers abzufragen? Der Timer
wird inkrementiert durch ein externes Signal, und ich würde diesen Wert
gerne multiplexen auf 7-segment Anzeigen.
Sprich: kann ich den Zählerstand in eine Variable einlesen?
2.) Kennt ihr ein gutes "Tutorial" für's muxen in C? Hier auf der Seite
ist ja ein umfangreiches Tutorial für ASM, würde aber gerne in C
schreiben ...
Möchte es zwar selbst schreiben, jedoch wenigstens vorher vergleichen,
bevor ich den nachgeschalteten 4511 zerschieße...
Danke schonmal und Gruß
Daniel
Hallo Daniel,
vorab eine Frage zur Klärung:
Möchtest Du den Timer als Zähler nutzen oder verwendest Du den Timer als
als Timer dessen Reload Wert durch einen externen Impuls inkrementiert
wird?
Hallo,
ich möchte den Timer ganz simpel als Zähler nutzen. Es wird nicht höher
als maximal 99 gezählt, sodass der 8-bit Timer ausreicht.
Er soll eben auf den externen Takt am Pin reagieren, dann um 1
inkrementieren. Diesen "Zählerstand" würde ich gerne auslesen.
Zuerst mußt du den Timer als Zähler definieren. Hierzu sind einige Bits
in Statusregistern zu setzen. Welche genau mußt du dir im Datneblatt
ansehen.
Der Zähler hat ein oder zwei Zählerregister. Je nach dem ob es ein 8Bit
oder 16Bit Zähler ist. Wenn du bis 99 Zählst reichen dir 8Bit aus. Also
mußt du das Low Byte Register auslesen. Wenn du ein Include File hast in
dem die SFR deines Controller definiert sind dann machst du einfach eine
Zuweisung von diesem Register an eine Variable.
unsigned char meineVariable;
meineVariable = cntLow;
cntLow ist das deklarierte SFR deines Zählers. Ich weiß nicht wie es
beim AVR richtig heist. Im Datenbaltt und in der Include Datei
nachsehen.
Setzten muss ich ja eigentlich jeweils nur CS12, CS11, CS10 sowie CS02,
CS01, CS00, welche die Quelle für den Counter angeben.
Mir fällt gerade auf, dass dies auch nebenbei im Tutorial dieser Seite
erwähnt wird ...
TCNT0 sowie TCNT1L ...
oder hab ich jetzt was übersehen?
Danke dir schonmal ;)
@all: bleibt noch Frage zwei nach dem Multiplexen in C
Dazu brauchst du keinen Timer, sondern nur eine einfache Variable. Immer
wenn du einen Flankenwechsel feststellst, zählst du selbige um 1 hoch.
Den Timer brauchst du bestenfalls um eine Entprellung für Deinen Eingang
zu realisieren. Im einfachsten Fall nimmst du einen interruptfähigen
Pin, und in der passenden ISR zählst du Deine Variable hoch.
Es gibt am AtMega8 nur zwei Interruptfähige Pins, welche ich allerdings
beide schon belegt habe. Daher wollte ich es einfach mit einem Timer
lösen, vor allem, weil die nicht anderweitig verwendet werden.
Es geht natürlich vieles.
TCNT0 sowie TCNT1L hört sich gut. Das L steht für das Low Register im
Zähler 1. Zähler 0 scheint ein reiner 8Bit Zähler zu sein.
Ja mann wrote:
> Dazu brauchst du keinen Timer, sondern nur eine einfache Variable. Immer> wenn du einen Flankenwechsel feststellst, zählst du selbige um 1 hoch.
Die Dinger heißen nicht umsonst Timer/Counter! Variable ist umständlich,
wenn man nen freien Timer zur Verfügung hat. Warum sich in Software
einen abbrechen, wenn Hardware dafür vorhanden ist, die das ganz allein
machen und nebenbei bei Erreichen bestimmter Werte auch noch nen
Interrupt auslösen kann?
> Den Timer brauchst du bestenfalls um eine Entprellung für Deinen Eingang> zu realisieren.
Wenn das Signal nicht prellt, braucht's auch keine Entprellung!
> Im einfachsten Fall nimmst du einen interruptfähigen> Pin, und in der passenden ISR zählst du Deine Variable hoch.
Und das soll einfach sein?
Anderas Baehne wrote:
> Es geht natürlich vieles.> TCNT0 sowie TCNT1L hört sich gut. Das L steht für das Low Register im> Zähler 1. Zähler 0 scheint ein reiner 8Bit Zähler zu sein.
Richtig. Zähler 0 und 1 können eben durch einen externen Takt gesteuert
werden. Timer 2 hat eben nur BufferOverflow und nen CompareRegister,
daher nehme ich den fürs muxen ...
=> hat dazu jemand ne ausführliche Anleitung? Will nicht nur CopyPaste
machen, sondern das Multiplexen auch wirklich verstehen. (Das Prinzip
verstehe ich, nur die Umsetzung kann ich mir noch nicht genau
vorstellen)
Danke und Gruß
//Nochmal kurz zum Entprellen: Die einige Maßname, die ich angesetzt
habe, um den Timer zu inkrementieren, ist ein 10kOhm Pulldown
Widerstand. Sollte ich da noch mit nem Kondensator oder gar einem
Schmitt-Trigger arbeiten?
Daniel Herrmann wrote:
> //Nochmal kurz zum Entprellen: Die einige Maßname, die ich angesetzt> habe, um den Timer zu inkrementieren, ist ein 10kOhm Pulldown> Widerstand. Sollte ich da noch mit nem Kondensator oder gar einem> Schmitt-Trigger arbeiten?
Erstens: Woher kommt das Signal, mit dem der Timer inkrementiert wird?
Zweitens: Wenn es ein Signal von einem mechanischen Kontakt ist, dann
wird das mit dem Timer nur mit einigem Zusatzaufwand in Hardware etwas
(z.B. RC-Glied); in dem Fall wäre die bessere Lösung das zyklische
Abfragen des/der betreffenden Portpin(s) (siehe auch Entprellung)
Drittens: Die AVRs haben bereits Schmitt-Trigger-Eingänge.
Das Signal kommt von einem Taster.
Ich würde das gerne auch dabei belassen, sprich Taster, entprellen und
an den Counter-Eingang. Also dann doch besser mit RC-Glied?
Würde es reichen, es wie hier
(http://www.loetstelle.net/praxis/entprellen/entprellen.php) beschrieben
zu machen? Ohne Schmitt-Trigger. Dann habe ich halt ne fallende Flanke,
ist aber egal, kann man beim AVR ja einstellen.
@Daniel Herrmann (danielh)
>Das Signal kommt von einem Taster.
Dann kann man das spielend in Software entprellen und zählen.
Siehe Entprellung.
>Ich würde das gerne auch dabei belassen, sprich Taster, entprellen und>an den Counter-Eingang.
Wozu? Um zu lernen, wie man es NICHT macht?
>(http://www.loetstelle.net/praxis/entprellen/entprellen.php) beschrieben
Schlecht, de taster schliesst den Kondensator kurz. Das kann auf Dauer
die Kontakte abbrennen lassen.
MFG
Falk
Ja genau, so könntest du das machen. R0 begrenzt den Entladestrom vom
Kondensator. Da sollten wenige Ohm reichen. Er verlangsamt aber auch die
Entladung und somit die Zeit bis der Eingang einen Low-Pegel hat.
Schwellwert ist ca. 0,6V. Ein Schmitt Trigger wäre gut wenn dein Eingang
auf Flanke reakiert. Wenn er Zustandsgesteuert ist sollte es auch ohne
gehen. Mit ST ist aber sauber.
Öh ... Wat nun? ;)
Erstmal danke für eure beiden Antworten, auch wenn sie ein wenig
kontrovers sind. Mir wäre es lieber, wenn ich es mit den Countern machen
könnte und nicht per Software.
Das ist Flankengesteuert, also sollte doch der Schmitt-Trigger
eingesetzt werden? So habe ich auch teilweise die Taster für nen 4017
etc entprellt, sollte auch klappen, oder ?
@Falk: Was meinst du damit, dass die Kontakte abbrennen könnten? Welche
denn?
Daniel Herrmann wrote:
> Mir wäre es lieber, wenn ich es mit den Countern machen> könnte und nicht per Software.
Warum?
Als Weltmeister im Schnelltippen schaffst Du vielleicht 100ms, als
normaler Mensch 300ms Drückrate.
100ms sind für nen MC aber ne halbe Ewigkeit, der langweilt sich
tierisch.
Du hast also keinerlei Vorteil durch den HW-Counter, sondern nur den
Nachteil, daß er nicht entprellen kann.
Peter
Hi Peter,
Ja, stimmt soweit. Außerdem werden die werden nicht so "schnell" sein,
zwischen der einen Flanke und der nächsten können u.U. auch schonmal
mehrere Minuten vergehen.
Allerdings habe ich erstens Erfahrung mit Countern, das ist mir
irgendwie lieber, Software, insbesondere auch C, sind relatives Neuland
für mich. Ich würde es sicherlich hinbekommen, aber das bewährte, die
Hardwareentprellung ist irgendwie ein wenig vertrauter, zumal auch auf
der Platine kein Platzmangel herrscht.
1
2
#define TASTERPORT PINC
3
#define TASTERBIT PINC1
4
5
chartaster(void)
6
{
7
staticunsignedcharzustand;
8
charrw=0;
9
10
if(zustand==0&&!(TASTERPORT&(1<<TASTERBIT)))//Taster wird gedrueckt (steigende Flanke)
11
{
12
zustand=1;
13
rw=1;
14
}
15
elseif(zustand==1&&!(TASTERPORT&(1<<TASTERBIT)))//Taster wird gehalten
16
{
17
zustand=2;
18
rw=0;
19
}
20
elseif(zustand==2&&(TASTERPORT&(1<<TASTERBIT)))//Taster wird losgelassen (fallende Flanke)
Außerdem müsste ich diesen Code ja für jeden Taster den ich habe
einfügen, das sind immerhin 4. (Zwei an den Countern, und zwei an den
interrupt-eingängen)
Würde ziemlich lang werden das ganze, oder?
Und ich wollte eigentlich auch keine Diskussion auslösen, ob Hard- oder
Software entprellung, aber gut ... ;)
PS.: Frage II (multiplexen in C) steht noch aus (siehe erster Post).
Nochmal danke an alle bisherigen Helfer, ich bin echt angenehm
überrascht, wie schnell das hier geht ;)
@Daniel Herrmann (danielh)
>kontrovers sind. Mir wäre es lieber, wenn ich es mit den Countern machen>könnte und nicht per Software.
Machs per Software!
>Das ist Flankengesteuert, also sollte doch der Schmitt-Trigger>eingesetzt werden?
Ja, der ist aber schon im AVR drin. Steht auch im Artikel ;-)
>@Falk: Was meinst du damit, dass die Kontakte abbrennen könnten?
Ja, so in etwa.
> Welche denn?
Na die im Taster!
>Allerdings habe ich erstens Erfahrung mit Countern, das ist mir>irgendwie lieber, Software, insbesondere auch C, sind relatives Neuland>für mich.
Dann musst du es lernen. Wenn du schon bei sowas einfachem die
mädchenhaft anstellst kannst du gleich aufhören zu programmieren.
>Außerdem müsste ich diesen Code ja für jeden Taster den ich habe>einfügen, das sind immerhin 4. (Zwei an den Countern, und zwei an den>interrupt-eingängen)
Der Code von Perter ist ziemlich kompakt. Und es ist ja auch SEHR
SINNVOLL, für ier popelige Taster wertvolle Ressourcen wie Timer und
Interrupteingänge zu verbraten . . .
>Würde ziemlich lang werden das ganze, oder?
Nö.
>Und ich wollte eigentlich auch keine Diskussion auslösen, ob Hard- oder>Software entprellung, aber gut ... ;)
Da gibt es auch gar keine Diskussion. Für Taster ist Software die klar
bessere Methode. ;-)
MFG
Falk
Falk Brunner wrote:
>>Allerdings habe ich erstens Erfahrung mit Countern, das ist mir>>irgendwie lieber, Software, insbesondere auch C, sind relatives Neuland>>für mich.>> Dann musst du es lernen. Wenn du schon bei sowas einfachem die> mädchenhaft anstellst kannst du gleich aufhören zu programmieren.>
Einfach nur, weil es mir einfacher erscheint, das Hardwaretechnisch zu
lösen.
Dass das einfach ist, weiß ich selbst. Ne Variable zu inkrementieren
nach nem Funktionsaufruf dürfte ich gerade noch hinbekommen.
>>Außerdem müsste ich diesen Code ja für jeden Taster den ich habe>>einfügen, das sind immerhin 4. (Zwei an den Countern, und zwei an den>>interrupt-eingängen)>> Der Code von Perter ist ziemlich kompakt. Und es ist ja auch SEHR> SINNVOLL, für ier popelige Taster wertvolle Ressourcen wie Timer und> Interrupteingänge zu verbraten . . .
Da sie anderweitig nicht gebraucht werden, dachte ich eben, ich kann sie
dafür verwenden.
Aber gut, da ihr sicherlich mehr Erfahrung habt als ich, werde ich mich
dem beugen ;)
Wie muss der Taster denn dann angeschlossen werden? Einfach VCC ->
Taster -> PIN? Oder noch nen Pulldown hinter den Taster?
Außerdem: Welches Verfahren zur Entprellung würdet ihr empfehlen?
Am Besten so wie hier
(http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#.28Tasten-.29Entprellung)
beschrieben? Ist ja relativ simpel.
Gruß
Daniel
//edit: ich sehe grade, der AVR hat interne Pull-Ups ... Also einfach
die verwenden, dann einfach GND -> Taster -> Pin
Dann kann ich auch die vorgeschlagene Funktion 1zu1 verwenden.
Ich danke bisher dafür, hat den Hardwareaufwand nun doch deutlich
verringert ;)
Bleibt immer noch die Urspürngliche Frage, wie eine gute Software fürs
Multiplexen aussieht.
Danke nochmals an alle!
Daniel Herrmann wrote:
> Wie muss der Taster denn dann angeschlossen werden? Einfach VCC ->> Taster -> PIN? Oder noch nen Pulldown hinter den Taster?
Die AVRs haben eingebaute Pull-Ups. Warum willst Du also einen
zusätzlichen Pull-Down einbauen? Taster gegen GND und fallende Flanken
auswerten. Geht im einfachsten Falle, indem man sich im Programm jeweils
den letzten Zustand der Taster merkt und dann mit einer einfachen
logischen Verknüpfung alle paar zig Millisekunden abfragt, ob der
Zustand der Taster sich von High auf Low geändert hat.
Z.B. Taster an Port B:
1
uint8_ttaster_flags,taster_neu,taster_alt;
2
//...
3
taster_neu=PINB;
4
taster_flags=taster_alt&~taster_neu;
5
taster_alt=taster_neu;
Jedes Bit in taster_flags entspricht einem Pin des Ports. Nur wenn ein
Taster seinen Pegel zwischen zwei Abfragen von High auf Low ändert, wird
das dazugehörige Bit gesetzt, alle anderen Zustände und
Zustandsänderungen werden ignoriert. Das reicht normalerweise auch zur
Entprellung völlig aus.
Daniel Herrmann wrote:
> Muss man da echt 2* 50ms warten? Hängt das noch von was anderem außer> der Qualität der Taster ab ?
Mit einigermaßen gescheiten Tastern sind einmal 50 ms völlig
ausreichend. Ich arbeite seit Jahren mit den (allerdings schon nicht
ganz billigen) ITT-Rechtecktastern mit 20 ms zwischen zwei Abfragen und
hatte nie Probleme mit Prellen.
Ich würde es aber auch nicht mit einem delay machen, da der µC dann
nicht mehr viel anderes machen kann (außer Interrupts). Du magst die
Timer doch so sehr, warum konfigurierst Du nicht einfach einen Timer so,
dass er alle 50 ms einen Interrupt auslöst (Compare oder Overflow) und
in dem dazugehörigen Interrupt Handler machst Du einfach die o.g.
Abfrage?
/* Anwender Zeit zum Loslassen des Tasters geben */
11
_delay_ms(50);
12
_delay_ms(50);
13
return1;
14
}
15
}
16
return0;
17
}
nehme, und dann im Timer-Interrupt abfrage, dann hatte ich das sowiso so
vor ;)
Sehr qualitativ hochwertig sind meine Taster nicht, deshalb bleibe ich
dabei.
Wenn ich allerdings da 4 Taster abfrage, dann sind das immerhin 800ms,
also fast eine Sekunde, die nur fürs warten drauf gehen. Oder sehe ich
da was falsch?
Daniel Herrmann wrote:
> Falls du meinst, dass ich diese Funktion:>> [...]>> nehme, und dann im Timer-Interrupt abfrage, dann hatte ich das sowiso so> vor ;)
Nein, das meinte ich nicht! Erstens haben delays in einem
Interrupt-Handler nichts verloren und zweitens meinte ich mein obiges
Beispiel (Beitrag "Re: [AVR]Fragen zur C Programmierung (Timer / multiplexing)").
> Wenn ich allerdings da 4 Taster abfrage, dann sind das immerhin 800ms,> also fast eine Sekunde, die nur fürs warten drauf gehen. Oder sehe ich> da was falsch?
Allerdings. Deshalb werden in meinem Beispiel ja auch alle Taster an dem
betreffenden Port gleichzeitig abgefragt.
Daniel Herrmann wrote:
> Also das hier:>> [...]>> In einen Timer-Interrupt? Dann am besten mit hohem Vorteiler, oder? Es> muss ja dann schon eine gewisse Zeit vergangen sein... sonst nützt es ja> auch nichts gegen das Prellen.
Nicht einfach 1:1 übernehmen, sondern auch denken und v.a. das lesen,
was dabei steht! Wenn ich schreibe "alle paar zig Millisekunden", dann
ist damit gemeint, dass der Timer alle paar zig Millisekunden diese
Abfrage-Routine ausführen soll. Wie Du den Timer so konfigurierst, dass
er alle ca. 50 ms einen Interrupt auslöst, setze ich mal als bekannt
voraus... Und zumindest die Variablen taster_alt und taster_flags müssen
global sein (taster_alt darf auch lokal static sein). taster_neu darf
einfach lokal sein.
Gut, dann danke ich dir erstmal für deine Geduld. Ich weiß, die musstest
du haben ;)
Wie man einen Timer konfiguriert, ist mir klar, ich hatte nur oben dein
Post nicht vollständig gelesen, ist mir erst später aufgefallen, daher
auch nochmal editiert.
Sorry!