PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Helligkeitssteuerung einer LED mit PWM



vashan
01.04.2007, 14:58
Hallo!

Also zu meinem Problem, ich möchte mit Pulsweitenmodulation die Helligkeit einer Leuchtdiode steuern. Mit einem Poti möchte ich die Pulsbreite einstellen können, also wie hell bzw dunkel sie leuchtet.
Ich habe mir schon verschiedene Artikel durchgelesen, verstehe aber nicht wie ich das ganze umsetzen soll.
Als Hardware habe ich das myAVR Testboard, mit dem ATmega8 µC und als Software das MyAVR Workpad.

Folgendes habe ich mir schon überlegt:
Durch drehen des Potis ändert sich ja die Spannung, also müsste ich das mit dem Wert 5V (Boardspannung) irgendwie mit dem Spannungswert des Potis vergleichen damit dann die PWM jeweils die Pulsbreite ändert.
D.h. ich brauche wohl einen A/D Wandler? Dieser Wert muss dann in das PWM Register. (?)

Kann mir da vielleicht jemand helfen?

BT
01.04.2007, 15:19
hallo,

na wenn du das myavr workpad hast kannst dir die lösung ja anschauen... datei neu -> eine vorlage laden -> Analog -> PWM LED Dimmer

oder du setzt dir das ganze mit dem myavr codewizard einzeln zusammen...

kurz um du holst dir den ADC wert als 8Bit wert und schaffst ihn in des vergleichsregister des timers... vorausetzung adc und timer sind richtig initialisiert... aber das kannst du ja bequem mit dem codewizard machen

cu BT

vashan
01.04.2007, 15:32
Hallo!

Danke für deinen Tipp. Ich habe mir das Programm ja schon angeschaut und getestet, aber dort wird ja ein ein wechselndes PWM Signal an die rote LED gegeben. Es wird dort ja kein Poti oder so verwendet.

als Vergleichsregister meinst du damit:
out OCR1AH,r18
out OCR1AL,r16 ?

sorry, anscheinend versteh ich die Lösung dort nicht wirklich...

BT
01.04.2007, 15:40
joo, OCR Output Compare Register ;-)

Kurzformel: OCR1AH/L = ADCH/L

nimm noch das beispiel wo der ADC wert zu einer tonfrequenz gewandelt wird und zetzt beides sozusagen zusammen ;-)

cu BT

vashan
01.04.2007, 17:43
hi nochmals!

Habe gerade mit dem Codewizard etwas rumprobiert, (hab ihn vorher nie benutzt) und folgendes ist bei rausgekommen:


;-------------------------------------------------------------------------
; Titel : Helligkeitssteuerung einer LED mit PWM
;-------------------------------------------------------------------------
; Funktion :
; Schaltung : PORTC0=Pot1, PORTB1=LED Rot
;-------------------------------------------------------------------------
; Prozessor : ATmega8
; Takt : 3686400 Hz
; Sprache :
; Datum : 1.4.2007
; Version : 1.0
; Autor :
; Programmer:
; Port :
;-------------------------------------------------------------------------
; created by myAVR-CodeWizard
;-------------------------------------------------------------------------
.include "avr.h"

begin: rjmp main ; 1 POWER ON RESET
reti ; 2 Int0-Interrupt
reti ; 3 Int1-Interrupt
reti ; 4 TC2 Compare Match
reti ; 5 TC2 Overflow
reti ; 6 TC1 Capture
reti ; 7 TC1 Compare Match A
reti ; 8 TC1 Compare Match B
reti ; 9 TC1 Overflow
reti ;10 TC0 Overflow
reti ;11 SPI, STC Serial Transfer Complete
reti ;12 UART Rx Complete
reti ;13 UART Data Register Empty
reti ;14 UART Tx Complete
rjmp onADC ;15 ADC Wandlung komplett
reti ;16 EEPROM Ready
reti ;17 Analog Comparator
reti ;18 TWI (I²C) Serial Interface
reti ;19 Store Program Memory Ready

;------------------------------------------------------------------------
; Initialisierungen
;------------------------------------------------------------------------
main:
;--- Stack Initialisierung ---
ldi r16,hi8(RAMEND)
out SPH,r16
ldi r16,lo8(RAMEND)
out SPL,r16
; Ports initialisieren
sbi DDRB,1 ; PORTB1 auf Ausgang
;--- Timer 1 initialisieren ---
ldi r16,0b00000010 ; Teiler 1/8
ori r16,0b00001000 ; Modus: Zählen bis Vergleichswert (WGM12=1)
out TCCR1B,r16 ; Teiler+Modus schreiben (soll 50Hz sein)
ldi r16,lo8(9216) ; Vergleichswert speichern
ldi r17,hi8(9216)
out OCR1AH,r17
out OCR1AL,r16
ldi r16,0b01100000 ; Port, Referenzspannung und Auflösung
out ADMUX,r16
ldi r16,0b11101101 ; Modus, Interrupt und Start
out ADCSRA,r16
;--- Interrupts erlauben ---
sei
;------------------------------------------------------------------------
; Hauptprogramm-Schleife
;------------------------------------------------------------------------
mainloop: wdr
; ...
rjmp mainloop ; Sprung zum Beginn der Hauptprogrammschleife

;--------------------------------------------------------------------
; onADC - Interrupt bei ADC Wandlung komplett
;--------------------------------------------------------------------
onADC:
push r16 ; Register retten
push r17
push r18
push r19
in r16,SREG ; Statusregister retten
push r16
; Beginn der Ereignisbehandlung
in r16,ADCH ; Einlesen des Analogwertes

;.....??

pop r16 ; Statusregister wiederherstellen
out SREG,r16
pop r19 ; Register wiederherstellen
pop r18
pop r17
pop r16
reti ;Rücksprung


