; ; picbasic code for leo, a library for controlling leoprogrammable board ; copyright (c) 2006 Leo Villareal ; author: jesse lackey, aug 18 2006, jesse@celestialaudio.com ; ; Version 1.0: august 23 2006 ; ; TODO: ; ; ; To use: ; In the main code, do the following three lines at the top (w/o the semicolons): ; ; NUM_DMX_CHANNELS CON 16 ; goto main ; INCLUDE "leo_picbasic_library.bas" ; ; NUM_DMX_CHANNELS is how many DMX channels we will send out with a "gosub LIB_dmx_out". ; set to 0 to turn off the rs485 driver and save 40mA! ; ; ; picbasic sets the config bits in C:\PBP\18F4620.inc (which uses symbols from ; microchip's MPLAB: C:\Program Files\Microchip\MPASM Suite\P18F4620.INC) ; we want to be able to set our own config bits, but picbasic is rather stupid, ; and we MUST comment out the __CONFIG settings in their header file. ; our config settings: ; 4x PLL, fail-safe clock monitor off, internal/external osc switch off: @ __CONFIG _CONFIG1H, _OSC_HSPLL_1H & _FCMEN_OFF_1H & _IESO_OFF_1H ; power-up timer enabled, brownout enabled in hardware, voltage 2.79V typ @ __CONFIG _CONFIG2L, _PWRT_ON_2L & _BOREN_SBORDIS_2L & _BORV_2_2L ; watchdog off @ __CONFIG _CONFIG2H, _WDT_OFF_2H ; mclr enabled, timer1 osc disable, portB A/D off, CCP2 mux with C1 @ __CONFIG _CONFIG3H, _MCLRE_ON_3H & _LPT1OSC_OFF_3H & _PBADEN_OFF_3H & _CCP2MX_PORTC_3H ; two versions: one for debug yes, other (normally used) is debug off ; stack full reset off, lowvolt prog off, extended instructions off ; debug yes: ;@ __CONFIG _CONFIG4L, _STVREN_OFF_4L & _LVP_OFF_4L & _XINST_OFF_4L & _DEBUG_ON_4L ; debug no: @ __CONFIG _CONFIG4L, _STVREN_OFF_4L & _LVP_OFF_4L & _XINST_OFF_4L & _DEBUG_OFF_4L ; the rest are all code protect related, leave as defaults (no protection) ; tell picbasic the clock speed is 40Mhz: DEFINE OSC 40 ; setup A/D converter for the pots on channel 0 and 1: DEFINE ADC_BITS 10 ; 10-bit DEFINE ADC_CLOCK 3 ; clock source 3 is internal RC DEFINE ADC_SAMPLEUS 50 ; sampling time in usec; see page 43 ; setup hardware uart rx/tx @ 250kbaud, for DMX (see page 79) DEFINE HSER_RCSTA 90h DEFINE HSER_TXSTA 65h ; 65hex: 9-bit, tx enable, BRGH high, 9th bit is 1, to fake ; having 2 stop bits which DMX protocol requires DEFINE HSER_BAUD 250000 ; ; ------- DON'T use these in main program code, for my library use only. ; ; software serial in & out (same pins as external switches) bitbang_serial_out_pin var PORTB.1 bitbang_serial_in_pin var PORTB.0 ; hardware serial hardware_serial_out_pin var PORTC.6 hardware_serial_in_pin var PORTC.7 ; hardware rs485 tx/rx setting pin. if set to 0, then recieve, else xmit. hardware_rs485_direction var PORTC.5 ; the LED. to set it use "gosub LIB_set_led_green" etc. LED_anode var PORTC.4 LED_cathode var PORTC.3 ; bcd. to read it it use "gosub LIB_read_bcd" and use var g_bcd. bcd_a var PORTA.3 bcd_b var PORTA.2 bcd_c var PORTA.4 ; ; ------- use these in main program code: ; ; dipswitch. if ON, it is 1, if OFF 0. i.e. opposite logical... dipswitch_2 var PORTB.5 dipswitch_3 var PORTB.4 dipswitch_4 var PORTB.2 ; pushbuttons. if ON, it is 0, if OFF 1. i.e. opposite logical... ; NOTE! these are also PGC and PGD used to program the chip. So if ; running single-step with a debugger they will be unusable, and if ; pressed will probably screw up the debugging session... pushbutton_1 var PORTB.7 pushbutton_2 var PORTB.6 ; external switches. if ON, it is 0, if OFF 1. i.e. opposite logical... ; NOTE! these are also software serial in & out, so to use them as ; switches requires a change in "LIB_init_leoprogrammable", see ; TRISB. switch_1 var PORTB.0 switch_2 var PORTB.1 ; transistors. set to 1 to turn em on, 0 to turn off. or do ; "gosub LIB_set_transistors" to set them all to whatever is in the ; 16-bit variable g_transistors. transistor1 var PORTD.0 transistor2 var PORTD.1 transistor3 var PORTD.2 transistor4 var PORTD.3 transistor5 var PORTD.4 transistor6 var PORTD.5 transistor7 var PORTD.6 transistor8 var PORTD.7 transistor9 var PORTA.5 transistor10 var PORTE.0 transistor11 var PORTE.1 transistor12 var PORTE.2 transistor13 var PORTC.0 transistor14 var PORTC.1 transistor15 var PORTC.2 transistor16 var PORTB.3 ; ---------------------------- ; global variables to use in all code: ; potentiometers, range is 0 to 1023, do "gosub LIB_read_pots" to read them. g_pot1 var word ; pot 1 (finger-turnable) g_pot2 var word ; pot 2 (screwdriver adjust) ; LED g_led_color var byte ; this is 0 if LED is currently off, 1 for red, 2 for green ; BCD, range 0 to 7, do "gosub LIB_read_bcd" to read it. g_bcd var byte ; Transistors, do "gosub LIB_set_transistors" to set them all to the bits in g_transistors g_transistors var word ; Alternatively - to set a single transistor, set g_single_transistor from 1 to 16 and do ; "gosub LIB_set_single_transistor" g_single_transistor var Byte ; PWM. transistors 14 and 15 have hardware PWM possible; set these vars and do ; "gosub LIB_set_transistorXX_pwm" to turn them on. Range 0 to 255. g_pwm_transistor14 var Byte g_pwm_transistor15 var Byte ; DMX output array, do "gosub LIB_dmx_out" to set NUM_DMX_CHANNELS of channel data out, ; which is stored in g_dmx_data[] array. g_dmx_data var Byte[NUM_DMX_CHANNELS+1] ; +1 so it compiles if NUM_DMX_CHANNELS is 0 ; random number related - do "gosub LIB_get_rand_minmax" g_randHolder var word ; variable used for the random number generator g_randMin var word ; min value for g_randOut (inclusive) g_randMax var word ; max value for g_randOut (inclusive) g_randOut var word ; output of "gosub LIB_get_rand_minmax" ; --------------------- ; handy util routines ; --------------------- ; code below uses these temp vars g_localvar_bool var bit g_localvar_byte var byte g_localvar_word var word ; --- LED STUFF --- ; turn LED off, red, green LIB_set_led_off: g_led_color = 0 LED_anode= 0 LED_cathode= 0 return LIB_set_led_green: g_led_color = 2 LED_anode= 1 LED_cathode= 0 return LIB_set_led_red: g_led_color = 1 LED_anode= 0 LED_cathode= 1 return ; --- POT STUFF --- ; read pots into g_pot1 and g_pot2. LIB_read_pots: ADCIN 0,g_pot1 ADCIN 1,g_pot2 ; pot1 is largest CCW, smallest CW. this is backwards from what you'd ; normally think (and how pot2 works). fix it. g_pot1= 1023 - g_pot1 return ; --- BCD stuff ; read bcd into g_bcd. LIB_read_bcd: g_bcd= 0; if bcd_a = 0 then g_bcd= g_bcd | %1 if bcd_b = 0 then g_bcd= g_bcd | %10 if bcd_c = 0 then g_bcd= g_bcd | %100 return ; --- set single transistor, g_single_transistor is the one (range 1 to 16) LIB_set_single_transistor g_transistors = 0 lookup2 g_single_transistor -1,[1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768],g_transistors gosub LIB_set_transistors return ; --- set transistors to match bits in g_transistors LIB_set_transistors: ; TODO: faster way to do this? seems like there must be transistor1 = g_transistors & %1 if (g_transistors & %10) then transistor2 = 1 else transistor2 = 0 endif if (g_transistors & %100) then transistor3 = 1 else transistor3 = 0 endif if (g_transistors & %1000) then transistor4 = 1 else transistor4 = 0 endif if (g_transistors & %10000) then transistor5 = 1 else transistor5 = 0 endif if (g_transistors & %100000) then transistor6 = 1 else transistor6 = 0 endif if (g_transistors & %1000000) then transistor7 = 1 else transistor7 = 0 endif if (g_transistors & %10000000) then transistor8 = 1 else transistor8 = 0 endif if (g_transistors & %100000000) then transistor9 = 1 else transistor9 = 0 endif if (g_transistors & %1000000000) then transistor10 = 1 else transistor10 = 0 endif if (g_transistors & %10000000000) then transistor11 = 1 else transistor11 = 0 endif if (g_transistors & %100000000000) then transistor12 = 1 else transistor12 = 0 endif if (g_transistors & %1000000000000) then transistor13 = 1 else transistor13 = 0 endif if (g_transistors & %10000000000000) then transistor14 = 1 else transistor14 = 0 endif if (g_transistors & %100000000000000) then transistor15 = 1 else transistor15 = 0 endif if (g_transistors & %1000000000000000) then transistor16 = 1 else transistor16 = 0 endif return ; -- dmx output. send out NUM_DMX_CHANNELS from g_dmx_data[] array. LIB_dmx_out: ; first, need to do the timed pulse. turn of serial hw for this. RCSTA.7= 0 hardware_serial_out_pin = 0 ; low for frame start sync pauseus 100 ; 88us min required hardware_serial_out_pin = 1 ; high for mark after break pauseus 10 ; 8usec min required ; now back to uart for DMX data. RCSTA.7= 1 ; output first byte: a zero to indicate lighting data HSEROUT [0] ; now do the dmx channels g_localvar_word= 0 while g_localvar_word < NUM_DMX_CHANNELS HSEROUT [g_dmx_data[g_localvar_word]] g_localvar_word = g_localvar_word + 1 wend return ; -- PWM stuff. Set the pwm rates. Note! after this is called, the ; transistor is permanently in PWM mode, and setting it directly or calling ; "LIB_set_transistors" will have no effect. LIB_set_transistor14_pwm: HPWM 2,g_pwm_transistor14,2000 return LIB_set_transistor15_pwm: HPWM 1,g_pwm_transistor15,2000 return ; -- put random number into g_randOut, between g_randMin and g_randMax, inclusive LIB_get_rand_minmax: g_localvar_word= g_randMax - g_randMin ; calc range RANDOM g_randHolder ; get next rand number ; produce a random # within min/max range (inclusive) g_randOut= g_randMin + (g_randHolder // (g_localvar_word + 1)) return ; ************************************************************************ ; ************************************************************************ ; ************************************************************************ ; *** the most important function, always call this first in main code *** ; init everything ; LIB_init_leoprogrammable: ; *** first, configure all pins for input or output, and internal pullups on portB. TRISA = %00011111 ; A0 & A1 analog ins, bcd digital in ; for enternal switch input: ;TRISB = %11110111 ; for usb serial i/o: TRISB = %11110101 TRISC = %10000000 TRISD = 0 TRISE = 0 INTCON2.7 = 0 ; portB pullups on ADCON1= %00001101 ; a/d, channel 0 and 1 are analog ins ADCON2.7 = 1 ; right-justify, we are doing 10-bit a/d reads if NUM_DMX_CHANNELS = 0 then hardware_rs485_direction = 0 ; rs485 is receiving, much lower power (like 40mA less) else hardware_rs485_direction = 1 ; rs485 is transmitting ; clear dmx data g_localvar_word= 0 while g_localvar_word < NUM_DMX_CHANNELS g_dmx_data[g_localvar_word] = 0 g_localvar_word = g_localvar_word + 1 wend endif g_transistors = 0 g_pwm_transistor14 = 0 g_pwm_transistor15 = 0 ; seed random number generator, using sum of all of RAM g_localvar_word = 0 while g_localvar_word < 3986 ; 3986 bytes of ram for 18F4620 PEEK g_localvar_word,g_localvar_byte ; read from ram g_randHolder = g_randHolder + g_localvar_byte g_localvar_word = g_localvar_word + 1 wend ; read stuff now to make global vars nice n fresh gosub LIB_set_transistors gosub LIB_set_led_off gosub LIB_read_pots gosub LIB_read_bcd return