PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Timer für AVR ATtiny84 oder ander allgemein in C



ooweberoo
27.02.2014, 20:58
Hallo Leute brauche mal bitte Hilfe,

habe eine ATtiny84V10PU und möchte einfach nur einen Timer in abhängigkeit der Taktfrquenz laufen lassen und Überläufe zählen. Habe mir auch das Tutorial hier im Roboternetz (und viele andere) angeschaut und muss es als unbefriedigend bewerten. Wenn man in einem Tutorial schon Wissen vorraussetzt braucht man auch kein Tutorial machen:(:confused::(
Das hat nichts mit der Sprache C an sich zu tun, sind ja einfach nur Befehle an den Chip. Verstehe nicht wie man so eine einfache Sache so umständlich dumm gestalten kann. Für eine SPS ist das so einfach in AWL z.B.

U E 6.0
FR T1
L S5T#10S
SI T1
UE 5.5
R T1
Fertig

Was bedeutet z.B. das "SIGNAL(SIG_OUTPUT_COMPARE0A)" dazu finde ich nichts im Datenblatt des Chips, oder diese Befehle "SIGNAL(TIMER1_CAPT_vect)", "SIGNAL(TOIE0)", "SIGNAL(TIMER1_CAPT_vect_num)" ???
AVR Kauderwelsch:(? Scheinen Pointer zu sein aber was machen die da?

Alles was ich bis jetzt hin bekommen habe sieht so aus (CTC Mode):
-----------------------------------------------------------------
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 1000000UL //max. Takt ATtiny84

SIGNAL(SIG_OUTPUT_COMPARE0A)
{
TCNT0++;
}

TCCR0A = (1<<CS20) | (1<<WGM02); //Prescaler von 1 | CTC-Modus, ATtiny84 hat keine Prescaler Funktion ? richtig?
OCR0A = 10000;
TIMSK |= (1<<OCIE2); //Befehl aus Roboternetz Tutorial soll Interrupts aktivieren und damit Timer starten, bei mir Funktionirt es nicht
sei();
int main(void)
{
while(1)
{
}
}
-------------------------------------------------------------------
Der Code ist fehlerhaft, denke es liegt am Behehl TCCR0A. Aber was muss dort stehen für den CTC Mode zu starten???
Für mich liest sich der Code wie die Aussage eins Opfers das zusammengeschlagen wurde und versucht zu erklären was Gestern geschehen ist:o

Kann mir mal jemand helfen und mal die Struktur bzw. Syntaxablauf eines Timer erklären wie z.B.

Timer freigeben
Timer aufrufen " T1"
Timerwert setzen zB. 0 oder 20...
Timerfunktion wie CTC, Einschaltverzögert usw.
Vergleichswert für max. Zählwert festlegen z.B. 10000
Befehl was beim erreichen von 10000 geschehen soll z.B. LMW 10, R T1, = A 4.0...

So ein Ablauf der bei jedem Chip gleich ist und immer eingehalten werden muss und nur unterschiedliche Befehle aufweist da unterschiedliche Chips...

Kann jemand helfen.... do kend ich beklobbd were.....

??:confused: :confused: :confused: :confused: :confused:

Che Guevara
27.02.2014, 21:10
Hi,

also zunächst mal solltest du Code immer in den dafür vorgesehenen "Bereich" posten, ist leslicher und die Einschübe bleiben erhalten.
Außerdem: Man kann in einem Tutorial nicht immer ALLES erklären, aber es gibt meist auch Tuts, die das erklären, auf das andere aufbauen.

So zum Thema:


TCCR0A = (1<<CS20) | (1<<WGM02); //Prescaler von 1 | CTC-Modus, ATtiny84 hat keine Prescaler Funktion ? richtig?
OCR0A = 10000;
TIMSK |= (1<<OCIE2); //Befehl aus Roboternetz Tutorial soll Interrupts aktivieren und damit Timer starten, bei mir Funktionirt es nicht
sei();

Dieser Teil deines Codes steht weder in der MainRoutine, noch in einer Setup-Routine noch in einer ISR. --> Fehler
Eigentlich sollte der Code am Anfang der Main-Routine aufgerufen werden, bevor dann in die Endlosschleife gesprungen wird.

Das Keyword "SIGNAL" ist veraltet (sollte deswegen durch "ISR" ersetzt werden) und kennzeichnet eine Interrupt-Service-Routine (also ein Interrupt-Sprungvector). In der Klammer ist dann der jeweilige Auslöser angegeben, also z.b. Timer0-Overflow.

Wie genau der Timer (und auch alle andere Hardware) eingestellt / aufgesetzt werden muss, erfährst du im DB. Im Prinzip musst du nur die Register richtig setzen und in deinem Fall noch die Interrupts global aktivieren. Dann wird bei erreichen eines bestimmten Zustands (z.b. Ovf) in die jeweilige ISR gesprungen, der Code darin abgearbeitet und anschließend gehts da weiter, wo vorher unterbrochen wurde.

Gruß
Chris

ooweberoo
27.02.2014, 22:06
:confused:

ah ok nicht Signal sondern ISR.... Es wird ein Unterprogramm durch einen Pointer aufgerufen welches eine Syntax abarbeitet..ok.

Den Code in die "int main (void)"- Schleife? Komisch das ist in den Tutorial nie so, sondern immer davor.

Wie man die Register richtig setzt ist die golden Frage! Das Datenblatt ist eig. unbrauchbar.

Mit dem Datenblatt arbeite ich die ganze Zeit. Die Befehle und Bezeichnungen die dort stehen erzeuge Fehler im AVR Studio. Dort ist nicht ein einziges Syntax- Beispiel für Timer oder anders....

Hier mal der Auszug zum Them CTC Mode aus dem original ATtiny84 Datenblatt:

In Clear Timer on Compare or CTC mode (WGM02:0 = 2), the OCR0A Register is used to
manipulate the counter resolution. In CTC mode the counter is cleared to zero when the counter
value (TCNT0) matches the OCR0A. The OCR0A defines the top value for the counter, hence
also its resolution. This mode allows greater control of the Compare Match output frequency. It
also simplifies the operation of counting external events.

Als könnte man jetzt einen Code daraus erzeugen :mad: (als Anfänger). Das sind nur grobe Funktionserklärungen im Datenblatt sonst nix:(.

Trotzdem danke ersmal Chris....

Also kann mir jemand schreiben wie der Code aufzubauen ist?

oberallgeier
27.02.2014, 22:48
... Das Datenblatt ist eig. unbrauchbar ...Stimmt. Mal was Anderes: ich setze Dich in einen Airliner und geb Dir das Betriebshandbuch. Du wirst es als unbrauchbar wegwerfen - und das Ding nicht in die Luft kriegen. Dagegen ist ein CPL-Pilot meist in der Lage ohne Einweisung mit einem nicht gerade ungebräuchlichen Jet mit Hilfe des Betriebshandbuchs in die Luft zu gehen. Tut er aber nicht - er holt sich ne Einweisung. Die brauchst Du auch: ins Datenblatt, ins Programmierhandwerk etc.

Beispiel: der Code im Datenblatt ist möglicherweise nicht für den Compiler, den Du verwendest. Oder es sind eben nicht alle notwendigen Initialisierungen drin. Das Datenblatt ist sowieso schon sooo lang, oder? UND es wendet sich eigentlich nicht an Anfänger. Sorry, das soll nicht ätzend sein, soll Dich nicht entmutigen, es ist einfach so.


... kann mir jemand schreiben wie der Code aufzubauen ist? ...Das kann schätzungsweise jeder Zweite hier - denke ich. Und als kleine Hilfe für Dein Problem lege ich einen kompletten, lauffähigen Code für nen tiny13 dazu, bei dem der Timer zum Blinken einer LED eingesetzt wird. IDE dafür ist AVR-Studio4. Erklärungen stehen im Kommentar des Codes. Mehr schreibe ich hier nicht dazu.

Du solltest vermutlich das eine oder andere Tutorial noch durchgehen, dann ein KLEINES Programmschnippsel Dir irgenwo abschreiben, modifizieren, schaun ob was rauskommt ausser Fehlermeldungen etc etc. Die nicht unübliche Vorgehensweise eines Anfängers. Und - Timerprogrammierung ist schon eher fortgeschrittenes Können bei den AVR´s.


/* >>
Stand ...\...\LED_B3.c x20 21Jan14 2340
x20 21Jan14 2340 Timernutzung für Sound zusätzlich auf PB0 mit PWM
================================================== ============================= =
Target MCU : ATTiny 13
Target Hardware : Experimentierplatine tiny13
Target cpu-frequ. : Interner Oszillator (9,6 MHz)
================================================== ============================= =
*** Aufgabenstellung : LED auf Port PB3 blinkt z.B. 1 Hz, Sound auf PB4
Taktgeber durch Timer-ISR, Variation der Timerparameter
================================================== ============================ */
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h> // Für Interruptbehandlung nötig

// CPU Frequenz
#define F_CPU 9600000UL
// Setze Bit
#define SetBit(ADDR,BIT) ((ADDR) |= (1<<(BIT)))
// Lösche Bit
#define ClrBit(ADDR,BIT) ((ADDR) &= ~(1<<(BIT)))
// Toggel Bit
#define ToggleBit(ADDR,BIT) ((ADDR) ^= (1<<(BIT)))

// - - - - - - - - - - - - - - -
// Grüne LED auf Port PB3
#define L1G 3
// Anmerkung: die LED-Schaltung ist GND-Kathode-LED-Anode-Portpin

volatile int16_t Izeit_1; // Wertbereich int16: 32.767. uint16: 65.535
volatile int16_t ZHorznt; // Wertbereich int16: 32.767. uint16: 65.535
volatile int16_t Sekundn; // Zähler für Sekunden

// - - - - - - - - - - - - - - -
// Funktionsprototypen
void wms(uint16_t v) ; // Waitroutine (Controller zählt nur vor sich hin)
void TC0TMR_init(void) ; // Init Tmr/Cntr 0, 8-Bit auf 20 kHz = 50 µs
ISR(TIM0_COMPA_vect) ; // Vektor 7, Prog.Addr. 0x0006

// ================================================== =========================== =
// ================================================== =========================== =


// ================================================== =========================== =
// ===== Subroutinen ================================================== ======= =
// ================================================== =========================== =
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// PROCEDURE wms()
// - Warteroutine die NUR Zeit vertrödelt; Controller zählt runter bis Null
// PARAMETER
// - I uint16_t Wartezeit in Millisekunden
// Die geforderte Zeit ist i.A. nur ungefähr!
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void wms(uint16_t ms) // Waitroutine (Controller zählt runter bis Null)
// - - - - - - - - - - - - - - - -
{ //
for(; ms>0; ms--) //
{ //
uint16_t __c = 2395; // Anpassung an 9,6 MHz
__asm__ volatile ( // Beginn Assembler Routine / nicht optimieren
"1: sbiw %0,1" "\n\t"
"brne 1b"
: "=w" (__c)
: "0" (__c)
);
}
} // Ende void wms(uint16_t ms)
// ================================================== =========================== =


// ================================================== =========================== =
// === Initialisierung des Timer0 tiny13 für CTC
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TC0TMR_init(void) // Init Tmr/Cntr 0, 200µs bei 9,6 Mhz = 5kHz
// - - - - - - - - - - - - - - - -
{ //
TCCR0A |= (1<<WGM01); // Timer im CTC-Mode, Top=OCR0A 73
TCCR0B |= (1<<CS01); // Prescaler 8 => Clock = CPUclk/8 74
OCR0A = 239; // Preset 239 für 200µs bei 9,6 Mhz
// 200 µs <=> 2,5 kHz
TIMSK0 |= (1<<OCIE0A); // Tmr/Cntr0 CompareA interrupt enabled
} // Ende void TC0TMR_init(void)
// ================================================== =========================== =


// ================================================== =========================== =
// === Nicht unterbrechbare ISR für timer0
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ISR(TIM0_COMPA_vect) // Vektor 7, Prog.Addr. 0x0006
// - - - - - - - - - - - - - - - -
{ //
Izeit_1 --; // ###>>> Izeit_1 ist aktuell int16_t ==>>
// bleibt im Wertebereich < 32.767
ToggleBit (PORTB, 4); // .. Audioport toggeln
if ( Izeit_1 ) // Interrupt-Timer = 1 ... 40 000 ... (1 sec blink)
{ } // WENN Izeit_1 =|= Null => wahr => Anweisung ausgeführen
else // Izeit_1 = Null = unwahr, daher "else" ausführen
{ // Eine Sekunde ist voll =>
Izeit_1 = ZHorznt; // .. daher: Rückstellen auf Zeithorizont
ToggleBit (PORTB, L1G ); // .. und LED toggeln
Sekundn ++; // "Sekundencounter" hochzählen
} // Ende if (Izeit_1 )

return;
} // Ende ISR(TIM0_COMPA_vect)
// ================================================== =========================== =
// ================================================== =========================== =


// ================================================== =========================== =
// ===== ENDE Subroutinen ================================================= =
// ================================================== =========================== =


// ================================================== =========================== =
// === HAUPTProgramm ================================================== ======== =
// FUNCTION main()
// - Initialisierungen
// - LED kurzblinken als Signal für Programmstart
// - Pause 100 ms ohne Aktion
// - Hauptschleife

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int main(void) // Hauptprogramm
{ //
// - - - - - - - - - - - - - - -
// Variablendefinition
uint16_t i; // Zählvariable
uint16_t ton; // Zählvariable

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// === Grundlegende Initialisierungen der Hardware, Portdefinition
//PCINT5,/RESET,ADC0,dW PB5 1 8 Vcc
// PCINT3,CLKI,ADC3 PB3 2 7 PB2 SCK,ADC1,T0,PCINT2
// PCINT4, ADC2 PB4 3 6 PB1 MISO,AIN1,OC0B,INT0,PCINT1
// GND 4 5 PB0 MOSI,AIN0,OC0A,PCINT0
// - - - - - - - - - - - - - - -
// Portbelegung und Initialisierung der Anschlüsse :
// /RESET PB5 1 A + 28 Vcc
// L1G PB3 2 A A 27 PB2 nc
// Piezo1 PB4___3 A A 26___PB1 nc
// Piezo GND 4 - A 25 PB0 nc
// - - - - - - - - - - - - - - -
// Portkonfiguration
// Ports+Pins als Ein- (0) oder Ausgänge (1) konfigurieren, Pull Ups (1) aktiv.
// A = Ausgang, E = Eingang ohne , EU = Eingang MIT PullUp
DDRB = 0b11111111; // siehe aktuell oben
PORTB = 0b00000000; // und Port/Pull Ups (1) aktivieren
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

TC0TMR_init (); // Initialisierung des Timers
sei(); // Interrupts zulassen

// ================================================== =========================== =
// Es folgt das eigentliche "Hauptprogramm" mit den Aktionen
// ================================================== =========================== =

// Einstellen der Werte
ZHorznt = 5000; // Zeithorizont einstellen
Izeit_1 = ZHorznt; // Zeithorizont für Timer übernehmen
Sekundn = 0; // Boardzeit initialisieren
// Eine kurze Zeit Dauerton
while (Sekundn < 5) // Schleife ca. x sec
{ //
} // Ende while ( Sekundn < ...


// - - - - - - - - - - - - - - - -
// Jetzt Ton ab- und anschwellend
cli();
ZHorznt = 5000; // Setze Zeithorizont
Sekundn = 0; // Sekunden zurücksetzen
sei();
i = 0; // Schleifenzähler setzen
ton = OCR0A; //
while ( Sekundn < 10 )
{
for (i = 0; i<50; i++) //
{ //
ton--; // Ton tiefer stellen
OCR0A = ton; //
wms ( 10);
} //
for (i = 0; i<50; i++) //
{ //
ton++; // Ton hochdrehen
OCR0A = ton; //
wms ( 10);
} //
} // Ende while ( Sekundn < 10 )

// - - - - - - - - - - - - - - - -
// Konstanten Ton einschalten
cli();
ZHorznt = 5000; // Setze Zeithorizont
Sekundn = 0; // Sekunden zurücksetzen
sei();
// Eine kurze Zeit Dauerton
while (Sekundn < 5) // Schleife ca. x sec
{ //
} // Ende while ( Sekundn < ...

// - - - - - - - - - - - - - - -
// Zum Abschluss wieder Sirenentöne ab- und anschwellend
i = 0; // Schleifenzähler setzen
//ton = OCR0A; //
ton = 255; //
while ( 1 )
{
for (i = 0; i< 100; i++) //
{ //
ton--; // Ton tieferstellen
OCR0A = ton; //
wms ( 20);
} //
for (i = 0; i< 100; i++) //
{ //
ton++; // Ton hochdrehen
OCR0A = ton; //
wms ( 20);
} //
} // Ende while ( 1 ...

// - - - - - - - - - - - - - - -
return 0; //
} //
// ===== Ende
// ================================================== =========================== =
// ================================================== =========================== =Diesen Code hatte ich extra für ne Anfängerschulung geschrieben. Die Leute hatten davor schon ein paar wenige Stunden Einweisung hinter sich.

Und natürlich wünsche ich Dir viel Erfolg. Und Geduld.


Nachtrag: der tiny84 hat Prescaler. Für den Timer0 beispielsweise siehe Documentation 8006K–AVR–10/10, Seite 84.

Nochn Nachtrag:
... Datenblatt ist eig. unbrauchbar ... Mit dem Datenblatt arbeite ich die ganze Zeit ...
... #define F_CPU 1000000UL //max. Takt ATtiny84 ...Auf Seite 1 des Datenblatts steht der maximale Takt des tiny84 mit 20 MHz angegeben . . . Dazu muss natürlich der entsprechende Quarz benutzt werden.

Wsk8
28.02.2014, 09:25
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR

mfg

Besserwessi
28.02.2014, 12:02
Die Sache mit ISR() bzw. der alten Ausführung Signal(...) ist eine Compilerspezifische Erweiterung von C - im C Standard fehlt das einfach.

Die Timer bei den AVRs sind schon recht ähnlich, aber halt nicht alle gleich. Entsprechend unterscheidet sich die Programmierung der Register etwas. Für genau so etwas muss dann auch ein Anfänger mal ins Datenblatt schauen, wenn man nicht gerade den µC nutzt der auch im Tutorial beschrieben wird. Die AVR Datenblätter sind da sogar noch relativ übersichtlich. Wichtig ist vor allem die Registerbeschreibung, also Abschnitt 11.9 im Datenblatt zum Tiny24/44/84. Da findet man dann z.B. Das im Register TCCR0A der CTC Mode ausgewählt werden kann, aber nicht der Prescaler. Der Prescaler steht dann in TCCR0B. Das Register um dann den Interrupt zu Timer0 einzustellen heißt beim Tiny84, wie bei fast neueren AVRs dann TIMSK0.

Für die Anwendung hier ist der 8 Bit Timer 0 sowieso keine gute Wahl ist. Der 16 Bit Timer 1 ist da deutlich besser, weil da die 10000 auch ins Compare Register passen. .

ooweberoo
28.02.2014, 17:53
Hallo,

danke erst mal für euer Info's.

@ oberallgeier = für dass, das hier jeder 2 den Code aufbauen kann tut es aber keiner :( Mit deinem Code kann ich leider nichts anfangen. Zu viel durcheinander drin.
Klar kann der Tiny84 20MHz, aber laut Datenblatt erst ab 4,5V. Ich nutze nur 3V.

@ Wsk8 = Danke für dier Tutorials, werde sie durcharbeiten. Mal schauen ob dich dann schlauer bin...;)

@ Besserwissi = Habe ganz unten im Datenblatt die gesamte Registerbeschreibung gefunden. Wie man so was vermeidlich unwichtiges ganz nach hinten ins DB macht verstehe ich auch nicht.
Deine Angaben kann ich bestätigen. Scheinbar muss man die Register kreuz und quer ohne Sinn verwenden damit man die gewünscht Funktion erhält:mad:

Ich habe aus den Angaben folgenden Code generiert:

#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>

#define F_CPU 1000000UL

unsigned char wert;

ISR(SIG_OUTPUT_COMPARE0B)
{
wert++;
}
//----------------------------
int main(void)
{
TCCR0B= (1<<CS00)&&(1<<CS02)&&(1<<WGM02); CPU Takt/1024
OCR0B= xxx ;
TIMSK0 = (1<<OCR0B);
sei();
wert=0;
//------------------------------
while(1)
{
if (wert=1)
{
DDRA = 0x06;//wenn Zählerwert 1 erreicht ist gib 1 als BCD an 7-Segmentanzeige aus
}
}
//-----------------------------
}

Vergleichswert muss ich noch schaue wie man den angibt. Im Datenblatt steht "(CSn2:0 = 7)" CS = Vergleichswert, n = Variable von 1bis..., aber was 2:0=7 bedeutet weis ich nicht.
Wird ja im Datenblatt nirgends erwähnt was ATMEL's fiktive Rechenoperationen bedeuten.

Kann mir wenigstens jemand sagen wo der Fehler in meinem Code ist?

Wsk8
28.02.2014, 21:51
#include <avr/io.h>
#include <avr/interrupt.h>


#define F_CPU 1000000UL // 1MHz




volatile uint16_t timerVal = 0;




void InitTimer() {
TCCR1B = (1<<WGM12) | (1<<CS12) | (1<<CS10); // CTC Mode, CLK/1024
TIMSK1 = (1<<OCIE1A); // Output Compare A Match Interrupt Enable

OCR1A = 10000; // Top value
}




int main(void) {
timerVal = 0;


InitTimer();


sei();


while(1) {
if(timerVal == 1) {
DDRA = 0x06;
timerVal = 0;
}
}


return 0;
}




ISR(TIMER1_COMPA_vect) {
timerVal++;
}

Mal schnell programmiert, kA obs stimmt.

mfg

Besserwessi
28.02.2014, 22:40
Die Schreibweise mit dem 2:0 steht für die Bits 0 bis 2. In dem Beispiel (CSn2:0 = 7) also das CSn2, CSn1 und CSn0 zusammen als Binärzahl interpretiert 7 ergeben, also alle 3 Bits auf 1.

ooweberoo
28.02.2014, 23:58
Hallo,

@ Besserwissi : Das hört sich plausibel an. Jetzt kann man das auch verstehen. 1, 2, 3 --- BIN 111, DEZ 7, HEX 7. Komische das so zu schreiben aber Ok;) Danke

@ Wsk8: Danke erstmal für den Code. Hab in bei meinem ATtiny ausprobiert aber leider ohne Funktion. Keine Fehler im Code aber eine Warnung "TIMER0_COMPA_vect" appears to be
amisspelled Signal handler [enabled by default].

Mittlerweile nach den Tutorials und dem Datenblatt vom ATtiny84 bin ich zu folgender Lösung gekommen (wie macht man das Codefenster?)

8 Bit Timer0, Vorteiler 8, 125ms interupt.

Code:
[-------------------------------------------------------------------------------------------------------------------------
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>

#define F_CPU 1000000UL

volatile unsigned int millisekunden;

int main(void)
{
TCCR0B = (1<<WGM02) && (1<<CS01); // CTC Modus, Vorteiler 8, // ((1000000/8 )/1000) = 125
OCR0B = 125-1; // TCNT0 = OCR0A = 125-1
TIMSK0 = (1<<OCIE0B);
sei();
while(1)
{
}
}

ISR(TIMER0_OVF_vect)
{
millisekunden++;

if(millisekunden == 1000)
{
DDRA = 0x06;
}
}
]------------------------------------------------------------------------------------------------------------------------------------------------

Dieser Coder erzeugt aber auch eine Warnung "TIMER0_OV_vect" appears to be amisspelled Signal handler [enabled by default].

Wenn man nur irgendwo mal ne Lister aller ISR Befehle hätte... kann sein das mein µC den Befehl nicht bearbeiten kann oder so.

Wenn ich nur wüsste ob TCCR0B & OCR0B zueinander stimmen den im Netz wird TCCR0A verwendet???

Gibt es den Timer0 A und Timer0 B?

Kann jemand nochmal helfen;) ???

Verstehe es nicht ](*,) :MistPC :-k

?????????????????

Wsk8
01.03.2014, 00:05
Keine Fehler im Code aber eine Warnung "TIMER0_COMPA_vect" appears to be amisspelled Signal handler
In meinem Code gibts aber kein "TIMER0_COMPA_vect"


wie macht man das Codefenster?
Im Editor "#" anklicken

Da in deinem Code auch nichts initialisiert ist, wirst du auch vermutlich nichts sehen. LED etc um eine Änderung wahrzunehmen wäre nicht schlecht...

mfg

Besserwessi
01.03.2014, 10:24
Die Liste der zur verfügung stehenden Interruptvektoren steht bei GCC in den µC spezifischen files, die über eine paar Umwege (den µC aus der Umgebungsvariable suchen) eingebunden werden, über #include <avr/io.h>

Für den Tiny84 ist das File
iotnx4.h Im Verzeichnis von GCC avr/Include/avr/ - die Interruptvectoren stehen ganz unten im File.

Der gesuchte ist hier TIM0_COMPA_vect bzw. TIM0_OVF_vect . Wieso da jemand die Namen ander als etwa beim Mega32 gewählt hat, kann ich auch nicht sagen - ist irgendwie unpraktisch.

Wsk8
01.03.2014, 13:27
Die Liste der zur verfügung stehenden Interruptvektoren steht bei GCC in den µC spezifischen files, die über eine paar Umwege (den µC aus der Umgebungsvariable suchen) eingebunden werden, über #include <avr/io.h>

Für den Tiny84 ist das File
iotnx4.h Im Verzeichnis von GCC avr/Include/avr/ - die Interruptvectoren stehen ganz unten im File.

Der gesuchte ist hier TIM0_COMPA_vect bzw. TIM0_OVF_vect . Wieso da jemand die Namen ander als etwa beim Mega32 gewählt hat, kann ich auch nicht sagen - ist irgendwie unpraktisch.
Wie gesagt habe ich den Code ohne Hilfestellung nur schnell in nem Editor geschrieben. Ich weiß leider auch nicht alles auswendig.

mfg

derNeue
02.03.2014, 17:01
Verstehe es nicht ](*,) :MistPC :-k