Ich habe mir beide Programme genau angeschaut, aber ich versteh einfach nicht wie ich das jetzt zusammen bekommen soll :(
Meine Gedanken dazu bis jetzt wären wie folgt: Unter Mainloop würd ich jetzt ein "rcall initpwm" und dann unten dran



initPWM: push r16
sbi PORTB,1
ldi r16,0b10000001
out TCCR1A,r16
ldi r16,0b00000010
out TCCR1B,r16
pop r16
ret

wenn das schonmal stimmt, dann frag ich mich aber wo ich denn den Analogwert, den ich ja umgewandelt (?) hab, hin muss????? Ich versteh wirklich nur Bahnhof im moment...

:-s*verwirrt*

BT
01.04.2007, 17:54
ne init kommt nicht in die mainloop... bleib ganz ruhig der aha effekt wird sich schon einstellen...

-------- init sequenz ---------
initADC
initPWM
-------- mainloop -------------
r16/17=getADC
setOCR=r16/16
---------------------------------

es ist einfacher als dir im moment scheint... du bekommst vom ADC eine zahl und gibst sie an in das vergleichsregister des timers... und schon dimmt deine LED ;-) das kannstz du sogar in der ISR vom ADC machen *grins*

cu BT

vashan
02.04.2007, 11:36
wie meinst du das in der mainloop? das versteh ich nicht ganz

-------- mainloop -------------
r16/17=getADC
setOCR=r16/16
---------------------------------

so ich habe als init sequenz ADC und PWM jetzt drin.
Die LED leuchtet schon mal :D aber wie bekomme ich jetzt den umgewandelten Analogwert in das Vergleichsregister? argh ^^
hier nochmals mein bisheriger Code.

;-------------------------------------------------------------------------
; Titel :
;-------------------------------------------------------------------------
; Funktion :
; Schaltung : PORTB1=LED-Rot, PORTC0=Pot1
;-------------------------------------------------------------------------
; Prozessor : ATmega8
; Takt : 3686400 Hz
;-------------------------------------------------------------------------
.include "avr.h"

begin: rjmp main ; 1 POWER ON RESET
reti ; 2 Int0-Interrupt
reti ; 3 Int1-Interrupt
reti ; 4 TC2 Compare Match
reti ; 5 TC2 Overflow
reti ; 6 TC1 Capture
reti ; 7 TC1 Compare Match A
reti ; 8 TC1 Compare Match B
reti ; 9 TC1 Overflow
reti ;10 TC0 Overflow
reti ;11 SPI, STC Serial Transfer Complete
reti ;12 UART Rx Complete
reti ;13 UART Data Register Empty
reti ;14 UART Tx Complete
rjmp onADC ;15 ADC Wandlung komplett
reti ;16 EEPROM Ready
reti ;17 Analog Comparator
reti ;18 TWI (I²C) Serial Interface
reti ;19 Store Program Memory Ready

;------------------------------------------------------------------------
; Initialisierungen
;------------------------------------------------------------------------
main:
;--- Stack Initialisierung ---
ldi r16,hi8(RAMEND)
out SPH,r16
ldi r16,lo8(RAMEND)
out SPL,r16
; Ports initialisieren
sbi DDRB,1 ; PORTB1 auf Ausgang
;--- Interrupts erlauben ---
sei
;--- Timer 0 initialisieren ---
ldi r16,0b00000100 ; Teiler 1/256
out TCCR0,r16 ; Teiler+Modus schreiben
ldi r16,0b01100000 ; Port, Referenzspannung und Auflösung
out ADMUX,r16
ldi r16,0b11101101 ; Modus, Interrupt und Start
out ADCSRA,r16
;----------------------------------------------------------------------
; PWM und ADC initialisieren

rcall initPWM ;Schritt auf/ab
rcall initADC
;------------------------------------------------------------------------
; Hauptprogramm-Schleife
;------------------------------------------------------------------------
mainloop: wdr
out OCR1AH,r18
out OCR1AL,r16
rjmp mainloop ; Sprung zum Beginn der Hauptprogrammschleife
;------------------------------------------------------------------------
; UP: ADC initialisieren
; Beachte: Interrupt-Vektor "onADC" setzen
;------------------------------------
initADC: push r16
ldi r16,0
out ADMUX,r16 ; ADC Chanel
ldi r25,0b11011101
out ADCSRA,r25 ; enable ADC, INT, start
sei
pop r16
ret
;------------------------------------
; ISR: ADC initialisieren
; PA: r27:r26 10Bit, r25 8Bit
onADC: cli
in r26,ADCL
in r27,ADCH
asr r27
ror r26
asr r27
ror r26
mov r25,r26
sbi ADCSRA,6
sei
reti
;------------------------------------------------------------------------
; UP PWM initialisieren
; Parameter: keine
; PWM Chanel A Mode 1: 8-bit PWM, Phase-Correct, Clock/8
initPWM: push r16
sbi PORTB,1 ; PWM-Chanel A
ldi r16,0b10000001 ; PWM-Mode
out TCCR1A,r16
ldi r16,0b00000010 ; Vorteiler / PWM Frequenz
out TCCR1B,r16
pop r16
ret
;------------------------------------------------------------------------

vashan
02.04.2007, 15:32
Hallo nochmals, ich denke ich konnte endlich das Problem lösen...
Nachdem ich die Register in der Hauptschleife nach den Registern in der "onADC" ISR (r27 bzw r26) benannt habe funktioniert es endlich.
mainloop: wdr
out OCR1AH,r27
out OCR1AL,r26
rjmp mainloop ; Sprung zum Beginn der Hauptprogrammschleife

Es gibt sicher eine bessere Lösung für das Problem.
Ich würde mich über weitere Kommentare und Tipps freuen!

Gruß Vashan