' **************************************************************** ' * File: k51terme.bas - Ver. 1.1 * ' * Compiler: PIC Basic PRO * ' * IDE: MicroCode Studio Plus * ' * Compiler Version: 2.45 * ' * 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 08.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 ********************** ' 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 ********************** ' I2C_BUFFER_SIZE con 10 Saa1064 con $38 ' Slave address SAA1064 Wsaa1064 con $70 ' Slave address SAA1064 in Write Rsaa1064 con $71 ' Slave address SAA1064 in Read '****************** Addresses list for Saa1064 ************************* Ctb con 0 ' Address Control byte Dig1 con 1 ' Address Digit 1 Dig2 Con 2 ' Address Digit 2 Dig3 Con 3 ' Address Digit 3 Dig4 Con 4 ' Address Digit 4 ' ' ********************************************************************** ' Ds1621 con $4C ' Slave address DS1621 Wds1621 con $98 ' Slave address DS1621 in Write Rds1621 con $99 ' Slave address DS1621 in Read ' ***************** Commands list of DS1621 **************************** Cfg con $AC ' R/W Config register of DS1621 Rtemp con $AA ' read temperature 2 bytes Strct con $EE ' Start temperature conversion Stpct con $22 ' Stop temperature conversion ' ' ' ******************** Variables declaration ********************* ' ' Generic variables i var byte c var byte scelta var byte di var byte do 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 ' ' Figures of temperature to show Hundreds var byte Tenth var byte Units var byte ' ' Conversion read by DS1621 Th var byte Tl var byte ' ' '************************** Main Program ******************************* ' main: gosub Init_cpu ' Turn OFF relays port_val = 0 gosub set_relays ' Initialize hardware I2C BUS peripheral gosub i2cbusinit ' Initialize K51-AVR on board I2C BUS peripheral gosub k51_init ' Clear screen gosub clrscr for_ever: gosub read_temperature gosub vis_temp 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 ' ' ' 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_val. 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 ' ' ' Initialization of K51-AVR peripherals K51_init: ' ' Configuration of 7 segments display controller SAA 1064 ' gosub i2cbusstart i2c_data = rsaa1064 gosub i2cbussend gosub i2cbusget gosub i2cbusnack gosub i2cbusstop if i2c_data <> 0 then k51_init ' i2c_slave = wsaa1064 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 i2c_to_send = 6 gosub i2cbuswrite ' ' Configuration of thermometer DS 1621 ' ' Initialize thermometer i2c_slave = Wds1621 i2c_addr = cfg gosub i2cbuswritebyte ' ' Reads configuration register of DS 1621 ' i2c_slave = wds1621 i2c_addr = cfg gosub i2cbusreadbyte ' If conversion is enabled, start it if i2c_val.0 == 0 then begin_conversion ' If conversion is not enabled, enable it i2c_slave = wds1621 i2c_addr = cfg i2c_val = %00001010 ' Write configuration reg. ' bit1= 1 polarity "1" ' bit0= 0 continuous conversion gosub i2cbuswritebyte Begin_conversion: i2c_slave = wds1621 i2c_buffer[0] = strct i2c_to_send = 1 gosub i2cbuswrite return ' ' ' 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 th <= 127 then temppositive ' If temperature is negative, adjust the value making the one's ' complement th = th ^ $FF ' Turn on minus sign Hundreds = 10 goto temp_if1 TempPositive: if th <= 99 then temp1 ' If equal to or greater than 100, turn on hundreds Hundreds = 1 ' subtract 100 th = th - 100 goto temp_if1 Temp1: ' If not over 99, turn off hundreds Hundreds = 11 Temp_if1: if th <= 9 then temp2 ' If over 9, calculate the tenth Tenth = th / 10 ' Calculate the units c = Tenth * 10 Units = th - c goto cifre_esci Temp2: if Hundreds <> 11 then temp3 ' Less than 9 and hundreds off, also tenth off Tenth = 11 goto Cifre_Units_vale_0 Temp3: if Hundreds <> 10 then temp4 ' 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 = th 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 di = Hundreds gosub dec_to_7seg Hundreds = di ' Converts the decimal value in 7 segments code di = Tenth gosub dec_to_7seg Tenth = di ' Converts the decimal value in 7 segments code di = Units gosub dec_to_7seg Units = di ' ' Send the temperature value converted in 7 segments ' encoding to the driver of the 7 segments display i2c_slave = Wsaa1064 i2c_buffer[0] = dig1 i2c_buffer[1] = hundreds i2c_buffer[2] = tenth i2c_buffer[3] = units | $80 if tl <> $80 then ' Write 5 i2c_buffer[4] = $6D else ' Write 0 i2c_buffer[4] = $3F endif i2c_to_send = 5 gosub i2cbuswrite return Dec_to_7Seg: lookup di, [$3F, $06, $5B, $4F, $66, $6D, $7D, $07, $7F, $6F, $40, $00], di return ' ' ' Read the temperature measured by DS1621 in Th and Tl Read_temperature: i2c_slave = wds1621 i2c_buffer[0] = rtemp i2c_to_send = 1 i2c_to_receive = 2 gosub i2cbusread th = i2c_buffer[0] tl = i2c_buffer[1] return