PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : LED per PWM einschalten und dimmen PROBLEM



mat-sche
13.02.2014, 08:35
Guten Morgen liebe Gemeinde,

ich hänge schon eine geraume Zeit an meiner PWM-Dimmung eines LED-Strip.
Ich möchte diesen Strip einmal per PWM dimmen und ihn ein/ausschalten können.
Das Einschalten funktioniert: Start Timer1
Pwm_byte = 255 (Pwm1a = Pwm_byte in der Main-Do/Loop)
und dimmen auch: Pwm_byte = Pwm_byte - 10

Nur das Auschalten des PWM funktioniert nur sporadisch. Verkleinere ich den Wert für Pwm1a dann kann ich über: Pwm_byte = 0 und Stop Timer1 die LEDs ausschalten.
Steht aber eine 255 im Pwm1a drinnen, lassen sich die LEDs nicht ausschalten, warum???

Könnte mir bitte jemand einen Tipp geben, wie man den PWM so ansteuert, dass somit gedimmt und ausgeschalten werden kann???

Klar.... ich habe die Hilfe gelesen und gegoogelt aber keine Lösung gefunden.
Die LEDs hängen am OC1A.
Hier mein kleines Programmchen:



$regfile = "m88def.dat" ' specify the used micro ' used crystal frequency
$crystal = 14745600
$baud = 57600 ' use baud rate
$hwstack = 70 ' default use 32 for the hardware stack
$swstack = 70 ' default use 10 for the SW stack
$framesize = 60 ' default use 40 for the frame space
Const Release = "2014.02.13 RGB-On V1.00"
'------------------------------------------------------------------------------- Testvariablen

Dim Tempo As Byte '=> für Print
'------------------------------------------------------------------------------- rs232
Dim Rx_data As Byte , Uart_rxd As Bit
On Urxc Rxd_isr 'Interrupt Empfange String von RXD
Enable Urxc
'------------------------------------------------------------------------------- allg. Variablen
'Ddrc = &B01001111 ' PortC (LED + Relaisausgänge + FSK) auf Ausgang setzen
'Portc = &B10110000 ' PortC pull up Widerstand (Taster) einschalten
Config Pinb.0 = Input : Taster Alias Pinb.0 : Portb.0 = 1 ' Schalter von der Dunstabzugshaube
Config Portb.1 = Output : Led_pwm Alias Portb.1 ' hinterer LED-Strip dieser kann gedimmt werden
Config Portc.1 = Output : Led_vorn Alias Portc.1 ' vorderer LED-String nur für Beleuchtung
Dim Pwm_byte As Byte ' Konstante für hinterer Strip = 100%
Config Timer1 = Pwm , Pwm = 8 , Compare_a_pwm = Clear Up , Prescale = 1
'Dim Rgb_vorn_flag As Bit , Rgb_hinen_flag As Bit

'------------------------------------------------------------------------------- Variablen

'------------------------------------------------------------------------------- RFM12 Variablen & Hardwaresetup = Anschluss
Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes , Polarity = Low , Phase = 0 , Clockrate = 4 , Noss = 0 , Spiin = &HB0
Spiinit
Config Int0 = Rising 'Rising
On Int0 Ffit_isr
Enable Int0
Spi_sdo Alias Pinb.4
Spi_cs Alias Portb.2 : Ddrb.2 = 1
Set Spi_cs
Config Portc.3 = Input
Nirq Alias Pinc.3
Config Portc.2 = Input
Ffit Alias Pinc.2
'-------------------------------------------------------
Declare Sub Rf12_init()
Declare Sub Rf12_txdata(byval Txlen As Byte)
Declare Sub Rf12_ready
Declare Sub Rf_cmd(byval Wert As Word)
Dim Cmd(2) As Byte , Lv As Byte
Declare Sub Sdi_send(byval Sdi_byte As Byte)
Dim Sdi(2) As Byte , Fifo(2) As Byte
Sdi(1) = &HB8

