Quantcast
Channel: MEL PICBASIC Forum
Viewing all articles
Browse latest Browse all 4745

Scaling ADC Result to a Set Range

$
0
0
I'm using a trim pot to control a motor's speed via PWM on a PIC16F1825 but instead of the usual 0-100% duty cycles (corresponding to 0-255 from the ADCIN function with 8-bit resolution) I want to scale the adjustment of the duty to be around a set value. For example, if I determine that the typical duty cycle I want to provide in my application is 75% then I'd like to use the trim pot to adjust the value from 50-100% with 75% being the middle point of the pot. I can do this on an Arduino with the Map function but I can't seem to figure out how to do that similarly with PBP. Any guidance offered would be much appreciated.

Code:

#DEFINE USE_LCD_FOR_DEBUG  ; comment out for non-debug use

' ***************************************************************
' Pin Connections
' ***************************************************************

' Vdd      -> pin 1        -> +5V 
' RC4/Tx  -> pin 6        -> EUSART transmit (LCD)
' RC2      -> pin 8        -> Port motor direction signal (motor 2)
' RC1/CCP4 -> pin 9        -> Port motor PWM output (motor 2)
' RC0      -> pin 10        -> Stbd motor direction signal (motor 1)
' RA2/CCP3 -> pin 11        -> Stbd motor PWM output (motor 1)
' RA1      -> pin 12        -> trim pot input
' Vss      -> pin 14        -> GND
 
DEFINE OSC 16              ; Set oscillator 16Mhz

DEFINE ADC_BITS      8      ; Set number of bits in result
DEFINE ADC_SAMPLEUS  50    ; Set sampling time in uS (was 5)
DEFINE ADC_CLOCK    3      ; Set clock source (3=rc)

DEFINE HSER_TXSTA  20h    ; Set transmit status and control register
DEFINE HSER_BAUD    2400    ; Set baud rate

' ***************************************************************
' Device Fuses
' ***************************************************************

#CONFIG
  __config _CONFIG1, _FOSC_INTOSC & _WDTE_ON & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF
  __config _CONFIG2, _PLLEN_OFF & _STVREN_ON & _BORV_LO & _LVP_OFF
#ENDCONFIG

' ***************************************************************
' Initialization
' ***************************************************************

OSCCON    = %01111000      ; 16MHz internal osc

APFCON0.2 = 0              ; Tx on RC4 for LCD display
BAUDCON.4 = 1              ; Transmit inverted data to the Tx pin

FVRCON    = 0              ; Fixed Voltage Reference is disabled
ANSELA    = %00000010      ; Analog on PORTA.1 (AN1) only
ADCON0    = %00000101      ; ADC (analog-to-digital) is enabled on AN1 (RA1) only
ADCON1.7  = 0              ; Left-justified results in 8-bits
TRISA    = %00000010            ; Make all pins output except for RA1 (trim pot input)

ANSELC = 0                  ; Digital only for all PortC pins
TRISC  = 0                  ; Make all PORTC pins output

MOTOR_1_DIR    VAR PORTC.0  ; Alias PORTC.0 as "MOTOR_1_DIR"
MOTOR_1_PWM    VAR PORTA.2  ; Alias PORTA.2 as "MOTOR_1_PWM"
MOTOR_2_DIR    VAR PORTC.2  ; Alias PORTC.2 as "MOTOR_2_DIR"
MOTOR_2_PWM    VAR PORTC.1  ; Alias PORTC.1 as "MOTOR_2_PWM"
 
#IFDEF USE_LCD_FOR_DEBUG
    LCD_INST  CON 254      ' instruction
    LCD_CLR    CON 1        ' Clear screen
    LCD_L1    CON 128      ' LCD line 1
    LCD_L2    CON 192      ' LCD line 2
#ENDIF

' ***************************************************************
' Set up registers for PWM on CCP3 & CCP4
' ***************************************************************

CCP3CON = %00001100        ; Use CCP3 in PWM mode
CCP4CON = %00001100        ; Use CCP4 in PWM mode

' Use Mister E's PICMultiCalc_1.3.1.exe application (Windows only) 
' to determine prescaler and PR2 values for given OSC frequency (e.g. 16Mhz)
' and duty cycle (use 100% to see highest actual value)
                     
