Copyright (C) 2019 Erő János
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.
Ez a program szabad szoftver; terjeszthető illetve módosítható a Free Software Foundation által kiadott GNU General Public License dokumentumában leírtak; akár a licenc 3-as, akár (tetszőleges) későbbi változata szerint.
Ez a program abban a reményben kerül közreadásra, hogy hasznos lesz, de minden egyéb GARANCIA NÉLKÜL, az ELADHATÓSÁGRA vagy VALAMELY CÉLRA VALÓ ALKALMAZHATÓSÁGRA való származtatott garanciát is beleértve. További részleteket a GNU General Public License tartalmaz.
A felhasználónak a programmal együtt meg kell kapnia a GNU General Public License egy példányát; ha mégsem kapta meg, akkor tekintse meg a http://www.gnu.org/licenses/ oldalon.
-- Title: ad_dcc3.jal -- derived from; ad_dcc2_128.jal - for CONTROLLER BOARD with 16F88 -- Timer0 generates DCC signal, Timer1 controls ADC readout -- Generates DCC signal address "128 speed stages, swi controls light -- no jallib routines to accelerate -- Output to seven segment display -- 128 speed grades, -- synchronous output bit handling -- dcc3 - line OFF when SOUND+PROG button, ON when speed=0 + PROG button -- dcc31 - sound : F2 (code: ) -- pin a0 - analog input -- pin a1 - address load button input -- pin a2 - direction switch input -- pin a3 - light switch input -- pin a4 - display digit "1" output -- pin a5 - F1 (sound) button input -- pin a6 - DCC output + -- pin a7 - DCC output - -- pin b0 - display segment a -- pin b1 - display segment b -- pin b2 - display segment c -- pin b3 - display segment d -- pin b4 - display segment e -- pin b5 - display segment f -- pin b6 - display segment g -- pin b7 - display digit select INCLUDE 16F88 PRAGMA TARGET CLOCK 8_000_000 -- xtal frequency PRAGMA TARGET OSC INTOSC_NOCLKOUT -- internal oscillator, no osc. output OSCCON_IRCF = 7 -- set prescaler to 1 (8 MHz) PRAGMA TARGET LVP disabled -- low-voltage programming disabled PRAGMA TARGET WDT disabled -- watchdog disabled PRAGMA TARGET MCLR internal -- reset pin disabled INCLUDE DELAY -- set all IO as digital enable_digital_io() pin_a0_direction = INPUT pin_a1_direction = INPUT pin_a2_direction = INPUT pin_a3_direction = INPUT pin_a4_direction = OUTPUT pin_a5_direction = INPUT pin_a6_direction = OUTPUT pin_a7_direction = OUTPUT pin_b0_direction = OUTPUT pin_b1_direction = OUTPUT pin_b2_direction = OUTPUT pin_b3_direction = OUTPUT pin_b4_direction = OUTPUT pin_b5_direction = OUTPUT pin_b6_direction = OUTPUT pin_b7_direction = OUTPUT CONST BYTE timer0_load_1 = 210 -- set up for 56us CONST BYTE timer0_load_0 = 156 -- set up for 112us CONST BYTE timer0_presc = 0 CONST timer1_presc = 0 CONST BYTE timer1_load_l = 0 CONST BYTE timer1_load_h = 200 CONST BYTE func_lead = 0x80 VAR BYTE out_segment VAR BYTE sevenval VAR BIT digit_sel AT sevenval:7 VAR BIT digit_sel_int VAR BIT digit_100_int -- digit 100 internal value VAR BIT dcc_pin -- output pin value VAR BYTE dcc_pin_value VAR BIT dcc_bit VAR BYTE dcc_out VAR BYTE dcc_count VAR BIT sync AT dcc_count:3 -- preamble synchronization signal VAR BYTE word_counter VAR BYTE address VAR BYTE speed_pre VAR BYTE speed VAR BYTE checksum1 VAR BYTE func_code VAR BYTE checksum2 VAR BYTE speed_int VAR BIT dir AT speed_int:7 VAR BYTE func_int VAR BIT light AT func_int:4 VAR BIT light_int VAR BIT sound AT func_int:1 -- change code VAR BIT sound_int VAR BYTE measure VAR BYTE measure7 VAR BYTE result VAR BYTE result_ls VAR BYTE result_ms VAR BIT timflag_1 VAR BIT off_state VAR BYTE flash_counter_l VAR BYTE flash_counter_h VAR BIT flash_bit AT flash_counter_h:4 CONST BYTE seven_value_space[] = { 0B_0011_1111, -- value 0 is character 0 0B_0000_0110, -- value 1 is character 1 0B_0101_1011, -- value 2 is character 2 0B_0100_1111, -- value 3 is character 3 0B_0110_0110, -- value 4 is character 4 0B_0110_1101, -- value 5 is character 5 0B_0111_1101, -- value 6 is character 6 0B_0000_0111, -- value 7 is character 7 0B_0111_1111, -- value 8 is character 8 0B_0110_1111, -- value 9 is character 9 0B_0011_1110, -- value a is character U 0B_0011_1110, -- value b is character U 0B_0011_1110, -- value c is character U 0B_0011_1110, -- value d is character U 0B_0011_1110, -- value e is character U 0B_0011_1110 -- value f is character U } -- Table to convert 128 step to BCD without 100 values CONST BYTE dec_values[] = { 0B_0000_0000, 0B_0000_0001, 0B_0000_0010, 0B_0000_0011, 0B_0000_0100, 0B_0000_0101, 0B_0000_0110, 0B_0000_0111, 0B_0000_1000, 0B_0000_1001, 0B_0001_0000, 0B_0001_0001, 0B_0001_0010, 0B_0001_0011, 0B_0001_0100, 0B_0001_0101, 0B_0001_0110, 0B_0001_0111, 0B_0001_1000, 0B_0001_1001, 0B_0010_0000, 0B_0010_0001, 0B_0010_0010, 0B_0010_0011, 0B_0010_0100, 0B_0010_0101, 0B_0010_0110, 0B_0010_0111, 0B_0010_1000, 0B_0010_1001, 0B_0011_0000, 0B_0011_0001, 0B_0011_0010, 0B_0011_0011, 0B_0011_0100, 0B_0011_0101, 0B_0011_0110, 0B_0011_0111, 0B_0011_1000, 0B_0011_1001, 0B_0100_0000, 0B_0100_0001, 0B_0100_0010, 0B_0100_0011, 0B_0100_0100, 0B_0100_0101, 0B_0100_0110, 0B_0100_0111, 0B_0100_1000, 0B_0100_1001, 0B_0101_0000, 0B_0101_0001, 0B_0101_0010, 0B_0101_0011, 0B_0101_0100, 0B_0101_0101, 0B_0101_0110, 0B_0101_0111, 0B_0101_1000, 0B_0101_1001, 0B_0110_0000, 0B_0110_0001, 0B_0110_0010, 0B_0110_0011, 0B_0110_0100, 0B_0110_0101, 0B_0110_0110, 0B_0110_0111, 0B_0110_1000, 0B_0110_1001, 0B_0111_0000, 0B_0111_0001, 0B_0111_0010, 0B_0111_0011, 0B_0111_0100, 0B_0111_0101, 0B_0111_0110, 0B_0111_0111, 0B_0111_1000, 0B_0111_1001, 0B_1000_0000, 0B_1000_0001, 0B_1000_0010, 0B_1000_0011, 0B_1000_0100, 0B_1000_0101, 0B_1000_0110, 0B_1000_0111, 0B_1000_1000, 0B_1000_1001, 0B_1001_0000, 0B_1001_0001, 0B_1001_0010, 0B_1001_0011, 0B_1001_0100, 0B_1001_0101, 0B_1001_0110, 0B_1001_0111, 0B_1001_1000, 0B_1001_1001, 0B_0000_0000, 0B_0000_0001, 0B_0000_0010, 0B_0000_0011, 0B_0000_0100, 0B_0000_0101, 0B_0000_0110, 0B_0000_0111, 0B_0000_1000, 0B_0000_1001, 0B_0001_0000, 0B_0001_0001, 0B_0001_0010, 0B_0001_0011, 0B_0001_0100, 0B_0001_0101, 0B_0001_0110, 0B_0001_0111, 0B_0001_1000, 0B_0001_1001, 0B_0010_0000, 0B_0010_0001, 0B_0010_0010, 0B_0010_0011, 0B_0010_0100, 0B_0010_0101, 0B_0010_0110, 0B_0010_0111 } PROCEDURE init_tims() IS OPTION_REG_T0CS = 0 -- Timer0 Clock source: clock OPTION_REG_PSA = 0 -- Prescaler associated with Timer0 T0CON_T0PS = timer0_presc -- Timer0 Prescaler value TMR0 = timer0_load_1 INTCON_TMR0IF = off -- reset interrupt flag INTCON_TMR0IE = on -- enable Timer0 interrupt T1CON_TMR1CS = 0 -- Select internal clock for Timer1 T1CON_T1OSCEN = 0 -- No dedicated oscillator T1CON_T1CKPS = timer1_presc -- Timer1 Prescaler value T1CON_TMR1ON = 1 -- Enable run Timer1 PIR1_TMR1IF = off -- reset interrupt flag PIE1_TMR1IE = on -- enable Timer1 interrupt INTCON_GIE = on -- enable global interrupts INTCON_PEIE = on END PROCEDURE PROCEDURE init_adc() IS JANSEL_ANS0 = 1 -- pin a0 analog input ADCON1_ADCS2 = 1 ADCON0_ADCS10 = 01 -- ADC clock Fosc/16 ADCON0_CHS = 0 -- ADC channel: 0 ADCON1_ADFM = 0 -- AD value left justified - result ADRESH ADCON1_VCFG0 = 0 -- VCC and VSS as reference voltage ADCON1_VCFG1 = 0 ADCON0_ADON = on -- start ADC END PROCEDURE PROCEDURE isr_0 IS PRAGMA INTERRUPT IF INTCON_TMR0IF == TRUE THEN -- Timer0 interrupt IF dcc_bit == 1 THEN TMR0 = timer0_load_1 -- Reload timer counter ELSE TMR0 = timer0_load_0 -- Reload timer counter END IF dcc_pin = !dcc_pin IF off_state == 1 THEN -- off state: both pins to zero dcc_pin_value = 0b_0000_0000 ELSE IF dcc_pin == 1 THEN -- generate differential output dcc_pin_value = 0b_0100_0000 ELSE dcc_pin_value = 0b_1000_0000 END IF END IF IF digit_100_int == 1 THEN -- display 100 value connected to PORT_A, send here dcc_pin_value = dcc_pin_value | 0b_0001_0000 END IF portA = dcc_pin_value IF dcc_pin == 1 THEN -- next bit IF dcc_count == 0 THEN -- send delimiter IF word_counter == 8 THEN dcc_count = 15 -- set for preamble word_counter = 0 dcc_bit = 1 ELSIF word_counter == 4 THEN dcc_count = 15 -- set for preamble word_counter = word_counter + 1 dcc_bit = 1 ELSE dcc_bit = 0 word_counter = word_counter + 1 dcc_count = 9 IF word_counter == 1 THEN -- packet #1 dcc_out = address ELSIF word_counter == 2 THEN dcc_out = speed_pre ELSIF word_counter == 3 THEN dcc_out = speed ELSIF word_counter == 4 THEN dcc_out = checksum1 ELSIF word_counter == 6 THEN -- packet #2 dcc_out = address ELSIF word_counter == 7 THEN dcc_out = func_code ELSIF word_counter == 8 THEN dcc_out = checksum2 END IF END IF ELSE IF word_counter == 0 THEN -- preamble dcc_bit = 1 ELSIF word_counter == 5 THEN -- preamble dcc_bit = 1 ELSE dcc_bit = dcc_out & 0x80 dcc_out = dcc_out << 1 -- shift DCC value END IF END IF dcc_count = dcc_count - 1 END IF INTCON_TMR0IF = off -- reset interrupt flag END IF IF PIR1_TMR1IF == TRUE THEN -- Timer1 interrupt TMR1H = timer1_load_h -- Reload timer counter TMR1L = timer1_load_l timflag_1 = 1 -- set interrupt semaphore PIR1_TMR1IF = off -- reset interrupt flag INTCON_PEIE = on END IF END PROCEDURE FUNCTION adc_read_low_res() RETURN BYTE IS -- ADC readout routine VAR BYTE adc_value ADCON0_GO = 1 -- set interrupt semaphore WHILE ADCON0_GO LOOP -- wait until ADC finish END LOOP adc_value = ADRESH RETURN adc_value END FUNCTION -- return seven segment value corresponding to lower nibble of x FUNCTION seven_from_digit ( BYTE IN x ) RETURN BYTE IS RETURN seven_value_space[x] END FUNCTION FUNCTION dec_from_byte ( BYTE IN x ) RETURN BYTE IS RETURN dec_values[x] END FUNCTION -- MAIN off_state = 0 -- initialize internal variables and output pins dcc_bit = 0 dcc_pin_value = 0b_0101_0000 dcc_out = 0 dcc_count = 0 word_counter = 0 timflag_1 = 0 out_segment = 0 init_tims() init_adc() address = 03 -- default address = 03 speed_pre = 0x3F -- Extended speed tag speed = 0 checksum1 = 0 checksum2 = 0 FOREVER LOOP IF timflag_1 == 1 THEN measure = adc_read_low_res() -- read in ADC value measure = measure >> 1 -- make 7-bit value from 8-bit, DCC speed data 7-bits long speed_int = measure speed = speed_int sound_int = pin_a5 -- sound on <= pin_a5 (F1) IF off_state == 1 THEN -- in off-state flash display, wait for exit signal flash_counter_l = flash_counter_l + 1 IF flash_counter_l == 0B_1111_1111 THEN flash_counter_h = flash_counter_h + 1 END IF IF flash_bit == 1 THEN -- off-state: flash all display LEDs sevenval = 0B_0111_1111 digit_100_int = 1 ELSE sevenval = 0B_0000_0000 digit_100_int = 0 END IF digit_sel_int = !digit_sel_int digit_sel = digit_sel_int PORTB = sevenval -- write out seven value with digit sel IF (pin_a1 == 1) & (measure == 0x00) THEN -- if address select button AND speed = 0, exit off-state off_state = 0 -- when exit off-state, reset all outputs dcc_bit = 0 dcc_pin_value = 0b_0101_0000 dcc_out = 0 dcc_count = 0 word_counter = 0 -- reset DCC packet parameters, not to generate broken packet END IF ELSE dir = !pin_a2 -- run direction <= NOT pin_a2 (switch connected opposite) speed = speed_int sound_int = pin_a5 -- sound on <= pin_a5 (F1) checksum1 = address ^ speed ^ speed_pre light_int = !pin_a3 -- light on <= NOT pin_a3 (switch opposite) func_int = func_lead light = light_int sound = sound_int func_code = func_int checksum2 = address ^ func_code IF (pin_a1 == 1) THEN -- when address select button pressed IF (sound_int == 1) THEN -- if sound button is also pressed, go into OFF-STATE off_state = 1 ELSE IF measure != 0 THEN address = measure -- ELSE new address <= speed value END IF END IF END IF -- display IF measure > 99 THEN -- if speed is over 100, digit_100 on digit_100_int = 1 ELSE digit_100_int = 0 END IF result = dec_from_byte (measure) result_ms = result >> 4 -- separate medium segment value result_ls = result & 0b1111 -- separate low segment value digit_sel_int = !digit_sel_int -- change segment to show IF digit_sel_int == 0 THEN out_segment = result_ms ELSE out_segment = result_ls END IF sevenval = seven_from_digit ( out_segment ) digit_sel = digit_sel_int PORTB = sevenval -- write out seven value with digit sel timflag_1 = 0 -- reset timer-0 flag END IF END IF END LOOP