Here's an example of a Great Cow Basic program that uses the hardware PWM. It uses the enhanced core pic12f1822 and it brightens the LED and then dims an LED in a loop.
- Code: Select all
'output a pwm signal on ccp1.
'this is only an 8 bit output
#chip 12F1822, 4
#config osc = int
DIR PORTA.2 out 'this is the PWM output channel 1
' the 12F1822 only has one channel (ccp1)
'Main code
do
'Turn up brightness over 2.5 seconds
For Bright = 1 to 255
HPWM 1, 40, Bright
wait 10 ms
next
'Turn down brightness over 2.5 seconds
For Bright = 255 to 1
HPWM 1, 40, Bright
wait 10 ms
next
loop
Wasn't that easy? Openning a serial port and saying hello is also easy.
Here's what assembly code that the BASIC compiler created for the PWM above...
- Code: Select all
;Program compiled by Great Cow BASIC (0.9 19/7/2011)
;Need help? See the GCBASIC forums at http://sourceforge.net/projects/gcbasic/forums,
;check the documentation or email w_cholmondeley at users dot sourceforge dot net.
;********************************************************************************
;Set up the assembler options (Chip type, clock source, other bits and pieces)
LIST p=12F1822
#include "P12F1822.inc"
__CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
__CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_19 & _LVP_OFF
;********************************************************************************
;Set aside memory locations for variables
DELAYTEMP EQU .112
DELAYTEMP2 EQU .113
SYSDIVLOOP EQU .116
SYSDIVMULTA EQU .119
SYSDIVMULTA_H EQU .120
SYSDIVMULTB EQU .123
SYSDIVMULTB_H EQU .124
SYSDIVMULTX EQU .114
SYSDIVMULTX_H EQU .115
SysCalcTempA EQU .117
SysCalcTempA_H EQU .118
SysCalcTempB EQU .121
SysCalcTempB_H EQU .122
SysCalcTempX EQU .112
SysCalcTempX_H EQU .113
SysWaitTempMS EQU .114
SysWaitTempMS_H EQU .115
BRIGHT EQU .32
CCPCONCACHE EQU .33
PR2_TEMP EQU .34
PR2_TEMP_H EQU .35
PWMCHANNEL EQU .37
PWMDUTY EQU .38
PWMFREQ EQU .39
SysTemp1 EQU .40
SysTemp1_H EQU .41
SysTemp2 EQU .42
SysTemp2_H EQU .43
T2_PR EQU .44
;********************************************************************************
;Vectors
ORG 0
goto BASPROGRAMSTART
ORG 4
retfie
;********************************************************************************
;Start of program memory page 0
ORG 5
BASPROGRAMSTART
;Call initialisation routines
call INITSYS
call INITPWM
;Start of the main program
banksel TRISA
bcf TRISA,2
SysDoLoop_S1
banksel BRIGHT
clrf BRIGHT
SysForLoop1
incf BRIGHT,F
movlw 1
movwf PWMCHANNEL
movlw .40
movwf PWMFREQ
movf BRIGHT,W
movwf PWMDUTY
call HPWM
movlw .10
movwf SysWaitTempMS
clrf SysWaitTempMS_H
call Delay_MS
movlw .255
subwf BRIGHT,W
btfss STATUS, C
goto SysForLoop1
SysForLoopEnd1
clrf BRIGHT
SysForLoop2
decf BRIGHT,F
movlw 1
movwf PWMCHANNEL
movlw .40
movwf PWMFREQ
movf BRIGHT,W
movwf PWMDUTY
call HPWM
movlw .10
movwf SysWaitTempMS
clrf SysWaitTempMS_H
call Delay_MS
movf BRIGHT,W
sublw 1
btfss STATUS, C
goto SysForLoop2
SysForLoopEnd2
goto SysDoLoop_S1
SysDoLoop_E1
BASPROGRAMEND
sleep
goto BASPROGRAMEND
;********************************************************************************
Delay_MS
incf SysWaitTempMS_H, F
DMS_START
movlw .142
movwf DELAYTEMP2
DMS_OUTER
movlw 1
movwf DELAYTEMP
DMS_INNER
decfsz DELAYTEMP, F
goto DMS_INNER
decfsz DELAYTEMP2, F
goto DMS_OUTER
decfsz SysWaitTempMS, F
goto DMS_START
decfsz SysWaitTempMS_H, F
goto DMS_START
return
;********************************************************************************
HPWM
movlw 1
movwf T2_PR
movlw .232
movwf SysCalcTempA
movlw 3
movwf SysCalcTempA_H
movf PWMFREQ,W
movwf SysCalcTempB
clrf SysCalcTempB_H
call SysDivSub16
movf SysCalcTempA_H,W
movwf PR2_TEMP_H
movf SysCalcTempA,W
movwf PR2_TEMP
movf PR2_TEMP_H,W
sublw 0
btfsc STATUS, C
goto ENDIF3
movlw 4
movwf T2_PR
bcf STATUS,C
rrf PR2_TEMP_H,F
rrf PR2_TEMP,F
bcf STATUS,C
rrf PR2_TEMP_H,F
rrf PR2_TEMP,F
ENDIF3
movf PR2_TEMP_H,W
sublw 0
btfsc STATUS, C
goto ENDIF4
movlw .16
movwf T2_PR
bcf STATUS,C
rrf PR2_TEMP_H,F
rrf PR2_TEMP,F
bcf STATUS,C
rrf PR2_TEMP_H,F
rrf PR2_TEMP,F
ENDIF4
movf PR2_TEMP,W
movwf PR2
bcf T2CON,T2CKPS0
bcf T2CON,T2CKPS1
movlw 4
subwf T2_PR,W
btfsc STATUS, Z
bsf T2CON,T2CKPS0
movlw .16
subwf T2_PR,W
btfsc STATUS, Z
bsf T2CON,T2CKPS1
bsf T2CON,TMR2ON
movf PWMDUTY,W
movwf SysCalcTempA
clrf SysCalcTempA_H
movf PR2,W
movwf SysCalcTempB
clrf SysCalcTempB_H
call SysMultSub16
movf SysCalcTempX_H,W
movwf SysTemp1_H
movf SysCalcTempX,W
movwf SysTemp1
movf SysTemp1_H,W
movwf SysCalcTempA_H
movf SysTemp1,W
movwf SysCalcTempA
movlw .255
movwf SysCalcTempB
clrf SysCalcTempB_H
call SysDivSub16
movf SysCalcTempA,W
banksel CCPR1L
movwf CCPR1L
bsf CCP1CON,CCP1M3
bsf CCP1CON,CCP1M2
bcf CCP1CON,CCP1M1
bcf CCP1CON,CCP1M0
banksel STATUS
return
;********************************************************************************
INITPWM
movlw .26
movwf PR2
bcf T2CON,T2CKPS0
bcf T2CON,T2CKPS1
movlw .13
banksel CCPR1L
movwf CCPR1L
banksel CCPCONCACHE
bsf CCPCONCACHE,DC1B1
bcf CCPCONCACHE,DC1B0
bsf CCPCONCACHE,CCP1M3
bsf CCPCONCACHE,CCP1M2
bcf CCPCONCACHE,CCP1M1
bcf CCPCONCACHE,CCP1M0
bsf T2CON,TMR2ON
return
;********************************************************************************
INITSYS
movlw .135
banksel OSCCON
andwf OSCCON,F
movlw .104
iorwf OSCCON,F
bcf ADCON0,ADON
bcf ADCON1,ADFM
banksel ANSELA
clrf ANSELA
banksel CM1CON0
bcf CM1CON0,C1ON
banksel PORTA
clrf PORTA
return
;********************************************************************************
SYSCOMPEQUAL16
clrf SYSCALCTEMPX
movf SYSCALCTEMPA, W
subwf SYSCALCTEMPB, W
btfss STATUS, Z
return
movf SYSCALCTEMPA_H, W
subwf SYSCALCTEMPB_H, W
btfss STATUS, Z
return
comf SYSCALCTEMPX,F
return
;********************************************************************************
SYSCOMPLESSTHAN16
clrf SYSCALCTEMPX
movf SYSCALCTEMPA_H,W
subwf SYSCALCTEMPB_H,W
btfss STATUS,C
return
movf SYSCALCTEMPB_H,W
subwf SYSCALCTEMPA_H,W
btfss STATUS,C
goto SCLT16TRUE
movf SYSCALCTEMPB,W
subwf SYSCALCTEMPA,W
btfsc STATUS,C
return
SCLT16TRUE
comf SYSCALCTEMPX,F
return
;********************************************************************************
SYSDIVSUB16
movf SYSCALCTEMPA_H,W
movwf SYSDIVMULTA_H
movf SYSCALCTEMPA,W
movwf SYSDIVMULTA
movf SYSCALCTEMPB_H,W
movwf SYSDIVMULTB_H
movf SYSCALCTEMPB,W
movwf SYSDIVMULTB
clrf SYSDIVMULTX
clrf SYSDIVMULTX_H
movf SYSDIVMULTB_H,W
movwf SysCalcTempA_H
movf SYSDIVMULTB,W
movwf SysCalcTempA
clrf SysCalcTempB
clrf SysCalcTempB_H
call SysCompEqual16
btfss SysCalcTempX,0
goto ENDIF9
clrf SYSCALCTEMPA
clrf SYSCALCTEMPA_H
return
ENDIF9
movlw .16
movwf SYSDIVLOOP
SYSDIV16START
bcf STATUS,C
rlf SYSDIVMULTA,F
rlf SYSDIVMULTA_H,F
rlf SYSDIVMULTX,F
rlf SYSDIVMULTX_H,F
movf SYSDIVMULTB,W
subwf SYSDIVMULTX,F
movf SYSDIVMULTB_H,W
subwfb SYSDIVMULTX_H,F
bsf SYSDIVMULTA,0
btfsc STATUS,C
goto ENDIF10
bcf SYSDIVMULTA,0
movf SYSDIVMULTB,W
addwf SYSDIVMULTX,F
movf SYSDIVMULTB_H,W
addwfc SYSDIVMULTX_H,F
ENDIF10
decfsz SYSDIVLOOP, F
goto SYSDIV16START
movf SYSDIVMULTA_H,W
movwf SYSCALCTEMPA_H
movf SYSDIVMULTA,W
movwf SYSCALCTEMPA
movf SYSDIVMULTX_H,W
movwf SYSCALCTEMPX_H
movf SYSDIVMULTX,W
movwf SYSCALCTEMPX
return
;********************************************************************************
SYSMULTSUB16
movf SYSCALCTEMPA_H,W
movwf SYSDIVMULTA_H
movf SYSCALCTEMPA,W
movwf SYSDIVMULTA
movf SYSCALCTEMPB_H,W
movwf SYSDIVMULTB_H
movf SYSCALCTEMPB,W
movwf SYSDIVMULTB
clrf SYSDIVMULTX
clrf SYSDIVMULTX_H
MUL16LOOP
btfss SYSDIVMULTB,0
goto ENDIF7
movf SYSDIVMULTA,W
addwf SYSDIVMULTX,F
movf SYSDIVMULTA_H,W
addwfc SYSDIVMULTX_H,F
ENDIF7
bcf STATUS,C
rrf SYSDIVMULTB_H,F
rrf SYSDIVMULTB,F
bcf STATUS,C
rlf SYSDIVMULTA,F
rlf SYSDIVMULTA_H,F
movf SYSDIVMULTB_H,W
movwf SysCalcTempB_H
movf SYSDIVMULTB,W
movwf SysCalcTempB
clrf SysCalcTempA
clrf SysCalcTempA_H
call SysCompLessThan16
btfsc SysCalcTempX,0
goto MUL16LOOP
movf SYSDIVMULTX_H,W
movwf SYSCALCTEMPX_H
movf SYSDIVMULTX,W
movwf SYSCALCTEMPX
return
;********************************************************************************
END
You run that assembly program through the mplabx assembler and use your programmer to blow the code into the chip. Could life get any easier?
Also, the BASIC code is very portable. A couple of small changes and you now have code to do PWM on a pic18.
Great Cow BASIC is a totally free and open source program (for windows only, unfortunately). If you are bogged down in trying to understand the pic hardware or struggling with learning assembly language or C, then try this out.
http://gcbasic.sourceforge.net/
Great Cow also has a Great support forum.
http://sourceforge.net/p/gcbasic/discussion/