;-------------------------------------------------------------------------------
;16F684
;
;Servotester
;versie 20120806
;-------------------------------------------------------------------------------
include 16f684
pragma target clock 4_000_000 ;oscillator frequency
pragma target OSC XT ;4MHz xTal
pragma target WDT disabled ;no watchdog
pragma target MCLR internal ;reset internally
enable_digital_io() ;alle pinnen digitale IO
;LED is via voorschakelweerstand aangesloten op pin A0
alias led is pin_A0
pin_A0_direction = output
led = off
alias servo is pin_A2
pin_A2_direction = output
servo = off
alias switch is pin_A3
pin_A3_direction = input
;-------------------------------------------------------------------------------
;instellingen voor Timer2
;Prescaler= 16
;PostScaler = 5
;PR2 = 250 - 1 voor herlaadtijd
;Freq = 50 Hz
;Tijd = 0.02 seconden
;-------------------------------------------------------------------------------
T2CON_TOUTPS = 0b0100 ;postscaler
T2CON_T2CKPS = 0b11
PR2 = 249 ;herlaadwaarde
PIE1_TMR2IE = high ;Timer2 interrupt enable
INTCON_PEIE = high ;perifierie interrupt enable
PIR1_TMR2IF = low ;wis interrupt vlag
var volatile byte TimeFlags = 0
var volatile bit FlagTimePassed at TimeFlags : 0
var volatile bit Flag20msPassed at TimeFlags : 1
var volatile bit FlagBlink at TimeFlags : 2
var volatile bit FlagBlinkState at TimeFlags : 3
var volatile bit FlagServoStep at TimeFlags : 4
var volatile bit FlagClear at TimeFlags : 7
;een seconde
const byte TimerCounterReload = 50
var byte TimerCounter = TimerCounterReload
;Led knipper frequentie
const byte BlinkTimerReload = 20
var byte BlinkTimer = BlinkTimerReload
;Servo update frequentie
const byte ServoStepReload = 10
var byte ServoStepTimer = ServoStepReload
;-------------------------------------------------------------------------------
;LCD declaratie en initialisatie
;-------------------------------------------------------------------------------
;Volgende constanten moeten gedeclareerd worden:
const byte LCD_ROWS = 2 -- 1, 2 or 4 lines
const byte LCD_CHARS = 16 -- 8, 16 or 20 chars per line
;Alisassen voor de handshake-lijnen:
alias lcd_rs is pin_c5 -- cmd/data select
alias lcd_en is pin_c4 -- trigger
pin_C5_direction = output
pin_C4_direction = output
;Aliassen voor de vier datalijnen:
alias lcd_dataport is portC_low -- 4 databits
pin_C0_direction = output
pin_C1_direction = output
pin_C2_direction = output
pin_C3_direction = output
;voor de aanduiding van 'micro' gebruiken we een 'u'
;het karakter 'mu' bestaat niet standaard op het display
;en kan eventueel zelf aangemaakt worden
const byte sTime[] = " us"
;laad de eigenlijke bibliotheek
include lcd_hd44780_4
;wacht even om trage LCD's te laten resetten
include delay
delay_100ms(5)
;en initialiseer het display
lcd_init() -- init the lcd controller
include print
;scherm wissen
lcd_clear_screen()
;-------------------------------------------------------------------------------
;ADC instellingen
;-------------------------------------------------------------------------------
const bit ADC_HIGH_RESOLUTION = true
const byte ADC_NVREF = 0
;de bibliotheek laden
include adc
;De ADC initialiseren
adc_init()
;en maak pen 12 (RA1/AN1) analoge ingang
set_analog_pin(1)
var word wADCValue
;-------------------------------------------------------------------------------
;Servo en timer1 instellingen
;-------------------------------------------------------------------------------
var volatile word wServoReload = 65535 - 1480
var volatile byte ServoReload[2] at wServoReload
var volatile word wServoValue = 1500
var byte NewServoValue = 0
var byte ServoDir = 0
var word wServoStep = 10
T1CON = 0b00000100
TMR1H = ServoReload[1]
TMR1L = ServoReload[0]
T1CON_T1CKPS = 0 ;geen prescaler
T1CON_T1OSCEN = high ;oscillator enable
T1CON_TMR1CS = low ;internal clock
T1CON_TMR1ON = low ;Timer1 off
T1CON_NT1SYNC = high ;do not synchronize clock
PIE1_TMR1IE = high
INTCON_PEIE = high
;-------------------------------------------------------------------------------
;INTERRUPT PROCEDURE
;-------------------------------------------------------------------------------
procedure TimerInterrupt is
pragma interrupt
;Timer 1 interrupt
if(PIR1_TMR1IF)then
;servo puls afgelopen
Servo = low
;stop de teller
T1CON_TMR1ON = low
;reset Timer1 interruptvlag
PIR1_TMR1IF = low
;Nieuwe waarde?
if(NewServoValue > 0)then
;De tijd dat de servopluls 'actief' moet zijn (tussen 1000 en 2000 µs)
;wordt berekend door de van de maximale tellerwaarde (0xFFFF = 65536)
;de werkelijke waarde af te trekken.
;De waarde 20 die extra bijgeteld wordt is om de 'verloren' microseconden
;te compenseren die nodig zijn om tot in de interruptprocedure te geraken
;(oa saven van registers).
wServoReload = 65535 - wServoValue + 20
end if
TMR1H = ServoReload[1]
TMR1L = ServoReload[0]
end if
;Timer 2 interrupt
if(PIR1_TMR2IF)then
;20ms zijn om: zet de servo en de teller aan
Servo = high
T1CON_TMR1ON = high
;reset Timer2 interrruptvlag
PIR1_TMR2IF = low
;meldt 20 ms gepasseerd
Flag20msPassed = true
;laat dit 50 keer gebeuren voor 1 seconde
TimerCounter = TimerCounter - 1
if(TimerCounter == 0)then
TimerCounter = TimerCounterReload ;herlaad de teller
FlagTimePassed = true ;tijd is verstreken
end if
;ServoStepTimer
ServoStepTimer = ServoStepTimer - 1
if(ServoStepTimer == 0)then
ServoStepTimer = ServoStepReload
FlagServoStep = true
end if
;Knipperteller
BlinkTimer = BlinkTimer - 1
if(BlinkTimer == 0)then
BlinkTimer = BlinkTimerReload
FlagBlink = true
end if
end if
;Einde interrupt
end procedure
;-------------------------------------------------------------------------------
;Instellingen voor de schakelaar
;-------------------------------------------------------------------------------
const byte SW_MODE_NEUTRAL = 0
const byte SW_MODE_RUN = 1
const byte SW_MODE_MANUAL = 2
var byte SW_MODE = SW_MODE_NEUTRAL
var byte SW_MODE_CHANGE = 1 ;voor initialisatie!
const byte SW_ON = 1
const byte SW_OFF = 0
var byte SW_STATE = SW_OFF
var byte SW_PREVIOUS_STATE = SW_OFF
;-------------------------------------------------------------------------------
T2CON_TMR2ON = high ;turn timer2 on;
INTCON_GIE = high ;enable interrupts
;-------------------------------------------------------------------------------
;Main loop
;-------------------------------------------------------------------------------
forever loop
if(Flag20msPassed)then
;20ms zijn gepasseerd, reset de vlag
Flag20msPassed = low
if(SW_MODE == SW_MODE_MANUAL)then
;De stand van de potmeter wordt gebruikt voor de servowaard.
;Lees de ADC (10 bits -> waarde van 0 tot 1023)
wADCValue = adc_read_high_res(1)
;de lsb hebben we niet nodig, zorgt voor jitter
wADCValue = wADCValue >> 1
;We hebben nu een waarde van 0 tot 511. Maal 2 geeft dit teur een
;waarde van 0 tot 1022 (die 1000 hebben we nodig voor 1ms)
wADCValue = wADCValue + wADCValue
;Tel de offset bij voor een waarde van 1ms tot 2ms
wServoValue = 1000 + wADCValue
;En zet die waarde op het display
lcd_cursor_position(1,0)
print_word_dec(lcd, wServoValue)
print_string(lcd, sTime)
;geef de interruptroutine te kennen dat er een nieuwe waarde is
NewServoValue = 1
end if
;Schakelaar gewijzigd? (laag waar)
if(Switch == high)then
;Als de vlaggen nog aan stonden dan afzetten
if(SW_STATE == SW_ON)then
SW_STATE = SW_OFF
SW_PREVIOUS_STATE = SW_OFF
end if
end if
if(Switch == low)then
;Als het indrukken van de schakelaar nog niet gemeld is, melden
if(SW_STATE == SW_OFF)then
;dender onderdrukken
if(SW_PREVIOUS_STATE == SW_OFF)then
;zet die vlag al en na 20 ms de eigenlijke vlag
SW_PREVIOUS_STATE = SW_ON
else
;de vorige keer was de schakelaar al ingedrukt, geen dender
SW_STATE = SW_ON
;verhoog de MODE
SW_MODE = SW_MODE + 1
if(SW_MODE > SW_MODE_MANUAL)then
SW_MODE = SW_MODE_NEUTRAL
end if
;en meldt dit
SW_MODE_CHANGE = 1
end if
end if
end if
end if
if(SW_MODE_CHANGE != 0)then
;Mode is gewijzigd!
;initialiseer
SW_MODE_CHANGE = 0
if(SW_MODE == SW_MODE_NEUTRAL)then
;1500 us
;zet 1500 op de bovenste regel
lcd_clear_screen()
wServoValue = 1500
lcd_cursor_position(0,0)
print_word_dec(lcd, wServoValue)
print_string(lcd, sTime)
NewServoValue = 1
end if
if(SW_MODE == SW_MODE_RUN)then
;begin neutraal en verhoog; de juiste stand staat al op de LCD
wServoValue = 1500
ServoDir = 1
end if
if(SW_MODE == SW_MODE_MANUAL)then
;Wis het display en vanaf nu is er elke 20 ms een update
lcd_clear_screen()
end if
end if
if(FlagServoStep)then
if(SW_MODE == SW_MODE_RUN)then
;pas de servo aan (enkel in RUN modus)
if(ServoDir == 0)then
;aflopend
if((wServoValue - wServoStep) >= 1000)then
wServoValue = wServoValue - wServoStep
NewServoValue = 1
else
ServoDir = 1
end if
else
;oplopend
if((wServoValue + wServoStep) <= 2000)then
wServoValue = wServoValue + wServoStep
NewServoValue = 1
else
ServoDir = 0
end if
end if
lcd_cursor_position(0,0)
print_word_dec(lcd, wServoValue)
print_string(lcd, sTime)
end if
FlagServoStep = low
end if
if(FlagBlink)then
;knipper de led
Led = !Led
FlagBlink = low
end if
if(FlagTimePassed)then
;1 seconde
FlagTimePassed = low
end if
;Einde mail loop
end loop
;-------------------------------------------------------------------------------