?????????????????


Ich finde, du musst viel ruhiger werden. Oberallgeier hat dir so ein top Beispiel gegeben. Versuch das doch einfach mal zu verstehen. Druck es aus, wenns dir hilft, lösche halt die Zeilen raus, die dich stören, aber versuche zu verstehen, was dort eigentlich passiert. Hier alles mit unbrauchbar zu betiteln, nur weil es nicht speziell für dich geschrieben ist, ist schon ziemlich anmaßend. So viele Leute, die mit den Datenblättern zurecht kommen und es stimmt, AVR Datenblätter sind ansich gut aufgeräumt. Versuche einfach mal den Code von Oberallgeier zu verstehen, versuche herauszufinden, welche Infos er aus dem Datenblatt hat, und wo sie stehen. Wenn du einzelnes nicht findest, darfst du hier gern nachfragen, da gibt es dann Hilfsbereite, die dir sagen, wo du es findest. Und ganz schnell wirst du feststellen, das alles doch ganz logisch aufgebaut ist. C hat mit AWL einer sps nunmal rein gar nix zu tun. Evtl hilft es auch, wenn du erstmal ein reines C-Tutorial ansiehst, zumindest die ersten paar Themen, das du erstmal C-spezifische Dinge verstehst, und dann später kannst du dich mit den Besonderheiten des C eines AVR's bekannt machen.


