Forum: Mikrocontroller und Digitale Elektronik PWM - Frage


von funker (Gast)


Angehängte Dateien:

Lesenswert?

Habe hier in der Codesammlung eine Datei für PMW gefunden, die für den
AT90S4433 umgeschrieben worden ist.
Die LEDs hängen bei mir an PIN B0-B5, also 6 stück.
Jetzt kompiliere ich das Programm und lade es in den µC, aber es wird
nur eine LED gedimmt.
Es wird immer nur an PIN B1 gedimmt!

dann habe ich die Zeile
PORTB = 0xFF;
gelöscht, jetzt leuchten zwar alle LEDs, aber wieder wird nur B1
gedimmt...

Brauche Rat!

von funker (Gast)


Lesenswert?

hat sich erledigt, eine Bestätigung wäre noch gut:

Laut Datenblatt AT90S4433 ist PIN B1 -> OC1

darum oder?

gibt es aber nicht eine Möglichkeit alle LEDs dimmen zu lassen?

von funker (Gast)


Lesenswert?

Und was ich eigentlich damit gemeint?

#define OC1A PD5                   // output compareA pin

Wenn ich die Zeile komplett weglasse ändert sich auch nichts...

die Zeilen haben scheinbar auch keine Funktion, das gleiche ohne sie:
sbi(DDRD,OCR1);                // set OC1A pin as output
cbi(PORTD,OCR1);               // clear OC1A

von Fabian Braun (Gast)


Lesenswert?

Servus funker!

Gut bemerkt! Mit diesem Programm kannst du nur
die eine LED dimmen lassen, da nur dies der PWM
Ausgang ist...um mehrer zu dimmen müsstest du
sie halt parallel oder in serie schalten. Dann
werden aber alle gleich gedimmt. Um alle verschieden
zu dimmen und z.b. 8 pins dimmen müsstest du
dann eher ein softwaremässigen pwm programmieren
mit timer, sofern dies überhaupt möglich ist.
also theoretisch schon :-)

#define OC1A PD5
hat meiner meinung nach auch kein sinn, daa OC1A im
Programm nirgens benötigt wird :-S...komische sache

beim anderen bin ich mir jetzt gerade nicht so sicher
möchte nichts behaupten und hab jetzt keine zeit mehr
sorry!

hoffe es hat dir geholfen!

gruss fabian

von Oliver (Gast)


Lesenswert?

Hi,
wenn man Dioden parallel schaltet, leuchten sie unterschiedlich hell,
da die Schwellspannung immer stwas verschieden ist. Besser ist die
Reihenschaltung.

Gruß Oliver

von Frank Linde (Gast)


Lesenswert?

Eine Software-PWM mit 8 unabhängigen Kanälen ist problemlos machbar.
Hier geistert irgendwo auch eine fertige Version (Assembler) von Peter
Dannegger herum. Ist IMHO sehr elegant, kurz und schnell.

Gruß, Frank

von funker (Gast)


Lesenswert?

Danke schon mal für eure Hilfe!
Ach zum C-Programm: delay(1000000) ist natürlich Schwachsinn, mehr als
65536 wird wohl wegen der 16bit Integer nicht gehen.

Mir reicht vorerst die eine LED. Aber ich würde gerne diese Stelle
delay(10000);
also den Wert von delay durch ein Poti regeln.
10k-Poti, also 10k Ohm -> delay(10000)

Kann mir da jemand helfen?

von Frank Linde (Gast)


Lesenswert?

Im Prinzip ganz einfach: Potentiometer als Spannungsteiler an einem
ADC-Port anschließen, Wert einlesen, Wert in gewünschte Delayzeit
umrechnen und als Variable an Delay-Routine übergeben.

Gruß, Frank

von funker (Gast)


Lesenswert?

Ich habe jetzt eine ganze weile die Codesammlung und die Suchmaschine
durchforstet und von Andreas Schwarz was gefunden, der gibt es
allerdings über UART weiter, die Werte...

Kann sich mal jemand ansehen, ob es so funktionieren könnte:

.include "include/4433def.inc"

.def temp = r16
.def temp2 = r17

;Stackpointer initialisieren
ldi temp, RAMEND
out SP, temp

;Port C auf Eingang schalten
ldi temp, 0x00
out DDRC, temp

;ADC initialisieren
;ADEN (ADC Enable) = 1
;ADSC (ADC Start Conversion) = 1
;ADFR (ADC Free Run Select) = 1
ldi temp, ((1<<ADEN)|(1<<ADSC)|(1<<ADFR))+7
out ADCSR, temp

      ;Kanal auswählen
