' **************************************************************** ' * File: uk_gmb_rtc.pbas - Ver. 1.1 * ' * Compiler: mikroBasic for PIC by mikroElektronica * ' * IDE: mikroBasic for PIC by mikroElektronica * ' * Compiler Version: 1.1.5.0 * ' * 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 16.02.05 * ' **************************************************************** ' ' GMM 4620 is provided with on board Real Time Clock, RTC, backed ' through the on board Lithium battery, disconnectable. ' Such component can be used to schedule sequences of operations ' or to create a timestamp for certain events. ' Interface between RTC and microcontroller is I2C BUS. ' functionality, both to get and to set time, through a set of ' widely commented functions. ' Such functions are charged to communicate to the component and ' to show time and date. ' ' Rel 1.1 - by Graziano Gaiba ' Demo program of buffered I/O peripherals of GMB HR168 driven by ' Mini Module GMM 4620 ' ' ' ******************** Compiler definitions ********************** ' program uk_gmb_rtc ' ' ******************* Constants declaration ********************** ' const RTCSLA = $A0 const ASC_y = $79 const ASC_yU = $59 ' ' ******************** Variables declaration ********************* ' ' Generic variables dim i as byte dim s as string[2] ' ' Used by RTC management dim rtc_year as byte dim rtc_month as byte dim rtc_weekday as byte dim rtc_day as byte dim rtc_hour as byte dim rtc_minute as byte dim rtc_second as byte ' ' ' **************** Procedures definition ****************** ' ' ' CPU and signals directions initialization sub procedure Init_cpu ' Initialize portc for hardware I2C BUS peripheral trisc.3 = 0 trisc.4 = 0 portc.3 = 1 portc.4 = 1 ' 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 and $03 ' Relay outputs of CN4 are: ' OUT D1 <-> RA3 ' OUT D2 <-> RC2 (J10 in position 3-4) trisa.3=0 trisc.2=0 ' Initialize module USART (8 bit, 19200 baud rate, ' no parity) Usart_init(19200) end sub ' ' ' Send a string of characters to the serial port sub procedure print_USART(dim byref txt as char[255]) dim i as byte dim l as byte l = txt[0] for i = 1 to l USART_Write(txt[i]) next i end sub ' ' ' Send CR + LF sub procedure print_CRLF USART_Write(10) USART_Write(13) end sub ' ' ' Clear screen, sending 25 times CR + LF. sub procedure clrscr for i = 0 to 24 print_CRLF next i end sub ' ' ' Asks for a key press sub procedure wait_key dim c as byte print_usart("Press a key...") do nop loop until USART_Data_Ready = 1 c = USART_Read end sub ' ' ' 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) sub procedure set_relays(dim port_val as byte) ' Relays are driven in complemented logic, so port_val must be ' complemented too port_val=port_val xor $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 end sub ' ' ' Indicates that an expected acknowledge has not been received. sub procedure I2CBUSNotAck print_USART("Acknowledge not received.") print_crlf ' Disables I2CBUS sspcon1.5=0 end sub ' ' ' 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 returned. sub function I2CBUSReadByte(dim i2c_slave as byte, dim i2c_addr as byte) as byte dim b as byte sspcon1.5 = 0 sspcon1.5 = 1 ' ' Generates I2CBUS Start. I2C_start ' Send Slave Address if I2C_wr(i2c_slave) <> 0 then ' If acknowledge not received, signal an error I2CBUSNotAck end if ' Send address if I2C_wr(i2c_addr) <> 0 then ' If acknowledge not received, signal an error I2CBUSNotAck end if ' Generates repeated I2CBUS Start. I2C_Repeated_Start ' Send Slave Address for reading if I2C_wr(i2c_slave or $01) <> 0 then ' If acknowledge not received, signal an error I2CBUSNotAck end if ' Get data and Send NOT acknowledge b = I2C_Rd(0) ' Generate stop I2C_Stop Result = b end sub ' ' ' 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. sub procedure I2CBUSWriteByte(dim i2c_slave as byte, dim i2c_addr as byte, dim i2c_data as byte) sspcon1.5 = 0 sspcon1.5 = 1 ' ' Generates I2CBUS Start. I2C_start ' Send Slave Address for writing if I2C_wr(i2c_slave) <> 0 then ' If acknowledge not received, signal an error I2CBUSNotAck end if ' Send address if I2C_wr(i2c_addr) <> 0 then ' If acknowledge not received, signal an error I2CBUSNotAck end if ' Send data if I2C_wr(i2c_data) <> 0 then ' If acknowledge not received, signal an error I2CBUSNotAck end if ' Generates stop I2C_Stop end sub ' ' ' Inputs a positive decimal vale of up to five digits. ' Input parameter is number of digits, it returns a word ' containing the value input by te user. ' It can manage backspace (ASCII 08) and accepts digits from ' '0' to '9'. ' It sends a bell character (ASCII 07) when receives a character ' not acceptable for input, or user tries to input or delete out ' of possible range. sub function inputDEC(dim n_char as byte) as word dim str_input as byte[6] dim idx as byte dim chr_input as byte dim pow_of_10 as word[5] dim value as word pow_of_10[1] = 1 pow_of_10[2] = 10 pow_of_10[3] = 100 pow_of_10[4] = 1000 ' Index must start from 1 idx = 1 Inc(n_char) ' No character in input chr_input = 0 ' Starting value value = 0 ' Loop until CR is received while chr_input <> 13 ' If a data is ready if usart_data_ready = 1 then ' Read it chr_input = USART_Read ' If backspace (ASCII BS) if chr_input = 8 then ' and buffer is not empty if idx > 1 then ' Send data read USART_Write(chr_input) ' Delete character USART_Write(32) USART_Write(chr_input) ' delete last input data Dec(idx) else ' Bell to indicate an error USART_Write(7) end if end if ' If CR received, elaborate the value and return it if chr_input = 13 then n_char = 0 while idx > 1 Dec(idx) Inc(n_char) value = value + (str_input[n_char] - 48) * pow_of_10[idx] wend else ' If character can be input if idx < n_char then ' If data received is in valid range: ' 0..9 if (chr_input >= 48) or(chr_input <= 57) then ' Send data read USART_Write(chr_input) ' Store it in input buffer str_input[idx] = chr_input ' Point to next position Inc(idx) end if else ' Bell to indicate an error USART_Write(7) end if end if end if wend print_CRLF Result = value end sub ' ' ' Sets date and time on RTC I2C BUS PCF8583 sub procedure set_rtc(dim rtc_weekday as byte, dim rtc_day as byte, dim rtc_month as byte, dim rtc_year as byte, dim rtc_hour as byte, dim rtc_minute as byte, dim rtc_second as byte) dim dummy as byte ' Stop RTC I2CBUSWriteByte(RTCSLA,$0,$84) ' Set hundres of seconds i2cbuswritebyte(RTCSLA,$1,$0) ' Set seconds dummy = Dec2Bcd(rtc_second) i2cbuswritebyte(RTCSLA,$2,dummy) ' Set minutes dummy = Dec2Bcd(rtc_minute) i2cbuswritebyte(RTCSLA,$3,dummy) ' Set hours dummy = Dec2Bcd(rtc_hour) i2cbuswritebyte(RTCSLA,$4,dummy) ' Set day and set year = 0 dummy = Dec2Bcd(rtc_day) i2cbuswritebyte(RTCSLA,$5,dummy) ' Set month and weekday dummy = Dec2Bcd(rtc_month) dummy = dummy or (rtc_weekday << 5) i2cbuswritebyte(RTCSLA,$6,dummy) ' Set timer mode i2cbuswritebyte(RTCSLA,$7,0) ' Start RTC i2cbuswritebyte(RTCSLA,$0,0) ' Save year offset i2cbuswritebyte(RTCSLA,$ff,rtc_year) end sub ' ' ' Gets date and time from RTC I2C BUS PCF8583 sub procedure get_rtc(dim byref rtc_weekday as byte, dim byref rtc_day as byte, dim byref rtc_month as byte, dim byref rtc_year as byte, dim byref rtc_hour as byte, dim byref rtc_minute as byte, dim byref rtc_second as byte) dim dummy as byte ' Read and calculate seconds rtc_second = Bcd2Dec(i2cbusreadbyte(RTCSLA, $2)) ' Read and calculate minutes rtc_minute = Bcd2Dec(i2cbusreadbyte(RTCSLA, $3)) ' Read and calculate hours rtc_hour = Bcd2Dec(i2cbusreadbyte(RTCSLA, $4)) ' Read and calculate day and year dummy = i2cbusreadbyte(RTCSLA, $5) rtc_year = (dummy and $c0) >> 6 dummy = dummy and $3f rtc_day = Bcd2Dec(dummy) ' Read and calculate weekday and month dummy = i2cbusreadbyte(RTCSLA, $6) rtc_weekday = (dummy and $e0) >> 5 dummy = dummy and $1f rtc_month = Bcd2Dec(dummy) ' Calculate year in the range 00..99 ' Year offset is in location $FF of PCF internal SRAM. ' This location is reserved. dummy = i2cbusreadbyte(RTCSLA, $ff) rtc_year = (dummy + rtc_year) mod 100 end sub ' '************************** Main Program ******************************* ' main: ' Init_cpu ' Turn OFF relays set_relays(0) ' Initialize hardware I2C BUS peripheral I2C_init(100000) for_ever: clrscr print_USART("I2C BUS RTC demo Rel 1.1 for GMM 4620 rel 120304 and GMB HR168 rel 110104") print_CRLF print_CRLF print_USART("Time and date stored in I2C BUS RTC module is continuously visualized") print_CRLF print_USART("Do you want to set RTC (y/n)? ") do nop loop until USART_Data_Ready = 1 i = USART_Read USART_Write(i) if (i = ASC_y) or (i = ASC_Y) then print_CRLF print_CRLF print_USART("Week day (0 is Sunday, 1 is Monday, .. , 6 is Saturday): ") rtc_weekday = inputDEC(1) print_USART("Day: ") rtc_day = inputDEC(2) print_USART("Month: ") rtc_month = inputDEC(2) print_USART("Year: 20") rtc_year = inputDEC(2) print_USART("Hour: ") rtc_hour = inputDEC(2) print_USART("Minute: ") rtc_minute = inputDEC(2) print_USART("Second: ") rtc_second = inputDEC(2) print_CRLF set_rtc(rtc_weekday,rtc_day,rtc_month,rtc_year,rtc_hour, rtc_minute,rtc_second) end if print_CRLF vis_rtc_loop: get_rtc(rtc_weekday,rtc_day,rtc_month,rtc_year,rtc_hour, rtc_minute,rtc_second) select case rtc_weekday case 0 print_USART("Sunday ") case 1 print_USART("Monday ") case 2 print_USART("Tuesday ") case 3 print_USART("Wednesday ") case 4 print_USART("Thursday ") case 5 print_USART("Friday ") case 6 print_USART("Saturday ") end select ' Print day ByteToStr(rtc_day,s) if length(s) = 1 then print_USART("0") end if print_USART(s) print_USART(".") ' Print month ByteToStr(rtc_month,s) if length(s) = 1 then print_USART("0") end if print_USART(s) print_USART(".20") ' Print year ByteToStr(rtc_year,s) if length(s) = 1 then print_USART("0") end if print_USART(s) print_USART(" ") ' Print hour ByteToStr(rtc_hour,s) if length(s) = 1 then print_USART("0") end if print_USART(s) print_USART(":") ' Print minute ByteToStr(rtc_minute,s) if length(s) = 1 then print_USART("0") end if print_USART(s) print_USART(".") ' Print second ByteToStr(rtc_second,s) if length(s) = 1 then print_USART("0") end if print_USART(s) USART_Write(13) goto vis_rtc_loop goto for_ever end.