3-fach 10bit Software PWM mit 16F88
Dienstag, 22. Mai 2012
 
 

PIC Mikrocontroller Forum  |  PIC Mikrocontroller  |  CCS Compiler  |  LCD (CCS)  |  3-fach 10bit Software PWM mit 16F88 « vorheriges nächstes »
Seiten: [1] Nach unten Drucken
Autor Thema: 3-fach 10bit Software PWM mit 16F88  (Gelesen 2239 mal)
 
wolfi_b
Jr. Member
**
Offline Offline

Beiträge: 84


Profil anzeigen
« am: Januar 13, 2008, 20:35:48 »

Hi Leute!

Ich möchte mit einem 16F88 eine RGB-LED steuern und zwar sollen alle drei Farben mit 10 bit Auflösung ansteuerbar sein. Dazu habe ich eine 3-fache Software PWM mit 10 bit geschrieben.
Der PIC wird mit 20MHz betrieben, der Timer2 ist so konfiguriert das er bis 70 zählt, Vorteiler 1:1, Nachteiler 1:1. Wenn der Timer überläuft wird in der ISR ein Zähler erhöht (pwmCounter). In der ISR wird der Zähler mit den 3 Duty-Cycles verglichen und die entsprechenden Pins dann deaktiviert oder aktiviert. Damit komme ich auf eine Frequenz von 70Hz aber man merkt noch ganz leichtes flackern weshalb ich gerne 100Hz hätte. Ich kann die Frequenz aber nicht erhöhen (Timer2-Obergrenze) weil die ISR dafür einfach zu lang ist, 70Hz ist schon die Grenze. Durch Inline-Assambler konnte ich die ISR schon drastisch kürzen (was macht CCS blos in den unzähligen Codezeilen???):

Code:
#int_global
isr()
{
  #asm ASIS
  MOVWF W_TEMP          ;Copy W to TEMP register
  SWAPF STATUS,W        ;Swap status to be saved into W
  CLRF  STATUS          ;bank 0, regardless of current bank, Clears
  MOVWF STATUS_TEMP     ;Save status to bank zero STATUS_TEMP register
  MOVF  PCLATH, W       ;Only required if using page 1
  MOVWF PCLATH_TEMP     ;Save PCLATH into W
  CLRF  PCLATH          ;Page zero, regardless of current page
   
  BTFSS PIR1,1          ;TMR2IF interrupt?
  goto ISR_END;
  #endasm
 
  pwmCounter++;
  if(pwmCounter==1024)
    pwmCounter=0;

  if(pwmCounter<pwmRedDS_10)
    PIN_RED=1;
  else
    PIN_RED=0;

  if(pwmCounter<pwmGreenDS_10)
    PIN_GREEN=1;
  else
    PIN_GREEN=0;

  if(pwmCounter<pwmBlueDS_10)
    PIN_BLUE=1;
  else
    PIN_BLUE=0;
   
  #asm ASIS
ISR_END:
  MOVF  PCLATH_TEMP, W  ;Restore PCLATH
  MOVWF PCLATH          ;Move W into PCLATH
  SWAPF STATUS_TEMP,W   ;Swap STATUS_TEMP register (sets bank to original)
  MOVWF STATUS          ;Move W into STATUS register
  SWAPF W_TEMP,F        ;Swap W_TEMP
  SWAPF W_TEMP,W        ;Swap W_TEMP into W
 
  BCF   TMR2IF            ;TMR2 Interrupt Flag löschen
  #endasm
}

