Sub HPWM(channel As uByte,freq As uInteger,duty_cycle As uInteger,Output_Config As uByte,Output_polarity As uByte) Dim period As uShort, ps As uInteger, CCP As uShort ' Hardware PWM module ' Larry Bradley, November 26, 2003 ' "Channel" is the desired CCP channel (1 or 2) ' ' "Freq" is the frequency in hertz desired for the output. Note that there ' are miniumum frequencies that can be used, depending on the oscillator ' frequency being used. Check the data sheets. ' For example, at 20 mHz, the min freq is 1221 Hz ' ' "duty_cycle" specifies the on/off ratio of the output waveform ' It ranges from 0 to 1023, the on fraction being "duty_cycle/1024" ' ' The following are only used on PICs with the enhanced PWM module. Check ' the PIC documentation for details. ' "Output_config" is 0,1,2,3: single-ended, full-brigde forward, half_bridge, full-bridge reverse ' ' "Output_polarity" is 0,1,2,3: 0 is active high for the single-ended output, 2 is active low ' ' Requires the following #DEFINE statements, either in the 18Fxxxx.BAS file ' or in the user's code: ' '#DEFINE CCP_CHANNELS [1|2] ' Compute the prescaler value duty_cycle = duty_cycle And 0x3FF ' Restrict to < 1024 movlw LOW (( FOSC ) / 1024) movwf ps movlw (( FOSC ) / 1024) >> 8 movwf ps+1 ps = ps/freq ' Set up period movlw LOW (( FOSC ) / 4) movwf period movlw LOW ((( FOSC ) / 4) >> 8) movwf period+1 movlw (( FOSC ) / 4) >> 16 movwf period+2 ' Set up Timer 2 prescale value ' Assume ps = 0, thus 1:1 T2CKPS0 = 0 : T2CKPS1 = 0 If ps > 0 Then ' 1:4 or 1:16 T2CKPS0 = 1 period = Shr(period,2) 'pr2 = pr2/4 If ps > 4 Then ' 1:16 T2CKPS1 = 1 period = Shr(period,2) 'pr2 = pr2/16 End If End If ' Set up CCP PR register PR2 = period / freq - 1 ' The PR register will have a value from 0 to 255 - this is ' the period of the output waveform ' We specify duty cycle as the fraction of the period that ' the waveform is ON, the fraction being (0 to 1023)/1024 ccp = (PR2+1) ccp = ccp * duty_cycle ' We have an 18 bit result in a 24 bit field, and we only want the high order 10 bits ' of those 18 ' 0b 0000 00nn nnnn nnnn xxxx xxxx ' Shift right by 2 bits gets ' 0b 0000 000 nnnn nnnn nnxx xxxx ' Put the middle byte into the CCPRxL register (most sign. 8 bits) ' and the next 2 bits into the CCPxCON register ccp = Shr(ccp,2) '#If CCP_CHANNELS <> 2 #ifndef CCP2CON ' Only one channel ' Set output config and polarity CCP1CON = 0x0C ' Set CCP module into PWM mode P1M1 = Output_config.1 P1M0 = Output_config.0 CCP1M1 = Output_polarity.1 CCP1M0 = Output_polarity.0 CCPR1L = ccp.Byte1 ' Set duty cycle high 8 bits ' Set duty cycle low 2 bits DC1B1 = ccp.7 DC1B0 = ccp.6 #else If channel = 1 Then CCP1CON = 0x0C ' Set CCP module into PWM mode CCPR1L = ccp.Byte1 ' Set duty cycle high 8 bits ' Set duty cycle low 2 bits DC1B1 = ccp.7 DC1B0 = ccp.6 ' Set output config and polarity P1M1 = Output_config.1 P1M0 = Output_config.0 CCP1M1 = Output_polarity.1 CCP1M0 = Output_polarity.0 End If If channel = 2 Then CCP2CON = 0x0C ' Set CCP module into PWM mode CCPR2L = ccp.Byte1 ' Set duty cycle high 8 bits ' Set duty cycle low 2 bits DC2B1 = ccp.7 DC2B0 = ccp.6 ' Set output config and polarity P2M1 = Output_config.1 P2M0 = Output_config.0 CCP2M1 = Output_polarity.1 CCP2M0 = Output_polarity.0 End If #endif ' Turn on timer 2 TMR2ON = 1 ' For testing ... ' Dim s(12) As String ' putcrlf() ' ' str(duty_cycle,s) ' puts(s) ' putc(" ") ' ' strhex(pr2,s) ' puts(s) ' putc(" ") ' ' strhex(ccp,s) ' puts(s) ' putc(" ") ' ' Dim x As uInteger ' x = Shr(ccp,6) ' str(x,s) ' puts(s) End Sub