Const Myadress = 40 'Nodeadresse vom Teilnehmer
Const Snap_sync = &H54 'Synczeichen SNAP-Protokoll
Const Hdb2_ = &H50
Const Recive_buffer_size = 15
Dim Slaveadress As Byte
Dim Mem_dummy As Byte , Dummy As Byte ' Variablen für Lösche des Empfangsarray
Dim Rf12_timeout As Word , Rf12_err As Byte , Byteanzahl As Byte
Dim Framelength As Byte , Crc As Byte , Crc_rx As Byte , Rf_sync As Bit , Rf_rxd As Bit , Crclength As Byte
Dim Rf12_data(20) As Byte ' , Rf12_s(12) As Byte At Rf12_data + 4 ' Rx_data(40) As Byte
Dim Temp As Byte , Temp_rfm As Word
Sync Alias Rf12_data(1)
Hdb2 Alias Rf12_data(2)
Hdb1 Alias Rf12_data(3)
Dab1 Alias Rf12_data(4)
Sab1 Alias Rf12_data(5)


'-------------------------------------------------------------------------------
'**************************** Programmstart *********************************
Enable Interrupts
Call Rf12_init()
Print Release
Stop Timer1 ' PWM-Erzeugung gestoppt, wird über RFM12 zugeschalten

'################################################# ################################################## ##
'############################################# MAIN DO ###########################
'################################################# ################################################## ##
Do
Pwm1a = Pwm_byte ' Timervorgaben für Timer => Steuerung Helligkeit
'************************************************* ****************************** UART-Auswertung
If Uart_rxd = 1 Then
Select Case Rx_data
Case 123 : Goto $c00 'vom MCS-Programmer geschickte "123" empfangen?
Case "1" : Pwm_byte = Pwm_byte - 10
Print " pwm_byte " ; Pwm_byte
Case "2" : Start Timer1
Pwm_byte = 100
Case "3" : Pwm_byte = 0
Stop Timer1
Reset Led_pwm

End Select
Print Pwm_byte
Uart_rxd = 0
End If

'************************************************* *****************************
Debounce Taster , 0 , Led_an , Sub ' Lichtschalter an Haube

'************************************************* ****************************** RFM12 abfragen & Empfangsbereit schalten
If Rf_rxd = 1 Then
Rf_rxd = 0
'Gosub Framehandler
'Gosub Rf12_rxd_on
End If '

Loop
End

'+++++++++++++++++++++++++++++++++++++++++++++++Su broutinen+++++++++++++++++++++
'+++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++
'(********* ISR Timer 1 ************************************************** *
25ms_irq: ' 25ms Interrupt für die Tastenentprellung und Zeitzählung Rolladen Hoch/Runter

Timer1 = Timer1vorgabe
Incr Timecount
Return 'and exit isr with RETI
')
'+++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++ Tasterdebounce
Led_an:
Toggle Led_vorn
Select Case Led_vorn
Case 0 : If Rf12_data(6) = 1 Then
Pwm_byte = 155
Start Timer1
Else
Stop Timer1
Pwm_byte = 0
Reset Led_pwm
End If
Case 1 : Start Timer1
Pwm_byte = 255
End Select
Return

'++++++++++++++++++++++++++++++ Auswertung des RFM12 Frames auf Pausablität & Sende-Empfangsroutinen +++++++++++++++++++++++++++++++++++++++++++
'++++++++++++++++++++++++++++ Einstellen des RFM 12 für 868,35MHz
'Einstellen des RFM 12
Sub Rf12_init()
Waitms 150
Call Rf_cmd(&H0000) 'Read Status
Call Rf_cmd(&Hc0e0) 'low battery, clock 10 MHz
Call Rf_cmd(&H80e7) 'Configuration: 868MHzband, 12pf, enable FIFO
Call Rf_cmd(&H82d8) 'power management: enable receiver, enable clock output
Call Rf_cmd(&Hc2ac) 'data filter command
Call Rf_cmd(&Ha686) 'Frequency: 868,35MHz
'Call Rf_cmd(&Ha74e) 'Frequency: 869,35MHz
Call Rf_cmd(&Hc611) 'Datarate: 19,2 kbit
Call Rf_cmd(&H94a1) 'receiver setting: 134kHz, -97dbm
Call Rf_cmd(&Hc2ac) 'data filter:
Call Rf_cmd(&Hc483) 'AFC:
Call Rf_cmd(&H9850) 'TX control
Call Rf_cmd(&He000) 'wake-up
Call Rf_cmd(&Hc800) 'low duty-cycle
Call Rf_cmd(&Hca81) 'Reset FIFO
Call Rf_cmd(&Hca83) 'enable FIFO
Call Rf_cmd(&H0000) 'read Status
End Sub
'+++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++ Sende Daten
Sub Rf12_txdata(byval Txlen As Byte)
'
Print "Rf12_txdata(framelength) " ; Framelength
For Tempo = 1 To Framelength
Print "send-data " ; Rf12_data(tempo) ; " " ; Tempo
Next
Print "txdata-end "
Print

