Hallo erstmal,
ich versuche mit einem attiny2313 eine binäruhr zu bauen, ich benutze
(da ein uhrenquarz ja leider nicht funktioniert) einen 4MHz quarz....
wie bekomme ich es hin, das er relativ genau nach einer sekunde eine
bestimmte variable hochzählt... per delay wird es ungenau und schwierig,
wenn sich der rest des programms ändert.
ich bin allerdings grade zudoof mit dem internen timer oder einem
interupt zu arbeiten, verstehe das tutorial leider ned....
ich programmiere ihn in c...
könnte mir da jemand helfen???
Sinnvoll ist das nur mit Timern machbar, in diesem Fall einen
16-Bit-Timer. Vorteilhaft, aber kein Muss ist ein Uhrenquarz mit
4194304Hz (2^22).
Gruss,
Michael
In C kann ich Dir nicht helfen, aber in Bascom:
'By Paul Baumann
$regfile = "2313def.dat" 'AT90S2313-Deklarationen
$crystal = 4000000 'Quarz: 4
MHz
Dim Umlauf As Byte
Dim X As Bit
On Timer0 Ontimer0
Config Timer0 = Timer , Prescale = 64 '4Mhz/64 = 62500
Hz
'Timer auf 6 heißt 250 Schritte
'bis Überlauf
Enable Timer0 'Timer erzeugt 250 Hz
Enable Interrupts 'Interrupts global zulassen
Timer0 = 6
Umlauf = 250 'Umlauf zählt die Interrupts
Config Portd.6 = Output 'LED an Port D6
Portd.6 = 0
Do
If Umlauf = 0 Then
Umlauf = 250
If X = 0 Then
Portd.6 = 0
X = 1
Else
Portd.6 = 1
X = 0
End If
End If
Loop
'Interrupt-Routine
Ontimer0:
Timer0 = 6 'Timer sofort neu laden
Decr Umlauf
Return
' **** END OF PROGRAM
Vielleicht läßt sich das Prinzip auch in C anwenden. Ich hatte Timer1
schon
mit etwas Anderem beschäftigt, deswegen mußte ich es so machen.
MfG Paul
erstmal danke für die hilfe problem ist, das wir nur den internen takt
zur verfügung haben, hatte ich glaube ich nicht erwähnt dann habe ich ja
keine xta.. eingänge
momentan sieht es so aus, was ich bis jetz aus den tutorials entnehmen
und verstanden konnte, sind noch paar sachen drin die später dazukommen
zb. stellen der uhr..
[c]
#include <avr/io.h>
#include <stdint.h>
#include <util/delay.h>
#include <avr/interrupt.h>
//---------------------------------------
#ifndef F_CPU
#warning "F_CPU war noch nicht definiert, wird nun definiert"
#define F_CPU 400000UL
#endif
//----- taster prellung
#define TASTERPORT PIND
#define TASTERBIT PIND5
int8_t stunde=0;
int8_t minute=0;
int8_t sekunde=0;
int64_t timmmer=0;
ISR(TIMER0_OVF_vect)
{
timmmer++;
}
TCCR0 = 0x03;
/*
if (taster()== 1)
{minute++;}
if (stunde ==25)
{stunde=1;}
if (minute ==60)
{minute=0; stunde++;
}
char taster(void)
{
static unsigned char zustand;
char rw = 0;
if(zustand == 0 && !(TASTERPORT & (1<<TASTERBIT))) //Taster wird
gedrueckt (steigende Flanke)
{
zustand = 1;
rw = 1;
}
else if (zustand == 1 && !(TASTERPORT & (1<<TASTERBIT))) //Taster wird
gehalten
{
zustand = 2;
rw = 0;
}
else if (zustand == 2 && (TASTERPORT & (1<<TASTERBIT))) //Taster wird
losgelassen (fallende Flanke)
{
zustand = 3;
rw = 0;
}
else if (zustand == 3 && (TASTERPORT & (1<<TASTERBIT))) //Taster
losgelassen
{
zustand = 0;
rw = 0;
}
return rw;
}
*/
//-------------------------------------------------
int main (void) {
sei();
/* Setzt das Richtungsregister des Ports B auf 0xff
(alle Pins als Ausgang): */
DDRB = 0xff;
DDRA = 0xff;
DDRD = 0xff;
/* Setzt PortB auf 0x00, "low": */
PORTB = 0x00;
PORTA = 0x00;
PORTD = 0x00;
while(1) {
if (sekunde == 60)
{minute++; sekunde = 0;}
if (minute ==60)
{minute=0; stunde++;
}
if (stunde ==25)
{stunde=1;}
PORTD=stunde;
PORTA=minute;
PORTB=sekunde;
}
return 0;
}
[c]
Rhamirez wrote:
> erstmal danke für die hilfe problem ist, das wir nur den internen takt> zur verfügung haben, hatte ich glaube ich nicht erwähnt dann habe ich ja> keine xta.. eingänge
Dann kannste das mit der Uhr gleich wieder vergessen. Und der ATTiny
2313 unterstuetzt einen externen Quarz, das tun (fast) alle AVRs.
Michael
Für den Anfang schon nicht schlecht....... aaaaaaber
Wozu zählst du denn "timmer" hoch ? (irgendwann sollten doch auch mal
die Sekunden hochgezählt werden)
Was ist das für ein neues C-Schlüsselwort - "[c]" an Anfang und Ende ?
;-)
Viel Erfolg beim Üben (nicht ironisch gemeint!)
ok mit einen externen quarz werd ich schon bekommen, problem war nur, er
wollte meinen uhrenquarz nicht (das kann der attiny ned)
wie gesagt es soll relativ genau werden, muss nicht 100% wenn ich die
uhr pro tag eine minute stellen muss ist das auch kein problem, nur habe
es mit delay probiert und das ging ganz ganz schlecht
naja üben es ist ein schulprojekt, welches freitag mittag fertig sein
soll und der einzige lehrer der uns helfen konnte ist krank =(, und das
projekt kommt auf zeugniss.
das [c] sollte nur für euch als hilfe sein...
timmmer sollte hochzählen bis ich die sekunde relativ genau setzen kann
nur irgendwie blicke ich nicht durch das dieser timer wieder resettet
werden muss oder so, da bräuchte ich ja eure hilfe... wer voin denen
jetz bis 255 hochzählt etc
sry wegen der doppelposts, das problem ist, weshalb auch der tiny
genommen wird das es relativ stromsparend sein soll, momentan ist es
aber wichtig, das es überhaupt läuft ich verzweifle langsam und sehe
mein projekt... kritisch
@ Rhamirez (Gast)
>ok mit einen externen quarz werd ich schon bekommen, problem war nur, er>wollte meinen uhrenquarz nicht (das kann der attiny ned)>wie gesagt es soll relativ genau werden, muss nicht 100% wenn ich die>uhr pro tag eine minute stellen muss ist das auch kein problem, nur habe>es mit delay probiert und das ging ganz ganz schlecht
Dan bleib mal ganz unruhig und lies die beiden Artikel. Steht alles
idiotensicher drin.
AVR - Die genaue Sekunde / RTCAVR-Tutorial: Uhr
MfG
Falk
> das [c] sollte nur für euch als hilfe sein...
Wenn du beim zweiten einen / genutzt hättest, wär's wirklich ne Hilfe,
weil dann das Syntaxhighlighting aktiviert würde.
>timmmer sollte hochzählen bis ich die sekunde relativ genau setzen kann
Hä? ...
Der Sourcecode sieht im übrigen auch etwas seltsam aus. Möglicherweise
wäre es sinnvoll die Klammern entsprechend zu setzen. Derzeit ist die
Interruptroutine nämlich nur aus timmer++; aufgebaut, der ganze Rest,
der da wohl dazu gehören sollte, steht leer im Raum.
Ansatz: Timer nutzen, um eine LED zum Blinken zu bringen. (Siehe auch
hier in der Codesammlung) Timer so einstellen, dass jede Sekunde blinkt.
Dann modifizieren.
Die hier:
>int8_t stunde=0;>int8_t minute=0;>int8_t sekunde=0;>int64_t timmmer=0;
müssten alle mit 'volatile' deklariert werden, sonst nützt all das
Hochzählen nix, weil der Compiler nicht weiss, dass sie sich
zwischenzeitlich(im Interrupt) geändert haben (könnten).
> if (stunde ==25)> {stunde=1;}
Soll dann da 24:30 und dergleichen angezeigt werden? ;)
Ansonsten hilft wohl auch ein gut formatierter Code etwas, dann kann man
ihn wesentlich besser lesen und Fehler schneller erkennen.
Wenn es wirklich nur um die Nutzung des Timers geht, schau dich in der
Codesammlung um, da gibt's wirklich genügend Beispiele. Oder aber teile
uns dein konkretes Problem mit. Anfragen wie 'Hä? Wie verwende ich nen
Timer?' Werden nicht wirklich gerne beantwortet...
Rhamirez wrote:
> naja üben es ist ein schulprojekt, welches freitag mittag fertig sein> soll und der einzige lehrer der uns helfen konnte ist krank =(, und das> projekt kommt auf zeugniss.
Da biste dann reichlich frueh dran ;-P
Das ist meine geek-Clock, kannst Dir den Code ja mal "ansehen":
http://coremelt.net/filebrowser.php?mode=coremelt&order=name&dir=files%2Ftrees%2Fgeek_clock-1.1
Ach ja, da sind mir im Nachhinein noch einige Verbesserungen
eingefallen, ich bin aber nicht dazu gekommen bisher. Funktionieren tut
die Uhr aber ganz gut, die Abweichung ist minimal -- hoffe das aber
sogar noch etwas besser hinzubekommen. Nach etwa zwei 6-8 Wochen geht
die Uhr langsam aber sicher eine Minute daneben.
Konkrete Verbesserung: Den Sekundentakt in nen 16-Bit-Timer, immo mache
ich alles in einem 8-Bit-Timer inklusive dem Multiplexing der Anzeige,
das wollte ich noch auslagern.
Gruss,
Michael
@ Rhamirez (Gast)
>gibt es das mit der uhr auch in c?
Zitat
"ich versuche mit einem attiny2313 eine binäruhr zu bauen, ich benutze"
Als Idee sollte das doch reichen. Jetzt bis DU an der Reihe, das in C
umzusetzen.
MfG
Falk
ok und entschuldigung, eine anzeige von 24.30 wird es nicht geben, es
wird eine binäruhr..
wenn man seid 7 uhr vor dem pc sitzt und programmiert wird man etwas
seltsam...
den interupt bekomme ich ja nicht fertig deshalb fehlt da was
Rhamirez wrote:
> wenn man seid 7 uhr vor dem pc sitzt und programmiert wird man etwas> seltsam...
Haste auch Fortschritte vorzuweisen? ;) Wie gesacht nochma, schau Dir
meine Uhr mal an, aber wennst gar zu sehr zulangst waere eine
Quellen-Erwaehnung angebracht. Und tu mir nen Gefallen und denk drueber
nach was Du tust, das sollte ja der Sinn eines solchen Projekts sein,
nicht einfach die Arbeit anderer zu kopieren und abzugeben.
Gruss,
Michael
ok habe das obere verstanden mit der genauen sekunde, naja fast aber was
bedeutet
int main( void )
{
LED_DIR = 0xFF;
while( KEY_INPUT & 1 ); // start with key 0 pressed
TCCR1B = 1<<WGM12^1<<CS10; // divide by 1
// clear on compare
OCR1A = XTAL / DEBOUNCE - 1; // Output Compare Register
TCNT1 = 0; // Timmer startet mit 0
second = 0;
prescaler = (uchar)DEBOUNCE; //software teiler
TIMSK = 1<<OCIE1A; //bitte erklären // beim
Vergleichswertes Compare Match
// Interrupt
(SIG_OUTPUT_COMPARE1A)
sei();
for(;;){ //was ist das??
if( second == 60 )
second = 0;
LED_DIR = second; // display second (binary)
}
}
könnte doch einfach second durch meine sekunde ersetzen oder???
und wozu ist das debounce?
Du hast vergessen die Interrupts mit einem sei() freizugeben.
Edit: Irrtum - Du hast das sei() gleich am Anfang in main(). Hab
ich nicht gesehen.
Dort ist aber kein guter Platz dafür.
sei() ist normalerweise die letzte Aktion, bevor die
Hauptschleife betreten wird. Denn dann ist alles korrekt
aufgesetzt und ab dann sind Interrupts auch zugelassen.
Interrupts vorher freizugeben, schwört nur Ärger herauf
int main()
{
..... Alles initialisieren
// jetzt gilts. Alles ist initialisiert, ab jetzt dürfen
// Interrupts zuschlagen
sei();
while( 1 ) {
... Hauptschleife
}
}
PS: Gewöhn dir eine vernünftige Formatierung und konsistente
Einrückung an. Auch so kann man Fehler vermeiden
TCCR1B = 1<<WGM12^1<<CS10; // divide by 1
// clear on compare
OCR1A = XTAL / DEBOUNCE - 1; // Output Compare Register
TCNT1 = 0; // Timmer startet mit 0
second = 0;
prescaler = (uchar)DEBOUNCE; //software teiler
TIMSK = 1<<OCIE1A;
Hast du kontrolliert, ob bei deinem Prozessor die Bits auch gleich
heissen bzw. ob sie auch im jeweilgen Register liegen?
TCCR1B = 1<<WGM12^1<<CS10; // divide by 1
Das hier soll den CTC Modus einschalten. Der Timer zählt dabei
vor sich hin und wenn der Timerwert den Wert in OCR1A erreicht,
wird ein Interrupt ausgelöst und der Timer auf 0 zurückgesetzt.
Die SChreibweise ist etwas ungewöhnlich. Normalerweise schreibt
man das so
TCCR1B = ( 1 << WGM12 ) | ( 1 << CS10 );
macht aber in dem Fall keinen Unterschied.
Also: Kontrollier mal im Datenblatt, ob der Tiny13 die Bits
WGM12, CS10 besitzt und ob sie im Register TCCR1B liegen.
Weiters kontrollierst du im Datenblatt, ob alleiniges
Setzen von CS10 einen Vorteiler von 1 einstellt und ob
das Setzen von WGM12 den CTC Modus aktiviert. Alle anderen
Bits die du bei der Registerbeschreibung im Datenblatt finden
wirst sind als 0 anzusehen.
Dieselbe Kontrolle machst du auch hier:
TIMSK = 1<<OCIE1A; // beim Vergleichswertes Compare
danke hatte gedacht, wenn es die register nicht gibt oder so bekome ich
direkt nen fehler, weil ich ja am anfang im studio einstelle welcher
controller es ist, klar werde es mit dem datenblatt abgleiche schauen
viell hilft es ja.
allerdings ist es ja größtenteils aus eine echte sekunde und dieses
tutorial bezieht sich doch auf nen attiny2313 oder??
es ist eine berufschule, schulischer bildungsgang mit fachabitur
// Target: Mega8, 2313
#include <io.h>
#include <interrupt.h>
#include <signal.h>
#ifndef OCR1A
#define OCR1A OCR1 // 2313 support
#endif
sagen mir diese zeilen nicht das es auf dem mega8 und den attiny2313
läufen müsste?
gibt es sonst eine andere idee, wie es hinbekommt, das die variable nach
einer bestimmten zeit hochgezählt wird, weil ich verstehe den interrupt
nicht, und das datenblatt hilft auch nicht weiter
Alles der Reihe nach, du hast da oben Debounce Funktionen (zur
Tastenentprellung) drin die du schonmal gar nicht brauchst.
Vorgehensweise:
* Lies dich ein wie der Timer funktioniert und wie er nach Ablauf einer
bestimmten Zeit einen Interrupt erzeugt.
(http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Die_Timer.2FCounter_des_AVR)
* Wenn ein Interrupt erzeugt wird springt der uC in den Interrupt
Handler (Interrupt Service Routine, ISR).
* In dieser ISR kannst du jetzt diverse Dinge machen.
Was du versuchen solltest:
* Schau, dass du eine LED sekündlich blinken lässt. Schließe eine LED
(mit Vorwiderstand) an einen freien Pin an, konfiguriere diesen als
Ausgang und in jeder ISR toggelst du diesen. Dann hast du deinen
Sekundenrythmus.
* Wenn du das geschafft hast musst du nur noch eine Variable definieren,
die du nun anstatt die LED zu toggeln hinaufzählst. var++;
ich verstehe allerdings in dem tutorial nicht wie ich den interrupt für
meinen attiny2313 einstelle
habe noch nie mit etwas derartigem gearbeitet, deshalb weißß ich nicht
wie das mit dem overflow oder so laufen muss
togglen würd ich mit PORTB = !PORTB hinbekommen, mit sei schalte ich
anscheinend die interrupts an nur vertsehe nicht wie ich am einfachsten
den interrupt bei dem controller initialisiere, weil im tutorial steht
das man den immer zurücksetzen muss oder so und das er zählt und nach so
und soviel takten auslöst
Also die includes sind soweit korrekt.
Dann hast du Code der IRGENDWO steht, der sollte wohl in die main rein.
Dafür gehört die ISR aus der while Schleife und aus der main raus ...
Die Struktur sollte dann in etwas so aussehen
ok das wurde in die maiun geschoben
TCCR2 = 6; // Vorteiler 256 -> ~65ms
Überlaufperiode
TIMSK |= (1<<TOIE2); // Timer Overflow Interrupt
freischalten
allerdings kennt er die drei begriffe nicht, wie definiere ich die?
Nunja, ein bischen mit dem Datasheet musst du dich schon beschäftigen.
Dann würdest du draufkommen wie die Register wirklich heissen - das
steht übrigens so ca. auf Seite 108 (die Seiten davor und danach sind
auch interessant)
TIMSK sollte jedoch eigentlich passen, TOIE2 ist wahrscheinlich jedoch
falsch.
Sieht doch gleich mal besser aus ...
Wahrscheinlich sollte das TIMER_OVF_vect ein TIMER1_OVF_vect sein.
Beachte auch dass es 2 wichtige Register für den Timer 1 gibt: TCCR1A
und TCCR1B
Beschreibe mal in Worten welche Bits in diesen beiden Registern du
setzen willst und vor allem: Warum.
ich möchte, das er bei einem overflow im timer, einen interupt auslöst,
möglichst so das man den timer counter so einstellt, das es nach einer
sekunde passiert oder in einem abstand das man eine sekunde berechnen
kann
ich sehe nur tabellen =(
@ dede (Gast)
>ich möchte, das er bei einem overflow im timer, einen interupt auslöst,>möglichst so das man den timer counter so einstellt, das es nach einer>sekunde passiert oder in einem abstand das man eine sekunde berechnen>kann
Das ist schon dreimal erklärt worden.
AVR - Die genaue Sekunde / RTC
MfG
Falk
Soweit waren wir schonmal ;)
Du hast jetzt zwei Register in denen du Einstellungen vornehmen kannst,
TCCR1A und TCCR1B.
Auf Seite 108 ist TCCR1A beschrieben.
Du musst nun der Tabelle entnehmen welche Bits du setzen willst.
Bei TCCR1A helfe ich dir:
Wir wollen (vorerst mal) eine "normal Port Operation" was den OC Pin
anbelangt. Außerdem wollen wir "Timer / Counter Operation" auf "Normal".
Das Register auf Seite 108 hat die folgenden Bits:
COM1A1
COM1A0
COM1B1
COM1B0
--
--
WGM11
WGM10
(unten = niedrigwertestes Bit)
Wir wollen sämtliche Bits auf 0 setzen (wegen den oben definierten
Bedingungen), die korrekte Zeile lautet also
TCCR1A = 0x00; // Hex Darstellung ist etwas lesefreundlicher
So, jetzt bist du dran.
Schau dir an welche Bits das Register TCCR1B hat und suche in den
Tabellen nach dem Richtigen Modus
habe jetz m,ich etwas reingearbeitet, der größte problem den ich hatte
war, das ich dachte er simuliert es in echtzeit, naja...
habe im anhang jetzt mein program habt ihr noch verbesserungsvorschläge
oder eine idee wie ich das besser mache weil portD gibt die stunden aus
und dort muss auch noch der schalter dran
das sollte eine softwäreseitige entprellung eines schalters sein, der an
pind6
angeschaltet wird.
habe das problem, das ich gleichzeitig an portd (0-5) die stunden
ausgeben möchte und am verbleibenen port (pind6) einen schalter machen
soll, außerdem sollte es unterscheiden, ob man lange den taster drückt,
um stunden zu stelen oder nur antippt um die minuten zu stellen, oder
habt ihr eine bessere idee wie sich das lösen lässt?
MfG Rhamirez
@ rhamirez (Gast)
>das sollte eine softwäreseitige entprellung eines schalters sein, der an>pind6>angeschaltet wird.
Wäre es da nicht sinnvoll, das auch im Timerinterrupt zu machen?
Entprellung
Dort gibts die Creme de la creme, incl. langer und kurzer
Tastendruckerkennung.
MfG
Falk
@ rhamirez (Gast)
>das problem ist, das es die creme dela creme nicht verstehe, wie das>dann ist wenn ich den port gleichzetig als ausgang nutzeAVR-Tutorial: IO-Grundlagen
MfG
Falk
soweit habe ich es ja verstanden, und wenn ich DDRD auf0xbf setze dann
sind doch die pins 0-5 ausgänge und der pin 6 eingang oder?
nun stehe ich hier und dann eine abfrage mache ob PIND6 ==1 ist oder?
würde das denn so gehen???
rhamirez wrote:
> soweit habe ich es ja verstanden, und wenn ich DDRD auf0xbf setze dann> sind doch die pins 0-5 ausgänge und der pin 6 eingang oder?>> nun stehe ich hier und dann eine abfrage mache ob PIND6 ==1 ist oder?>> würde das denn so gehen???
Abgesehen davon, dass du mit deiner Syntax so nicht weit kommen
würdest: ja so in etwa würde das funktionieren (wenn wir mal
das Problem der prellenden Taster ignorieren und deine Taster
höchstwahrscheinlich low-aktiv angeschlossen sind)
Die Frage ist aber: wozu?
Die Entprellroutinen sind creme de la creme. Den ISR Anteil
in deine bisherige SIGNAL Routine mit aufnehmen, so dass
der einzige Interrupt beides erledigt, die restlichen
Funktionen mit in das Projekt einkopieren und die Tastenfunktionen
benutzen. Ist fast so einfach wie einem Baby den Schnuller klauen -
wenn man weiss was man tut!
@ rhamirez (Gast)
>soweit habe ich es ja verstanden, und wenn ich DDRD auf0xbf setze dann>sind doch die pins 0-5 ausgänge und der pin 6 eingang oder?>nun stehe ich hier und dann eine abfrage mache ob PIND6 ==1 ist oder?>würde das denn so gehen???
Nicht ganz.
Schau dir das nochmal in C an.
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#I.2FO-RegisterBitmanipulation
MfG
Falk
verstehe ich das richtig das meine abfrage dann bit_is_set (PORTD,64)
64 weil die die wertigkeit ja abgefragt wird oder???
setzt sich das bit dann automatisch sobald am eingang ein highsignal
ist?
aber die deklaration der ein ausgänge war richtig oder?
@ rhamirez (Gast)
>verstehe ich das richtig das meine abfrage dann bit_is_set (PORTD,64)>64 weil die die wertigkeit ja abgefragt wird oder???
Nein. Das Makro arbeitet mit der Bitnummer, nicht Wertigkeiten.
>setzt sich das bit dann automatisch sobald am eingang ein highsignal>ist?
IN PIND schon, ja.
>aber die deklaration der ein ausgänge war richtig oder?
Aber sehr unleserlich. Viel besser lesbar als 0xBF ist ~(1<<PD6). Siehe
Bitmanipulation.
MFG
Falk