' **************************************************************** ' * File: gmbtmpe.bas - Ver. 1.1 * ' * Compiler: PIC Basic PRO * ' * IDE: MicroCode Studio Plus * ' * Compiler Version: 2.45 * ' * Boards: GMM 4620 + GMB HR168 * ' * GRIFO(R) via Dell'Artigiano 8/6 * ' * 40016 S. Giorgio di Piano (BO) * ' * Tel. +39 051 892052 Fax. +39 051 893661 * ' * http://www.grifo.com http://www.grifo.it * ' * by Graziano Gaiba 04.02.05 * ' **************************************************************** ' ' GMM 4620 provided with Real Time Clock. ' This demo allows to manage three timers that act on relays ' outputs of CN3 and CN4. ' In detail, it is possible to input from console the action to ' perform and the time of activation for each of the three timers; ' two timers allow to input a combination for output relays, the ' third timer opens all the output relays. ' NOTE: Last location of RTC SRAM (hexadeciamal FF) is reserved. ' ' Rel 1.1 - by Graziano Gaiba ' Demo program of timed activities with GMB HR168 driven by ' Mini Module GMM 4620 ' ' ' ******************** Compiler definitions ********************** ' DEFINE OSC 10 ' Oscillator frequency 9,8304 MHz DEFINE HSER_RCSTA 90h ' Enable EUSART serial receiver DEFINE HSER_TXSTA 20h ' Enable EUSART serial transmitter DEFINE HSER_BAUD 19200 ' Baud Rate ' ' ******************* Constants declaration ********************** ' RTCSLA con $A0 I2C_BUFFER_SIZE con 10 ' ' ******************** Variables declaration ********************* ' ' Generic variables i var byte scelta var byte di var byte do var byte ' ' ' Used to manage timed activities act1_enable var bit act2_enable var bit act3_enable var bit act1_time var byte act2_time var byte act3_time var byte act1_val var byte act2_val var byte ' ' Used by I/O management procedures port_val var byte ' Value read or to be written to the I/O ' ' Used by I2C BUS hardware management i2c_buffer var byte[I2C_BUFFER_SIZE] i2c_to_send var byte i2c_to_receive var byte i2c_val var byte i2c_data var byte i2c_slave var byte i2c_addr var byte i2c_cnt var byte ' ' Used by RTC management bin_bcd var byte ' Used by binary/BCD conversions rtc_year var byte rtc_month var byte rtc_weekday var byte rtc_day var byte rtc_hour var byte rtc_minute var byte rtc_second var byte ' ' '************************** Main Program ******************************* ' main: gosub Init_cpu ' Turn OFF relays port_val = 0 gosub set_relays ' Initialize hardware I2C BUS peripheral gosub i2cbusinit for_ever: gosub clrscr ' Clear timed activity enables act1_enable = 0 act2_enable = 0 act3_enable = 0 hserout ["Timed activities demo Rel 1.1 for GMM 4620 rel 120304 and GMB HR168 rel 110104", 13, 10, 13, 10] hserout ["The user can enable three timed activities: first two can set the relays", 13, 10] hserout ["status at specified value, third can reset the relays status.", 13, 10] hserout ["It is possible to specify the second when the three activities must trigger", 13, 10] hserout ["and the relays status for the first two ones.", 13, 10] hserout ["RTC will be set to 12:00:00", 13, 10, 13, 10] ' hserout ["Enable timed activity 1 (y/n)? "] hserin [i] hserout [i, 13, 10] if i == "y" or i == "Y" then act1_enable = 1 hserout ["Second of activation (type two digits)? "] hserin [dec2 act1_time] hserout [dec2 act1_time, 13, 10] hserout ["Relay status to set (in UPPERCASE hexadecimal)? "] hserin [hex2 act1_val] hserout [hex2 act1_val, 13, 10] endif ' hserout ["Enable timed activity 2 (y/n)? " ] hserin [i] hserout [i, 13, 10] if i == "y" or i == "Y" then act2_enable = 1 hserout ["Second of activation (type two digits)? "] hserin [dec2 act2_time] hserout [dec2 act2_time, 13, 10] hserout ["Relay status to set (in UPPERCASE hexadecimal)? "] hserin [hex2 act2_val] hserout [hex2 act2_val, 13, 10] endif ' hserout ["Enable timed activity 3 (y/n)? " ] hserin [i] hserout [i, 13, 10] if i == "y" or i == "Y" then act3_enable = 1 hserout ["Second of activation (type two digits)? "] hserin [dec2 act3_time] hserout [dec2 act3_time, 13, 10] endif ' Set RTC to 12:00:00 rtc_weekday = 0 rtc_day = 1 rtc_month = 1 rtc_year = 1 rtc_hour = 12 rtc_minute = 0 rtc_second = 0 gosub set_rtc timed_activity_loop: gosub get_rtc ' if act1_enable then ' If second is equal to activity trigger second if rtc_second == act1_time then port_val = act1_val gosub set_relays endif endif ' if act2_enable then ' If second is equal to activity trigger second if rtc_second == act2_time then port_val = act2_val gosub set_relays endif endif ' if act3_enable then ' If second is equal to activity trigger second if rtc_second == act3_time then port_val = 0 gosub set_relays endif endif ' hserout [dec2 rtc_hour, ":", dec2 rtc_minute, ".", dec2 rtc_second, 13] pause 100 goto timed_activity_loop goto for_ever end ' ' **************** Procedures definition ****************** ' ' ' CPU and signals directions initialization Init_cpu: ADCON1=$0f ' Imposta come I/O digitale i pin AN0..12 CMCON=$07 ' Imposta come I/O digitale RA0..4 ' Optocoupled Inputs of CN1 are: ' IN1-1 <-> RA0 ' IN2-1 <-> RA1 ' IN3-1 <-> RB0 ' IN4-1 <-> RB1 ' IN5-1 <-> RA4 ' IN6-1 <-> RC0 ' IN7-1 <-> RC1 ' IN8-1 <-> RC5 trisa.0 = 1 trisa.1 = 1 trisa.4 = 1 trisb.0 = 1 trisb.1 = 1 trisc.0 = 1 trisc.1 = 1 trisc.5 = 1 ' Optocoupled Inputs of CN2 are: ' IN1-2 <-> RD0 ' IN2-2 <-> RD1 ' IN3-2 <-> RD2 ' IN4-2 <-> RD3 ' IN5-2 <-> RD4 ' IN6-2 <-> RD5 ' IN7-2 <-> RD6 ' IN8-2 <-> RD7 trisd = $ff ' Relay outputs of CN3 are: ' OUT A1 <-> RB4 ' OUT A2 <-> RB5 ' OUT B1 <-> RB6 ' OUT B2 <-> RB7 ' OUT C1 <-> RB3 ' OUT C2 <-> RB2 trisb = trisb & $03 ' Relay outputs of CN4 are: ' OUT D1 <-> RA3 ' OUT D2 <-> RC2 (J10 in position 3-4) trisa.3 = 0 trisc.2 = 0 return ' ' ' Clear screen, sending 25 times CR + LF. clrscr: for i= 0 to 24 hserout [13, 10] next i return ' ' ' Asks for a key press wait_key: hserout ["Press a key..."] wait_key_loop: hserin 1, wait_key_loop, [i] return ' ' ' Procedure to set the status of the relays on connectors CN3 and CN4. ' According to the bits of port_val, each relay is turned ON ' (contact closed) or OFF (contact open). ' Bits of port_val have this meanging: ' -- CN3 ' port_val.0 drives relay OUT A1 ' port_val.1 drives relay OUT A2 ' port_val.2 drives relay OUT B1 ' port_val.3 drives relay OUT B2 ' port_val.4 drives relay OUT C1 ' port_val.5 drives relay OUT C2 ' -- CN4 ' port_val.6 drives relay OUT D1 ' port_val.7 drives relay OUT D2 ' ' Each bit has the following meaning: ' bit Meaning ' 0 Relay turned OFF (contact open) ' 1 Relay turned ON (contact closed) set_relays: ' Relays are driven in complemented logic, so port_val must be ' complemented too port_val = port_val ^ $ff portb.4 = port_val.0 portb.5 = port_val.1 portb.6 = port_val.2 portb.7 = port_val.3 portb.3 = port_val.4 portb.2 = port_val.5 porta.3 = port_val.6 portc.2 = port_val.7 return ' ' ' Convert a number from decimal to BCD. ' Value to be converted must be in variable bin_to_bcd. ' Result of conversion is put in variable bin_to_bcd. bin_to_bcd: bin_bcd = ((bin_bcd / 10) << 4) | (bin_bcd // 10) return ' ' ' Converts a number from BCD to decimal. ' Value to be converted must be in variable bin_to_bcd. ' Result of conversion is put in variable bin_to_bcd. bcd_to_bin: bin_bcd = ((bin_bcd >> 4 ) * 10) + (bin_bcd & $0F) return ' ' ' Set date and time on RTC I2C BUS PCF8583 ' Last location of RTC SRAM (hexadeciamal FF) is reserved. set_rtc: i2c_slave = RTCSLA ' i2c_addr = $0 i2c_val = $84 gosub i2cbuswritebyte ' risi2c=wr_i2c(RTCSLA,0x00,0x84); // Stop RTC i2c_addr = $1 i2c_val = $0 gosub i2cbuswritebyte ' risi2c=wr_i2c(RTCSLA,0x01,0x00); // Set hundreds of seconds bin_bcd = rtc_second gosub bin_to_bcd i2c_val = bin_bcd i2c_addr = $2 gosub i2cbuswritebyte ' risi2c=wr_i2c(RTCSLA,0x02,bintobcd(sec)); // Set seconds bin_bcd = rtc_minute gosub bin_to_bcd i2c_val = bin_bcd i2c_addr = $3 gosub i2cbuswritebyte ' risi2c=wr_i2c(RTCSLA,0x03,bintobcd(min)); // Set minutes bin_bcd = rtc_hour gosub bin_to_bcd i2c_val = bin_bcd i2c_addr = $4 gosub i2cbuswritebyte ' risi2c=wr_i2c(RTCSLA,0x04,bintobcd(ore)); // Set hours, format 24h bin_bcd = rtc_day gosub bin_to_bcd i2c_val = bin_bcd i2c_addr = $5 gosub i2cbuswritebyte ' risi2c=wr_i2c(RTCSLA,0x05,bintobcd(gio)); // Set day and year=0 bin_bcd = rtc_month gosub bin_to_bcd i2c_val = bin_bcd | (rtc_weekday << 5) i2c_addr = $6 gosub i2cbuswritebyte ' risi2c=wr_i2c(RTCSLA,0x06,(bintobcd(mes)|(set<<5))); // Set month,week i2c_val = $0 i2c_addr = $7 gosub i2cbuswritebyte ' risi2c=wr_i2c(RTCSLA,0x07,0x00); // Set timer i2c_val = $0 i2c_addr = $0 gosub i2cbuswritebyte ' risi2c=wr_i2c(RTCSLA,0x00,0x00); // Start RTC i2c_val = rtc_year i2c_addr = $ff gosub i2cbuswritebyte ' risi2c=wr_i2c(RTCSLA,0xFF,ann); // Save year offset in last SRAM byte 'return ' ' Get date and time from RTC I2C BUS PCF8583 ' Last location of RTC SRAM (hexadeciamal FF) is reserved. get_rtc: i2c_slave = RTCSLA ' i2c_addr = $2 gosub i2cbusreadbyte bin_bcd = i2c_val gosub bcd_to_bin rtc_second = bin_bcd ' risi2c=rd_i2c(RTCSLA,0x02,&dr); // Get seconds ' *sec=bcdtobin(dr); i2c_addr = $3 gosub i2cbusreadbyte bin_bcd = i2c_val gosub bcd_to_bin rtc_minute = bin_bcd ' risi2c=rd_i2c(RTCSLA,0x03,&dr); // Get minutes ' *min=bcdtobin(dr); i2c_addr = $4 gosub i2cbusreadbyte bin_bcd = i2c_val gosub bcd_to_bin rtc_hour = bin_bcd ' risi2c=rd_i2c(RTCSLA,0x04,&dr); // Get hours ' *ore=bcdtobin(dr); i2c_addr = $5 gosub i2cbusreadbyte bin_bcd = i2c_val & $3f gosub bcd_to_bin rtc_day = bin_bcd rtc_year = (i2c_val & $c0) >> 6 ' risi2c=rd_i2c(RTCSLA,0x05,&dr); // Get day and year offset ' *gio=bcdtobin(dr&0x3F); ' *ann=(dr&0xC0)>>6; i2c_addr = $6 gosub i2cbusreadbyte bin_bcd = i2c_val & $1f gosub bcd_to_bin rtc_weekday = (i2c_val & $e0) >> 5 rtc_month = bin_bcd ' risi2c=rd_i2c(RTCSLA,0x06,&dr); // Get weekday and month ' *set=(dr&0xE0)>>5; ' *mes=bcdtobin(dr&0x1F); i2c_addr = $ff gosub i2cbusreadbyte rtc_year = (i2c_val + rtc_year) // 100 ' risi2c=rd_i2c(RTCSLA,0xFF,&dr); // Get year offset from last SRAM byte ' dr=dr+*ann; // Calculate year with offset ' dr=dr%100; // Force year with offset to two digits ' *ann=dr; // Return year with offset of two digits return ' ' ' Initialize I2C BUS hardware I2CBUSInit: ' ' Initialize I2C BUS ' Configure RC3 and RC4 as inputs trisc.3 = 1 trisc.4 = 1 ' Enable SSP module in master I2C BUS mode, clock 50 kHz sspstat.6 = 0 sspadd = $32 sspcon1 = $28 return ' ' ' Generate I2C BUS start I2CBUSStart: sspcon2.0 = 1 I2CBUSStartLoop: if sspcon2.0 = 1 then I2CBUSStartLoop pir1.3 = 0 return ' ' ' Generate I2C BUS repeated start I2CBUSRepStart: sspcon2.1 = 1 I2CBUSRepStartLoop: if sspcon2.1 = 1 then I2CBUSRepStartLoop pir1.3 = 0 return ' ' ' Generate I2C BUS stop I2CBUSStop: sspcon2.2 = 1 I2CBUSStopLoop: if sspcon2.2 = 1 then I2CBUSStopLoop pir1.3 = 0 return ' ' ' Send content of variable i2c_data to I2C BUS I2CBUSSend: sspbuf = i2c_data I2CBUSSendSynch: ' Wait for last operation of hardware I2C interface to complete if pir1.3 = 0 then I2CBUSSendSynch pir1.3 = 0 return ' ' ' Read a data from I2C BUS and returns it in variable i2c_data I2CBUSGet: sspcon2.3 = 1 I2CBusGetLoop: if sspcon2.3 = 1 then I2CBusGetLoop i2c_data = sspbuf I2CBUSGetSynch: ' Wait for last operation of hardware I2C interface to complete if pir1.3 = 0 then I2CBUSGetSynch pir1.3 = 0 return ' ' ' Send NOT acknowledge I2CBUSNACK: ' Send NOT acknowledge... sspcon2.5 = 1 sspcon2.4 = 1 ' Wait for last operation of hardware I2C interface to complete I2CBUSNACKSynch: if pir1.3 = 0 then I2CBUSNACKSynch pir1.3 = 0 return ' ' ' Send acknowledge I2CBUSACK: ' Send acknowledge... sspcon2.5 = 0 sspcon2.4 = 1 ' Wait for last operation of hardware I2C interface to complete I2CBUSACKSynch: if pir1.3 = 0 then I2CBUSNACKSynch pir1.3 = 0 return ' ' ' Indicates that an expected acknowledge has not been received. I2CBUSNotAck: hserout ["Acknowledge not received.", 13, 10] ' Disables I2CBUS sspcon1.5 = 0 return ' ' ' Read one byte from device whose slave address is indicated in variable ' i2c_slave and whose address is specified in variable i2c_addr. ' Data read is in variable i2c_val. I2CBUSReadByte: ' ' Generates I2CBUS Start. gosub i2cbusstart ' Send Slave Address i2c_data = i2c_slave gosub i2cbussend ' If acknowledge not received, signal an error if sspcon2.6 = 1 then I2CBUSNotAck ' Send address i2c_data = i2c_addr gosub i2cbussend ' If acknowledge not received, signal an error if sspcon2.6 = 1 then I2CBUSNotAck ' Generates repeated I2CBUS Start. gosub i2cbusrepstart ' Send Slave Address for reading i2c_data = i2c_slave | $01 gosub i2cbussend ' If acknowledge not received, signal an error if sspcon2.6 = 1 then I2CBUSNotAck ' Get data gosub i2cbusget i2c_val = i2c_data ' Send NOT acknowledge. gosub I2CBUSNACK ' Generate stop gosub i2cbusstop return ' ' ' Write one byte to device whose slave address is indicated in variable ' i2c_slave and whose address is specified in variable i2c_addr. ' Data to write must be in variable i2c_data. I2CBUSWriteByte: ' ' Generates I2CBUS Start. gosub i2cbusstart ' Send Slave Address for writing i2c_data = i2c_slave gosub i2cbussend ' If acknowledge not received, signal an error if sspcon2.6 = 1 then I2CBUSNotAck ' Send address i2c_data = i2c_addr gosub i2cbussend ' If acknowledge not received, signal an error if sspcon2.6 = 1 then I2CBUSNotAck ' Send data i2c_data = i2c_val gosub i2cbussend ' If acknowledge not received, signal an error if sspcon2.6 = 1 then I2CBUSNotAck ' Generates stop gosub i2cbusstop return ' ' ' Send a sequence of bytes to I2C BUS device. ' Slave address must be in variable i2c_slave. ' Data to send must be in array i2c_buffer. User may change its size by ' changing value of I2C_BUFFER_SIZE. ' Number of bytes to send must be in variable i2c_to_send. User must check ' for overflows. I2CBUSWrite: ' ' Generates I2CBUS Start. gosub i2cbusstart ' Send Slave Address for writing i2c_data = i2c_slave gosub i2cbussend ' If acknowledge not received, signal an error if sspcon2.6 = 1 then I2CBUSNotAck for i2c_cnt = 0 to i2c_to_send - 1 ' Send data i2c_data = i2c_buffer[i2c_cnt] gosub i2cbussend ' If acknowledge not received, signal an error if sspcon2.6 = 1 then I2CBUSNotAck next i2c_cnt ' Generate stop gosub i2cbusstop return ' ' ' Send a sequence of bytes then read a sequence of byte from I2C BUS device. ' Slave address must be in variable i2c_slave. ' Data to send must be in array i2c_buffer. User may change its size by ' changing value of I2C_BUFFER_SIZE. ' Data will be received in the abovce mentioned array. ' Number of bytes to send must be in variable i2c_to_send. User must check ' for overflows. ' Number of bytes to receive must be in variable i2c_to_receive. User must ' check for overflows. I2CBUSRead: ' ' Generates I2CBUS Start. gosub i2cbusstart ' Send Slave Address for writing i2c_data = i2c_slave gosub i2cbussend ' If acknowledge not received, signal an error if sspcon2.6 = 1 then I2CBUSNotAck for i2c_cnt = 0 to i2c_to_send - 1 ' Send data i2c_data = i2c_buffer[i2c_cnt] gosub i2cbussend ' If acknowledge not received, signal an error if sspcon2.6 = 1 then I2CBUSNotAck next i2c_cnt ' Generate repeated I2CBUS Start. gosub i2cbusrepstart ' Send Slave Address for reading i2c_data = i2c_slave | $01 gosub i2cbussend ' If acknowledge not received, signal an error if sspcon2.6 = 1 then I2CBUSNotAck for i2c_cnt = 0 to i2c_to_receive - 1 ' Read data gosub i2cbusget i2c_buffer[i2c_cnt] = i2c_data if i2c_cnt == i2c_to_receive - 1 then ' Send NOT acknowledge. gosub I2CBUSNACK else ' Send acknowledge. gosub I2CBUSaCK endif next i2c_cnt ' Invia lo stop gosub i2cbusstop return