Call Rf_cmd(&H8220) : Rf12_ready ' Sender aktivieren
Call Sdi_send(&Haa) : Rf12_ready 'Preamble
Call Sdi_send(&Haa) : Rf12_ready 'Preamble
Call Sdi_send(&H2d) : Rf12_ready 'Startzeichen: 2D für den Empfänger 'Preamble
Call Sdi_send(&Hd4) : Rf12_ready 'Startzeichen: D4 für den Empfänger
For Lv = 1 To Txlen
Rf12_ready
Call Sdi_send(rf12_data(lv))
Next Lv
Call Sdi_send(&Haa) : Rf12_ready 'Dummybyte nachschieben
Call Sdi_send(&Haa) : Rf12_ready

End Sub
'+++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++ Befehl zum RFM senden z.bsp. Initialisierungen
'
Sub Rf_cmd(byval Wert As Word)
Cmd(2) = Wert And 255
Shift Wert , Right , 8
Cmd(1) = Wert
Spiout Cmd(1) , 2
End Sub

'+++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++ Daten zum RFM12 senden
Sub Sdi_send(byval Sdi_byte As Byte) 'wait for TX FIFO IRQ
Bitwait Nirq , Reset
Sdi(2) = Sdi_byte
Spiout Sdi(1) , 2
End Sub

'+++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++ Busy check
' nach jeder SPI-Übertragung wird geprüft, ob Übertragung erfolgreich und neue Daten gesendet werden können
Sub Rf12_ready
Rf12_timeout = 60000 'Timeout Zeit (orig. 50000)
Reset Spi_cs 'SS-Pin--> select RF12
While Spi_sdo = 0 'MISO muss von RF12 auf high gehen 'In der Sim. auf 1 stellen
If Rf12_timeout > 0 Then 'Timeout Loop
Decr Rf12_timeout
Else
Rf12_err = 1 'Flag setzen
Exit While 'Timeout --> Abbruch kein ready vom RF12
End If
Waitus 20
Wend 'Warten bis senden bzw. empfangen fertig
End Sub
'+++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++ RFM12 - Empfänger einschalten
Rf12_rxd_on:
Print "rxd on"
'Dummy = Memcopy(mem_dummy , Rf12_data(1) , Framelength , 2)
Lv = 1 ' Empfangsbytezähler zurück setzen
Rf_sync = 0 'Sync-Erkennung zurücksetzen 'sync-Flag
Rf_rxd = 0 ' Empfangserkennung zurücksetzen
Call Rf_cmd(&H0000) 'Status lesen
Call Rf_cmd(&H82d8) ' Empfänger einschalten
Call Rf_cmd(&Hca81) 'FIFO&Reset CMD: sensitiver Reset aus (Brownout)
Call Rf_cmd(&Hca83) 'FIFO&Reset CMD: Synchroner Zeichenemfang (warte auf Startzeichen: 2DD4)
Enable Int1
Enable Interrupts
Return
'+++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++ INT1 ISR(Daten vom RFM12)
'Interrupt Routine zum empfangen der bytes aus dem RFM 12
Ffit_isr:
Spiin Fifo(1) , 2 '1 Byte lesen
Temp = Fifo(2)
If Temp = Snap_sync And Rf_sync = 0 Then
Rf_sync = 1
Lv = 1
Framelength = 4
End If
Rf12_data(lv) = Temp
If Lv = 3 Then Framelength = Temp
If Framelength >= Recive_buffer_size Then
Dummy = Memcopy(mem_dummy , Rf12_data(1) , Framelength , 2)
Framelength = Recive_buffer_size
Call Rf_cmd(&H8208)
Disable Int1
Gosub Rf12_rxd_on
End If
If Lv = Framelength And Rf_sync = 1 Then 'alles eingetroffen
Rf_rxd = 1 'Flag setzen und Empfänger zurück setzen
Rf_sync = 0
Call Rf_cmd(&H8208)
Disable Int1
End If
Incr Lv
Return

