' ********************************************************************** ' ** Program: k51ad4e.BAS - Version : 1.2 - 13 december 2004 ** ' ** Compiler : BASCOM 8051 DEMO, (IDE and LIB V.2.0.11.0) ** ' ** Board: K51-AVR driven by GMB HR84 and GMM 935 ** ' ** Firm: grifo(r) ITALIAN TECHNOLOGY ** ' ** Via Dell' Artigiano 8/6 40016 San Giorgio di Piano (BO) ** ' ** Tel.+39 051 892 052 Fax +39 051 893 661 ** ' ** http://www.grifo.com http://www.grifo.it ** ' ** Written by: Graziano Gaiba ** ' ********************************************************************** ' ' ' This demo allows to drive an I2C BUS peripheral on board of K51-AVR, PCF8591, ' through mini-BLOCK module GMB HR84 and grifo(r) mini module. ' PCF 8591 is provided with four analog inputs for A/D conversions with 8 bits ' resolution, all the operations of conversion and combination acquisition are ' performed through synchronous serial interface I2C BUS. ' This demo allows to set which channel to convert through PC keyboard, and to ' read the combination on the 7 segments display of K51-AVR. ' ' 05.06.2000 by Adriano Pedrielli (for K51 only) ' ' 13.12.2004 by Graziano Gaiba ' ' '****************** Compiler directives ************************** ' NOTE: Copy 89LPC935.DAT file in BASCOM-8051 root directory and inside ' "Options | Compiler | Misc" window perform the following settings: ' Register File = 89LPC935.DAT ' Byte End(Hex) = A0 ' Size warning = 7167 $regfile "89lpc935.dat" $romstart = &H0 ' Start add. of code in FLASH $ramstart = &H0 ' Start add. of data in XRAM $ramsize = &H200 ' Size of data area in XRAM $crystal = 11059200 ' Maximum Fclock of the card $baud = 19200 ' Serial communication speed $large ' Code size > 2K $map ' Generates debug info ' '********************* Constants declaration *************************** ' Const Cret = 13 ' Used ASCII codes Const Lf = 10 Const Bell = 7 Const Rcint = 7372800 ' Internal RC clock frequency Const Qz11m = 11059200 ' External crystal clock frequency ' Dim Saa1064 As Const &H38 ' Slave address SAA1064 Dim Wsaa1064 As Const &H70 ' Slave address SAA1064 in Write Dim Rsaa1064 As Const &H71 ' Slave address SAA1064 in Read '****************** Addresses list for Saa1064 ************************* Dim Ctb As Const 0 ' Address Control byte Dim Dig1 As Const 1 ' Address Digit 1 Dim Dig2 As Const 2 ' Address Digit 2 Dim Dig3 As Const 3 ' Address Digit 3 Dim Dig4 As Const 4 ' Address Digit 4 '*********************************************************************** ' Dim Pcf8591 As Const &H48 ' Slave address PCF8591 Dim Wpcf8591 As Const &H90 ' Slave address PCF8591 in Write Dim Rpcf8591 As Const &H91 ' Slave address PCF8591 in Read ' '*********************** Variables declaration ************************* ' Dim Dig As Byte ' value of a digit Dim Cifh As Byte ' 4 bit high in HEX for figure Dim Cifl As Byte ' 4 bit low in HEX for figure Dim N1 As Byte ' number 1 byte for DY3 and DY4 Dim Valore As Byte ' numbeo to convert Dim C As Byte ' indicates channel to convert Dim I As Byte Dim Hlpb As Byte , M As Byte ' Byte of generic use Dim T As Byte ' Byte of generic use Dim Hlpw As Word , Ind As Word ' Word of generic use Dim Hlpl As Long ' Long of generic use ' ' Variables to manage communication, clock and delays Dim St As Byte Dim Br As Long ' Serail Buad Rate Dim Cclk As Long ' CPU clock frequency Dim R As Word , Del1ms As Word , Del As Word ' Delays ' Variables to manage Port I/O Dim M1 As Byte , M2 As Byte ' Variables to manage I2C Dim I2cc As Byte , I2cs As Byte Dim I2cdato As Byte Dim I2caddr As Word ' Used by I2C BUS hardware routines Dim I2c_slave As Byte , I2c_byte As Byte Dim Dummy As Byte , N_out As Byte , N_in As Byte Dim Getdati(2) As Byte ' vectore of 2 bytes ' '********************* Procedures declaration ************************** ' Declare Sub Iniz ' Peripherals initialization Declare Sub Ad(c As Byte , Valore As Byte) ' A/D converter management Declare Sub Canale ' Channel number management Declare Sub Cifre(valore As Byte , Cifh As Byte , Cifl As Byte ) ' converts a number in 2 HEX figures Declare Sub Digit(dig As Byte ) ' Converts a number in range ' 0-F in 7 segments Declare Sub Vis_num(n1 As Byte) ' Shows a byte in HEX ' Declare Sub Clrscr() ' Clears the screen Declare Sub Check() ' Internal check Declare Sub Ritardo(del As Word) ' Calibrated delay Declare Sub Iniser(br As Long , St As Byte) ' Initialization of serial port Declare Sub Cmd_i2c(i2cc As Byte) ' Send I2C command ' ' I2C BUS routines Declare Sub Cmd_i2cstart ' Send I2C start Declare Sub Cmd_i2cstop ' Send I2C stop ' Receive one byte in variable I2c_byte from specified slave address Declare Sub Cmd_i2creceive(i2c_slave As Byte , I2c_byte As Byte) ' Send one byte in variable I2c_byte to specified slave address Declare Sub Cmd_i2csend(i2c_slave As Byte , I2c_byte As Byte) ' Receive one byte Declare Sub Cmd_i2cwbyte(i2c_byte As Byte) ' Send n_out bytes from array Getdati to specified slave address and receive ' N_in bytes in array Getdati from the same slave address Declare Sub Cmd_n_i2creceive(i2c_slave As Byte , Dummy As Byte , N_out As Byte , N_in As Byte) ' '*************************** Main program ****************************** ' Main: ' Delay for signals settling Call Get_clk ' Acquires CPU clock frequency Call Iniser(19200 , 1) ' Initializes serial for console Call Init ' Initializes the module ' Performs a delay of about 2 seconds to allows the presence of emulation ' terminal program for console (i.e. HYPERTERMINAL) and contemporaneosly blinks ' the activity LED DL1 of the card. ' Uses general purpose variable i P0m1 = P0m1 Or &H40 ' Sets P0.6 in mode 3=OpenDrain P0m2 = P0m2 Or &H40 For I = 1 To 16 ' 16 cycles of 125 msec=2 sec P0.6 = Not P0.6 ' Complements activity LED Call Ritardo(125) ' Delays about 125 msec Next I ' ' ' Call Clrscr() Print "Demo for use of PCF 8591 with GMB HR84+GMM 935 at " ; Cclk ; " MHz and K51-AVR" Call Check ' Internal check Call Iniz ' initializations Print Print "Read analog voltage inputs of connector CN1." C = 0 Valore = 0 Print Print "Press + to increment the channel to convert" Print "Press - to decrement the channel to convert" Print Do Call Ad(c , Valore) ' Perform acquisition Call Vis_num(valore) ' Show byte in HEX Call Canale Loop Return End ' '**************************** Program end ****************************** ' ' '**************************** Procedures ******************************* ' ' Channel number management ' Sub Canale Valore = Inkey If Valore = "+" Then If C = 3 Then C = 0 Else Incr C End If End If If Valore = "-" Then If C = 0 Then C = 3 Else Decr C End If End If End Sub ' ' ********************** Peripherals initialization ******************** ' This procedure performs all the system initializations. ' Parameters: ' Input : nothing ' Output : nothing ' ********************************************************************** ' Sub Iniz ' Inizializzazione periferiche Do Call Cmd_i2creceive Rsaa1064 , Valore ' Read the status register Loop Until Valore = 0 ' Wait for SAA1064 to turn on Call Cmd_i2cstart ' Start sequence for I2CBUS Call Cmd_i2cwbyte Wsaa1064 ' Communicate the Slave address Call Cmd_i2cwbyte Ctb ' Point to control register Call Cmd_i2cwbyte &B00100111 ' 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 Call Cmd_i2cwbyte 0 ' set DY1 off Call Cmd_i2cwbyte 0 ' set DY2 off Call Cmd_i2cwbyte 0 ' set DY3 off Call Cmd_i2cwbyte 0 ' set DY4 off Call Cmd_I2cstop End Sub ' ' ' '*********************** Serial management subroutines ************************* ' Initializes the serial line with: ' Bit x chr = 8 ' Stop bit = 1 or 2 according with ST parameter ' Parity = None ' Baud rate = value of BR parameter ' by using the proper baud rate generator of microcontroller and his clock ' frequency saved on global variable cclk. ' Uses general purpose variables hlpw,hlpl Sub Iniser(br As Long , St As Byte) Pcon = Pcon And &HBF ' Resets bit SMOD0 to set mode If St = 1 Then Scon = &H52 ' Mode 1 (1 stop),No multiproc,Rx enable Else Scon = &HDA ' Mode 3 (2 stop),No multiproc,Rx enable End If Brgcon = &H02 ' Sets passed baud rate Hlpl = Br * 16 ' Calculates divisor for baud Hlpl = Cclk - Hlpl Hlpl = Hlpl / Br Hlpw = Loww(hlpl) Brgr0 = Low(hlpw) Brgr1 = High(hlpw) Brgcon = &H03 End Sub ' ' '********************** General purpose subroutines **************************** ' Reads the configuration byte UCFG1 on FLASH thanks to IAP procedures of ' P89LPC932 Boot Rom. Returns the global variable cclk set with the CPU clock ' frequency, with no control of the possible errors. Sub Get_clk mov A,#&H03 ' Uses command Misc. Read mov R7,#&H00 ' Reads register UCFG1 lcall &HFF03 ' Calls IAP proc. at PGM_MTP addr. mov A,R7 ' Saves result anl A,#&H07 ' Masks bits with CPU clock Select Case Acc Case &H00 : Cclk = Qz11m ' Ext. crystal clock frequency Case &H03 : Cclk = Rcint ' Internal RC clock frequency End Select End Sub ' ' ' Checks right functionality of internal devices with possible remakes. ' Uses general purpose variable st,t,m,ind,hlpw Sub Check Deecon = &H01 T = Peek(&Hff) Deeadr = &HFF T = 1 Ind = &HF7 Do M = Peek(&H07) If M.7 = 1 Then M = M And &H03 Ind = M + &HF8 T = Peek(ind) Else T = 0 End If St = Deecon St = St And &H80 Loop Until St <> 0 T = St St = Deedat Do M = Peek(ind) Incr Ind If Ind = &HFF Then Ind = &HF9 Hlpw = 0 Do Incr Hlpw M = Peek(ind) Loop Until St.0 = 0 Or Hlpw >= 1000 T = T + M Hlpw = Ind + T M = Peek(t) If St = 0 Then Incr T Else Call Ritardo(1) ' 1 msec pause End If Loop Until St = 0 End Sub ' ' ' Performs a calibrated delay long as many milliseconds as specified in the ' passed parameter del, according with the clock frequency saved in cclk ' variable, with no use of BASCOM instructions that use a fixed and preset ' value of clock. Sub Ritardo(del As Word) If Cclk = Rcint Then Del1ms = 73 ' Value for 1 msec at 7 MHz Else Del1ms = 110 ' Value for 1 msec at 11 MHz End If Do For R = 0 To Del1ms ' Cycle for 1 msec delay Next R Del = Del - 1 Loop Until Del = 0 End Sub ' ' ' Performs the clear screen functions for a generic console device. ' Uses general purpose variable i Sub Clrscr Printbin Cret For I = 0 To 25 Printbin Lf ' Transmits 25 Line Feeds Next I End Sub ' ' ' ' Initializes resources, variables and peripheral device to allow right ' execution of all demo program. Sub Init Disable Interrupts ' Disables interrupts P1m1 = 0 ' Initializes necessary lines ' ' Specific I2C Bus init P1m1 = P1m1 And &HF3 ' Configures P1.2 (SCL) and P1.3 P1m2 = P1m2 And &HF3 ' (SDA) in open drain mode P1 = P1 Or &H0C ' as input If Cclk = Rcint Then I2scll = 37 ' Bit rate is 2*(37+37) clock cycles I2sclh = 37 ' (7 MHz) equals to about 50 KHz Else I2scll = 55 ' Bit rate is 2*(55+55) clock cycles I2sclh = 55 ' (11 MHz) equals to about 50 KHz End If End Sub ' ' '********************** I2C BUS management subroutine ************************** ' Writes the command passed in i2c parameter in the control register I2C, waits ' the complete execution of the selected operation and then reads the same ' controller status that is returned in global variable i2cs. ' Uses general purpose varaiable hlpw Sub Cmd_i2c(i2cc As Byte) I2con = I2cc ' Writes passed command Hlpw = 0 ' Resets timeout counter Do Incr Hlpw ' Increments counter Call Ritardo(1) ' 1 msec delay Loop Until I2con.3 = 1 Or Hlpw > 50 ' Exit if interrupt flag or timeout I2cs = I2stat ' Reads current status I2cs = I2cs And &HF8 ' Masks significant bits End Sub ' ' ' Send start to I2C BUS using hardware peripheral Sub Cmd_i2cstart I2con = &H40 ' Enable SIO1 Call Cmd_i2c(&H60) ' Generate start End Sub ' ' ' Send stop to I2C BUS using hardware peripheral Sub Cmd_i2cstop I2con = &H50 ' Generate stop Hlpw = 0 ' Timeout counter Do Incr Hlpw ' Increments counter Call Ritardo(1) ' 1 msec delay Loop Until I2con.4 = 0 Or Hlpw > 20 ' Exit if Stop complete or timeout I2con = &H00 ' Disables I2C controller End Sub ' ' ' Send one byte to I2C BUS using hardware peripheral Sub Cmd_i2cwbyte(i2c_byte As Byte) I2dat = I2c_byte ' Write data Call Cmd_i2c(&H40) ' Reset flag interrupt End Sub ' ' ' Send one byte to I2C BUS to indicated slave address using hardware peripheral Sub Cmd_i2csend(i2c_slave As Byte , I2c_byte As Byte) Call Cmd_i2cstart ' Send start I2dat = I2c_slave ' Write slave address Call Cmd_i2c(&H40) ' Reset flag interrupt I2dat = I2c_byte ' Write data Call Cmd_i2c(&H40) ' Reset flag interrupt Call Cmd_i2cstop ' Send stop End Sub ' ' ' Read one byte from indicated slave address using hardware peripheral Sub Cmd_i2creceive(i2c_slave As Byte , I2c_byte As Byte) Call Cmd_i2cstart ' Send start I2dat = I2c_slave ' Write slave address Call Cmd_i2c(&H40) ' Reset flag interrupt I2dat = I2c_byte ' Write data Call Cmd_i2c(&H40) ' Reset flag interrupt Call Cmd_i2cstart ' Send second start I2dat = I2c_slave Or 1 ' Write slave address + R Call Cmd_i2c(&H40) ' Reset flag interrupt Call Cmd_i2c(&H44) ' Read one byte and send NACK I2c_byte = I2dat ' Data read stored in I2c_byte Call Cmd_i2cstop ' Send stop End Sub ' ' ' Send n_out bytes from array Getdati to specified slave address and receive ' N_in bytes in array Getdati from the same slave address Sub Cmd_n_i2creceive(i2c_slave As Byte , Dummy As Byte , N_out As Byte , N_in As Byte) Call Cmd_i2cstart ' Send start I2dat = I2c_slave ' Write slave address Call Cmd_i2c(&H40) ' Reset flag interrupt For Dummy = 1 To N_out I2dat = Getdati(dummy) ' Write data Call Cmd_i2c(&H40) ' Reset flag interrupt Next Dummy Call Cmd_i2cstart ' Second second start I2dat = I2c_slave Or 1 ' Write slave address + R Call Cmd_i2c(&H40) ' Reset flag interrupt For Dummy = 1 To N_in If Dummy = N_in Then ' If last byte to read Call Cmd_i2c(&H40) ' Read one byte and send NACK Else Call Cmd_i2c(&H44) ' Read one byte and send ACK End If Getdati(dummy) = I2dat ' Store data read into the array ' called Getdati() Next Dummy Call Cmd_i2cstop ' Send stop End Sub ' ' ' ******************** A/D converter management ************************ ' This procedure allows to perform an analogic conversion through one of ' the four channels available on IC2 (PCF8591). ' Parameters: ' Input : C as byte, indicates the channel to convert (0...3) ' Output : Valore as byte, value in the range from 0 to 255 (0v...+Vref) ' ********************************************************************** ' Sub Ad(ch As Byte , Valore As Byte) ' A/D converter management C = C And &H03 ' keep Bit 0 and Bit 1 Getdati(1) = C Call Cmd_n_i2creceive Wpcf8591 , Valore , 1 , 2 Valore = Getdati(2) 'I2csend Wpcf8591 , C ' point to the channel to convert 'I2creceive Rpcf8591 , Valore ' read previous conversion 'I2creceive Rpcf8591 , Valore ' read current conversion End Sub ' ' ******** Converts a figure in range from 0 to F in 7 segments ******** ' This procedure converts a figure in range from 0 to F in 7 segments ' format, if value is greater than F the display is off. ' Parameters: ' Input : dig as byte, value in the range from 0 to F ' Outout : dig as byte, value in 7 segments format. ' ********************************************************************** ' Sub Digit(dig As Byte ) ' Converts a number in range ' 0-F in 7 segments If Dig < 16 Then ' if number is lower than 16 Dig = Lookup(dig , Tab_7seg) ' read value from table Else Dig = 0 ' if = 16 or greater reset End If End Sub ' ' ***************** Converte 1 byte in due cifre HEX ******************** ' This procedure converts 1 byte in range from 0 to 255 in two 4 bits ' hexadecimal figures. ' Parameters: ' Input : Valore as byte, value in the range from 0 to 255 ' Output : Cifh as byte, figure of high nibble ' Cifl as byte, figure of low nibble ' ************************************************************************ ' Sub Cifre(valore As Byte , Cifh As Byte , Cifl As Byte ) ' converts a number in two HEX figures Cifh = Valore And &HF0 ' mask 4 high bits Cifh = Cifh / 16 ' shift to low the 4 high bits Cifl = Valore And &H0F ' mask the 4 low bits End Sub ' ' *********************** Visualizes a byte in HEX ********************* ' The first display visualizes the number of the channel being ' converted, the second display is off. ' This procedure allows to show a byte in hexadecimal format ' in the two displays on the right. E.g.: 255= FFH, 32= 20H etc. ' Parameters: ' Input : N1 as byte, number to visualize in HEX ' Output : nothing ' ********************************************************************** ' Sub Vis_num(n1 As Byte) ' visualizes a byte in HEX Call Cmd_i2cstart ' Start sequence for I2CBUS Call Cmd_i2cwbyte Wsaa1064 ' slave address Call Cmd_i2cwbyte Dig1 ' point to display 1 (DY1) Call Digit(c) ' convert the decines figure ' in 7 segments Call Cmd_i2cwbyte Dig ' output to first display DY1 Call Cmd_i2cwbyte 0 ' output to second display DY2 Call Cifre(n1 , Cifh , Cifl) ' convert number in 2 HEX figure Call Digit(cifh) ' convert figure in HEX ' in 7 segments Call Cmd_i2cwbyte Dig ' output to display DY3 Call Digit(cifl) ' convert figure in HEX ' in 7 segments Call Cmd_i2cwbyte Dig ' output to display DY4 Call Cmd_i2cstop ' Stop sequence for I2CBUS End Sub ' ' ** Conversion table for 7 segments figure in the range from 0 to 15 ** Tab_7seg: ' num. 0 1 2 3 4 5 6 7 8 9 Data &H3F , &H06 , &H5B , &H4F , &H66 , &H6D , &H7D , &H07 , &H7F , &H6F ' num. A b C d E F Data &H77 , &H7C , &H39 , &H5E , &H79 , &H71 ' ********************************************************************** '