Der gesuchte ist hier TIM0_COMPA_vect bzw. TIM0_OVF_vect . Wieso da jemand die Namen ander als etwa beim Mega32 gewählt hat, kann ich auch nicht sagen - ist irgendwie unpraktisch.

Die Begriffe sind auch im Datenblatt zu finden, unter der Kategorie Interrupts. Es war also Atmels Idee mit den unterschiedlichen Namen.


Dennis

ooweberoo
04.03.2014, 09:49
Hallo,

@Wsk8: Zunächstmal Danke aber ich kann kein # finden. 27665 hier mal ein Bild von meinem Editor Menue. Wo ist da die Raute?
Mein AVR Studio schlägt mir immer "TIMER0_COMPA_vect" vor, dachte dann würde es den Befehl auch geben. Aber dein Timer Beisiel war trotzdem sehr
hilfreich für mich\\:D/.

@Besserwissi: Danke für die info. Bei mir muss das ein anderer Ordner sein, diese Verzeichnisse gibt es bei mir nicht:( TIM0_COMPA_vect bzw. TIM0_OVF_vect
erzeugt gerade keine Fehler oder Warnungen. Ich probiere und melde mich dann nochmal. :pray:Danke !

@derNeue: Danke! Ja es ist ein sehr gutes Programm.

oberallgeier
04.03.2014, 14:52
... ich kann kein # finden ...
Es ging um Deine Frage wie ein Codefenster aufgemacht wird.

Dies ist ein CodefensterKollege Wsk8 hatte Dir dazu geraten "Im Editor "#" anklicken".

Es gibt in meinem Browser bei seiner Funktion als Beitragseditor fürs Forum in der zweiten von drei Befehlszeilen ganz rechts die Buttons [#] [<>] und [php]. Dies gilt für die "Standardansicht" - wenn im Fenster "Direkt antworten" nur eine Befehlszeile offen ist, dann rechts unten auf [Erweitert] drücken. Und dieses "#" hatte WSK8 gemeint *gg*.


... Mein AVR Studio schlägt mir immer "TIMER0_COMPA_vect" vor ...Dann ist möglicherweise im Studio der falsche Controller angewählt oder sonst etwas nicht im Lot; im Datenblatt zum tiny84, doc 8006K–AVR–10/10, Seite 48, stehen nämlich als Vector 10 und 12 in der Spalte Source genau diese ISR-Adressen.

ooweberoo
04.03.2014, 17:15
@ oberallgeier: achso:oops:... bei erweitert wie versteckt. Naja wenigstens weis ich jetzt um die ISR Befehle... aber der entweder der Timer 0 wird nicht aktiviert oder der Interupt funktioniert nicht.


#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>

#define F_CPU 1000000UL

volatile unsigned int millisekunden;


//-------OB1--------------------------------------------------------------------------------------------------------------------

int main(void)
{
//---8 Bit Timer CTC Modus---

TCCR0B = (1<<WGM02) && (1<<CS01); // CTC Modus, Vorteiler 8, // ((1000000/8)/1000) = 125
OCR0B = 125-1; //TCNT0 = OCR0A = 125-1
TIMSK0 = (1<<OCIE0B); // Interups EIN
sei();

while(1)
{

}
}

//------DB1------------------------------------------------------------------------------------------------------------------------

ISR(TIM0_COMPA_vect)
{
millisekunden++;

if(millisekunden == 200)//1000
{
DDRA = 0x06;
}

}



weis auch nichtmehr weiter.... je länger ich schau desto verwirrter werde ich...TCCR0B = (1<<WGM02) stimmt das nun, oder doch TCCR0A = (1<<WGM01) :MistPC

vielleicht sollte ich doch den 2313 bestellen, mit dem arbeiten wenigstens Leute die dann eventuell schon wissen wie die Timer dort funktionieren.. :MistPC <<<der ist so geil...

oberallgeier
04.03.2014, 19:24
... Du solltest vermutlich das eine oder andere Tutorial noch durchgehen ...Und, tust Du das? Ich denke nicht, ich glaube dass Du nur abschreibst - und das noch dazu falsch. Trotzdem mal ein Punkt zur Hilfe:

...
...
TCCR0B = (1<<WGM02) && (1<<CS01); // CTC Modus, Vorteiler 8, // ((1000000/8)/1000) = 125
...
TIMSK0 = (1<<OCIE0B); // Interups EIN
...
//------DB1------------------------------------------------------------------------------------------------------------------------
ISR(TIM0_COMPA_vect)
{ ...
}
...Der Kommentar zu TIMSK0 ist falsch. Ich meine nicht die Rechtschreibung sondern der Plural. Es wird nur EIN Interrupt frei eingeschaltet, der von Kanal B. Deshalb tut sich nix bei Deiner Interruptroutine für den Kanal A *ggg*. Wie leider oben gesagt - abgeschrieben, aber vermutlich nix gedacht. Mehr schreibe ich nicht, denn Du meinst ja, mit meinem Code kannst Du "leider nichts anfangen. Zu viel durcheinander drin". Aber der Code funktioniert bestens *gg*.


... vielleicht sollte ich doch den 2313 bestellen ...Der programmiert sich auch nicht von selbst! Deshalb fürchte ich, dass Du bei dem mit Deiner gegenwärtigen Programmiermethode (bzw. Deiner Abschreibetechnik) auch auf die Nase fällst. Und - das täte mir dann doch leid.

Wsk8
04.03.2014, 20:03
int main(void) {
TCCR0A |= (1<<WGM01); // CTC Modus
TCCR0B |= (1<<CS01); // Vorteiler 8
OCR0A = 125-1; // ((1000000/8)/1000) = 125
TIMSK0 = (1<<OCIE0A); // Interups EIN
sei();

while(1) {}
}



mfg

ooweberoo
05.03.2014, 12:21
Hallo,

@ oberallgeier: ziemlich voreingenommen zu behaupten ich würde nur abschreiben. Ich habe das Tutorial hier, auf Microcontroller.net und
andere gemacht. Überall ist es anders. Jeder verwendet einen andern Chip und zufälligerweise keiner den 84er.
Den Befehl " TIMSK0" habe ich aus meinem Datenblatt da in diesem Register das Bit "OCIE0B" existiert. Das es Falsch ist
konnte ich nicht ahnen, wie auch wenn es so in den Tutorials angegeben ist.
Ich meinte ja nur das es im Netz eher Hilfe zum 2313er gib als vom 84er.

@ Wsk8: Danke dir. Aber so wie du das geschrieben hast setze ich im Register (TCCR0A) von Timer 0 den
CTC- Modus und im Register (TCCR0B) von Timer 0 die entsprechenden Vorteilerbits ???

Im Microcontroler.net wird ein 2313 verwendet und hier im Tutorial ein mega32. Habe mich halt an die Tutorials gehalten und die Registerbezeichnungen vom 84 eingesetzt. Wenn das dann nicht hinhaut liegt das bestimmt nicht daran das ich nicht nachdenke. Wollte lediglich etwas Hilfe.
Zudem was soll mir ein Programm bringen in dem auch ein 2313 verwendet wird??? Da bin ich genauso nass wie in den Tutorials.
Dann sollte man ein Tutorial für alle chips machen. Aber mich nicht anhauen weil ich Tutorials falsch interpretiere.


Mal der Code aus dem Roboternetz Tutorial hier:



/* Es wird der Timer2 (8-Bit) eines ATmega32 verwendet, der mit einem Quarz
mit 7,3728 MHz betrieben wird. Im Abstand von 0,01 ms erzeugt der Timer
einen Interrupt, also eine Frequenz von 100000 Hz (oder 100 kHz).
Der Timer wird auf einen Prescaler von 1 und einem OCR2-Wert von 73 konfiguriert. */

volatile uint8_t countTimer2; // Speichert den aktuellen Zählerwert

SIGNAL(SIG_OUTPUT_COMPARE2)
{
countTimer2++;
}

// Initialisierung:
TCCR2 = (1<<CS20) | (1<<WGM21); // Prescaler von 1 | CTC-Modus (siehe unten für Beschreibung)
OCR2 = 73; // Vergleichswert
TIMSK |= (1<<OCIE2); // Interrupts aktivieren und damit Timer starten
sei();

// Funktionen zum benutzen der Timer:
/** Diese Funktion nicht aufrufen. Wird von sleep_millisec aufgerufen.
Bei t=100 schläft die Funktion 1 ms. */
inline void sleep(uint8_t t)
{
// countTimer2 wird in der ISR oben inkrementiert
countTimer2 = 0;
while (countTimer2 < t);
}

/** Schläft x-Millisekunden. */
inline void sleep_millisec(uint16_t msec)
{
uint16_t i;
for(i=0; i<msec; i++) {
sleep(100);
}
}
--------------------------------------------------------------------------------



Ich wollte zufällig die gleiche Funktion wie im Beispiel. Das dann an dem Code alles falsch ist kann ich ja nicht wissen.

Falsch bei mir war : ISR statt SIGNAL, SIG_OUTPUT_COMPARE2 war auch falsch, statt TIMSK sthet bei mir TIMSK0, auch falsch,
statt OCR2 muss ich TCCR0A oder TCCR0B verwenden....
Also werde ich es mal mit den 2 Registen getrennt versuchen (TCCR0A &&TCCR0B)..... Mal sehen...

Danke :MistPC

Wsk8
05.03.2014, 13:10
@ Wsk8: Danke dir. Aber so wie du das geschrieben hast setze ich im Register (TCCR0A) von Timer 0 den
CTC- Modus und im Register (TCCR0B) von Timer 0 die entsprechenden Vorteilerbits ???

Hast du dir das Datenblatt überhaupt mal angesehen??
27674

Hier ist alles eigentlich Idiotensicher aufgelistet.

Im Table 11-8 gibts nur einen CTC-Mode und hier ist nur das WGM01-Bit gesetzt. Keine Ahnung wie du hier auf was anderes kommen kannst. Und hier steht auch, dass der MAX Value im OCRA steht. WGM00 und 02 sind "0" und müssen daher nicht beachtet werden. Keine Ahnung warum du hier den Reserved Mode wählst, ergibt für mich keinen Sinn.

Zudem hab ich dir bereits einen zu 100% funktionierenden Code gepostet mit kurzer, prägnanter Erklärung. Vlt. solltest du den einfach 1 zu 1 kopieren, denn wie von Vorredner bereits gesagt, hast du es noch nicht mal geschafft andere Codeschnitzel richtig abzuschreiben und noch mehr Fehler eingebaut.

Und um µC zu programmieren, muss man gute C-Kenntnisse besitzen. Nur leider wird C nicht zu Unrecht als "Hochsprache" bezeichnet und ist nicht Vergleichbar mit SPS, dass jeder mal in nem 2 Tage Seminar locker lernt. Das braucht Jahre!!

mfg

ooweberoo
05.03.2014, 19:33
Hallo,

nein das habe ich jetzt zum ersten mal gesehen.
Ich habe mich an das gehalten
27676
und an
27677

http://www.ne555.at/atmel-avr-mikrocontrollertechnik/352.html
http://www.physik.uni-regensburg.de/studium/edverg/elfort/C_KURS_Atmel_Programmieren%20htm/Timer_Counter.htm
http://www.mikrocontroller.net/articles/Uhr
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR

Speziel an den ersten link hab ich mich gehalten.... dort wird es halt mit "CS02" gemacht.

Zudem bleib bitte sachlich ! behaltet euere inkompetenten äußerungen für euch=;.

weis nicht wieso ihr mich so angeht....wo liegt das problem?

ich beschäftige mich mit der sache und stelle sachliche fragen und bedanke mich auch jedesmal.....

echt das ist ganz unterste schublade....

derNeue
05.03.2014, 20:14
http://www.mikrocontroller.net/articles/FAQ#Timer

Dieser Artikel ist wirklich top geschrieben. Ich hatte am Anfang auch meine Probleme mit dem Datenblatt, aber eher, weils englisch ist. Dieser Artikel ist in deutsch geschrieben, und sehr anfängertauglich.

Auch SPS lernt man nicht in zwei Tagen, das wirst du wohl gut wissen, zumindest wenn man den vollen Funktionsumfang einer SPS nutzen will. Ist mit den Controllern nicht anders. Ich habe mich am Anfang gewundert, wie manch einer aus einem Attiny unglaublich viel rausgeholt hat. Gerade Interrupts sind eigentlich nicht ein Thema, mit dem man beginnt. Ich denke, du willst einfach zuviel auf einmal. Klar isses am Anfang affig, eine LED zum blinken zu bringen. Da fragt man sich schon erstmal, was das bringen soll. Aber damit lernst du einfach die Grundlagen, die du nicht wirklich bereit bist, zu lernen. Es reicht nicht, ein tutorial einfach mal grob durchzulesen. Versuche, die Beispiele zu verstehen, versuche die Beispiele zum laufen zu bekommen. Wenn das klappt, mach einfach mal ein paar Änderungen am Code. Wenns danach nicht mehr läuft, versuch zu verstehen, warum das so ist und bring deinen geänderten Code zum laufen. So und nicht anders wirst du Erfolg haben. Du musst ganz einfach anfangen, und zwar mit eigenem Code. Und dann freut man sich, wenn eine LED leuchtet, wenn man den Taster drückt. Wenn du den Luxus einer SPS haben willst, dann bleib dabei, den wirst du bei einem Controller nicht bekommen.


Dennis

ooweberoo
05.03.2014, 22:30
Hallo Dennis,

ich muss dir voll zustimmen. Danke das du erwähnst das das SPS programmieren ebenfalls nicht einfach ist:rolleyes:.

Hab das mit den LED's usw. auch alles schon durch... sogar multiplexen war machbar....oder switch case statt die If Then Else Funktion... Die 7- Segmentanzeige hoch und runterzählen ging auch....
Nur die Sache mit dem Timer hat mich verzweifeln lassen.... lag auch daran das die Tutorials und die Beispielprozessoren unterschiedlich sind. Des Weiteren ist Englisch auch nicht meine Stärke was
das ohnehin komplexe Datenblatt noch komplexer werden lies. Der hellste bin ich auch nicht:Haue
Gerade bei den Timern muss man die richtigen Register wählen.
Aber trotzdem besteht noch Übungsbedarf, daher geht es weiter mit Tutorials und Übungen...
Eigene Codes habe ich schon viel, vielleicht eher einfach was Profis zum lachen bringt:lol: aber voll funktionsfähig...
Momentan beschäftige ich mich mit array und Pointern um Programme kürzer zu gestalten...

Danke erstmal für deine / euere Hilfe!

derNeue
06.03.2014, 14:50
Das Datenblatt ist schon komplex, keine Frage, aber ist auch logisch aufgebaut. Und da gibts auch für jeden Timer eine extra Kategorie, die du im Inhaltsverzeichnis des PDF anwählen kannst. Und am Ende dieser Kategorie gibts die Überschrift Register-Description, wurde hier schon von jemanden erwähnt und von dir ganz schnell ignoriert. Dort findest du alles wichtige zu den Registern nochmal zusammen gefasst. WEnn du nicht weist, was irgend ein Bit in so einem Register nun genau macht, hilft nur den Text davor lesen, da stehts genauer.


Dennis

ooweberoo
12.03.2014, 19:35
Hallo zusammen,

bin bis auf einige Feiheiten bei den Kommentaren soweit fertig.

Was haltet ihr von diesem Uhrprogramm für 2 BCD Anzeigen. Zuerst eine Einleitshow, danach die Stunden für ca. 3 Sek und

dann die Minuten für 3 Sek. und zuletzt wieder alles aus bis zum nächsten Knopfdruck.

Nochmal ! Danke ! an alle die mir mit dem Timer geholfen haben! Als Verbesserung kommt eventuell noch ein Quarz dazu.



#include <stdlib.h>
#include <avr/io.h> // Makefile ATtiny 84
#include <avr/interrupt.h> // Datei für Interrupts
#define F_CPU 1000000UL // Prozessortakt festlegen
#include <util/delay.h> // Datei für Wartezeiten,immer nach CPU Takt einfügen


//---- Variablen deklarieren ----
volatile unsigned int Millisekunden;
volatile unsigned int Stundenzehner;
volatile unsigned int Stundeneiner;
volatile unsigned int Minutenzehner;
volatile unsigned int Minuteneiner;
volatile unsigned int Sekunden;
volatile unsigned int Tagessekunden;


int i, t, e;




//---- Hauptprogramm -------------------------------------------------------
int main(void)
{

//---------------------------------------------------------------------------------------------------------
//---8 Bit Timer CTC Modus aktivieren---------------------------------
TCCR0A |= (1<<WGM01); // im TCCR0A Register Bit für CTC Modus setzen
TCCR0B |= (1<<CS01); // im TCCR0B Register das entsprechende Bit für Vorteiler 8 setzen
OCR0A = 125-1; // Überlaufwert festlegen im Register OCR0A max. Wert 255 Bit., entsprechend berechnen für die gewollte Zeit
// 1.000.000Hz/8=125.000, 125.000Hz/125=1.000Hz, T=1/f = 1/1000Hz =0,001 Sekunden
// Beim erreichen von 125 wird ISR(TIM0_COMPA_vect)ausgeführt, und somit die Variable "millisekunden" um 1 erhöt, nach 1000 Ausführungen ist 1 Sekunde vergangen!
TIMSK0 = (1<<OCIE0A); // Interupsfunktion einschalten
sei();
//----------------------------------------------------------------------------------------------------------------------
//---- Uhr stellen--------------------------------------------------

Stundenzehner = 0;
Stundeneiner= 0;

Minutenzehner = 1;
Minuteneiner= 1;

Millisekunden= 0;
Sekunden = 0;

Tagessekunden = (Stundenzehner*36000)+(Stundeneiner*3600)+(Minuten zehner*600) +(Minuteneiner*60);
//-----------------------------------------------------------------------------------------------

t=3; //Wert der Variablen für Einleitshow vordefinieren
i=0;


//---------------------------------------------------------------
//---- Endlosschleife---------------------------------------------------
while(1)
{




if ( PINA & (1<<PINA7) ) //Wenn Pin PA7=1 dann zeige Uhrzeit sonst....
{
//----- Kleine LED Show vor der Zeitanzeige-------------------------------------------
while (i !=t) //Schleife 5 mal durchlaufen
{PORTB=0x3;
//Start show
DDRB = 0x01;
DDRA = 0x01;
_delay_ms(100);
DDRA = 0x02;
_delay_ms(100);
DDRA = 0x04;
_delay_ms(100);
DDRA = 0x08;
_delay_ms(100);

DDRB = 0x02;
DDRA = 0x08;
_delay_ms(100);
DDRA = 0x010;
_delay_ms(100);
DDRA = 0x20;
_delay_ms(100);
DDRA = 0x01;
_delay_ms(100);
i=i+1;}
//----------------- show Ende --------------------------------------------------------------------------------------
//
//----------------------------------- Zeit anzeigen Stunden ---------------------------------------------------------------
while (e !=300)
{
//---- Multiplexen ----------------------------------------------------------------------------------------------
PORTB=0x3; // Pull up Widerstände an Port B PB0+PB1 aktivieren. Ausgänge geben nun 5V aus.
DDRB = 0x01;

switch(Stundenzehner)//----- Ausgabe der Stundenzehner Segment 1 -----
{case 0: DDRA = 0x3f; break;
case 1: DDRA = 0x06; break;
case 2: DDRA = 0x5b; break;}

_delay_ms(5);// Multiplexzeit in der DDRB = (1 << DDB0)bzw. PB0 = 1 ist und nur Minutenzehner ausgegeben werden

//---- Multiplexen --------------------------------------------------------------------------------------------
PORTB=0x3; // Pull up Widerstände an Port B PB0+PB1 aktivieren. Ausgänge geben nun 5V aus.
DDRB = 0x02;

switch(Stundeneiner)//----- Ausgabe der Stundeneiner Segment 2 -----
{case 0: DDRA = 0x3f; break;
case 1: DDRA = 0x06; break;
case 2: DDRA = 0x5b; break;
case 3: DDRA = 0x4f; break;
case 4: DDRA = 0x66; break;
case 5: DDRA = 0x6d; break;
case 6: DDRA = 0x7d; break;
case 7: DDRA = 0x07; break;
case 8: DDRA = 0x7f; break;
case 9: DDRA = 0x6f; break;}

_delay_ms(5);// Multiplexzeit in der DDRB = (1 << DDB1)bzw. PB1 = 1 ist und nur Minuteneiner ausgegeben werden.

e=e+1; // Zählvariable für Schleifendurchlauf, pro Durchlauf um 1 erhöhen.
}

e =0; // Schleifenzähvariablen auf 0 setzen
i = 0;

//----------------------------------- Zeit anzeigen Stunden ---------------------------------------------------------------
while (e !=300)
{
//---- Multiplexen ----------------------------------------------------------------------------------------------
PORTB=0x3; // Pull up Widerstände an Port B PB0+PB1 aktivieren. Ausgänge geben nun 5V aus.
DDRB = 0x01;

switch(Minutenzehner)//----- Ausgabe der Minutenzehner Segment 1 -----
{case 0: DDRA = 0x3f; break;
case 1: DDRA = 0x06; break;
case 2: DDRA = 0x5b; break;
case 3: DDRA = 0x4f; break;
case 4: DDRA = 0x66; break;
case 5: DDRA = 0x6d; break;}

_delay_ms(5);// Multiplexzeit in der DDRB = (1 << DDB0)bzw. PB0 = 1 ist und nur Minutenzehner ausgegeben werden
//--------------------------------------------------------------------------------------------------------------

//---- Multiplexen --------------------------------------------------------------------------------------------
PORTB=0x3; // Pull up Widerstände an Port B PB0+PB1 aktivieren. Ausgänge geben nun 5V aus.
DDRB = 0x02;

switch(Minuteneiner)//----- Ausgabe der Minuteneiner Segment 2 -----
{case 0: DDRA = 0x3f; break;
case 1: DDRA = 0x06; break;
case 2: DDRA = 0x5b; break;
case 3: DDRA = 0x4f; break;
case 4: DDRA = 0x66; break;
case 5: DDRA = 0x6d; break;
case 6: DDRA = 0x7d; break;
case 7: DDRA = 0x07; break;
case 8: DDRA = 0x7f; break;
case 9: DDRA = 0x6f; break;}

_delay_ms(5);// Multiplexzeit in der DDRB = (1 << DDB1)bzw. PB1 = 1 ist und nur Minuteneiner ausgegeben werden.

e=e+1; // Zählvariable für Schleifendurchlauf, pro Durchlauf um 1 erhöhen.
}

DDRA = 0x00;
DDRB = 0x00;
//---------------------------------------------------------------------------------------------------------------
}//if ende

e =0; // Schleifenzähvariablen auf 0 setzen
i = 0;

}// while(1) ende

return 0;

}//int main(void) ende

//--------- Interruptprogramm bzw. Unterprogramm -------------

ISR(TIM0_COMPA_vect)
{
Millisekunden++;

if(Millisekunden == 1000)
{
Sekunden++;
Tagessekunden++;
Millisekunden = 0;

if(Sekunden == 60)
{Minuteneiner++;Sekunden = 0;}

if(Minuteneiner== 10)
{Minutenzehner++; Minuteneiner = 0;}

if(Minutenzehner == 6)
{Stundeneiner++; Minutenzehner = 0;}

if(Stundeneiner == 10)
{Stundenzehner ++;Stundeneiner = 0;}


if(Stundenzehner == 3)
{Stundenzehner = 0;}


if(Tagessekunden == 86400)
{Stundenzehner = 0; Stundeneiner = 0;
Minutenzehner = 0; Minuteneiner = 0;
Sekunden = 0; Millisekunden = 0;
Tagessekunden = 0;}

}
}
//---------------------------------------------------------------------------

derNeue
14.03.2014, 15:16
Ich werf einfach mal folgendes in den Raum, was du einfach mal googlen kannst, Tastenentprellung.

Als weiteres ist es ehrlich gesagt kein schöner Stil, Multiplexen mit delays zu realisieren. Sowas macht man auch in einem Timerinterrupt. Dafür kannst du ja einen anderen nehmen als den, den du bis jetzt schon nutzt. Dazu gibts eigentlich auch den ein oder anderen Code frei im Netz. Einfach mal suchen und schauen, wie das andere gelöst haben. Das hat einen ganz einfachen Vorteil. Bis jetzt änderst du ja einfach nur ein paar Variablen in deinem Interrupt. Aber es gibt ja auch andere Anwendungen für 7-Segment-Anzeigen, wo du in deinem Hauptprogramm auch noch anderen Code ausführen willst. Da kommt es dann mit deiner Methode zu Problemen.


Dennis

ooweberoo
19.03.2014, 19:05
Hallo,

ok, als Anfänger gibt es eben noch viel zu lernen.... ich bin jedoch forh das ich erstmal die gewünschte Funktion umsetzten konnte...

Entprellen wollte ich sowieso, hatte ich vergessen zu erwähnen :o

Ein weit aus größeres Problem stellt für mich der externe Quarz dar. Ich will mich mit falsch gesetzten Fusebits nicht aus dem µC

aussperren. Wollte eine 10MHz Quart mit 2X 22pF Kondensatoren nutzen. Gleicher Takt wie der interne Quarz.

Leider werd ich aus den Fusebits nicht ganz schlau...hab nur ein 8 Bit Fusebit Register....:?

Wenn du dazu vielleicht noch etwas weist ?:oops:

Einmal den Haken falsch gesetzt und das wars dann.... blöde Sache.... so sieht mein Fusebit Register aus!

27809

derNeue
19.03.2014, 19:31
Hallo!


ok, als Anfänger gibt es eben noch viel zu lernen

Das ging allen so. Aber mit der richtigen Fragestellung bekommst du hier auch umfassende Hilfe :-)


Ein weit aus größeres Problem stellt für mich der externe Quarz dar.

Die Frage ist, warum willst du unbedingt einen externen Quarz nehmen? Belasse es doch erstmal bei dem internen, damit kannst du nix verfusen. Ich glaube nicht, dass du schon Anwendungen programmierst, die unbedingt einen externen Quarz benötigen. Oder warum willst du unbedingt einen einsetzen?

Dennis

Wsk8
19.03.2014, 19:34
Du musst ganz unten die richtige Clock auswählen. Bei einem Quarz immer Ext Crystal!
Hier (http://www.engbedded.com/fusecalc) gibts ne Liste, was für 10MHz geeignet ist.

mfg

ooweberoo
22.03.2014, 17:43
Hallo,

@derNeue: Das stimmt, eigentlich brauche ich den Quarz nur der genauen Frequenz wegen. Mein Projekt ist eine 7-Segment Uhr. Und momentan läuft sie ohne
Probleme, geht aber pro Tag ca. 8-10 Minuten nach. Er ist quasi meine Unruh und die muss genau schwingen.

@WsK8: Achso ich muss dan folgendes auswählen :
EXT. Crystal Osc. frequency 8.0- MHz... danach die gleiche Startup- Zeit usw. wie jetzt. Somit steht 8.0-MHz für 8 MHz und mehr also auch 10, 12, 20, 40 ....?:confused: Des Weiterne das Häckchen bei CKDIV8 entfernen wenn ich das richtig gelesen habe???

mfG

derNeue
22.03.2014, 23:57
Hallo!

Okay, für eine Uhr ist das zwar noch etwas anderes, aber ich glaube, da wirst du mit deinem 10MHz Quarz auch noch nicht ganz glücklich. Sicher wird die Abweichung der Uhr nicht mehr so groß sein. Allerdings würdest du mehr Genauigkeit erreichen, indem du einen Uhrenquarz mit rund 32KHz nimmst und damit einen Timer ansteuerst. Der Attiny84 bietet die Möglichkeit, einen Timer mit einer externen Taktquelle zu versorgen. Perfekt für einen Uhrenquarz. Ist zwar wieder etwas neues für dich, aber du möchtest ja lernen hast du geschrieben :) So würde ich das machen und ich habe auch schon am Anfang meiner µC-Zeit eine Uhr gebaut und gedacht, der interne Quarz wird das schon machen. Nur leider war das bei meinem Projekt nicht ganz so einfach, ich hatte nur noch einen Pin frei.


EXT. Crystal Osc. frequency 8.0- MHz... danach die gleiche Startup- Zeit usw. wie jetzt. Somit steht 8.0-MHz für 8 MHz und mehr also auch 10, 12, 20, 40 ....?:confused: Des Weiterne das Häckchen bei CKDIV8 entfernen wenn ich das richtig gelesen habe???

Die Start-up Zeit ist die Zeit, die der Controller benötigt, um selbst hochzufahren. Ich kenne kein Hobbyprojekt, bei dem es auf die ersten µs nach Spannung anlegen ankommt. Deswegen auf der sicheren Seite bleiben und die höchste Zeit wählen, wie warsch jetzt schon auch bei dir gewählt. Die MHz stehen für alle Frequenzen bis zum Maximum, was schon auf der ersten Seite angegeben wird. Ich bin gerade zu faul, das Datenblatt des Attiny 84 zu suchen, was bei diesem angebeben ist. Aber nicht mehr als 20MHz, mehr macht eig kein AVR mit. Das Häckchen CKDIV8 bedeutet einfach nur, dass der Systemtakt nochmal durch 8 geteilt wird, bevor er dem Attiny zuf Verfügung steht. Sozusagen ein Prescaler von 8. Machst du das Häckchen raus, hast du einen Prescaler von 1.


Dennis

ooweberoo
23.03.2014, 18:30
Hallo Dennis,

danke erstmal für deine Meinug und Erfahrungen. Du meinest einen Quarzoszilator statt einen normalen Quarz. Der verbraucht auch nur einen Pin das stimmt.
Mal schauen wie groß der ist da die Uhr ja an den Arm soll:)
32,768KHz habe ich schon oft gelesen wobei ich dachte desto höher der Takt desto höher die Genauigkeit aber auch der Stromverbrauch...
Zudem hätte ich mit 10MHz den gleichen Takt wie jetzt nur genau..... naja ok mal schauen...