'+++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++Send Frame over RF12
Sendsnapframe:
' Zusammenstellung des Sendepaketes mit SNAP-Protokoll
'Header aufbereiten (SNAP) => 5 Byte-Header
Select Case Byteanzahl '6Byte<=sync+HDB2+HDB1+DAB+SAB+letztes Byte = CRC
'Case 0 To 8 : Framelength = 6 '6-14 (0--8 Datebyte)
Case 5 : Byteanzahl = 11
Case 9 : Byteanzahl = 16 '22 (16 Datenbyte)
Case 10 : Byteanzahl = 4
Case 15 : Byteanzahl = 15 '38 (32 Datenbyte)
End Select
Rf12_data(1) = Snap_sync
Rf12_data(3) = Byteanzahl 'HDB1 0..32DatenByteInfo
Rf12_data(4) = Slaveadress 'Zieladresse
Rf12_data(5) = Myadress 'Senderadresse
'ab 6.Stelle <--0...40 Datenbyte rein
Framelength = Byteanzahl
Crclength = Byteanzahl - 1
Rf12_data(framelength) = Crc8(rf12_data(1) , Crclength) 'CRC an letzter Stelle anhängen und raus senden
Call Rf12_txdata(framelength) ' Datenpaket senden
Return

'+++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++ Auswertung empfangener Frams
Framehandler:
If Sync = Snap_sync Then 'Check auf richtiger SNAP-Knoten Syncbyte richtig? ' Adressraum = 1 Byte?
If Dab1 = Myadress Then ' Stimmt die Adressierung?
Crc = Framelength - 1 ' CRC-Länge bestimmen
Crc_rx = Crc8(rf12_data(1) , Crc) ' CRC berechnen
Print "CRC " ; Crc ; " " ; Rf12_data(framelength)
If Crc_rx = Rf12_data(framelength) Then ' in letzter Stelle steht der berechnete Sende-CRC => überprüfen
Print "CRC OK! => " ; Crc_rx
Select Case Hdb2
' Case 1 weiter ohne ACK
Case 1 : Print "ohne ACK "
Gosub Rf12_rxd_on
Gosub Funkdaten_handler
'Dummy = Memcopy(mem_dummy , Rf12_data(1) , Framelength , 2)
' Case 2 als Master => Slave hat mit ACK geantwortet
Case 2 : Print "CRC good => "
Hdb2 = &H0
'Dummy = Memcopy(mem_dummy , Rf12_data(1) , Framelength , 2)
' Case 3 als Slave => sende Master ein ACK
Case 3 : Print "Master fordert ACK "
Gosub Rf12_rxd_on
Swap Dab1 , Sab1
Hdb2 = &H2
Rf12_data(framelength) = Crc8(rf12_data(1) , Crc)
Call Rf12_txdata(framelength)
Gosub Funkdaten_handler ' => Hier Dann Aktionen Ausführen
'Dummy = Memcopy(mem_dummy , Rf12_data(1) , Framelength , 2)
End Select
Else
Print "Framehandler-CRC-Bad" ; Crc_rx
'Dummy = Memcopy(mem_dummy , Rf12_data(1) , Framelength , 2)
End If
Else
Print "das war nicht für mich " ; Dab1
End If

End If
Return
'+++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++
Funkdaten_handler: 'Auswertung der Nutzdaten.... nur als Denkhilfe :)

