REM SBC2000-062 PWM/BEEP support routines REM REM Author: Steven R. Wheeler REM REM Date: 17 September 1998 REM REM Copyright 1998-2000 Vesta Technology, Inc. REM All rights reserved. REM REM Revision history: REM Feb 10, 1999 SRW REM Removed unused 'channel' parameter from PWM argument list. REM Apr 7, 2000 SRW REM Cleaned up comments slightly. REM Timer 2 control register CONSTANT VTI_T2CON AS INTEGER = 0x12 REM Duty cycle register CONSTANT VTI_CCPR1L AS INTEGER = 0x15 REM Control register CONSTANT VTI_CCP1CON AS INTEGER = 0x17 REM Period register CONSTANT VTI_PR2 AS INTEGER = 0x92 REM Port C direction register CONSTANT VTI_TRISC AS INTEGER = 0x87 REM PWM on the SBC2000-062 is subject to certain limitations. 10-bit precision REM in specifying the PWM percentage is only available at 3 specific frequencies: REM 305 Hz, 1221 Hz, and 4883 Hz. The lowest frequency available is 305 Hz. REM As the frequency increases from one of the three frequencies with the most REM precision, the precision available drops steadily until the next "best" REM frequency is reached. REM Set up a new PWM hightime proportion and frequency. The hightime parameter REM is expressed in 10ths of percents. In other words, 500 specifies 50%. The REM freq argument is specified in Hertz, and has a legal range from 305 to 32767. VITAL SUBROUTINE PWM(hightime AS INTEGER, freq AS INTEGER) LOCAL range AS INTEGER : REM Frequency prescaler selection LOCAL portion AS INTEGER : REM Working variable IF hightime > 1000 REM if over 100% specified, turn it off hightime = 0 ENDIF IF freq < 305 REM Unable to set this frequency; it's too low. REM Turn it off POKE(VTI_CCP1CON, 0) POKE(VTI_T2CON, PEEK(VTI_T2CON) AND 0xFB) RETURN ENDIF range = 0 REM Determine which frequency range we need to select. Note that a REM range value of 3 has the same effect as a range of 2. We will REM scale all frequencies down so that we can get by with one REM simplified equation for calculating the period register value. IF freq < 1221 range = 2 ENDIF IF freq < 4883 IF range = 0 range = 1 freq = freq / 4 ENDIF ELSE range = 0 freq = freq / 16 ENDIF REM Set the range POKE(VTI_T2CON, (PEEK(VTI_T2CON) AND 0xFC) OR range) REM The PR2 value is calculated using an equation which depends upon REM the crystal frequency, the prescaler, and a scaling constant. To REM simplify things, we'll precalculate as much as possible. REM This test is necessary because of the limitations of signed REM 16-bit integer arithmetic. For frequencies in the range REM specified, the "more precise" portion of the calculation REM results in a negative number due to overflow. Therefore, REM we check for the problematic range and specify the return REM value manually. IF (freq > 9765) AND (freq < 11340) range = 7 ELSE IF freq > 19531 range = 2 ELSE range = (19531 / freq) * 4 : REM 78125 / freq range = range + (19531 \ freq) * 4 / freq : REM more precise ENDIF ENDIF range = MIN(255, range - 1) : REM adjust and limit POKE(VTI_PR2, range) REM Now we have to program the high time. This is messy, because the REM maximum value you can place into the hightime registers depends REM upon the value you've put into the PR2 register. REM Convert from 0.1% units to machine increments. portion = (hightime \ 10) * 1024 / 1000 portion = portion + ((hightime / 10) \ 10) * 1024 / 100 portion = portion + ((hightime / 100) \ 10) * 1024 / 10 portion = portion + ((hightime / 1000) \ 10) * 1024 portion = MIN(portion, 1023) REM These next equations try to maintain as much precision as is REM possible. The high time value must be split between two registers, REM but the most significant portion of the value cannot exceed the REM value in the PR2 register. POKE(VTI_CCPR1L, portion * 31 / (31744/range)) POKE(VTI_CCP1CON, 0x0C + ((portion * 31) / (7936/range) \ 4)*0x10) REM Now make certain that the PWM pin is an output, and turn the PWM REM output on if it isn't already on POKE(VTI_TRISC, PEEK(VTI_TRISC) AND 0xFD) POKE(VTI_T2CON, PEEK(VTI_T2CON) OR 4) END REM The BEEP subroutine is implemented in terms of the PWM subroutine. It is REM subject to the same limitations, except that since BEEP produces a 50% REM duty cycle, it isn't affected by limitations on precision. REM SUBROUTINE BEEP(frequency AS INTEGER) REM PWM(500, frequency) REM END REM 8 bit PWM at fixed freq - 5 kHz (-062) REM PWM control word REM SUBROUTINE set_duty_cycle(arg AS INTEGER) rem CONSTANT VTI_T2CON AS INTEGER = 0x12 rem CONSTANT VTI_CCPR1L AS INTEGER = 0x15 rem CONSTANT VTI_CCP1CON AS INTEGER = 0x17 rem CONSTANT VTI_PR2 AS INTEGER = 0x92 rem CONSTANT VTI_TRISC AS INTEGER = 0x95 REM POKE(VTI_T2CON, (PEEK(VTI_T2CON) AND 0xFC) OR 0) REM POKE(VTI_PR2,255) REM POKE(VTI_CCPR1L, arg):REM Time hi REM POKE(VTI_CCP1CON, 0x0C + (1 * 0x10)):REM 2 lsb time hi REM POKE(VTI_TRISC, PEEK(VTI_TRISC) AND 0xFD) REM POKE(VTI_T2CON, PEEK(VTI_T2CON) OR 4) REM END REM FUNCTION read_PWM() AS INTEGER REM read_PWM = PEEK(VTI_CCPR1L) REM END REM SUBROUTINE adjust_PWM(arg AS INTEGER) REM LOCAL temp AS INTEGER REM temp = read_PWM() REM temp = temp + arg REM temp = MAX(MIN(temp,255),0) REM set_duty_cycle(temp) REM END