Danke dir!

Chris

derNeue
23.03.2014, 19:38
Na auch die externen Quarze haben eine Abweichung, wenn auch nicht so groß, wie der interne des Attiny. Die Uhrenquarze sind eben dafür ausgelegt, die exakte Uhrzeit anzuzeigen. Und du brauchst nicht mehr viel umrechnen, wie bei 10MHz, deswegen diese krumme Frequenz. Wie gesagt, nicht als Hauptquarz die 32,768KHz nehmen, sondern nur als Taktquelle für den Timer, also an die Pins "T1" und "T0" anschließen. Wie der dort genau angeschlossen wird, musst du mal im Datenblatt nachsehen.

Dennis

ooweberoo
24.03.2014, 20:22
Hallo Denis,

mit 2 x 22pF an XTAL1 und XTAL2 gegen Masse. Aber ich habe gelesen das der Tiny disen Takt dann als Pozessortakt übernimmt.
Wäre nicht so schlimm da es Strom spart aber mit dem Multiplexen komme ich dann nicht mehr hin denke ich. Flackert bestimmt.
Deshalb den 10MHz Quarz. 32,786MHz wäre mir auch lieber da man 128 Überläufe pro Sekunde ohne Prescaler hat.
Mal sehen wie ich das löse:confused:

Gruß Chris