ldi temp, 0    ;PC0 als Eingang
out ADMUX, temp

loop:
in temp, ADCL      ;ADC einlesen
in temp2, ADCH
push temp          ;temp auf dem Stack sichern
rjmp loop

Und ob ich das Assembler (was mir immer besser gefällt) - Programm
richtig verstanden habe.
Also die Initialisierung sollte doch so klappen, wobei mir "free run"
nicht wirklich viel sagt.
Der Wert (Spannung?) wird an PC.0 eingelesen und in "r16" und "r17"
abgelegt, anschliessend mit push temp auf dem Stack gesichert.

Sollte das einlesen und "speichern" meines Wertes klappen, dann muss
ich also den Wert vom Stack holen und in mein C-Programm in der
While-Schleife einfügen.

while(temp){}  <- wie sieht das dann richtig aus?
while(r16){}   <- oder so?
pop r17        <- brauche ich den pop-Befehl? der holt doch eigentlich
die Wert aus den Registern zurück?

Brauche ich eigentlich temp2 ???


...ganz so einfach ist das für mich jetzt auch wieder nicht.

von Frank Linde (Gast)


Lesenswert?

Free runing mode bedeutet, daß der AD-Wandler ununterbrochen die
anliegende Spannung digitalisiert, also kein "Los, digitalisier das
jetzt"-Kommando erforderlich ist. Da der ADC einen 10-Bit-Wert
ausgibt, benötigst Du temp2.

Was Du mit den while-Konstruktionen bezwecken möchtest, erschließt sich
mir gerade nicht. Außerdem kannst Du den ADC doch auch direkt in C
auslesen:

variable1 = in (ADCL)
variable2 = in (ADCH)

So geht's jedenfalls mit dem AVRGCC...

Gruß, Frnak


Gruß, Frank

von funker (Gast)


Lesenswert?

Danke für den Hinweis mit dem auslesen in C... Ich muss momentan noch
immer erst Google fragen, dann hier die Suchmaschine anwerfen und was
rauskommt ist meistens Assembler!

Gute Beschreibungen in AVR-GCC habe ich noch nirgends gefunden, ausser
bei Peter Fleury, den ich jetzt mal loben möchte dafür. Auch das
Tutorial hier ist ganz gut, aber auch viel in Assembler.

Wo ich gerade meine Schwierigkeiten habe, das sind die Timerfunktionen
in C und einen Wert irgendwo ablegen und später im Programm wieder
zurückholen. Darum wollte ich auch einfach mal einen abgespeicherten
Wert zurückholen und in die While-Schleife schreiben.
Ich benutze die Assemblerprogramme um den Ablauf zu verstehen und mit
der C-Syntax für die AVR-Befehle habe ich meine Schwierigkeiten. Ich
nutze dann meistens Fleurys-C-Programme um an die Syntax zu kommen.

Initialisierung in C: korrekt?

void InitADC(void)
{
  sbi(ADCSR, ADEN);  // ADC bekommt Power
  cbi(ADCSR, ADFR);  // Free Run Modus
  sbi(ADCSR, ADIE);  // enable ADC interrupts
  sei();    // Interrupts on - wenn nicht schon on
}


Das in C zu übersetzen, daran hänge ich mich auf!

loop:
in temp, ADCL      ;ADC einlesen
in temp2, ADCH
push temp          ;temp auf dem Stack sichern
rjmp loop

von funker (Gast)


Lesenswert?

Ich meine das "push temp" und dann später wieder zurückholen...
Hat vielleicht jemand ein kleines progrämmchen, mit dem man das
nachvollziehen kann?

cbi(ADCSR, ADIE);  muss es ja heissen

funktioniert das dann so?



while(1){
          uint16_t temp = in (ADCL);
          uint16_t temp2 = in (ADCH);
          uint16_t speichern;

          in (ADCL);
          in (ADCH);
          speichern = temp;
}

von Frank Linde (Gast)


Lesenswert?

Du denkst in Assembler. Warum programmierst Du dann nicht in Assembler?
Es gibt nichts Besseres, um die Grundlagen zu lernen. Danach kannst Du
immer noch auf C wechseln. So wie Du es jetzt versuchst, mußt Du Dich
mit Assembler UND C auseinandersetzen, was offensichtlich beides
Neuland für Dich ist.

Wenn Du einen Wert in C einliest, dann brauchst Du diesen Wert nicht
explizit über den Stack in eine Unterroutine zu schaufeln, das erledigt
der Compiler für Dich. Wenn schon C, dann nutze auch die Vorteile (hier
Variablen).

Gruß, Frank

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.