Code:
'--------Program Desciption--------
' Program uses Timer0 Interrupt to average motor rpm over one minute.
' Motor power set by potentiometer before program begins.
' LCD display updates time, position count and average rpm every second.
'---Review PicBasic Pro Command----
' The PicBasic Pro Compiler Manual is on line at:
' http://www.microengineeringlabs.com/resources/index.htm#Manuals
'---------PIC Connections----------
' 18F4331 Pin Wiring
' --------- ----------
' RA0(AN0) Potentiometer, controls motor power
' RA3 Signal 1 from Encoder
' RA4 Signal 2 from Encoder
' RB5 In Circuit Serial Programming (ICSP) PGM
' 100K Resistor to GND
' RB6 ICSP PGC (Clock)
' RB7 ICSP PGD (Data)
' RC0 Brake Motor 1 on Xavien XDDCMD-1 (Pin 1)
' RC1 PWM Motor 1 on Xavien XDDCMD-1 (Pin 2)
' RC3 Direction Motor 1 on Xavien XDDCMD-1 (Pin 3)
' RD4 LCD Data Bit 4
' RD5 LCD Data Bit 5
' RD6 LCD Data Bit 6
' RD7 LCD Data Bit 7
' RE0 LCD Register Select
' RE1 LCD Enable
' MCLR 4.7K Resistor to +5V & ICSP Vpp
' VDD +5V
' VSS GND
' OSC1 & OSC2 4 MHz Crystal w/ 2-22 pF Cap. to GND
'----Xavien XDDCMD-1 Connections---
' Xavien 2x5 Header Pin Wiring Pin Layout 2x5 Header
' --------------------- ------ ---------------------
' 2 4 6 8 10
' Pin 1 Motor 1 Brake RC0 o o o o o
' Pin 2 Motor 1 PWM RC1 o o o o o
' Pin 3 Motor 1 Direction RC3 1 3 5 7 9
' See schematic at:
' http://cornerstonerobotics.org/schematics/18f4331_hpwm_motor_encoder.pdf
'--Sample POSCNTH, POSCNTL Values and Corresponding Position Counter--
' position = 256 * POSCNTH + POSCNTL
' POSCNTH POSCNTL Position Counter
' ------- ------- ----------------
' 0 0 0
' 0 1 1
' 1 0 255
' 0 128 128
' 128 0 32768
' 0 255 255
' 255 0 65280
' 255 255 65535
'-------------Defines--------------
DEFINE LCD_DREG PORTD ' Set LCD Data port
DEFINE LCD_DBIT 4 ' Set starting Data bit to 4
DEFINE LCD_BITS 4 ' Set LCD bus size to 4
DEFINE LCD_RSREG PORTE ' Set LCD Register Select port to E
DEFINE LCD_RSBIT 0 ' Set LCD Register Select bit to 0
DEFINE LCD_EREG PORTE ' Set LCD Enable port to E
DEFINE LCD_EBIT 1 ' Set LCD Enable bit to 1
DEFINE LCD_LINES 2 ' Set number of lines on LCD to 2
DEFINE LCD_COMMANDUS 2000 ' Set command delay time to 2000 us
DEFINE LCD_DATAUS 50 ' Set data delay time to 50 us
DEFINE ADC_BITS 8 ' Set number of bits in result to 8
DEFINE ADC_CLOCK 3 ' Set clock source (rc = 3)
DEFINE ADC_SAMPLEUS 50 ' Set sampling time in us
DEFINE CCP2_REG PORTC ' Set HPWM Channel 2 port to C
DEFINE CCP2_BIT 1 ' Set HPWM Channel 2 bit to 1
'------------Variables-------------
mot_pwr var byte ' Declare mot_pwr variable, reserve byte
pot_val var byte ' Declare pot_val, reserve byte
position var word ' Declare position, reserve word
second VAr word ' Declare second, reserve word
ticks var byte ' Declare ticks, reserve byte
update var byte ' Declare update, reserve byte
rpm var word ' Declare rpm, reserve word
'----------Initialization----------
CCP1CON = %00111111 ' Set Capture/Compare/PWM Module Control
' Register CCP1CON in PWM mode (bits 0-3),
' bits 4,5 set LSBs of 10-bit duty cycle,
' see 18F4331 datasheet page 151 +/-.
ANSEL0 = %00000001 ' Set AN0 to analog, AN1-AN7 to digital,
' see datasheet page 249 +/-.
ANSEL1 = %00000000 ' Set AN8 to digital, see datasheet
' page 249 +/-.
TRISA = %00011111 ' Set TRISA register, RA7-RA5 as outputs,
' RA4-RA0 as inputs, see datasheet
' page 107 +/-.
LATA = %00000000 ' Set all LATA register bits to 0.
TRISB = %00000000 ' Set RB7-RB0 pins in PORTB as outputs.
TRISC = %00000000 ' Set RC7-RC0 pins in PORTC as outputs.
QEICON = %10001000 ' Set Quadrature Encoder Interface Control
' Register. See page 171 +/- for
' encoder set up.
T0CON = %11010101 ' Set TMR0 configuration and enable PORTB
' pullups. Set Timer0 Prescaler Select bits
' (bits 2-0) to 1:64 prescaler value. Timer0
' interrupt occurs every 256 us for a
' 4 MHz crystal so 256us * 64 = 16.384ms.
' 16.384ms * 61 ticks = 0.9994 seconds.
' See Timer0 Control Register 18F4331
' datasheet page 135 +/-.
INTCON = %10100000 ' Enable Timer0 interrupts.
ON INTERRUPT GoTo tickint ' Jump to interrupt handler "tickint"
' after receiving an interrupt.
PORTC.0 = 1 ' Turn on brake.
PORTC.1 = 0 ' Set PWM bit for Channel 2 of HPWM to LOW.
'-------------Main Code------------
pause 500 ' Pause to start up LCD
PORTC.0 = 0 ' Turn off brake
PORTC.3 = 0 ' Set direction of motor
' If position value on LCD is in the 65,000s
' and counting down, then change the
' motor direction: PORTC.3 = 1.
second = 0 ' Set initial values for second and ticks.
ticks = 0
update = 1 ' Enable first display
' Set counter starting position:
POSCNTH = 0 ' Set counter for encoder, H bit
POSCNTL = 0 ' Set counter for encoder, L bit
' position = 256 * POSCNTH + POSCNTL
' With POSCNTH and POSCNTL = 0,
' position counter will start at 0.
' See table above for more sample values.
' Read motor power setting, set motor power before main loop:
ADCIN 0, pot_val ' Read AN0 and store result in pot_val.
' This potentiometer (connected to AN0)
' sets the motor power.
mot_pwr = 11 * pot_val / 16 + 77
' mot_pwr = 11/16 * pot_val + 77
' (Can't write equation as 11/16 * pot_val
' since interger division truncates: any
' fractional part is discarded. Since 11
' and 16 are integers, 11/16 would be
' truncated to zero.)
' 77 is the minimum power to start motor.
' 11/16 is the slope of the line to give
' mot_pwr values from 77 to about 255.
' See graph & equation in schematic.
HPWM 2, mot_pwr, 20000 ' Send PWM signal from RC1 to Pin 2 on
' the Xavien XDDCMD-1 DC motor driver.
loop:
if update = 1 then
POSITION = 256 * POSCNTH + POSCNTL ' Read position
rpm = 60 * (position/32) / second
' 60, (60 seconds/minute)
' position/32, number of revolutions
' (Our motor has 16 holes which generates
' 32 position counts/revolution)
' second, number of seconds
' rev 60 seconds position counts 1 revolution 1
' rpm = --- = ---------- * * ------------------ * ---------
' min 1 minute 32 position counts # seconds
LCDOUT $FE, $80, "rpm=",dec5 rpm, " s=", dec3 second
' Display rpm and seconds on the first line
LCDOUT $FE, $C0, "position = ",DEC5 POSITION
' Display position on second line
' Position will count to 65535, then
' cycle back to 0 and continue counting.
' in 5 decimal digits.
update = 0 ' Reset update to 0
endif
' After 60 seconds, shut down:
if second = 60 then gosub shut_down
' Stop program at 60 seconds
goto loop:
Disable ' Disable interrupts during interrupt handler
' Interrupt handler:
tickint:
ticks = ticks + 1 ' Count parts of a second
if ticks < 61 then tiexit ' Timer0 interrupt occurs every 256 us for
' a 4 MHz crystal so 256us * 64 = 16.384ms.
' 16.384ms * 61 ticks = 0.9994 seconds.
' (61 ticks per 0.9994 seconds)
' One second elapsed, reset ticks and update time:
ticks = 0 ' Reset ticks to 0
second = second + 1 ' Add one second
update = 1 ' Permits LCD update
tiexit: INTCON.2 = 0 ' Reset timer interrupt flag,
' (Reset Timer0 to 0 - next Timer0
' interrupt is in 16.384ms)
resume
' End of interrupt handler
enable ' Enable interrupts
shut_down:
PORTC.0 = 1 ' Turn on motor controller brake
end
Bookmarks