derNeue
24.03.2014, 22:18
mit 2 x 22pF an XTAL1 und XTAL2 gegen Masse

Nein, eben genau das nicht. Jetzt hab ich mir doch das Datenblatt fix angesehen. Die Pins PA3 und PA4 haben auch die Bezeichnung T0 und T1. Je nachdem, welchen Timer du nutzen willst kannst du ein Clock-Signal entweder bei T0 oder T1 einspeißen. Dazu brauchst du einen Oszillator, mit einem einfachen Quarz klappts nicht, das war mein Fehler. So kannst du den Attiny einfach mit seinem internen ungenauen Takt laufen lassen und nur einen der Timer lässt du über 32khz takten. So kommst du mit dem multiplexen hin und hast trotzdem eine genaue Uhrzeit. Auf Datenblatt-Seite 115 wird der externe Takt für die Timer nochmal beschrieben.


Dennis

ooweberoo
27.03.2014, 07:57
Hallo Dennis,

das sind sehr gute Informationen die du mir gegeben hast. Danke dir. Ich werde mich an deine Lösung halten und eine Quarzoszillator mit 32,786MHz an T0 setzen. Wie ich dem Datenblatt entnommen habe muss der Takt extern doppelt so langsm sein als der interne.
Das heist in meinem Fall unter 5MHz bzw f(intern)/2,5=f(ext.clock) 4MHz, das wäre mit 32kHz dann ja mehr als ausreichend.
Somit müsste ich an den Fuse Bits eigentlich nichts ändern!?
Im Netz gibt es auch keine Beispiele oder Tutorial da jeder einen Normalen Quarz am XTAL1 & XTAL2 verwendet.
Läuft der Timer dann automatisch auf der angelegten Frequenz oder muss man das irgendwo einstellen?

