Archiv verlassen und diese Seite im Standarddesign anzeigen : Timer mit einem ATTiny2313 - ERLEDIGT, danke euch allen
Guten Abend,
Ich habe schon das halbe Forum durchsucht auf der Suche nach einem Codeschnipsel wie man ein Software PWM Signal ausgibt.
Ich habe auch diverses gefunden.
Nur mein Problem besteht darin das ich mit dem PWMsignal dimmen möchte (Led's).
Sprich die Led im Low zustand langsam hochdimmen (in 2sec... oä).
Anschliessend eine gewisse Zeit auf High halten und anschliessend wieder runterdimmen.
Und dies auf drei Kanälen.
Hat dazu jemand einen Beispielcode oder einen Tipp.
Bin dankbar für alles.
dankeschön
EDIT:
Hab mir nun vorgenommen einfach mal meine drei Pins in bestimmten abständen auf High zu schalten.... siehe meinen Post unten.
Hi,
du könntest einen Timer laufen lassen der gibt dir dann bsw. alle ms einen Interrupt. Dann zählst du bei jedem interrupt eine Variable hoch, vergleichst die Variable mit einer Konstanden größe und kannst somit die Zeit für Ein bzw. Ausschaltimpuls variieren. Ich hoffe ich konnt dir helfen.
mfg franz
Danke für deine Antwort.
Das ist eine gute Idee, also eine Schleife in der ich den Wert vergleiche und dann hochdimme. Wen der Wert der "Zählervariable" meiner Konstanten entspricht gehe ich aus der Schleife und lasse eine weitere laufen um eine Zeit auf High zu bleiben. Und beim runterdimmen das selbe. Nur muss ich ja min. 2 Kanäle gleichzeitig dimmen lassen was ja mit dieser lösung nicht machbar wäre. oder?
Ich sehe gerade im Datasheet das der Tiny 4 PWM ausgänge hat.. stimmt das?
Ich habe schon das halbe Forum durchsucht auf der Suche nach einem Codeschnipsel wie man ein Software PWM Signal ausgibt.
Der Tiny2313 unterstützt PWM auch hardewareseitig. Muss es Software PWM sein?
Das habe ich gerade auch gelesen, so wie ich das datasheet verstehe hat er 4 PWM kanäle. Ist das richtig?
Es steht Four PWM Channels..... also 4Pins die mit unterschiedlichen PWM signalen ansteuerbar sind?
Das habe ich gerade auch gelesen, so wie ich das datasheet verstehe hat er 4 PWM kanäle. Ist das richtig?
Es steht Four PWM Channels..... also 4Pins die mit unterschiedlichen PWM signalen ansteuerbar sind?
ja
OC0A Timer0 PB2
OC0B Timer0 PD5
OC1A Timer1 PB3
OC1B Timer1 PB4
aber er hat nur 2 Timer, damit wären dann alle belegt ?
Timmer brauche ich ja nur einen oder? :-k
Dieser gibt ja nur den Takt an, das ausgangssignal wird ja durch den "PWM-Modus" generiert?
Wie würd ich den den PWM hochdimmen?
Wie würd ich den den PWM hochdimmen?
z.B. ungefähr so:
for I = 0 to 1023
pwm1a = I
waitms 10
next I
Die korrekte Syntax hängt natürlich von der verwendeten Programmiersprache ab.
Wenn du 3 LEDs gleichzeitig und unabhängig voneinander dimmen willst, musst du dir allerdings was schlaueres einfallen lassen.
Richtig, und genau da liegt das grosse Problem. Hat vieleicht jemand einen vorschlag?
TIMER MIT DEM ATTINY 2313
Ich probiere mit dem ATTINY einen Timer zu benutzen um meine Pins in gewissen abständen zu schalten.
Im mom. benutzte ich noch einen ATMega 8, sollte beim Tiny aber ähnlich sein nehme ich an.
void initTimer0()
{TCCR0=0x05; // 0b00000011, Vorteiler 1024 ca. 4khz
Damit stelle ich den verteiler auf 1024 des CPU Taktes.
Mit folgendem:
TIMSK=0x01;
wird ja ein TimerOverflow 1 Interupt ausgelöst.
Jetzt war die Idee immer wen dieser Interupt ausgelöst wird eine Variable hochzählen zu lassen und ab einem bestimmten Wert meinen Pin auf High zu schalten. Leider find ich nicht heraus wie ich diesen Interupt überhaupt registriere.
Das wollte ich mit allen 3 Pins machen und wen alle auf High oder low sind die Variable wieder auf 0 zu setzten (z.B. bei 20000) und das spiel von vorne zu beginnen.
Bin ich auf dem Richtigen weg?
Und wo wird dieser Interrupt "gespeichert"?
Hallo,
also ich häng jetz mal mein Beispiel für den mega8 ms timer an.
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 16000000
#define timer (256-F_CPU/64/1000)
int ms;
ISR(TIMER0_OVF_vect) //Timer Interrupt Vector
{TCNT0 = timer;
ms++;
}
int main(void)
{
//Ports Init
DDRC |= (1<<PORTC3);
//Timer Init
TIMSK |= (1<<TOIE0); //Timerinterrupt freigeben
TCCR0 |= (1<<CS00) | (1<<CS01) | (!(1<<CS02)); //Timer Prescaler = 64
sei(); //Interrupts global aktivieren
//main Schleife
for (;;)
{ if(ms >=100)
{PORTC ^= (1<<PORTC3);ms = 0;}
}
}
läuft nur timer0 über so wird in die timer isr gesprungen. hoffe ich konnt dir helfen. Ach übrigens 0x05 ist 0b00000101.
mfg franz
Vielen dank für die antwort, es tut sich schonmal was.
Ich wäre froh wen du mir zwei dinge noch erklären könntest.
zum einen was passiert hier?:
ISR(TIMER0_OVF_vect) //Timer Interrupt Vector
{TCNT0 = timer;
ms++;
}
Timer wird ja durch: (256-F_CPU/64/1000)
ersetzt. Was passiert den hier genau?
TCNT0 ist ja das Daten Register des Timer 0.
Hier wird diesem Register ja ein Wert zugewissen.... wird nicht normal ein Wert aus diesem Register gelesen?
Die Variable ms wird nach jedem Interupt um 1 erhöht... richtig?
{if(ms >=100)
{PORTB ^= (1<<PORTB0);ms = 0;}
Und was geschieht hier?
Wen die Variable ms grösser oder gleich 100 ist... also nach 100 interupts...
Wird PORTB im zustand gewechselt... also High zu low und low zu High... anschliessend wird die Variable ms auf null gesetzt und die Schleife beginnt von vorn?
Hi,
also zu 1. ich weise timer0 einen erechneten Wert zu um genau auf 1ms zu kommen. Das heißt jeder Interrupt ist 1ms. Dann springt das Programm alle ms in die ISR und weißt dem Register wieder diesen Wert zu und zählt meine Variable 1 hoch. Die Variable timer errechnet sich aus 256(weil der timer0 8-bit breit ist) - Quarztakt/Prescaler/1000 (wegen ms).
zu 2. ja richtig erkannt nach 100ms wird der Zustand des Ports gewechselt und meine Variable auf 0 zurückgesetzt, dadurch beginnt der Vorgang erneut.
hoffe es ist jetz klarer sonst frag einfach nochmal nach
mfg franz
Es klappt.. endlich. Nur etwas will nicht.
Ich hab mir folgenden code zusammengeschrieben:
#include <avr\io.h>
#include <inttypes.h>
#include <avr\interrupt.h>
#define F_CPU 3686400
#define timer (256-F_CPU/64/1000)
#define RotH PORTB0
#define RotV PORTB1
#define BlauV PORTB2
int ms;
void initPorts()
{
DDRB |= (1<<PB0) | (1<<PB1) | (1<<PB2);
}
ISR(TIMER0_OVF_vect) //Timer Interrupt Vector
{
TCNT0 = timer;
ms++;
}
int main(void)
{
initPorts(); // Timer Interrupt initialisieren
TIMSK |= (1<<TOIE0);
TCCR0=0x05; // 0b00000011, Vorteiler 1024 ca. 4khz
sei(); // enable interrupts
do
{
PORTB &= ~( (1<<RotH) | (1<<PORTB1) | (1<<PORTB2)); //PORTB Pins 0,1,2 auf low
if(ms >= 5)
{
PORTB |= (1<<RotH); //Rot High
if(ms >=30)
{
PORTB |= (1<<RotV); //Gelb High
if(ms >= 100)
{
PORTB &= ~(1<<RotH); //ROT Low
PORTB |= (1<<BlauV); //GRUEN High
if(ms >= 200)
{
ms = 0; //ms auf NULL
}
}
}
}
}
while (true);
}
//================================================== ====================
Dieser funktioniert auch, ausser das das setzten von PORTB0 auf low nicht klappt.
Ich meinte einmal gelesen zu haben, das es damit zusammenhäng wie man die PORT's definiert und schaltet. Also ob man sie erst als Ausgänge setzt und dann auf High oder umgekehrt.
Kann mir da vieleicht jemand behilflich sein?
SprinterSB
19.07.2007, 08:03
Die Ports werden ja immer nur sehr kurz auf HIGH gesetzt, weil sie in jedem Durchlauf der do-Schleife wieder auf LOW gesetzt werden. Ähmliches gilt nochmals für PORTB0. Du solltest hier komplett in if-then-else verzweigen und immer das setzen/löschen, was gerade angesagt ist statt die Werte immer wieder hin- und her zu setzen.
Noch was generelles:
-- korrekt schreibt man avr/io.h, nicht avr\io.h (auch unter Win32)
-- der Zugriff auf ms müsste eigentlich atomar sein, sollte aber für das Programm hier trotzdem zu keinen Ausfällen wie Kernschmelze führen ;-)
Damit dieses Problem weg ist möste ich einen Operator haben mit dem ich abfragen könnte ob ms zum Beispiel zwischen 50 und 70 liegt anstatt nur grösser/gleich als.
if(ms >=50 & <= 70) klappt nicht.
Oder muss ich das ganz anderst machen?
Wäre sehr froh wen mir jemand ein Beispiel machen könnte wie man es richtig macht.
Dankeschön
Hi,
also du musst wenn dann schreiben if(ms>=50 & ms<=70) dann klappts auch , hoffe ich konnt dir helfen.
mfg franz
Sehr schön, so klappts. danke euch vielmals
Ich hab das programm nun auf den Tiny geschrieben.
Nur scheint es darauf nicht zu funktionieren. Das ist mein Code:
#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#define F_CPU 3686400
#define timer (256-F_CPU/64/1000)
#define RotH PORTB0
#define RotV PORTB1
#define BlauV PORTB2
int ms;
void initPorts()
{
DDRB |= (1<<PB0) | (1<<PB1) | (1<<PB2);
}
ISR(TIMER0_OVF_vect) //Timer Interrupt Vector
{
TCNT0 = timer;
ms++;
}
int main(void)
{
initPorts(); // Timer Interrupt initialisieren
TIMSK |= (1<<TOIE0);
TCCR0A=0x05; // 0b00000011, Vorteiler 1024 ca. 4khz
sei(); // enable interrupts
do
{
if(ms <= 1)
{
PORTB &= ~( (1<<RotH) | (1<<RotV) | (1<<BlauV)); //PORTB Pins 0,1,2 auf low
}
if(ms >= 5& ms <= 100)
{
PORTB |= (1<<RotV);
}
if(ms >= 100& ms <= 210)
{
PORTB |= (1<<RotH);
}
if(ms >= 210& ms <= 400 )
{
PORTB |= (1<<BlauV);
PORTB &= ~(1<<RotV);
}
if(ms >= 600)
{
ms = 0;
}
}
while (true);
}
Ich habe einzig den TCCR0=0x05; auf TCCR0A=0x05; gewechselt da der beim Tiny anderst heisst. Hab ich sonst noch einen Fehler?
Auf dem Mega 8 hat es wunderbar funktioniert
SprinterSB
22.07.2007, 17:01
if(ms >=50 & <= 70) klappt nicht.
Es muss heissen
if (ms >=50 && ms <= 70)
Ich habe in meinem Code
if(ms >= 50 & ms <= 70)
verwendet (Siehe code in meinem letzten Post)
Und auf dem Atmega8 klappt alles wie es sollte.
Auf dem Tiny passiert aber gar nichts.....
Es liegt klar daran das der Tiny mit meinen Timer"angaben" nicht arbeitet.
Ich habe einfach mal alle Led's eingeschaltet und das funktioniert.
Hat den noch nie jemand mit den Timern des Tiny's gearbeitet?
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.