Select Case Rf12_data(6)
Case 0 : Reset Led_vorn
Stop Timer1
Pwm_byte = 0
Reset Led_pwm

Case 1 : Reset Led_vorn 'Led_vorn = 0
Start Timer1
Pwm_byte = 155


End Select
Return
'+++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++ Uart ISR
Rxd_isr: '
Rx_data = Udr 'Zeichen aus Uart holen
Uart_rxd = 1
Return


Vielen Dank für Eure Hilfe!!!
MAT

for_ro
13.02.2014, 21:26
Setze die TCCR1A.COM1Ax bits auf disconnect, bevor du Reset LED_pwm machst.
Beim Starten musst du dann vor dem PWM_Byte=xxx die bits wieder auf Clear setzen.

mat-sche
14.02.2014, 08:25
Hallo for_ro,

gut, jetzt weiss ich, wie ich den Ausgang OC1A auch als Portpin nutzen kann. Habe ich es richtig verstanden, dass wenn ich TCCR1A.COM1A0/TCCR1A.COM1A1 auf Null setze ich den Portpin als Normalen Input/Outputpin nutzen kann?
Ich wollte nicht umbedingt über diesen Weg gehen. Ursprünglich möchte ich den PWM/OC1a nur ein/ausschalten (LED an/aus) und ich habe gelesen, dass die über Start und Stop Timer1 gehen soll. Nur leider funktioniert dies nicht immer richtig, auch wenn ich den PWM-Wert auf null setze nicht....
Irgend eine Idee du haben :)

Sauerbruch
14.02.2014, 09:39
Ich sehe das Problem eigentlich hier: Wenn Du den Timer einfach so anhältst weißt Du ja nie, ob er gerade über oder unter der Wert von PWM1A ist. Folglich ist es auch nicht beeinflussbar, ob der OC-Pin gerade auf 1 oder auf 0 steht, wenn der Timer stoppt.

Ich konfiguriere meine PWM-Anwendungen immer direkt über die Register, aber "Clear Up" verstehe ich so, dass der Ausgang auf 0 gesetzt wird, wenn der Timer den Wert von PWM1A beim hochzählen überschreitet (korrigiert mich, wenn das nicht stimmt!). Wenn aber 255 in diesem Register steht, tritt dieser Fall aber niemals ein, d.h. der Ausgang bleibt dauerhaft auf 1. Dementsprechend wird der Ausgang immer auf 0 bleiben, wenn 0 im PWM1A-Register steht.

Für alle anderen PWM1A-Werte dürfte der Ausgang beim Stoppen vom Timer 1 "zufällig" 1 oder 0 führen, je nachdem an welcher Stelle der Timer angehalten wurde.

Ich denke, dass das "Abhängen" des OC1A-Pins die beste Lösung ist (wie ja schon von for_ro beschrieben).

mat-sche
14.02.2014, 11:56
@Sauerbruch,

Genau so ist es wie Du es beschreibt. das ausschalten der LEDs ist nur spontan möglich. Und Dein erklärtes bestätigt mir meine Vermutung. Dann werde ich per Hand den OC1a direkt ausschalten.
Danke an alle

mat-sche
14.02.2014, 17:35
Soooo und gleich mal ausprobiert :)



'zum Ausschalten mega88 OC1A
Tccr1a.7 = 0
Tccr1a.6 = 0
"Clear OC1A on Compare Match (Set output to
low level)"

'zum Wiedereinschalten
Tccr1a.7 = 1
Tccr1a.6 = 0
Start Timer1 ' PWM aktivieren
Ocr1a = 100 ' PWM Wert bei dem begonnen werden soll



Also das Heißt, dass durch diese Zuweisung mein OC1A-Pin auf 0 geschalten wird.
Noch eine Frage: wie könnte ich die Schreibweise vereinfachen, also ala Tccr1a = &H..... Was ich mich schon immer gefragt habe ist, wie kann ich einzellne Bits im Byte so verändern, dass nur diese geändert werden (siehe obriges Beispiel).

Vielen Dank an alle!