Forum: Mikrocontroller und Digitale Elektronik Attiny13 mit PWM und 2 LEDs


von Manuel X. (scratliner)


Lesenswert?

Hallo Leute,

ich bin neu hier und habe mich schon etwas mit C und dem Tiny13 
beschäftigt, trotzdem bekomme ich es nicht hin, 2 Ausgänge mit jedweils 
1 LED per interner PWM zu dimmen.
dies soll über 2 tastern am eingang passieren.
ich verstehe manche C befehle noch nicht, bzw komm durcheinander.
finde ich irgendwo hier im netz ein grund- C programm, umzu sehen, wie 
die PWM eingestellt wird und funktioniert mit dem Tiny13 ?

ausgang am tiny13 : PB0,1,2
eingang : PB3,4,5

ist es schon mal richtig das dies in Hex :

DDRB= 0xA1 wäre?
und ich den TCCR0A = 0xA1 und
TCCR0B=0x01

setze??

Ich hofe ihr könnt mir helfen :(

Grüße
Manu

von Karl H. (kbuchegg)


Lesenswert?

Manuel F. schrieb:

> ausgang am tiny13 : PB0,1,2
> eingang : PB3,4,5
>
> ist es schon mal richtig das dies in Hex :
>
> DDRB= 0xA1 wäre?

wie kommst du auf 0xA1
Du willst PB0,  PB1 und PB2 auf Ausgang schalten.
Dann schreibs halt so

   DDRB |= ( 1 << PB0 ) | ( 1 << PB1 ) | ( 1 << PB2 );

und schon brauchst du dich nicht mehr darum kümmern, was das als 
Hex-Zahl ausmacht. Und als Nebeneffekt siehst du in der Anweisung gleich 
direkt, welche 'Bits' (und damit welche Pins) du auf 1 und damit auf 
Ausgang gestellt hast.

> und ich den TCCR0A = 0xA1 und
> TCCR0B=0x01

Detto.
Die Bits in den Registern haben Namen. Benutze sie und vieles wird 
einfacher.
Es ist ein Trugschluss für alles und jedes Hex-Zahlen zu benutzen. Die 
Schreibweise von Zahlen richtet sich danach, in welchem Zusammenhang sie 
vorkommen. Je nachdem ist die eine oder andere Schreibweise viel besser 
geeignet.

FAQ: Timer

von Karl H. (kbuchegg)


Lesenswert?

> ich verstehe manche C befehle noch nicht, bzw komm durcheinander.

Dann musst du üben.
Ein nicht unwesentlicher Sinn in den ersten Übungsprogrammen, die sich 
um LED ein/ausschalten drehen, besteht darin, Schreibweisen für 
Bit-Setzen bzw. Bit-Löschen solange zu wiederholen, bis man sie im 
Schlaf beherrscht.

Dazu muss man aber selbst Programme schreiben! Einfach nur anderer Leute 
Programme anzusehen und laufen zu lassen ist zu wenig.

Die Themenkreise

* Bedeutung der jeweiligen DDRx, PORTx, PINx
* wie werden Einzelbits an den Rgeister gesetzt, gelöscht, getoggelt und
  abgefragt

das sind sind die wesentlichen Punkte, um die es bei den ersten x (x 
größer 15) Programmen, die sich mit LED ein/aus in allen Variationen, 
über Blinken bis hin zum Lauflicht in allen möglichen Schattierungen 
tatsächlich dreht.

Und genau das sind auch die absoluten Basisgrundlagen, deren 
Beherrschung für alles weitere vorausgesetzt wird.

von Moritz M. (moritz_m35)


Lesenswert?

Hallo,

hast du schon mal einfach nur LED ein/aus programmiert? Wenn nein, dann 
versuch doch das erstmal. z:B. So:
1
#include <avr/io.h>
2
#include <avr/delay.h>
3
4
void main (void)
5
{
6
   DDRB |= (1 << PB0);   // PB0 als Ausgang
7
   while(1)
8
   {
9
      PORTB &= ~(1 << PB0); // PB0 Aus
10
      _delay(500);           //warten
11
      PORTB |= (1 << PB0);  //PB0 Ein
12
   }
13
}

Moritz

von Manuel X. (scratliner)


Lesenswert?

danke schon mal für eure antworten.

ja das mit einer LED an/aus automatisch habe ich schon hinbekommen :)
nur der rest mit PWM haut nicht so hin.
Hex mit A1 war natürlich mist.
ich meinte eigentlich

