Forum: Mikrocontroller und Digitale Elektronik Software Pwm auf 8 Pin´s mit Bascom


von Gast (Gast)


Lesenswert?

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

von Mario Müh (Gast)


Lesenswert?

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

von Gast (Gast)


Lesenswert?

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

von Avr N. (avrnix) Benutzerseite


Lesenswert?

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

von Erwin (Gast)


Lesenswert?

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

von Gast (Gast)


Lesenswert?

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.

von Gast (Gast)


Lesenswert?

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

von Erwin (Gast)


Lesenswert?

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

von Erwin (Gast)


Lesenswert?

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

von Gast (Gast)


Lesenswert?

Das hatte ich mir leichter vorgestellt. Hat der M128 nicht von hause aus 
8 PWM
kanäle, die ich unabhängik nutzen kann ?

von Gast (Gast)


Lesenswert?

Oder wie sieht es mit einem TDA8444 aus ? Kennt den einer ?

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.