Gruß Chris

derNeue
02.04.2014, 22:20
Habs gar nicht mitbekommen, dass du nochmal geschrieben hast.

Wie du den Timer einstellen musst, kannst du dem Datenblatt entnehmen, was du vielleicht schon gemacht hast. Irgendwas einstellen musst du auf alle Fälle, woher soll der Timer sonst wissen, woher er seinen Takt beziehen soll.

Dennis

ooweberoo
03.04.2014, 08:55
Hallo Dennis,

ich habe ätzend lange im Datenblatt gesucht und gefunden das mann das Timeregister so bescheiben muss:
TCCR0B |=((1<<CS00)&&(1<<CS01)&&(1<<CS02)); externer Takt
Habe das ganze aber noch nicht probiert.
Denke ich werde den Chip auch auf 32,768Hz laufen lassen da er so sparsamer mit dem Stromverbrauch ist.
Was meinst du?
Will ja nur eine 3V Batterie nutzen.

GRuß Chris

oberallgeier
03.04.2014, 09:11
... gefunden das mann das Timeregister so bescheiben muss:
TCCR0B |=((1<<CS00)&&(1<<CS01)&&(1<<CS02)); ...Muss? Für mich wärs mal einen Versuch wert. Aber meine übliche Syntax (AVRStudio 4.18, Build 700, AVRGCC) ist:

