Interessantes Konstrukt:
>PORTA = TCCR1A|=(1<<0)|(1<<1); // PULLUP für Tasten Bit 0 und 1
Warum das:
OCR1C=240; // Max Zählwert CK/Vorteiler/f (interner Oscill
OCR1A=a; // oben a(%) * OCR1C (z.B. 50% Puls-Pausenverhältnis)
Zumindest ist a kein % von OCR1C, sondern "pro 241".
Wie entprellst du die Tasten? (Man könnte den Timer "misbrauchen"...)
> (0<<..)
ist sehr sinnlos und verwirrt höchstens beim "flüchtigen" Lesen.
Die Defines sollte man sich eigentlich auch sparen können, weil sie in
der io.h zum Tiny26 vorhanden sein sollten.
Sonst aber ein nettes Anfängerprojekt.
Wenn ich auch noch darf:
Ein aggressiv optimierender Compiler, lässt dir
davon:
1
voidPause(void)//etwa 0,5s
2
{uint8_ti;
3
uint8_tj;
4
5
for(i=0;i<30;i++)
6
{
7
for(j=0;j<250;j++){}
8
}}
nichts übrig.
Für Warteschleifen, gibt es die <util/delay.h>
und dort die Funktionen _delay_ms und _delay_us.
Achtung: Beide haben Obergrenzen, abhängig vom
Quarztakt. Du wirst die _delay_ms also in
eine Schleife packen muessen.
Und noch was:
Wenn du für Anfänger schreibst, was grundsätzlich
zu begrüssen ist, dann achte auf deine Code-Formatierung.
Deine Einrückungen da oben sind alles andere als konsistent.
1
};
2
}
Der ';' ist überflüssig.
1
for(;;)//Abfrage der Tasten alle 0,5s (Pause)
2
{
3
4
if(bit_is_clear(PINA,0)){
Entscheide dich, wo du die { platzierst. Entweder
in der selben Zeile am Ende oder in einer neuen Zeile
drunter. Wenn neue Zeile, dann entweder unter dem Statement
oder eingerückt.
Aber nicht 3 verschiedene Stile in einer Source!
Das wichtigste an einem { } Setzungs- und Einrückstil ist
nicht wie er konkret aussieht, sondern dass man ihn konsequent
durchzieht.
Nun mal zur Hardware: In der Schaltung fehlt ein Pufferelko für die 12V.
Einige 100 bis 1000uF mit nicht allzuhohem ESR sollten es schon sein.
Sowas ist bei PWM Pflicht. Ebenso der 100nF vor und hinter dem 5V Stabi
(bzw. ein Elko davor).
Ebenso sollte an den Reset Pin ein kleiner Kondensator gegen Masse.
Der Mosfet Treiber dagegen ist vorbildlich.
Du fragst du Tasten jetzt zwar in der Timer-ISR ab, due entprellst sie
aber immer noch nicht. Dazu musst du den aktuellen Zustand der Tasten
mit dem letzten vergleichen. Wenn die beiden über eine bestimmte Zeit
gleich bleiben, ist die Taste in einem stabilen Zustand.
Das verstehe ich nicht.
Tastenprellen ensteht doch nur beim Drücken oder?
Die Taste bleibt aber gedrückt bis die gewünschte Heligkeit eingestellt
ist.
Etwa alle 0,5s wird abgefragt ob eine Taste gedrückt ist und
entsprechend das Puls/Pausenverhältnis geändert.
Was soll da passieren ohne Entprellung?
Ich "entprelle" meine Taster genauso: Einfach den Taster alle 10-100ms
abfragen. Man erhält nun eine Information ob der Taster gedrückt ist
oder nicht. Prellt der Taster noch, kann die Information falsch sein
(was aber nicht weiter stört), denn spätestens beim nächsten Abfragen
stimmt es. Die Fehlinformation kann keinen zusätzlichen Tastendruck
bewirken, denn entweder war die Fehlinformation eine 0 oder 1, also
entweder wurde der eine Zustand zu früh erkannt, oder zu spät.
Ich setze allerdings immer ein Bit, das bedeutet das der Taster gedrückt
wurde (oder es immer noch ist).
In diesem Fall hier, kann man auf ein Entprellen eigentlich aber
komplett verzichten.
> Was soll da passieren ohne Entprellung?
In diesem konkreten Fall nichts. Das liegt daran, dass
es völlig Wurscht ist, ob der µC eine oder zwei Dimmstufen
zu hoch oder zu niedrig liegt. Die Wartezeit von 0.5
Sekunden tut ihr übriges. Allerdings ist 0.5 Sekunden
meist nicht akzeptabel. Im Grunde benutzt du ja die
0.5 Sekunden eigentlich als 'Taste-immer-noch-gedrückt-
Aktion-wiederholen' Timer. Und es gibt natürlich Benutzer
die mal ganz schnell den Taster antippen und wieder
loslassen. In weniger als 0.5 Sekunden. Wenn er Pech
hat, passiert dieser Tastendruck dann in der Zeit
in der der µC grade nicht hinsieht :-)
Anders ist es, wenn wirklich jeder Tastendruck zählt
und der Benutzer einen ganz bestimmten Wert einstellen
muss. Es ist einfach lästig, wenn du kurz auf die
Taste drückst und der µC zählt deine 7-Segment Anzeige
um 2 Einheiten hoch, weil er durch das Prellen die
Sequenz 000000001101111111000000 für den kurzzeitigen
Tastendruck eingelesen hat.
Alles richtig und auch wichtig was ihr sagt.
Ich habe ja erst vor ein paar Wochen mir C angefangen.
Vorher habe ich einiges in Ass. geschreiben.
Das PWM war mein 2. Projekt, gleich nach einer blinkenden LED.
Ich wollte es anderen Anfängern zur Verfügung stellen, damit die weiter
dran rumbasteln. Man ist ja manchmal froh wenn erst mal was
funktioniert, das man dann anpassen kann.
Die SW hat noch einige Nachteile. z.B wenn ich eine höhere Taktrate
nehme, geht die Tastenabfrage zu schnell.
Ihr könnt ja gerne hier mal ein paar Codeauschnitte reinstellen, wie man
es besser machen kann. Dann kann jeder an dem Projekt lernen, weil es ja
recht überschaubar ist und trotzdem PWM und Timerinter. benutzt.
Ausserdem hielt ich es für wichtig, mal eine funktionierende
MOSFET-Ansteuerung hier zu verewigen.
Ich hänge hier gerade mal noch die Eagle-Datei dran.
Mit ISP-Stecker
> Die SW hat noch einige Nachteile. z.B wenn ich eine höhere Taktrate> nehme, geht die Tastenabfrage zu schnell.> Ihr könnt ja gerne hier mal ein paar Codeauschnitte reinstellen,> wie man es besser machen kann
Für die Tastenabfrage gibt es eigentlich nur eine Antwort:
http://www.mikrocontroller.net/articles/Entprellung
Das Teil ist absolut genial.
Unterscheidet zwischen:
Taste kurz gedrückt
Benutzer ist auf der Taste eingeschlafen.
Ich würds so machen ( C-Skizze )
1
#define LED_PORT PORTB
2
#define LED_PIN ( 1 << PINB1 )
3
4
uint8_tPWMCounter;
5
volatileuint8_tLEDValue;
6
7
//
8
// Der Interrupt implementiert die PWM
9
// Ein Zähler läuft von 0 bis 100 durch
10
// Liegt der Zähler unter dem Schwellwert einer Led, so wird
11
// die Led eingeschaltet. Liegt er darüber wird die Led ausgeschaltet.
12
// Durch Verändern das Schwellwertes kann also das Verhältnis
13
// der An-Zeit zur Aus-Zeit einer Led eingestellt werden. Je
14
// laenger eine Led in so einem Zyklus eingeschaltet ist,
15
// desto heller erscheint sie uns.
16
// Die Zyklen muessen natuerlich schnell genug erfolgen, ansonsten
17
// sehen wir nur ein Blinken.
18
//
19
SIGNAL(TIMER0_OVF0_vect)
20
{
21
//
22
// Den Zaehler erhoehen. Hat er 100 erreicht (entspricht
23
// 100 PWM Stufen), dann wieder bei 0 anfangen
24
//
25
PWMCounter++;
26
if(PWMCounter==101)
27
PWMCounter=0;
28
29
//
30
// Muss die LED ein oder ausgeschaltet sein?
31
//
32
if(LEDValue<PWMCounter)
33
LED_PORT|=LED_PIN;// Led ein
34
else
35
LED_PORT&=~LED_IN;// Led aus
36
}
37
38
39
intmain()
40
{
41
LEDValue=0;// Led aus
42
43
// Code zur initialisierung des Timers
44
45
while(1){
46
//
47
// Die LED etwas heller stellen. Ist der Endwert erreicht
48
// dann wieder bei ganz Dunkel anfangen
49
//
50
if(LEDValue==100)
51
LEDValue=0;
52
else
53
LEDValue++;
54
55
_dealay_ms(20);// etwas warten
56
}
57
}
Das Wichtiste an diesem Code ist, dass dieser Code die eigentliche
PWM von einer ev. Auswertung von Tasten, die in main() gemacht
werden würde, trennt. Letztendlich ist es ja für die PWM
völlig egal, wie der Vorgabewert zustandekommt. Bei einer
Meiner Anwendungen hab ich zb. ein Schema aus Hellzeit, Dunkelzeit,
HellHelligkeit, DunkelHelligkeit. Alle 4 Parameter werden mit
Zufallszahlen zur Laufzeit berechnet. Der Effekt ist, dass eine
Ansammlung von 60 Leds völlig unabhängig voneinander vor sich
hinblinken. Mal heller, mal dunkler. Mal sieht es aus wie Sterne
die in einer kalten Winternacht funkeln, mal sieht es aus wie
die Blitzlichtgewitter in einem Sportstadion.
@kbucheg: Deine Anwendung würde mich mal interessieren. Ich bin gerade
dabei einen Sternenhimmel zu bauen, da sollen die "Sterne" dann auch
funkeln. Ich habe aber bisher noch nicht die richtigen Parameter dafür
gefunden. Hast Du da welche parat?
Auch die Ansteuerung würde mich interessieren. Wie steuerst Du 60 LEDs
unabhängig voneinander?
mfg, Stefan.
Mega8, 12 Mhz
Daran eine Schieberegisterkette aus 595 + Treiber
Ich benutzte den CTC Modus um den Grundtakt zum raustakten
in die Schieberegister zu kriegen.
Jede Led durchläuft einen Zyklus
Der erste Teil des Zyklus ist die 'Hellphase', der zweite
die 'Dunkelphase'.
Für jede Phase sind variabel:
* die Zeitdauer
* die Helligkeit
Jede der beiden Variablen folgt einer Gleichung
Wert = Konstant + zufälliger Anteil
Halte ich den zufälligen Anteil klein, so wirkt sich nur
der konstante Anteil aus und alle LED's verhalten sich gleich.
Je höher ich den zufälligen Anteil wähle, desto größer sind
die Unterschiede von einer Led zur nächsten.
Für jede Led gibt es einen Zähler, der von der maximalen Zeit
(Hell + Dunkel) auf 0 herunterzählt. In der Idle Time, wenn also
der Prozessor nichts anderes zu tun hat, werden sukzessive
alle Zähler überprüft, ob einer davon 0 geworden ist. Wird
so einer aufgefunden, so werden dieser Led neue Werte
verpasst. Das heist die Zeiten wird nicht exakt eingehalten.
Das spielt aber keine grosse Rolle, denn ob die Led jetzt
1/100 Sekunde länger den vorhergehenden Zustand einhält
oder nicht, spielt keine Rolle.
Übrigens: Hell und Dunkelphase muss nicht heissen, dass
die Led in der Hellphase heller sind als in der Dunkelphase :-)
Eine lange Hellphase, in der die Led auf 5% sind und eine sehr
kurze aber helle Dunkelphase gibt auch einen netten Effekt.
Anbei mal das Pgm. Das ganze ist so ausgelegt, dass ich alle
Parameter über die UART verändern kann.
? Hilfe
i info über die momentane Einstellung.
g Die Zyklus ab bzw. einschalten
Ein Besonderheit ist die Verarbeitung von Zahlen. Es wird
zuerst die Zahl angegeben und dann erst die Operation die
damit gemacht werden soll. Um also die konstante Helligkeit
in der Hellphase zu ändern, gebe ich ein:
30o
o ist dabei das Kommando um den konstanten Anteil der Helligkeit
den neuen Wert (in dem Fall 30) zu setzten.
Dazu kommt dann noch ein Bedienteil, der aus ebenfalls einem
Mega8, LCD und 3 Tastern besteht. Die Steuerung über die UART
werde ich beibehalten. Der Steuerteil sitzt hinter der abgehängten
Decke und den Bedienteil möchte ich natürlich bequem in Griffhöhe
haben.
Die Elektronik ist soweit fertig (der eigentliche Rechner für
das Bedienteil muss noch gebaut werden, gestern hab ich die
Platine gemacht, die LCD+Taster Platine ist fertig). Eine erste
Version seiner Programmierung läuft auch schon. Dann brauch
ich nicht mehr mit dem Laptop an den Himmel ran um damit zu
spielen.
Der Deckenaufbau ist soweit auch erledigt, LED eingebaut, der
Steuerrechner hängt noch aus dem Loch in der Decke (damit ich noch
an die RS232 rankomme).
Jetzt kommt der Aufbau der ganzen 'Wandgehäuse'.
Vielleicht mach ich noch ein Video von dem Teil 'in Action'
@ Karl heinz,
if( LEDValue == 100 )
LEDValue = 0;
else
LEDValue++;
_dealay_ms( 20 );
Das macht man aber eigentlich nicht, oder? Wenn das Programm
umpfangreicher wird, kann durchaus LEDValue = 100 übergangen werden.
Dann muss ein ganzer Zyklus vergehen, damit das wieder greift. Besser:
if( LEDValue > 99 )
...
MW
> kann durchaus LEDValue = 100 übergangen werden.
Im Moment kann das nicht passieren.
Das ist die einzige Stelle an der LEDValue geändert wird.
Das ist Code aus der main() Schleife. Die Idee dahinter
ist es, eine kleine Testanwendung zu haben, damit man
auch sieht, dass die LED gedimmt wird. In dem Fall
durchläuft sie eine Helligkeitsrampe. In einer realen
Applikation wird man dafür ja sowieso was anderes machen,
daher hab ich keinen besonderen Aufwand getrieben.
Hallo Karl-Heinz,
was für Treiber hast du denn benutzt hinter den hc595?
Hast du das Projekt denn jetzt finalisiert? Wärest du bereit zu teilen?
;-)
Gruß
Fabian