Hallo, ich versuche gerade auf einem Port unterschiedliche PWM´s zu
programmieren. Es bleiben aber leider alle LED´s gleich hell, also es
läuft nicht. Könnte mir bitte jemand helfen ? (Trotz Bascom......)
Danke !!!
CODE:
$regfile = "m16def.dat"
$crystal = 16000000
Config Portb = Output
Config Timer0 = Timer , Prescale = 256
On Timer0 Timer_irq
Dim X As Byte
Dim Pwm_led(8) As Byte
For X = 1 To 8
Read Pwm_led(x)
Next
Enable Timer0
Enable Interrupts
Portb = 255
Do
Loop
Timer_irq:
For X = 0 To 7
If Pwm_led(x + 1) <= Timer0 Then
Portb.x = 0
Else
Portb.x = 1
End If
Next
Return
End
Data 55 , 55 , 255 , 255 , 255 , 255 , 255 , 255
So wie ich das sehe hast du da eine Kleinigkeit übersehen, nämlich:
Der Timer-INT wird beim Überlauf der Timer-Registers ausgelöst, sprich
beim 8-bit-Timer0 alle 256 Timer-Takte.
Das bedeutet, wenn du das Timer-Register in der Zeile
"If Pwm_led(x + 1) <= Timer0 Then"
ausliest, dann ist Timer0 immer 0, weil der Überlauf gerade
stattgefunden hat. Alternativ könntest du z.B. eine Variable vom Typ
Byte nehmen, die du bei jedem Timer-INT um eine Stelle erhöhst. Was das
setzen der Port-Pins angeht, kannst du das einfach machen: Setz die
Portpins auf ON, immer wenn die Variable den Wert 0 hat und schalte sie
(einzeln!) ab, wenn die Variable den zum Pin zugehörigen PWM-Wert
überschreitet.
Da die Variable beim hochzählen beim erreichen von Werten > 255
automatisch auf 0 zurückspringt, musst du nur im INT mit einer
IF-Bedingung prüfen, ob sie den Wert 0 hat und dann "Portb = 255"
setzen.
Also z.B.
Dim PWM As Byte
Timer_irq:
If PWM = 0 Then portb = 255
For X = 0 To 7
If Pwm_led(x + 1) <= PWM Then
Portb.x = 0
End If
Next
Incr PWM
Return
Gruß Mario
Danke für deinen rat. Habe es wie unten gebessert, aber es sind
immernoch alle led´s gleich hell (an).
$regfile = "m16def.dat"
$crystal = 16000000
Config Portb = Output
Config Timer0 = Timer , Prescale = 256
On Timer0 Timer_irq
Dim X As Byte
Dim Pwm_led(8) As Byte , Pwm_counter As Byte
For X = 1 To 8
Read Pwm_led(x)
Next
Enable Timer0
Enable Interrupts
Portb = 255
Do
Loop
Timer_irq:
If Pwm_counter = 0 Then Portb = 255
For X = 0 To 7
If Pwm_led(x + 1) <= Pwm_counter Then
Portb.x = 0
End If
Next
Incr Pwm_counter
Return
End
Data 255 , 255 , 255 , 100 , 100 , 255 , 255 , 255
Hallo
Kann das sein das der IRQ Routine nicht ganz durchlaufen wird und dann
sich selbst aufruft?
Hast du mal das im Simulator getestet wie hoch PWM_Counter kommt und was
die anderen Werte stehen.
Bascom-Projekte auf http://www.comwebnet.de
In der Interrupt-Routine solltest du grundsätzlich möglichst wenig Zeit
verbringen. Deshalb setze ich dort nur ein Flag, das ich in der main
loop abfrage.
Bascom stellt sich mit Interrupts ziemlich blöd an: er pushed und popped
ALLE Register, ob sie in der Interrupt-Routine benutzt werden oder
nicht. Deshalb sollte man (mit AVR-Studio) nachsehen welche Register
benutzt werden und nur diese gezielt sichern.
Dann kann mein beim On Interrupt Befehl den Parameter Nosave angeben, so
dass Bascom von sich aus nichts sichert.
Teste mal diesen Code:
$regfile = "m16def.dat"
$crystal = 16000000
Config Portb = Output
Config Timer0 = Timer , Prescale = 256
On Timer0 Timer_irq Nosave
Dim X As Byte
Dim Pwm_led(8) As Byte , Pwm_counter As Byte
Dim Pwm_update As Byte
For X = 1 To 8
Read Pwm_led(x)
Next
Enable Timer0
Enable Interrupts
Portb = 255
Do
If Pwm_update = 1 Then
Pwm_update = 0
Incr Pwm_counter
For X = 0 To 7
If Pwm_led(x + 1) <= Pwm_counter Then
Portb.x = 0
Else
Portb.x = 1
End If
Next
End If
Loop
End
Timer_irq:
'Wenn weitere Befehle in der ISR ausgeführt werden sollen,
'muss überprüft werden welche Register diese benutzen und diese
'Register müssen dann ebenfalls auf den Stack gerettet werden!!!
PUSH R24 'Nachfolgend wird nur R24 benutzt, dieses also
retten
IN r24, SREG
PUSH R24
Pwm_update = 1
POP R24
!Out Sreg , R24
POP R24
Return
Data 255 , 255 , 255 , 100 , 100 , 255 , 255 , 255
So, habe folgenden Code geschrieben. Wenn ich den Teiler auf 8 oder 1
stelle, läuft der PWM-Teil super, kann aber nix anderes mehr machen.
Z.B. ausgabe auf dem LCD ist extrem langsam. Stelle ich den Teiler wider
auf 256, ist der PWM-Teil zu lahm, aber der rest geht. Kann mann es
nicht machen, das der PWM-Teil funktioniert, und der AVR noch was
anderes machen kann ?
Bitte um hilfe !!!
@Erwin, bei deinem beispiel ist es das selbe.
ach, der code........
$regfile = "m16def.dat"
$crystal = 16000000
Config Portb = Output
Config Timer0 = Timer , Prescale = 256
On Timer0 Timer_irq
Const Timervorgabe = 6
Dim X As Byte
Dim Pwm_led(8) As Byte
Dim Pwm_counter As Byte
Restore Pwm_daten
For X = 1 To 8
Read Pwm_led(x)
Next
Enable Timer0
Enable Interrupts
Cls
Cursor Off
Portb = 0
Do
Locate 1 , 1
Lcd "Moin"
Waitms 60
Loop
Timer_irq:
Timer0 = Timervorgabe
Incr Pwm_counter
For X = 0 To 7
If Pwm_counter < Pwm_led(x + 1) Then
Portb.x = 1
Else
Portb.x = 0
End If
Next
Return
Pwm_daten:
Data 10 , 20 , 30 , 40 , 40 , 30 , 20 , 10
In der Artikel-Sammlung gibt es einen sehr interessanten Artikel zum
Thema Soft PWM, ich denke von Falk(?)
Leider ist der Programmcode in C.
Ich hab mal versucht, das unten beschriebene 'intelligente' Verfahren in
ein verbesserungsfähiges Bascom Programm umzusetzten.
Schau doch mal, ob diese Routine weniger Rechenzeit braucht!
$regfile = "m16def.dat"
$crystal = 8000000
Config Portb = Output
Config Timer0 = Timer , Prescale = 256
On Timer0 Timer_irq Nosave
Dim X As Byte
Dim Pwm_led(8) As Byte
Dim Pwm_zeit(8) As Byte
Dim Action As Byte
Dim Zustand As Byte
Dim Lcdwait As Byte
Restore Helligkeit
For X = 1 To 8
Read Pwm_zeit(x)
Next
Enable Timer0
Enable Interrupts
Portb = 0
Do
If Action = 1 Then
Action = 0
Stop Timer0
If Zustand = 0 Then
Portb = 0
Decr Zustand
Else
Decr Zustand
Set Portb.zustand
End If
Zustand = Zustand + 2
Timer0 = Pwm_zeit(zustand)
If Zustand = 10 Then Zustand = 0
Start Timer0
Incr Lcdwait
End If
If Lcdwait = 10 Then 'nur jeden
10. Durchlauf LCD schreiben
Lcdwait = 1
Locate 1 , 1
Lcd "Moin"
End If
Loop
End
Timer_irq:
'Wenn weitere Befehle in der ISR ausgeführt werden sollen,
'muss überprüft werden welche Register diese benutzen und diese
'Register müssen dann ebenfalls auf den Stack gerettet werden!!!
PUSH R24 'Nachfolgend
wird nur R24 benutzt, dieses also retten
Action = 1
POP R24
Return
Helligkeit:
Data 255 , 249 , 237 , 219 , 193 , 156 , 230 , 253
' 1 7 19 37 63 100 26 3 "An-Zeit" =
256-Data Summe =256
Wegen des LCD-Zugriffs flackern die LEDs in meinem Programm von
23:09Uhr.
Sorry, hab ich nicht bemerkt.
Hier jetzt flimmert nix mehr, ich habe es gerade getestet.
Ob die LCD-Ausgabe schnell genug ist, musst du selbst sehen, ich habe
gerade keines angeschlossen.
Das Programm muss für die praktische Anwendung noch ergänzt werden:
Das Array Pwm_zeit(8) enthält jetzt erstmal die Zeitdifferenzen zwischen
den 8 einzelnen PWM-Kanäle.
Eigentlich will man aber das Tastverhältnis der 8 Kanäle in einem Array
haben.
Das erfordert ein zweites Array. Nach einer Änderung der Werte dieses
zweiten Arrays müssen die Abstände in Pwm_zeit(8) neu berechnet werden.
$regfile = "m16def.dat"
$crystal = 8000000
$baud = 57600
Config Lcdpin = Pin , Db4 = Portc.0 , Db5 = Portc.1 , Db6 = Portc.2 ,
Db7 = Portc.3 , E = Portc.4 , Rs = Portc.5
Config Portb = Output
Config Timer0 = Timer , Prescale = 256
On Timer0 Timer_irq Nosave
Dim X As Byte
Dim Pwm_zeit(8) As Byte
Dim Action As Byte
Dim Zustand As Byte
Restore Helligkeit
For X = 1 To 8
Read Pwm_zeit(x)
Next
Enable Timer0
Enable Interrupts
'-----------------------------------------------------------
'Main Schleife
Do
Locate 1 , 1
Lcd "Moin"
Waitms 100
Loop
'-----------------------------------------------------------
End
Timer_irq:
'Wenn weitere Befehle in der ISR ausgeführt werden sollen,
'muss überprüft werden welche Register diese benutzen und diese
'Register müssen dann ebenfalls auf den Stack gerettet werden!!!
PUSH R27
PUSH R26
PUSH R25
PUSH R24
PUSH R16
PUSH R11
PUSH R10
IN R24, SREG
PUSH R24
Stop Timer0
If Zustand = 0 Then
Portb = 0
Decr Zustand
Else
Decr Zustand
Set Portb.zustand
End If
Zustand = Zustand + 2
Timer0 = Pwm_zeit(zustand)
If Zustand = 10 Then Zustand = 0
Start Timer0
POP R24
!OUT SREG, R24
POP R10
POP R11
POP R16
POP R24
POP R25
POP R26
POP R27
Return
Helligkeit:
Data 255 , 249 , 237 , 219 , 193 , 156 , 230 , 253
' 1 7 19 37 63 100 26 3 "An-Zeit" =
256-Data Summe =256