DDRB = 0x07

aber die andere schreibweise ist übersichtlicher und einfacher.

ich werde mich hier etwas rumschauen und bei fragen,frag ich einfach:)

von Manuel X. (scratliner)


Lesenswert?

Nun habe ich es schon mal hinbekommen,eine LED am Ausgang OCR0A zu 
Dimmen.
Mit Taster 1 >> LED Hoch dimmen,
Mit Taster 2 >> LED runter Dimmen.
WIe bekomme ich es nun hin, das ich dieses verhalten nur mit EINEM 
Taster mache?
Sprich,Taster 1 drücken, dimmt hoch, los lassen, warten und wert halten, 
weiter drücken, dann runter dimmen?

von kopfkratzer (Gast)


Lesenswert?

Dann schau Dir mal die Tastenentprellung vom PeDa hier an, dann brauchst 
Du noch eine Variable die anzeigt ob hoch oder runter und das war's ;-)

von Manuel X. (scratliner)


Lesenswert?

Die PeDa datei habe ich gefunden,aber....
Das verstehe ich nicht  :(
Wie realisiere ich das denn?

von Karl H. (kbuchegg)


Lesenswert?

Manuel F. schrieb:
> Die PeDa datei habe ich gefunden,aber....
> Das verstehe ich nicht  :(

Ist fürs erste ok.

Sieh dir nur in main() an, wie die Funktionen verwendet bzw. der Timer 
eingebunden wird. Dann passt du noch am Anfang die #define an deine 
Situation an und die restlichen Funktionen übernimmst du einfach so wie 
sie sind (inkl. der ISR-Funktion)

von Manuel X. (scratliner)


Lesenswert?

Hallo erneut :)
soweit habe ich es nun alles zum laufen bekommen.
Ich muss nur noch versuchen, die werte ins EEPROM zu schreiben,bevor ich 
die platine spannungslos mache.
So dass meine LEDs leuchten, wie ich sie ausgeschaltet habe.
Und noch eins bekomme ich nicht hin.
Beide Register OCR0a und OCR0b sollen gegeneinander laufen; Sprich wenn 
ein ausgang 10% und der andere 90% helligkeit hat, und ich nun BEIDE 
ZUSAMMEN dimmen möchte, ist logischerweise die 10%tige schneller aus als 
die andere. ich möchte aber das beide zusammen langsam ausdimmen.
wie bekomm ich das denn hin?

von Karl H. (kbuchegg)


Lesenswert?

Manuel F. schrieb:
> Hallo erneut :)
> soweit habe ich es nun alles zum laufen bekommen.
> Ich muss nur noch versuchen, die werte ins EEPROM zu schreiben,bevor ich
> die platine spannungslos mache.
> So dass meine LEDs leuchten, wie ich sie ausgeschaltet habe.

AVR-GCC-Turoial
Da gibt es einen Abschnitt über das EEPROM

> Beide Register OCR0a und OCR0b sollen gegeneinander laufen; Sprich wenn
> ein ausgang 10% und der andere 90% helligkeit hat, und ich nun BEIDE
> ZUSAMMEN dimmen möchte, ist logischerweise die 10%tige schneller aus als
> die andere. ich möchte aber das beide zusammen langsam ausdimmen.
> wie bekomm ich das denn hin?

indem du für den Benutzer eine Variablen einführst, die die jeweilige 
Dimmstufe der einen LED angibt. Die andere ist dann logischerweise 100-x 
davon.
Weiters führst du dir einen Masterdimmer ein. Ebenfalls eine 
Prozentzahl, die angibt, wieviele Prozent der Dimmstufe bzw. des 
Gegenteils davon dann tatsächlich realisiert werden sollen.

Angenommen mit deinen Tasten hast du eingestellt, dass die eine LED zu 
35% leuchten soll. Dann leuchtet die andere LED zu 65%.
Soweit so gut.
Dein Masterdimmer steht auf 100%, was soviel heisst wie: die 35% bzw. 
65% sollen auch tatsächlich realisiert werden.

Wie hell leuchtet dann jede LED wirklich?

LED1:   35 * 100 / 100  ->  35%
LED2:   65 * 100 / 100  ->  65%

Jetzt sei der Wert des Masterdimmers auf 90%. Wie hell müssen jetzt die 
LED eingestellt werden?

LED1:   35 * 90 / 100   ->  31%
LED2:   65 * 90 / 100   ->  58%

