RossWaddell
- 19th November 2015, 16:33
With the line "#DEFINE USE_LCD_FOR_DEBUG" commented out the chip works perfectly; the PWM duty cycle sent to the SN754410 driver spins up the attached motor slowly and the trim pot attached to ADC 1 works smoothly in adjusting the speed.
When I uncomment it, though, (so I can see the debug info on the LCD) the motor immediately starts spinning when power is connected and the ADC behaviour is lagging, as if it takes more time to get the results.
I'm using a 16F1825 chip. What's weird is that this was working just fine with my old LCD @ 2400 baud but since I accidentally fried that and had to get a new one I changed it to 9600 baud as that's the default with the new serial LCD I got from SparkFun (I also needed to comment out "BAUDCON.4 = 1" with this LCD as otherwise it displayed garbage)
'#DEFINE USE_LCD_FOR_DEBUG ; comment out for non-debug use
' ************************************************** *************
' TODOs
' ************************************************** *************
' 1. Need to calibrate motor RPMs so they spin at the same rate
' -> Separate "MotorDuty" EEPROM variables?
' ************************************************** *************
' Pin Connections
' ************************************************** *************
' Vdd -> pin 1 -> +5V
' RA5 -> pin 2 -> Blue LED (USART motor control indicator)
' RA4 -> pin 3 -> Green LED (ADC motor control indicator)
' RC5/Rx -> pin 5 -> EUSART receive
' RC4/Tx -> pin 6 -> EUSART transmit (LCD)
' RC2 -> pin 8 -> Port motor direction signal (motor 2)
' RC1/CCP4 -> pin 9 -> Port/Stbd motor PWM output (motor 1 & 2)
' RC0 -> pin 10 -> Stbd motor direction signal (motor 1)
' RA2/INT -> pin 11 -> Motor control option select button
' RA1 -> pin 12 -> trim pot input
' Vss -> pin 14 -> GND
DEFINE OSC 16 ; Set oscillator 16Mhz
' EUSART Settings for Tx/Rc (e.g. LCD)
' > use Mister E PIC Multi-Calc application to get register/DEFINE settings
' > as the values are dependent on the OSC and desired baud rate
DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1
DEFINE HSER_CLROERR 1 ' Clear overflow automatically
DEFINE HSER_SPBRG 160 ' 9600 Baud @ 16MHz, -0.08%
' ************************************************** *************
' 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
pause 100
APFCON0.2 = 0 ; Tx on RC4 for LCD display
APFCON0.7 = 0 ; Rx on RC5
' Some LCD serial modules need inverted data, some do not
' Enable the line below if needed, but for SparkFun SerLCD it should be
' commented out
'BAUDCON.4 = 1 ; Transmit inverted data to the Tx pin
' From Mister E's Multi-Calc for EUSART:
' ************************************************** ***************
SPBRGH = 1
BAUDCON.3 = 1 ' Enable 16 bit baudrate generator
' ************************************************** ***************
ANSELC = 0 ; Digital only for all PortC pins
TRISC = %00001000 ; Make all pins output except for RC3
; (motor control option button input)
ANSELA = %00000010 ; Analog on PORTA.1 (AN1) only
TRISA = %00000110 ; Make all pins output except for RA1 & RA2
; (trim pot input & button input)
FVRCON = 0 ; Fixed Voltage Reference is disabled
ADCON0 = %00000101 ; ADC enabled on AN1 (RA1) only; ADC conversion
; enabled
PAUSEUS 20 ; Wait for the analog switch 'glitch' to die down
ADCON1 = %00110000 ; Left-justified results in 8-bits; Frc as timer
' The INT pin can be used to generate an asynchronous edge-triggered interrupt.
' This interrupt is enabled by setting the INTE bit of the INTCON register. The
' INTEDG bit of the OPTION_REG register determines on which edge the interrupt
' will occur. When the INTEDG bit is set, the rising edge will cause the
' interrupt. When the INTEDG bit is clear, the falling edge will cause
' the interrupt. The INTF bit of the INTCON register will be set when a valid
' edge appears on the INT pin. If the GIE and INTE bits are also set, the
' processor will redirect program execution to the interrupt vector.
OPTION_REG.6 = 1 ; 1=Rising edge (default) or button "PRESS";
; 0=Falling edge or button "RELEASE"
#IFDEF USE_LCD_FOR_DEBUG
' Display control codes for SerLCD serial LCD (SparkFun part #LCD-09395)
' (see 'Dropbox\PBP Projects\PIC Datasheets\SerLCD_V2_5 Datasheet.pdf'
' for list of control codes)
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
LCD_BR_CMD CON 124 ' command character for adjusting backlight brightness
LCD_BR_LVL CON 140 ' 140==40%
#ENDIF
' ************************************************** *************
' Includes
' ************************************************** *************
INCLUDE "DT_INTS-14.bas" ' Base Interrupt System
INCLUDE "ReEnterPBP.bas" ' Include if using PBP interrupts
' --> copy both files to PBP main folder
' (i.e. c:\pbp3)
;-- Place a copy of these variables in your Main program -------------------
;-- The compiler will tell you which lines to un-comment --
;-- Do Not un-comment these lines --
;---------------------------------------------------------------------------
;wsave VAR BYTE $20 SYSTEM ' location for W if in bank0
;wsave VAR BYTE $70 SYSTEM ' alternate save location for W
' if using $70, comment wsave1-3
' --- IF any of these three lines cause an error ?? ------------------------
' Comment them out to fix the problem ----
' -- Which variables are needed, depends on the Chip you are using --
;wsave1 VAR BYTE $A0 SYSTEM ' location for W if in bank1
;wsave2 VAR BYTE $120 SYSTEM ' location for W if in bank2
;wsave3 VAR BYTE $1A0 SYSTEM ' location for W if in bank3
' --------------------------------------------------------------------------
' ************************************************** *************
' ASM Interrupt Definitions
' ************************************************** *************
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler INT_INT, _Mtr_Speed_Ctrl_Btn, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM
' ************************************************** *************
' 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 30 ; Value to subtract from MinDutyToSpin for motor spin up
MinDutyToSpin CON 75 ; 75 for 8-bit resolution
MinDuty CON 80 ; Minimum speed to rotate motor for this application
SpinUpPause VAR BYTE ; Pause during motor spin up
SpinUpPause = 75
#IFDEF USE_LCD_FOR_DEBUG
SpinUpPause = 17 ; Less pause is needed when using LCD
#ENDIF
MaxDuty VAR BYTE ; According to Darrel:
; MaxDuty = (PR2 + 1) * 4
MaxDuty = (PR2 + 1) * 4 ; 252 but with prescaler resolution it's actually
; 250 (8-bit)
MotorDuty VAR BYTE ; Actual duty cycle for motor
i VAR BYTE
MaxADCVal CON 255 ; 255 for 8-bit; 1023 for 10-bit
VrefInVal VAR BYTE ; stores ADCIN result read from trim pot
compVal VAR BYTE ; stores last-changed ADC value
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"
ButtonPress VAR PORTA.2 ; Alias PORTA.2 as "ButtonPress"
LED_ADC VAR PORTA.4 ; Alias PORTA.4 as "LED_ADC"
LED_USART VAR PORTA.5 ; Alias PORTA.4 as "LED_USART"
Old_Mtr_Ctrl_Opt VAR BIT ; Stoes last set motor speed control option
' ************************************************** *************
' Read EEPROM value(s)
' ************************************************** *************
' 1 = Trim pot via ADC
' 0 = Serial data via USART Rc (external source)
Mtr_Ctrl_Opt_Default CON 1
EE_Mtr_Ctrl_Opt DATA Mtr_Ctrl_Opt_Default
Mtr_Ctrl_Opt VAR BIT
READ EE_Mtr_Ctrl_Opt, Mtr_Ctrl_Opt
' ************************************************** *************
' Set default values
' ************************************************** *************
' Set initial value of comparison variable
Old_Mtr_Ctrl_Opt = Mtr_Ctrl_Opt
' Turn on appropriate LED indicator
LED_ADC = Mtr_Ctrl_Opt
LED_USART = !Mtr_Ctrl_Opt ; inverts value of Mtr_Ctrl_Opt
'if Mtr_Ctrl_Opt = 1 then
' HIGH LED_ADC
' LOW LED_USART
'else
' LOW LED_ADC
' HIGH LED_USART
'endif
LOW MOTOR_1_DIR ; Set stbd motor (motor 1) to fwd (CW)
'LOW MOTOR_1_PWM
LOW MOTOR_2_DIR ; Set port motor (motor 2) to fwd (CW)
LOW MOTOR_2_PWM ; (motor will be connected in reverse in model for
; CCW movement)
' Should only need to do this one time to adjust backlight brightness
'#IFDEF USE_LCD_FOR_DEBUG
' HSEROUT [LCD_BR_CMD, LCD_BR_LVL]
' PAUSE 5
'#ENDIF
#IFDEF USE_LCD_FOR_DEBUG
pause 1000
HSEROUT [LCD_INST, LCD_CLR, "LCD Init"]
pause 5
HSEROUT [LCD_INST, LCD_L2, " SerLCD_V2_5"]
pause 2000
#ENDIF
#IFDEF USE_LCD_FOR_DEBUG
HSEROUT [LCD_INST, LCD_CLR]
pause 5
HSEROUT ["Mtr_Ctrl_Opt=", DEC Mtr_Ctrl_Opt, " "]
pause 2000
#ENDIF
GOSUB Do_Speed_Chk
compVal = VrefInVal ; set initial compare value
GOSUB Map_VrefInVal_to_PWM_Duty
#IFDEF USE_LCD_FOR_DEBUG
HSEROUT [LCD_INST, LCD_CLR]
pause 5
HSEROUT ["MotorDuty=",DEC MotorDuty," "]
pause 2000
#ENDIF
' Spin up motors to MotorDuty
' (Below a value of 'MinDutyToSpin', the motors don't move at all)
FOR i = 0 to MotorDuty
'FOR i = (MinDutyToSpin - PreSpinVal) to MotorDuty
' CCP3CON.4 = i.0
' CCP3CON.5 = i.1
' CCPR3L = i >> 2
CCP4CON.4 = i.0
CCP4CON.5 = i.1
CCPR4L = i >> 2
pause SpinUpPause
#IFDEF USE_LCD_FOR_DEBUG
HSEROUT [LCD_INST, LCD_CLR]
pause 5
HSEROUT ["i=",DEC i," "]
#ENDIF
NEXT i
#IFDEF USE_LCD_FOR_DEBUG
HSEROUT [LCD_INST, LCD_CLR]
pause 5
HSEROUT ["Final set Duty:", LCD_INST, LCD_L2," ",DEC MotorDuty]
#ENDIF
; Henrik Olson says I don't need this
; -----------------------------------
;INTCON = %10010000 ' Global int enabled (GIE), INTE enabled, INTF flag bit 0 clr
; -----------------------------------
@ INT_ENABLE INT_INT ; INT Port Change Interrupt
Main:
' Check if motor speed control option has changed
IF Mtr_Ctrl_Opt <> Old_Mtr_Ctrl_Opt Then
' Turn on appropriate LED indicator
LED_ADC = Mtr_Ctrl_Opt
LED_USART = !Mtr_Ctrl_Opt ; inverts value of Mtr_Ctrl_Opt
' Save selected motor speed control option
WRITE EE_Mtr_Ctrl_Opt, Mtr_Ctrl_Opt
PAUSE 100
Old_Mtr_Ctrl_Opt = Mtr_Ctrl_Opt
EndIF
gosub Do_Speed_Chk
pause 100
If VrefInVal <> compVal Then
#IFDEF USE_LCD_FOR_DEBUG
HSEROUT [LCD_INST, LCD_CLR]
pause 5
HSEROUT ["new VrefInVal=", DEC VrefInVal, " "]
#ENDIF
compVal = VrefInVal
GOSUB Map_VrefInVal_to_PWM_Duty
gosub ChngMotorHPWM
endif
GOTO Main
Do_Speed_Chk:
IF Mtr_Ctrl_Opt = 1 then
' Read trim pot Vref to set motor speed
PAUSEUS 50 ' Wait for A/D channel acquisition time
ADCON0.1 = 1 ' Start conversion
WHILE ADCON0.1 = 1 ' Wait for it to complete
WEND
VrefInVal = ADRESH
else
' Get data from USART Rc channel
ENDIF
return
ChngMotorHPWM:
' CCP3CON.4 = MotorDuty.0
' CCP3CON.5 = MotorDuty.1
' CCPR3L = MotorDuty >> 2
CCP4CON.4 = MotorDuty.0
CCP4CON.5 = MotorDuty.1
CCPR4L = MotorDuty >> 2
RETURN
Map_VrefInVal_to_PWM_Duty:
' Arduino Map function to emulate:
' ===============================
' map(value, fromLow, fromHigh, toLow, toHigh)
' long map(long x, long in_min, long in_max, long out_min, long out_max)
' {
' return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
' }
' TODO: If switching from onboard trim pot to ext trim pot and there isn't one
' one connected to the 3-pin connector, may need to make in_min greater
' than 0
MotorDuty = (compVal - 0) * (MaxDuty - MinDuty)/(MaxADCVal - 0) + MinDuty
' MotorDuty = (compVal ** 39322) + MinDuty ' Same as 100 + VrefInValue * 0.600006 but likely faster than 100+VrefInValue*6/10
#IFDEF USE_LCD_FOR_DEBUG
HSEROUT [LCD_INST, LCD_CLR]
pause 5
HSEROUT ["compVal=",DEC compVal," ",LCD_INST, LCD_L2]
pause 1500
HSEROUT ["MotorDuty=",DEC MotorDuty," "]
#ENDIF
RETURN
END
' ************************************************** *************
' [INT - interrupt handler]
' ************************************************** *************
Mtr_Speed_Ctrl_Btn:
' Toggle motor speed control option (values are 0 or 1)
Mtr_Ctrl_Opt = NOT Mtr_Ctrl_Opt
' Shouldn't need to do this as the interrupt handler was defined above
' to have ResetFlag = yes
; INTCON.1 = 0 ' Clear RA2/INT External Interrupt Flag
@ INT_RETURN
Why would the conditional compile define cause such weird behaviour? Is it because I'm now transmitting serially @ 9600 baud? Are there other configuration parameters I need with this LCD?
When I uncomment it, though, (so I can see the debug info on the LCD) the motor immediately starts spinning when power is connected and the ADC behaviour is lagging, as if it takes more time to get the results.
I'm using a 16F1825 chip. What's weird is that this was working just fine with my old LCD @ 2400 baud but since I accidentally fried that and had to get a new one I changed it to 9600 baud as that's the default with the new serial LCD I got from SparkFun (I also needed to comment out "BAUDCON.4 = 1" with this LCD as otherwise it displayed garbage)
'#DEFINE USE_LCD_FOR_DEBUG ; comment out for non-debug use
' ************************************************** *************
' TODOs
' ************************************************** *************
' 1. Need to calibrate motor RPMs so they spin at the same rate
' -> Separate "MotorDuty" EEPROM variables?
' ************************************************** *************
' Pin Connections
' ************************************************** *************
' Vdd -> pin 1 -> +5V
' RA5 -> pin 2 -> Blue LED (USART motor control indicator)
' RA4 -> pin 3 -> Green LED (ADC motor control indicator)
' RC5/Rx -> pin 5 -> EUSART receive
' RC4/Tx -> pin 6 -> EUSART transmit (LCD)
' RC2 -> pin 8 -> Port motor direction signal (motor 2)
' RC1/CCP4 -> pin 9 -> Port/Stbd motor PWM output (motor 1 & 2)
' RC0 -> pin 10 -> Stbd motor direction signal (motor 1)
' RA2/INT -> pin 11 -> Motor control option select button
' RA1 -> pin 12 -> trim pot input
' Vss -> pin 14 -> GND
DEFINE OSC 16 ; Set oscillator 16Mhz
' EUSART Settings for Tx/Rc (e.g. LCD)
' > use Mister E PIC Multi-Calc application to get register/DEFINE settings
' > as the values are dependent on the OSC and desired baud rate
DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1
DEFINE HSER_CLROERR 1 ' Clear overflow automatically
DEFINE HSER_SPBRG 160 ' 9600 Baud @ 16MHz, -0.08%
' ************************************************** *************
' 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
pause 100
APFCON0.2 = 0 ; Tx on RC4 for LCD display
APFCON0.7 = 0 ; Rx on RC5
' Some LCD serial modules need inverted data, some do not
' Enable the line below if needed, but for SparkFun SerLCD it should be
' commented out
'BAUDCON.4 = 1 ; Transmit inverted data to the Tx pin
' From Mister E's Multi-Calc for EUSART:
' ************************************************** ***************
SPBRGH = 1
BAUDCON.3 = 1 ' Enable 16 bit baudrate generator
' ************************************************** ***************
ANSELC = 0 ; Digital only for all PortC pins
TRISC = %00001000 ; Make all pins output except for RC3
; (motor control option button input)
ANSELA = %00000010 ; Analog on PORTA.1 (AN1) only
TRISA = %00000110 ; Make all pins output except for RA1 & RA2
; (trim pot input & button input)
FVRCON = 0 ; Fixed Voltage Reference is disabled
ADCON0 = %00000101 ; ADC enabled on AN1 (RA1) only; ADC conversion
; enabled
PAUSEUS 20 ; Wait for the analog switch 'glitch' to die down
ADCON1 = %00110000 ; Left-justified results in 8-bits; Frc as timer
' The INT pin can be used to generate an asynchronous edge-triggered interrupt.
' This interrupt is enabled by setting the INTE bit of the INTCON register. The
' INTEDG bit of the OPTION_REG register determines on which edge the interrupt
' will occur. When the INTEDG bit is set, the rising edge will cause the
' interrupt. When the INTEDG bit is clear, the falling edge will cause
' the interrupt. The INTF bit of the INTCON register will be set when a valid
' edge appears on the INT pin. If the GIE and INTE bits are also set, the
' processor will redirect program execution to the interrupt vector.
OPTION_REG.6 = 1 ; 1=Rising edge (default) or button "PRESS";
; 0=Falling edge or button "RELEASE"
#IFDEF USE_LCD_FOR_DEBUG
' Display control codes for SerLCD serial LCD (SparkFun part #LCD-09395)
' (see 'Dropbox\PBP Projects\PIC Datasheets\SerLCD_V2_5 Datasheet.pdf'
' for list of control codes)
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
LCD_BR_CMD CON 124 ' command character for adjusting backlight brightness
LCD_BR_LVL CON 140 ' 140==40%
#ENDIF
' ************************************************** *************
' Includes
' ************************************************** *************
INCLUDE "DT_INTS-14.bas" ' Base Interrupt System
INCLUDE "ReEnterPBP.bas" ' Include if using PBP interrupts
' --> copy both files to PBP main folder
' (i.e. c:\pbp3)
;-- Place a copy of these variables in your Main program -------------------
;-- The compiler will tell you which lines to un-comment --
;-- Do Not un-comment these lines --
;---------------------------------------------------------------------------
;wsave VAR BYTE $20 SYSTEM ' location for W if in bank0
;wsave VAR BYTE $70 SYSTEM ' alternate save location for W
' if using $70, comment wsave1-3
' --- IF any of these three lines cause an error ?? ------------------------
' Comment them out to fix the problem ----
' -- Which variables are needed, depends on the Chip you are using --
;wsave1 VAR BYTE $A0 SYSTEM ' location for W if in bank1
;wsave2 VAR BYTE $120 SYSTEM ' location for W if in bank2
;wsave3 VAR BYTE $1A0 SYSTEM ' location for W if in bank3
' --------------------------------------------------------------------------
' ************************************************** *************
' ASM Interrupt Definitions
' ************************************************** *************
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler INT_INT, _Mtr_Speed_Ctrl_Btn, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM
' ************************************************** *************
' 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 30 ; Value to subtract from MinDutyToSpin for motor spin up
MinDutyToSpin CON 75 ; 75 for 8-bit resolution
MinDuty CON 80 ; Minimum speed to rotate motor for this application
SpinUpPause VAR BYTE ; Pause during motor spin up
SpinUpPause = 75
#IFDEF USE_LCD_FOR_DEBUG
SpinUpPause = 17 ; Less pause is needed when using LCD
#ENDIF
MaxDuty VAR BYTE ; According to Darrel:
; MaxDuty = (PR2 + 1) * 4
MaxDuty = (PR2 + 1) * 4 ; 252 but with prescaler resolution it's actually
; 250 (8-bit)
MotorDuty VAR BYTE ; Actual duty cycle for motor
i VAR BYTE
MaxADCVal CON 255 ; 255 for 8-bit; 1023 for 10-bit
VrefInVal VAR BYTE ; stores ADCIN result read from trim pot
compVal VAR BYTE ; stores last-changed ADC value
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"
ButtonPress VAR PORTA.2 ; Alias PORTA.2 as "ButtonPress"
LED_ADC VAR PORTA.4 ; Alias PORTA.4 as "LED_ADC"
LED_USART VAR PORTA.5 ; Alias PORTA.4 as "LED_USART"
Old_Mtr_Ctrl_Opt VAR BIT ; Stoes last set motor speed control option
' ************************************************** *************
' Read EEPROM value(s)
' ************************************************** *************
' 1 = Trim pot via ADC
' 0 = Serial data via USART Rc (external source)
Mtr_Ctrl_Opt_Default CON 1
EE_Mtr_Ctrl_Opt DATA Mtr_Ctrl_Opt_Default
Mtr_Ctrl_Opt VAR BIT
READ EE_Mtr_Ctrl_Opt, Mtr_Ctrl_Opt
' ************************************************** *************
' Set default values
' ************************************************** *************
' Set initial value of comparison variable
Old_Mtr_Ctrl_Opt = Mtr_Ctrl_Opt
' Turn on appropriate LED indicator
LED_ADC = Mtr_Ctrl_Opt
LED_USART = !Mtr_Ctrl_Opt ; inverts value of Mtr_Ctrl_Opt
'if Mtr_Ctrl_Opt = 1 then
' HIGH LED_ADC
' LOW LED_USART
'else
' LOW LED_ADC
' HIGH LED_USART
'endif
LOW MOTOR_1_DIR ; Set stbd motor (motor 1) to fwd (CW)
'LOW MOTOR_1_PWM
LOW MOTOR_2_DIR ; Set port motor (motor 2) to fwd (CW)
LOW MOTOR_2_PWM ; (motor will be connected in reverse in model for
; CCW movement)
' Should only need to do this one time to adjust backlight brightness
'#IFDEF USE_LCD_FOR_DEBUG
' HSEROUT [LCD_BR_CMD, LCD_BR_LVL]
' PAUSE 5
'#ENDIF
#IFDEF USE_LCD_FOR_DEBUG
pause 1000
HSEROUT [LCD_INST, LCD_CLR, "LCD Init"]
pause 5
HSEROUT [LCD_INST, LCD_L2, " SerLCD_V2_5"]
pause 2000
#ENDIF
#IFDEF USE_LCD_FOR_DEBUG
HSEROUT [LCD_INST, LCD_CLR]
pause 5
HSEROUT ["Mtr_Ctrl_Opt=", DEC Mtr_Ctrl_Opt, " "]
pause 2000
#ENDIF
GOSUB Do_Speed_Chk
compVal = VrefInVal ; set initial compare value
GOSUB Map_VrefInVal_to_PWM_Duty
#IFDEF USE_LCD_FOR_DEBUG
HSEROUT [LCD_INST, LCD_CLR]
pause 5
HSEROUT ["MotorDuty=",DEC MotorDuty," "]
pause 2000
#ENDIF
' Spin up motors to MotorDuty
' (Below a value of 'MinDutyToSpin', the motors don't move at all)
FOR i = 0 to MotorDuty
'FOR i = (MinDutyToSpin - PreSpinVal) to MotorDuty
' CCP3CON.4 = i.0
' CCP3CON.5 = i.1
' CCPR3L = i >> 2
CCP4CON.4 = i.0
CCP4CON.5 = i.1
CCPR4L = i >> 2
pause SpinUpPause
#IFDEF USE_LCD_FOR_DEBUG
HSEROUT [LCD_INST, LCD_CLR]
pause 5
HSEROUT ["i=",DEC i," "]
#ENDIF
NEXT i
#IFDEF USE_LCD_FOR_DEBUG
HSEROUT [LCD_INST, LCD_CLR]
pause 5
HSEROUT ["Final set Duty:", LCD_INST, LCD_L2," ",DEC MotorDuty]
#ENDIF
; Henrik Olson says I don't need this
; -----------------------------------
;INTCON = %10010000 ' Global int enabled (GIE), INTE enabled, INTF flag bit 0 clr
; -----------------------------------
@ INT_ENABLE INT_INT ; INT Port Change Interrupt
Main:
' Check if motor speed control option has changed
IF Mtr_Ctrl_Opt <> Old_Mtr_Ctrl_Opt Then
' Turn on appropriate LED indicator
LED_ADC = Mtr_Ctrl_Opt
LED_USART = !Mtr_Ctrl_Opt ; inverts value of Mtr_Ctrl_Opt
' Save selected motor speed control option
WRITE EE_Mtr_Ctrl_Opt, Mtr_Ctrl_Opt
PAUSE 100
Old_Mtr_Ctrl_Opt = Mtr_Ctrl_Opt
EndIF
gosub Do_Speed_Chk
pause 100
If VrefInVal <> compVal Then
#IFDEF USE_LCD_FOR_DEBUG
HSEROUT [LCD_INST, LCD_CLR]
pause 5
HSEROUT ["new VrefInVal=", DEC VrefInVal, " "]
#ENDIF
compVal = VrefInVal
GOSUB Map_VrefInVal_to_PWM_Duty
gosub ChngMotorHPWM
endif
GOTO Main
Do_Speed_Chk:
IF Mtr_Ctrl_Opt = 1 then
' Read trim pot Vref to set motor speed
PAUSEUS 50 ' Wait for A/D channel acquisition time
ADCON0.1 = 1 ' Start conversion
WHILE ADCON0.1 = 1 ' Wait for it to complete
WEND
VrefInVal = ADRESH
else
' Get data from USART Rc channel
ENDIF
return
ChngMotorHPWM:
' CCP3CON.4 = MotorDuty.0
' CCP3CON.5 = MotorDuty.1
' CCPR3L = MotorDuty >> 2
CCP4CON.4 = MotorDuty.0
CCP4CON.5 = MotorDuty.1
CCPR4L = MotorDuty >> 2
RETURN
Map_VrefInVal_to_PWM_Duty:
' Arduino Map function to emulate:
' ===============================
' map(value, fromLow, fromHigh, toLow, toHigh)
' long map(long x, long in_min, long in_max, long out_min, long out_max)
' {
' return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
' }
' TODO: If switching from onboard trim pot to ext trim pot and there isn't one
' one connected to the 3-pin connector, may need to make in_min greater
' than 0
MotorDuty = (compVal - 0) * (MaxDuty - MinDuty)/(MaxADCVal - 0) + MinDuty
' MotorDuty = (compVal ** 39322) + MinDuty ' Same as 100 + VrefInValue * 0.600006 but likely faster than 100+VrefInValue*6/10
#IFDEF USE_LCD_FOR_DEBUG
HSEROUT [LCD_INST, LCD_CLR]
pause 5
HSEROUT ["compVal=",DEC compVal," ",LCD_INST, LCD_L2]
pause 1500
HSEROUT ["MotorDuty=",DEC MotorDuty," "]
#ENDIF
RETURN
END
' ************************************************** *************
' [INT - interrupt handler]
' ************************************************** *************
Mtr_Speed_Ctrl_Btn:
' Toggle motor speed control option (values are 0 or 1)
Mtr_Ctrl_Opt = NOT Mtr_Ctrl_Opt
' Shouldn't need to do this as the interrupt handler was defined above
' to have ResetFlag = yes
; INTCON.1 = 0 ' Clear RA2/INT External Interrupt Flag
@ INT_RETURN
Why would the conditional compile define cause such weird behaviour? Is it because I'm now transmitting serially @ 9600 baud? Are there other configuration parameters I need with this LCD?