Der Compiler macht das draus:
Code:
.................... #int_global
.................... isr()
.................... {
....................   #asm ASIS 
....................   MOVWF W_TEMP          ;Copy W to TEMP register
*
0004:  MOVWF  70
....................   SWAPF STATUS,W        ;Swap status to be saved into W
0005:  SWAPF  03,W
....................   CLRF  STATUS          ;bank 0, regardless of current bank, Clears
0006:  CLRF   03
....................   MOVWF STATUS_TEMP     ;Save status to bank zero STATUS_TEMP register
0007:  MOVWF  71
....................   MOVF  PCLATH, W       ;Only required if using page 1
0008:  MOVF   0A,W
....................   MOVWF PCLATH_TEMP     ;Save PCLATH into W
0009:  MOVWF  72
....................   CLRF  PCLATH          ;Page zero, regardless of current page
000A:  CLRF   0A
....................     
....................   BTFSS PIR1,1          ;TMR2IF interrupt?
000B:  BTFSS  0C.1
....................   goto ISR_END;
000C:  GOTO   040
....................   #endasm
....................   
....................   pwmCounter++;
000D:  INCF   26,F
000E:  BTFSC  03.2
000F:  INCF   27,F
....................   if(pwmCounter==1024)
0010:  MOVF   26,F
0011:  BTFSS  03.2
0012:  GOTO   019
0013:  MOVF   27,W
0014:  SUBLW  04
0015:  BTFSS  03.2
0016:  GOTO   019
....................     pwmCounter=0;
0017:  CLRF   27
0018:  CLRF   26
.................... 
....................   if(pwmCounter<pwmRedDS_10)
0019:  MOVF   27,W
001A:  SUBWF  29,W
001B:  BTFSS  03.0
001C:  GOTO   025
001D:  BTFSS  03.2
001E:  GOTO   023
001F:  MOVF   28,W
0020:  SUBWF  26,W
0021:  BTFSC  03.0
0022:  GOTO   025
....................     PIN_RED=1;
0023:  BSF    06.4
....................   else
0024:  GOTO   026
....................     PIN_RED=0;
0025:  BCF    06.4
.................... 
....................   if(pwmCounter<pwmGreenDS_10)
0026:  MOVF   27,W
0027:  SUBWF  2B,W
0028:  BTFSS  03.0
0029:  GOTO   032
002A:  BTFSS  03.2
002B:  GOTO   030
002C:  MOVF   2A,W
002D:  SUBWF  26,W
002E:  BTFSC  03.0
002F:  GOTO   032
....................     PIN_GREEN=1;
0030:  BSF    06.3
....................   else
0031:  GOTO   033
....................     PIN_GREEN=0;
0032:  BCF    06.3
.................... 
....................   if(pwmCounter<pwmBlueDS_10)
0033:  MOVF   27,W
0034:  SUBWF  2D,W
0035:  BTFSS  03.0
0036:  GOTO   03F
0037:  BTFSS  03.2
0038:  GOTO   03D
0039:  MOVF   2C,W
003A:  SUBWF  26,W
003B:  BTFSC  03.0
003C:  GOTO   03F
....................     PIN_BLUE=1;
003D:  BSF    06.6
....................   else
003E:  GOTO   040
....................     PIN_BLUE=0;
003F:  BCF    06.6
....................     
....................   #asm ASIS
.................... ISR_END:
....................   MOVF  PCLATH_TEMP, W  ;Restore PCLATH
0040:  MOVF   72,W
....................   MOVWF PCLATH          ;Move W into PCLATH
0041:  MOVWF  0A
....................   SWAPF STATUS_TEMP,W   ;Swap STATUS_TEMP register (sets bank to original)
0042:  SWAPF  71,W
....................   MOVWF STATUS          ;Move W into STATUS register
0043:  MOVWF  03
....................   SWAPF W_TEMP,F        ;Swap W_TEMP
0044:  SWAPF  70,F
....................   SWAPF W_TEMP,W        ;Swap W_TEMP into W
0045:  SWAPF  70,W
....................   
....................   BCF   TMR2IF            ;TMR2 Interrupt Flag löschen
0046:  BCF    0C.1
....................   #endasm
.................... }
.................... 
0047:  RETFIE

Das sind 67 Anweisungen, wenn ich den Code auf 50 kürzen könnte dann wären ungefähr 100 Hz drin. Sieht einer von euch irgendwo Einsparungsmöglichkeiten?

Gruß Wolfi
Gespeichert
Bernd
Globaler Moderator
Hero Member
*****
Offline Offline

Beiträge: 3815



Profil anzeigen
« Antworten #1 am: Januar 14, 2008, 18:07:19 »

Zitat
Sieht einer von euch irgendwo Einsparungsmöglichkeiten?

1)
Code:
pwmCounter++;
if (pwmCounter & 0x400) // sollte nur einen Bit-Test generieren
   pwmCounter = 0;      // if(pwmCounter==1024) muß 16-Bit vergleichen
   
2)
Wenn es kein Problem ist, daß der minimal einstellbare Duty-Cycle 1 ist, könnte man schreiben:

Code:
pwmCounter++;
if (pwmCounter & 0x400)
{
   pwmCounter = 0;
   PIN_RED = 1;         // wenn sich die LEDs an einem Port befinden
   PIN_GREEN = 1;       // ist es besser, den Port komplett zu setzen
   PIN_BLUE = 1;        // (Stichwort Read-Modify-Write)
                        // zeitlich unkritisch, da die 3 Vergleiche
                        // sicherlich länger dauern
}
else
{
   if(pwmCounter >= pwmRedDS_10)
       LED_RED = 0;

   if (pwmCounter >= pwmGreenDS_10)
       LED_GREEN = 0;
   ...
}


Viele Grüße

Bernd
Gespeichert

Seiten: [1] Nach oben Drucken 
« vorheriges nächstes »
Gehe zu:  

Powered by MySQL Powered by PHP Made for Mozilla (Firefox) Made for Internet Explorer
Seite erstellt in 0.037 Sekunden mit 18 Zugriffen.
 
Top! Top!