TCCR1A &= ~(1<<COM1A1)|(1<<COM1B1); // Clear/set OC1A/OC1B on Cmp Match S132
TCCR1A |= (1<<COM1A1)|(1<<COM1B1); //Dabei sind die Löschbefehle des Registers eher nur dann erforderlich, wenn vorher das Register gesetzt wurde ;-), weil nach dem Reset alles auf "Null" steht.

Die 32,768 kHz sind schon lausig langsam - ich habe ähnlich langsame Takte (128 kHz) am tiny13 gefahren. Aber wenns für Deine Aufgabenstellung reicht - dann ist der gering(er)e Stromverbrauch sicher da. Wie groß die effektive Ersparnis ist, habe ich nie gemessen, fürchte aber dass das nur für wirkliche Spezialfälle Sinn macht. Dass es bei Deiner 7Segment-Anzeige Sinn macht (die Zahlen sind doch gemultiplext, oder?) kann ich mir nicht vorstellen, da tritt vielleicht doch ein Flimmern der Anzeige auf.

ooweberoo
03.04.2014, 09:49
Hallo oberallgeier,

interessant das kenne ich so nicht bzw. vielleicht ist das beim tiny84 anders....
Würde gerne die Tabelle als Bild hochladen wo es steht...geht aber gerade nicht...Es ist die Tabelle mit den Pescalern.

Ich verwende AVR Studio 6.1 :-)

Ok deine Einschätzung ist schon mal viel Wert für mich da ich keine Erfahrung vorweisen kann :-)

Der tiny84 läuft auf 1MHz? Steht jedenfalls so im Datenblatt das er ab 2,7V-5,5V 0-10MHz hat und "active system clock 1MHz"

daher bin ich etwas verwirrt :-)

Wäre nur die Ungenauigkeit die ich weg bekommen muss. Was würdest du tun?

Einen Quarz an XTAL1&2, einen Oszillator nur an XTAL1 oder einen Oszillator an den Timereingang T0?
Und welche Werte?

GRuß Chris

oberallgeier
03.04.2014, 11:21
Hi Chris.