T2CON  = %00000101        ; Timer2 on with 1:4 prescaler
PR2    = 62                ; For 16Mhz OSC the desired output freq of 15,873Hz is
                            ; achieved with this PR2 value (8-bit resolution
                            ; with 1:4 prescaler)
                           
                            ; PWM freq must be ~ 16-20kHz to reduce noise

PreSpinVal  CON 17          ; value to subtract from MinDuty for motor spin up
MinDuty    CON 75          ; 75 when max duty = 252 (8-bit resolution)
;SpinUpPause CON 17          ; Pause during motor spin up
SpinUpPause VAR BYTE        ; Pause during motor spin up
SpinUpPause = 99
#IFDEF USE_LCD_FOR_DEBUG
    SpinUpPause = 17        ; Less pause is needed when using LCD
#ENDIF
MaxDuty    VAR WORD        ; According to Darrel:
                            ;  MaxDuty = (PR2 + 1) * 4

MaxDuty = (PR2 + 1) * 4    ; 252 but with prescaler resolution it's actually 250

DutyVar    VAR WORD        ; temp variable to store duty variable for CCP3/4
MotorRPM    VAR BYTE   

adcVal      VAR BYTE        ; stores ADCIN results 
                                                             
' ***************************************************************
' Set default values
' ***************************************************************

ADCIN 1, adcVal            ' Read channel 1 to adval
MotorRPM = adcVal          ' (set speed for motors to spin up to)

' TODO: want to use trim pot to adjust motor speed but only within a
'      a certain range; midpoint of the pot should be the typical speed
'      observed from 'The Tholian Web' and the min/max adjustment accordingly
'      (i.e. max is 100% duty cycle but if mid is 75% then min would be 50%)

LOW MOTOR_1_DIR            ' Set stbd motor (motor 1) to fwd (CW)
LOW MOTOR_2_DIR            ' Set port motor (motor 2) to fwd (CCW)

' Spin up motors to saved value of _MotorRPM
' (Below a value of 'MinDuty', the motors don't move at all)
FOR DutyVar = (MinDuty - PreSpinVal) to MotorRPM
    'DutyVar4  = i

    CCP3CON.4 = DutyVar.0
    CCP3CON.5 = DutyVar.1
    CCPR3L    = DutyVar >> 2

    CCP4CON.4 = DutyVar.0
    CCP4CON.5 = DutyVar.1
    CCPR4L    = DutyVar >> 2
           
    pause SpinUpPause

#IFDEF USE_LCD_FOR_DEBUG
    HSEROUT [LCD_INST, LCD_CLR]
    pause 5
    HSEROUT ["RPM=", DEC DutyVar, "      ", 13, 10] ' Send text followed by carriage return and linefeed
#ENDIF
NEXT DutyVar

#IFDEF USE_LCD_FOR_DEBUG
    HSEROUT [LCD_INST, LCD_CLR]
    pause 5
    HSEROUT ["RPM=", DEC MotorRPM, "      ", 13, 10] ' Send text followed by carriage return and linefeed
#ENDIF

Main:
    ' Check if motor RPM has changed
    ADCIN 1, adcVal        ' Read channel 0 to adval

#IFDEF USE_LCD_FOR_DEBUG
    HSEROUT [LCD_INST, LCD_CLR]
    pause 5
    HSEROUT ["adcVal=", DEC adcVal, "      ", 13, 10] ' Send text followed by carriage return and linefeed
#ENDIF

' TODO: only change motor speed if reading is changed by +/- 2 since the
'      value can change by +/- 1.
'    If (adcVal - prevVal) > 1 Then
'        gosub ChngMotorHPWM
'    EndIf
 
 GOTO Main

ChngMotorHPWM:
    DutyVar  = MotorRPM

    CCP3CON.4 = DutyVar.0
    CCP3CON.5 = DutyVar.1
    CCPR3L    = DutyVar >> 2

    CCP4CON.4 = DutyVar.0
    CCP4CON.5 = DutyVar.1
    CCPR4L    = DutyVar >> 2
   
    RETURN


Viewing all articles
Browse latest Browse all 4745

Trending Articles