' **************************************************************** ' * File: uk_k51term.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 + K51-AVR * ' * 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 23.02.05 * ' **************************************************************** ' ' This demo allows to drive an I2C BUS peripheral on board of K51-AVR, ' DS1621, through mini-BLOCK module GMB HR168 and grifo(r) mini module. ' DS1621 is a programmable digital thermometer, whose resolution is ' half Celsius degree, all the operations of programming and temperature ' acquisition are performed through synchronous serial interface I2C BUS. ' This demo shows the temperature acquired on the 7 segments display of ' K51-AVR. ' ' ' Rel 1.1 - by Graziano Gaiba ' Demo program to use DS1621 on board of K51-AVR using a GMB HR168 ' driven by Mini Module GMM 4620 ' ' ' ******************** Compiler definitions ********************** ' program uk_k51term ' ' ******************* Constants declaration ********************** ' const Saa1064 = $38 ' Slave address SAA1064 const Wsaa1064 = $70 ' Slave address SAA1064 in Write const Rsaa1064 = $71 ' Slave address SAA1064 in Read '****************** Addresses list for Saa1064 ************************* const Ctb = 0 ' Address Control byte const Dig1 = 1 ' Address Digit 1 const Dig2 = 2 ' Address Digit 2 const Dig3 = 3 ' Address Digit 3 const Dig4 = 4 ' Address Digit 4 ' ' ********************************************************************** ' const Ds1621 = $4C ' Slave address DS1621 const Wds1621 = $98 ' Slave address DS1621 in Write const Rds1621 = $99 ' Slave address DS1621 in Read ' ***************** Commands list of DS1621 **************************** const Cfg = $AC ' R/W Config register of DS1621 const Rtemp = $AA ' read temperature 2 bytes const Strct = $EE ' Start temperature conversion const Stpct = $22 ' Stop temperature conversion ' ' ' ******************** Variables declaration ********************* ' ' Generic variables dim Tmp as byte ' ' Figures of temperature to show dim Units as byte dim Hundreds as byte dim Tenth as byte ' ' Used by I2C BUS hardware management dim i2c_buffer as byte[10] ' ' Conversion read by DS1621 dim Temp_h as byte dim Temp_l as byte ' ' ' **************** Procedures definition ****************** ' ' ' CPU and signals directions initialization sub procedure 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 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 dim i as byte 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 ' ' ' Initialize I2C BUS hardware sub procedure 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 end sub ' ' ' Generate I2C BUS start sub procedure I2CBUSStart sspcon2.0=1 while sspcon2.0=1 wend pir1.3=0 end sub ' ' ' Generate I2C BUS repeated start sub procedure I2CBUSRepStart sspcon2.1=1 while sspcon2.1=1 wend pir1.3=0 end sub ' ' ' Generate I2C BUS stop sub procedure I2CBUSStop sspcon2.2=1 while sspcon2.2=1 wend pir1.3=0 end sub ' ' ' Send content of variable i2c_data to I2C BUS sub procedure I2CBUSSend(dim i2c_data as byte) sspbuf=i2c_data ' Wait for last operation of hardware I2C interface to complete while pir1.3=0 wend pir1.3=0 end sub ' ' ' Read a data from I2C BUS and end subs it sub function I2CBUSGet as byte sspcon2.3=1 while sspcon2.3=1 wend result=sspbuf ' Wait for last operation of hardware I2C interface to complete while pir1.3=0 wend pir1.3=0 end sub ' ' ' Send NOT acknowledge sub procedure I2CBUSNACK ' Send NOT acknowledge... sspcon2.5=1 sspcon2.4=1 ' Wait for last operation of hardware I2C interface to complete while pir1.3=0 wend pir1.3=0 end sub ' ' ' Send acknowledge sub procedure I2CBUSACK ' Send acknowledge... sspcon2.5=0 sspcon2.4=1 ' Wait for last operation of hardware I2C interface to complete while pir1.3=0 wend pir1.3=0 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 ' ' Generates I2CBUS Start. i2cbusstart ' Send Slave Address i2cbussend(i2c_slave) ' If acknowledge not received, signal an error if sspcon2.6=1 then I2CBUSNotAck end if ' Send address i2cbussend(i2c_addr) ' If acknowledge not received, signal an error if sspcon2.6=1 then I2CBUSNotAck end if ' Generates repeated I2CBUS Start. i2cbusrepstart ' Send Slave Address for reading i2cbussend(i2c_slave or $01) ' If acknowledge not received, signal an error if sspcon2.6=1 then I2CBUSNotAck end if ' Get data result = i2cbusget ' Send NOT acknowledge. I2CBUSNACK ' Generate stop i2cbusstop 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) ' ' Generates I2CBUS Start. i2cbusstart ' Send Slave Address for writing i2cbussend(i2c_slave) ' If acknowledge not received, signal an error if sspcon2.6=1 then I2CBUSNotAck end if ' Send address i2cbussend(i2c_addr) ' If acknowledge not received, signal an error if sspcon2.6=1 then I2CBUSNotAck end if ' Send data i2cbussend(i2c_data) ' If acknowledge not received, signal an error if sspcon2.6=1 then I2CBUSNotAck end if ' Generates stop i2cbusstop end sub ' ' ' 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 the definition of array i2c_buffer. ' Number of bytes to send must be in variable i2c_to_send. User must check ' for overflows. sub procedure I2CBUSWrite(dim i2c_slave as byte, dim byref i2c_buffer as byte[10], dim i2c_to_send as byte) dim i2c_cnt as byte ' ' Generates I2CBUS Start. i2cbusstart ' Send Slave Address for writing i2cbussend(i2c_slave) ' If acknowledge not received, signal an error if sspcon2.6=1 then I2CBUSNotAck end if for i2c_cnt=0 to i2c_to_send - 1 ' Send data i2cbussend(i2c_buffer[i2c_cnt]) ' If acknowledge not received, signal an error if sspcon2.6=1 then I2CBUSNotAck end if next i2c_cnt ' Generate stop i2cbusstop end sub ' ' ' 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 the definition of array i2c_buffer. ' 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. sub procedure I2CBUSRead(dim i2c_slave as byte, dim byref i2c_buffer as byte[10], dim i2c_to_send as byte, dim i2c_to_receive as byte) dim i2c_cnt as byte ' ' Generates I2CBUS Start. i2cbusstart ' Send Slave Address for writing i2cbussend(i2c_slave) ' If acknowledge not received, signal an error if sspcon2.6=1 then I2CBUSNotAck end if for i2c_cnt=0 to i2c_to_send - 1 ' Send data i2cbussend(i2c_buffer[i2c_cnt]) ' If acknowledge not received, signal an error if sspcon2.6=1 then I2CBUSNotAck end if next i2c_cnt ' Generate repeated I2CBUS Start. i2cbusrepstart ' Send Slave Address for reading i2cbussend(i2c_slave or $01) ' If acknowledge not received, signal an error if sspcon2.6=1 then I2CBUSNotAck end if for i2c_cnt=0 to i2c_to_receive - 1 ' Read data i2c_buffer[i2c_cnt] = i2cbusget if i2c_cnt = i2c_to_receive - 1 then ' Send NOT acknowledge. I2CBUSNACK else ' Send acknowledge. I2CBUSaCK end if next i2c_cnt ' Invia lo stop i2cbusstop end sub ' ' ' Initialization of K51-AVR peripherals sub procedure K51_init dim dummy as byte ' ' Configuration of 7 segments display controller SAA 1064 ' do I2CBUSstart I2CBUSSend(rsaa1064) dummy = I2CBUSGet I2CBUSNACK I2CBUSStop loop until dummy = 0 ' i2c_buffer[0] = ctb ' Point to control register i2c_buffer[1] = %00100111 ' bit0 =1 dynamic mode ' bit1 =1 digit 1+3 not blanked ' bit2 =1 digit 2+4 not blanked ' bit3 =0 no test segment ' bit4 =0 no 3mA segment current ' bit5 =1 6mA segment current ' bit6 =0 no 12mA segment current ' bit7 =0 indifferent i2c_buffer[2] = 0 i2c_buffer[3] = 0 i2c_buffer[4] = 0 i2c_buffer[5] = 0 i2cbuswrite(wsaa1064, i2c_buffer, 6) ' ' Configuration of thermometer DS 1621 ' ' Initialize thermometer I2CBUSStart I2CBUSSend(Wds1621) I2CBUSSend(cfg) I2CBUSStop ' ' Reads configuration register of DS 1621 ' dummy = i2cbusreadbyte(wds1621,cfg) ' If conversion is enabled, start it if dummy.0 = 0 then goto begin_conversion end if ' If conversion is not enabled, enable it ' Write configuration reg. ' bit1= 1 polarity "1" ' bit0= 0 continuous conversion i2cbuswritebyte(wds1621,cfg,%00001010) Begin_conversion: i2c_buffer[0] = strct i2cbuswrite(wds1621,i2c_buffer,1) end sub ' ' ' Converts an hexadecimal figure to its 7-segments representation sub function DecTo7Seg(dim value as byte) as byte dim temp as byte select case value case 0 temp = $3F case 1 temp = $06 case 2 temp = $5B case 3 temp = $4F case 4 temp = $66 case 5 temp = $6D case 6 temp = $7D case 7 temp = $07 case 8 temp = $7F case 9 temp = $6F case 10 temp = $40 case 11 temp = 00 end select Result = temp end sub ' '************************** Main Program ******************************* ' main: Init_cpu ' Turn OFF relays set_relays(0) ' Initialize hardware I2C BUS peripheral I2Cbusinit ' Initialize K51-AVR on board I2C BUS peripheral k51_init ' Clear screen clrscr print_USART("Read temperature on a 7 segments display...") for_ever: gosub Read_temperature gosub Vis_temp ' goto for_ever ' ' ********************* Program End *********************** ' ' ' **************** Subroutines definition ****************** ' ' ' ' This procedure converts 1 byte in the range from 0 to 255 in a temperature ' value where positive degreeses (+0..+125) correspond to a value range from ' 0 to 125 and negative degreeses (-0...-55) correspond to a value range from ' from 255 to 201; bit 7 indicates the sign and negative degreeses can be ' obtained with the complement. e.g: Not 255=0, Not 201=54 Cifre: if Temp_h <= 127 then goto TempPositive end if ' If temperature is negative, adjust the value making the one's ' complement Temp_h = Temp_h xor $FF ' Turn on minus sign Hundreds = 10 goto Temp_if1 TempPositive: if Temp_h <= 99 then goto Temp1 end if ' If equal to or greater than 100, turn on hundreds Hundreds = 1 ' subtract 100 Temp_h = Temp_h - 100 goto temp_if1 Temp1: ' If not over 99, turn off hundreds Hundreds = 11 Temp_if1: if Temp_h <= 9 then goto Temp2 end if ' If over 9, calculate the tenth Tenth = Temp_h div 10 ' Calculate the units Tmp = Tenth * 10 Units = Temp_h - Tmp goto Cifre_esci Temp2: if Hundreds <> 11 then goto Temp3 end if ' Less than 9 and hundreds off, also tenth off Tenth = 11 goto Cifre_Units_vale_0 Temp3: if Hundreds <> 10 then goto temp4 end if ' Less than 9 and negative, tenth off Tenth = 11 goto Cifre_Units_vale_0 Temp4: ' Less than 9 and hundreds on, show one zero Tenth = 0 Cifre_Units_vale_0: ' Units Units = Temp_h Cifre_esci: return ' ' ' Visualization of temperature on 7 segments display Vis_temp: ' Separate value of temperature in three figures: ' Hundreds, Tenth and Untis gosub Cifre ' Converts the decimal value in 7 segments code Hundreds = DecTo7Seg(Hundreds) ' Converts the decimal value in 7 segments code Tenth = DecTo7Seg(Tenth) ' Converts the decimal value in 7 segments code Units = DecTo7Seg(Units) ' ' Send the temperature value converted in 7 segments ' encoding to the driver of the 7 segments display i2c_buffer[0] = dig1 i2c_buffer[1] = Hundreds i2c_buffer[2] = Tenth i2c_buffer[3] = Units or $80 if Temp_l = $80 then ' Write 5 i2c_buffer[4] = $6D else ' Write 0 i2c_buffer[4] = $3F end if i2cbuswrite(Wsaa1064, i2c_buffer, 5) return ' ' ' Read the temperature measured by DS1621 in Th and Tl Read_temperature: i2c_buffer[0] = rtemp i2cbusread(wds1621,i2c_buffer,1,2) Temp_h = i2c_buffer[0] Temp_l = i2c_buffer[1] return end.