... das kenne ich so nicht bzw. vielleicht ist das beim tiny84 anders ...Das fällt mir schwer korrekt und zuverlässig zu beantworten weil ich ein lausiger C-Programmierer bin. Es ist aber eher eine Frage der C-Syntax und weniger eine Controllerspezialität.


... Der tiny84 läuft auf 1MHz ...Das ist doch die übliche Einstellung ab Werk:

...
6.2.2 Calibrated Internal 8 MHz Oscillator
By default, the Internal Oscillator provides an approximate 8 MHz clock. Though voltage andtemperature dependent, this clock can be very accurately calibrated by the user. See

Table 20-2 on page 176and “Internal Oscillator Speed” on page 205 for more details. The device is shipped
with the CKDIV8 Fuse programmed. See “System Clock Prescaler” on page 30 for more details. ...
... Was würdest du tun?
Einen Quarz an XTAL1&2, einen Oszillator nur an XTAL1 oder einen Oszillator an den Timereingang T0?
Und welche Werte? ...Du hast bei Deiner Siebensegmentanzeige sicher genug Stromverbrauch um Dich nicht über ein paar Mikroampere sorgen zu müssen. Aber das kannst nur Du anhand Deiner Schaltung beurteilen. Ich kann mir vorstellen - ich kenne aber Dein Projekt nicht wirklich, dass ich bei Deiner Aufgabenstellung den internen Oszillator nehmen würde - ohne CKDIV8 - also bei 8 MHz und als Zeitreferenz den Timereingang T0 mit dem Uhrenquarz. WENN das dann gut genug funzt, kannst Du zur Stromminderung immer noch den CKDIV8 probieren und evtl. niedrigere Takte - oder im Notfall nen Quarz dran schalten. Letzteres halte ich nicht für nötig.

Allerdings bereite ich (meine To-Do-Liste eher unterstes Drittel) meine Uhrzeitdarstellung mit ner RTC vor (nicht die ganz billige, hat aber "alles").

ooweberoo
03.04.2014, 12:22
Hallo oberallgeier,

wenn ich das Fuse Bit CKDIV8 entferne wird also der CPU- Takt nicht mehr vorgeteilt und ich bekomme 8 statt 1MHz???

ok das klingt vernümpftig, aber ich hatte die Uhr ja bereits fertig und am laufen mit einem 1MHz.
allerdings war sie zu ungenau. nach 5 Stunden waren es schon 3-4min die sie nach ging.


8 Bit Timer CTC Modus aktivieren---------------------------------
TCCR0A |= (1<<WGM01);
TCCR0B |= (1<<CS01); // im TCCR0B Register, Vorteiler 8 setzen
OCR0A = 125; // Überlaufwert festlegen
// 1.000.000Hz/8=125.000, 125.000Hz/125=1.000Hz, T=1/f = 1/1000Hz =0,001 Sekunden
// Beim erreichen von 125 wird ISR(TIM0_COMPA_vect)ausgeführt, und somit die Variable "millisekunden" um 1 erhöt
TIMSK0 = (1<<OCIE0A); // Interrupfunktion einschalten
sei();

Wäre es genauer wenn ich 8MHz nutze? Also statt 1000Überläufe pro Sekunde 8000.

Gruß Chris

oberallgeier
03.04.2014, 13:42
... CKDIV8 entferne wird ... Takt nicht mehr vorgeteilt ... 8 statt 1MHz??? ...Ja.


... Wäre es genauer wenn ich 8MHz nutze ...Nein ziemlich sicher nicht. Denn der Oszillator bleibt ja der Gleiche, mit den gleichen Un-/Genauigkeiten. Nur dass die CPU eben langsamer getickert wird, weil der 8 MHz-Takt wegen des gesetzten CKDIV8 durch acht geteilt wird.

Genauer gehts nur mit einem genaueren Taktgeber für die CPU. Wie Du den Takt genauer bekommst ist egal. RICHTIG genau wirds dann mit einem Quarzofen der den Quarz auf einer konstanten Temperatur hält - weil der Quarztakt von der Temperatur des Quarzes abhängt. Genauer wirds aber auch durch den externen Taktgeber - Uhrenquarz, der dann Dein eigentliches Zeitsignal ist. Oder Du hängst noch ein DFC77-Modul dran und justierst die Uhr alle Stunde oder Minute oder so.

sternst
03.04.2014, 15:06
nach 5 stunden waren es schon 3-4min die sie nach ging.

OCR0A = 125;

Wenn du im CRC-Modus eine Teilung durch 125 haben möchtest, ist 124 der richtige Wert für OCR0A. Das wäre dann schon mal ein Fehler von ca. 2,5 Min pro 5 Std. In einem früheren Code hattest du es richtig, warum geändert?

derNeue
03.04.2014, 16:06
Hallo!

Ich denke auch, das als "Hauptquarz" die 32khz zu nehmen Probleme geben könnte. Würde ich auch nicht empfehlen.


Dennis

ooweberoo
04.04.2014, 11:55
Hallo Leute,

Danke erstmal für euere Infos! :-)

@oberallgeier: Das werde ich denke auch so machen und den Vorteiler drin lassen.

@Sternst: ja hatte ich drin muss ich dir Recht geben. Ich habe nochmal Überlegt und so gerechnet 8.000.000Hz/8(CKDIV8 )= 1.000.000Hz/8(Prescaler)= 125.000
125.000Hz/1000 = 125Hz also wird der Wert 125, 1000 mal in der Sekunde erreicht! Hatte vorher 124 damit war die Abweichung nicht ganz so drastisch aber nach 5 Stunde jedoch auch ca. 1min. Also die Ungenauigkeit ist schon spürbar.

@derNeue: Ok das stimmt dann wohl. Allerdings verwendet diesen Quarz (32,768kHz) so gut wie jeder im Netz. Man muss ja nur mal Uhrenquarz googeln....
versteh nur nicht wie das die anderen machen die so einen Quarz nutzen....


Aber ich habe gerade Material bestellt und mich für einen 8Mhz Quarz entschieden, dann lass ich alles und stell lediglich auf externen Takt um. So kann ich vergleichen wie groß der Unterschied ist. Zudem stelle ich später auf ATtiny2313 um da dieser als SMD nicht viel größer ist aber mehr Pins bietet.

Mit den 8MHz bin ich genau an der Grenze. Wie muss ich den einstellen, also bei CKSEL3:1 als 3-8MHz(110) oder als 8- MHz (111)?


Gruß Chris

Besserwessi
04.04.2014, 13:53
Beim 8 MHz Quarz ist es nicht kritisch welche der Beiden Einstellungen man nutzt: die werden beide funktionieren. Auch sonst die die AVRs da relativ tolerant.

Den Tiny2313 würde ich eher nicht empfehlen, wenn man nicht gerade die UART braucht. Das ist noch Chip mit der alten Pinbelegung mit GND und VCC weit auseinander. Das macht das Layout schwieriger, bzw. verursacht mehr HF Störungen. Als Alternative ggf. besser ein Tiny261, auch wenn der 2 nutzbare Pins weniger hat.

derNeue
05.04.2014, 08:55
@derNeue: Ok das stimmt dann wohl. Allerdings verwendet diesen Quarz (32,768kHz) so gut wie jeder im Netz. Man muss ja nur mal Uhrenquarz googeln....
versteh nur nicht wie das die anderen machen die so einen Quarz nutzen....

Ich habe ja nicht gesagt, das es nicht geht. du musst da nur eine vernünftige Programmierung haben. Kritisch wird eben dein multiplexen. Wenn du eine Multiplex-Frequenz von 200Hz hast, hast du zwischen dem Umschalten gerade mal 163Takte(32768Hz/200Hz). In diesen Takten musst du auf die andere Anzeige umschalten und alles für die Uhr berechnen. Das ist möglich, aber schon ein bisschen knifflig. Auf jedenfall nicht mit _delay_ms() zu lösen.

Dennis

Wsk8
05.04.2014, 15:23
Meiner Meinung nach gibts hier prinzipiell nur 3 sinnvolle Möglichkeiten:

1. Du nimmst den internen Oszi und nimmst die Ungenauigkeit in kauf.

2. Du nimmst einen externen Quarz und minimierst die Ungenauigkeit etwas.

3. Du nimmst einen externen Uhrenquarz für den Timer und nimmst für den µc was du willst und hast die beste Genauigkeit.

mfg

ooweberoo
07.04.2014, 09:35
Hallo,

sorry Leute aber hier schreib jeder was anderes, welche Möglichkeiten ich habe wies ich. Danke für die vielen Ideen und Hilfe.

Aber bevor ich ganz verunsichert bin und garnicht mehr weiß was ich machen soll,

sollten wir den talk vielleicht schließen.

GRuß

derNeue
07.04.2014, 15:47
sorry Leute aber hier schreib jeder was anderes, welche Möglichkeiten ich habe wies ich. Danke für die vielen Ideen und Hilfe.

Nun, weil einfach viele Wege nach Rom führen. Zum Schluss musst du einfach mal probieren. Und ja, es kann auch mal was schiefgehen und es ist möglich, das du wieder von vorn anfängst. Aber anders lernst du das nicht. Hier bekommst du nur Anregungen, was du zum Schluss machst, musst du selbst entscheiden. Und gerade am Anfang entscheidest du dich vielleicht auch mal falsch. Das ging allen so. Aber anders baut man sich keine Erfahrung auf.

Dennis