d.h. deine vom Benutzer eingestellten LED Werte sind beide auf 90% 
zurückgenommen worden.

D.h. der Benutzer verteilt seine 100% auf die beiden LED, während der 
Masterdimmer dafür zuständig ist, beide LED gemeinsam auf bzw. 
abzudimmen.

So wie es zb Windows in den Sound-Einstellungen macht: Jedes Gerät hat 
einen eigenen Regler. Und für alle gemeinsam ist ein Hauptregler 
zuständig, der alle mitsammen lauter bzw. leiser macht. Mathematisch 
sind das einfach nur Werte zwischen 0 und 1, die miteinander 
multiplizert werden. Aus naheliegenden Gründen wollen wir aber keine 
Gleitkommazahlen. Das 100-fache davon, welches man umgangssrachlich 
'Prozent' nennt, tut es dazu auch - und damit ganze Zahlen.

von Manuel X. (scratliner)


Lesenswert?

danke schon mal für die antwort.
ich werde es mal ausprobieren.
nun nochmal zum eeprom; der link geht nicht.
ich habe nun probiert das eeprom zu schreiben und zu lesen, es geht 
jedoch nicht.

mein programm sieht nun zb so aus:
ich benutze beide OCROA/B Register um je eine LED am ausgang zu dimmen.

erst definitionen....etc pp
dann das:

eeprom_busy_wait();         // wait while eeprom busy
OCR0A = eeprom_read_word(0x000);

eeprom_busy_wait();         // wait while eeprom busy
OCR0B = eeprom_read_word(0x000);

dann das hauptprogram.......

dann das zum schluss:

eeprom_busy_wait();            // wait while eeprom busy
old_OCR0A = eeprom_read_word(0x000);
if (old_OCR0A != OCR0A)
  {
  eeprom_busy_wait();
  eeprom_write_word(0x000,OCR0A);
  }

eeprom_busy_wait();         // wait while eeprom busy
old_OCR0B = eeprom_read_word(0x000);
if (old_OCR0B != OCR0B)
 {
  eeprom_busy_wait();
  eeprom_write_word(0x000,OCR0B);
 }
 }

was ist daran denn falsch?

von Karl H. (kbuchegg)


Lesenswert?

Manuel F. schrieb:
> danke schon mal für die antwort.
> ich werde es mal ausprobieren.
> nun nochmal zum eeprom; der link geht nicht.

Wow.
Und auf die Idee, dass ich einen Tippfehler gemacht haben könnte bist du 
nicht gekommen?

Was könnte wohl der Tippfehler in "AVR-GCC-Turoial" sein und wie wird 
das wohl richtig heissen?

AVR-GCC-Tutorial

von Karl H. (kbuchegg)


Lesenswert?

Manuel F. schrieb:

> was ist daran denn falsch?

kann kein Mensch sagen mit dem bisschen Information.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Du möchtest vermutlich auch kein 'word' aus dem EEPROM lesen, sondern 
nur ein byte. Statt
1
OCR0A = eeprom_read_word(0x000);
Ausserdem möchtest du sicher nicht OCR0A und OCR0B von der gleichen 
EEPROM Adresse laden.
nimm also besser
1
// definiere EEPROM Adressen und deren Inhalt. 
2
// Der Inhalt kann einmal mit dem Programmer ins EEPROM geladen werden
3
uint8_t ee_OCRA_Addr __attribute__((section(".eeprom"))) = 0;
4
uint8_t ee_OCRB_Addr __attribute__((section(".eeprom"))) = 0;
5
6
// Schreiben geht so
7
uint8_t a,b;
8
        a = OCR0A;
9
        b = OCR0B;
10
        sei();
11
  eeprom_busy_wait();
12
  eeprom_write_byte(&ee_OCRA_Addr,a);
13
  eeprom_busy_wait();
14
  eeprom_write_byte(&ee_OCRB_Addr,b);
15
  eeprom_busy_wait();
16
        cli();
17
// Und dann lesen. Das geht ohne busy wait
18
OCR0A = eeprom_read_byte(&ee_OCRA_Addr);
19
OCR0B = eeprom_read_byte(&ee_OCRB_Addr);
Du solltest auch dran denken, das eine EEPROM Zelle nach etwa 100000 mal 
schreiben kaputt geht, bzw. nicht mehr die Daten halten kann. Also nicht 
blind reinschreiben, sondern nur, wenn es wirklich was zu schreiben 
gibt, z.b. in einer Brownout Routine.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.