| 
 
| 我再用411连接X1226,使用SMBUS ,但是X1226地址是双字节的 
 应该如何使用呢?我有一个411读写24C02的驱动程序
 
 下面是例子程序
 
 //-----------------------------------------------------------------------------
 // F41x_SMBus_EEPROM.c
 //-----------------------------------------------------------------------------
 // Copyright 2006 Silicon Laboratories, Inc.
 // http://www.silabs.com
 //
 // Program Description:
 //
 // This example demonstrates how the C8051F41x SMBus interface can communicate
 // with a 256 byte I2C Serial EEPROM (Microchip 24LC02B).
 // - Interrupt-driven SMBus implementation
 // - Only master states defined (no slave or arbitration)
 // - Timer1 used as SMBus clock source
 // - Timer3 used by SMBus for SCL low timeout detection
 // - SCL frequency defined by <SMB_FREQUENCY> constant
 // - Pinout:
 //    P0.0 -> SDA (SMBus)
 //    P0.1 -> SCL (SMBus)
 //
 //    P2.1 -> LED
 //
 //    P2.7 -> C2D (debug interface)
 //
 //    all other port pins unused
 //
 // How To Test:
 //
 // 1) Download code to a 'F41x device that is connected to a 24LC02B serial
 //    EEPROM (see the EEPROM datasheet for the pinout information).
 // 2) Run the code:
 //         a) the test will indicate proper communication with the EEPROM by
 //            turning on the LED at the end the end of the test
 //         b) the test can also be verified by running to the if statements
 //            in main and checking the sent and received values by adding
 //            the variables to the Watch Window
 //
 // NOTE: On the 'F410 Target Board, verify J13 and J14 are not populated
 // before testing.
 //
 // FID:            41X000025
 // Target:         C8051F41x
 // Tool chain:     Keil C51 7.50 / Keil EVAL C51
 // Command Line:   None
 //
 // Release 1.0
 //    -Initial Revision (TP)
 //    -30 MAR 2006
 //
 
 //-----------------------------------------------------------------------------
 // Includes and Device-Specific Parameters
 //-----------------------------------------------------------------------------
 
 #include <C8051F410.h>
 
 //-----------------------------------------------------------------------------
 // Global CONSTANTS
 //-----------------------------------------------------------------------------
 
 #define  SYSCLK         24500000       // System clock frequency in Hz
 
 #define  SMB_FREQUENCY  50000          // Target SCL clock rate
 // This example supports between 10kHz
 // and 100kHz
 
 #define  WRITE          0x00           // SMBus WRITE command
 #define  READ           0x01           // SMBus READ command
 
 // Device addresses (7 bits, lsb is a don't care)
 #define  EEPROM_ADDR    0xA0           // Device address for slave target
 // Note: This address is specified
 // in the Microchip 24LC02B
 // datasheet.
 // SMBus Buffer Size
 #define  SMB_BUFF_SIZE  0x08           // Defines the maximum number of bytes
 // that can be sent or received in a
 // single transfer
 
 // Status vector - top 4 bits only
 #define  SMB_MTSTA      0xE0           // (MT) start transmitted 传输起始
 #define  SMB_MTDB       0xC0           // (MT) data byte transmitted
 #define  SMB_MRDB       0x80           // (MR) data byte received
 // End status vector definition
 
 //-----------------------------------------------------------------------------
 // Global VARIABLES
 //-----------------------------------------------------------------------------
 unsigned char* pSMB_DATA_IN;           // Global pointer for SMBus data
 // All receive data is written here
 
 unsigned char SMB_SINGLEBYTE_OUT;      // Global holder for single byte writes.
 
 unsigned char* pSMB_DATA_OUT;          // Global pointer for SMBus data.
 // All transmit data is read from here
 
 unsigned char SMB_DATA_LEN;            // Global holder for number of bytes
 // to send or receive in the current
 // SMBus transfer.
 
 unsigned char WORD_ADDR;               // Global holder for the EEPROM word
 // address that will be accessed in
 // the next transfer
 
 unsigned char TARGET;                  // Target SMBus slave address
 
 bit SMB_BUSY = 0;                      // Software flag to indicate when the
 // EEPROM_ByteRead() or
 // EEPROM_ByteWrite()
 // functions have claimed the SMBus
 
 bit SMB_RW;                            // Software flag to indicate the
 // direction of the current transfer
 
 bit SMB_SENDWORDADDR;                  // When set, this flag causes the ISR
 // to send the 8-bit <WORD_ADDR>
 // after sending the slave address.
 
 
 bit SMB_RANDOMREAD;                    // When set, this flag causes the ISR
 // to send a START signal after sending
 // the word address.
 // For the 24LC02B EEPROM, a random read
 // (a read from a particular address in
 // memory) starts as a write then
 // changes to a read after the repeated
 // start is sent. The ISR handles this
 // switchover if the <SMB_RANDOMREAD>
 // bit is set.
 
 bit SMB_ACKPOLL;                       // When set, this flag causes the ISR
 // to send a repeated START until the
 // slave has acknowledged its address
 
 // 16-bit SFR declarations
 sfr16    TMR3RL   = 0x92;              // Timer3 reload registers
 sfr16    TMR3     = 0x94;              // Timer3 counter registers
 
 sbit LED = P2^1;                       // LED on port P2.1
 
 sbit SDA = P0^0;                       // SMBus on P0.0
 sbit SCL = P0^1;                       // and P0.1
 
 //-----------------------------------------------------------------------------
 // Function PROTOTYPES
 //-----------------------------------------------------------------------------
 
 void SMBus_Init(void);
 void Timer1_Init(void);
 void Timer3_Init(void);
 void Port_Init(void);
 
 void SMBus_ISR(void);
 void Timer3_ISR(void);
 
 void EEPROM_ByteWrite(unsigned char addr, unsigned char dat);
 void EEPROM_WriteArray(unsigned char dest_addr, unsigned char* src_addr,
 unsigned char len);
 unsigned char EEPROM_ByteRead(unsigned char addr);
 void EEPROM_ReadArray(unsigned char* dest_addr, unsigned char src_addr,
 unsigned char len);
 
 //-----------------------------------------------------------------------------
 // MAIN Routine
 //-----------------------------------------------------------------------------
 //
 // Main routine performs all configuration tasks, then loops forever sending
 // and receiving SMBus data to the slave EEPROM.
 
 void main (void)
 {
 char in_buff[8] = {0};              // Incoming data buffer
 char out_buff[8] = "ABCDEFG";       // Outgoing data buffer
 
 unsigned char temp_char;            // Temporary variable
 bit error_flag = 0;                 // Flag for checking EEPROM contents
 unsigned char i;                    // Temporary counter variable
 
 
 PCA0MD &= ~0x40;                    // WDTE = 0 (disable watchdog timer)
 
 OSCICN |= 0x07;                     // Set internal oscillator to highest
 // setting of 24500000
 
 // If slave is holding SDA low because of an improper SMBus reset or error
 while(!SDA)
 {
 // Provide clock pulses to allow the slave to advance out
 // of its current state. This will allow it to release SDA.
 XBR1 = 0x40;                     // Enable Crossbar
 SCL = 0;                         // Drive the clock low
 for(i = 0; i < 255; i++);        // Hold the clock low
 SCL = 1;                         // Release the clock
 while(!SCL);                     // Wait for open-drain
 // clock output to rise
 for(i = 0; i < 10; i++);         // Hold the clock high
 XBR1 = 0x00;                     // Disable Crossbar
 }
 
 Port_Init ();                       // Initialize Crossbar and GPIO
 
 LED = 0;                            // Turn off the LED before the test
 // starts
 
 Timer1_Init ();                     // Configure Timer1 for use as SMBus
 // clock source
 
 Timer3_Init ();                     // Configure Timer3 for use with SMBus
 // low timeout detect
 
 SMBus_Init ();                      // Configure and enable SMBus
 
 
 EIE1 |= 0x01;                       // Enable the SMBus interrupt
 
 EA = 1;                             // Global interrupt enable
 
 
 
 // Read and write some bytes to the EEPROM and check for proper
 // communication
 
 // Write the value 0xAA to location 0x25 in the EEPROM
 EEPROM_ByteWrite(0x25, 0xAA);
 
 // Read the value at location 0x25 in the EEPROM
 temp_char = EEPROM_ByteRead(0x25);
 
 // Check that the data was read properly
 if (temp_char != 0xAA)
 {
 error_flag = 1;
 }
 
 // Write the value 0xBB to location 0x25 in the EEPROM
 EEPROM_ByteWrite(0x25, 0xBB);
 
 // Write the value 0xCC to location 0x38 in the EEPROM
 EEPROM_ByteWrite(0x38, 0xCC);
 
 // Read the value at location 0x25 in the EEPROM
 temp_char = EEPROM_ByteRead(0x25);
 
 // Check that the data was read properly
 if (temp_char != 0xBB)
 {
 error_flag = 1;
 }
 
 // Read the value at location 0x38 in the EEPROM
 temp_char = EEPROM_ByteRead(0x38);
 
 // Check that the data was read properly
 if (temp_char != 0xCC)
 {
 error_flag = 1;
 }
 
 // Store the outgoing data buffer at EEPROM address 0x50
 EEPROM_WriteArray(0x50, out_buff, sizeof(out_buff));
 
 // Fill the incoming data buffer with data starting at EEPROM address 0x50
 EEPROM_ReadArray(in_buff, 0x50, sizeof(in_buff));
 
 // Check that the data that came from the EEPROM is the same as what was
 // sent
 for (i = 0; i < sizeof(in_buff); i++)
 {
 if (in_buff != out_buff)
 {
 error_flag = 1;
 }
 }
 
 // Indicate communication is good
 if (error_flag == 0)
 {
 // LED = ON indicates that the test passed
 LED = 1;
 }
 
 while(1);
 
 }
 
 //-----------------------------------------------------------------------------
 // Initialization Routines
 //-----------------------------------------------------------------------------
 
 //-----------------------------------------------------------------------------
 // SMBus_Init()
 //-----------------------------------------------------------------------------
 //
 // Return Value : None
 // Parameters   : None
 //
 // The SMBus peripheral is configured as follows:
 // - SMBus enabled
 // - Slave mode disabled
 // - Timer1 used as clock source. The maximum SCL frequency will be
 //   approximately 1/3 the Timer1 overflow rate
 // - Setup and hold time extensions enabled
 // - Free and SCL low timeout detection enabled
 //
 void SMBus_Init (void)
 {
 SMB0CF = 0x5D;                      // Use Timer1 overflows as SMBus clock
 // source;
 // Disable slave mode;
 // Enable setup & hold time extensions;
 // Enable SMBus Free timeout detect;
 // Enable SCL low timeout detect;
 
 SMB0CF |= 0x80;                     // Enable SMBus;
 }
 
 //-----------------------------------------------------------------------------
 // Timer1_Init()
 //-----------------------------------------------------------------------------
 //
 // Return Value : None
 // Parameters   : None
 //
 // Timer1 is configured as the SMBus clock source as follows:
 // - Timer1 in 8-bit auto-reload mode
 // - SYSCLK / 12 as Timer1 clock source
 // - Timer1 overflow rate => 3 * SMB_FREQUENCY
 // - The maximum SCL clock rate will be ~1/3 the Timer1 overflow rate
 // - Timer1 enabled
 //
 void Timer1_Init (void)
 {
 // Make sure the Timer can produce the appropriate frequency in 8-bit mode
 // Supported SMBus Frequencies range from 10kHz to 100kHz.  The CKCON register
 // settings may need to change for frequencies outside this range.
 #if ((SYSCLK/SMB_FREQUENCY/3) < 255)
 #define SCALE 1
 CKCON |= 0x08;                   // Timer1 clock source = SYSCLK
 #elif ((SYSCLK/SMB_FREQUENCY/4/3) < 255)
 #define SCALE 4
 CKCON |= 0x01;
 CKCON &= ~0x0A;                  // Timer1 clock source = SYSCLK / 4
 #endif
 
 TMOD = 0x20;                        // Timer1 in 8-bit auto-reload mode
 
 TH1 = -(SYSCLK/SMB_FREQUENCY/12/3); // Timer1 configured to overflow at 1/3
 // the rate defined by SMB_FREQUENCY
 
 TL1 = TH1;                          // Init Timer1
 
 TR1 = 1;                            // Timer1 enabled
 }
 
 //-----------------------------------------------------------------------------
 // Timer3_Init()
 //-----------------------------------------------------------------------------
 //
 // Return Value : None
 // Parameters   : None
 //
 // Timer3 configured for use by the SMBus low timeout detect feature as
 // follows:
 // - Timer3 in 16-bit auto-reload mode
 // - SYSCLK/12 as Timer3 clock source
 // - Timer3 reload registers loaded for a 25ms overflow period
 // - Timer3 pre-loaded to overflow after 25ms
 // - Timer3 enabled
 //
 void Timer3_Init (void)
 {
 TMR3CN = 0x00;                      // Timer3 configured for 16-bit auto-
 // reload, low-byte interrupt disabled
 
 CKCON &= ~0x40;                     // Timer3 uses SYSCLK/12
 
 TMR3RL = -(SYSCLK/12/40);           // Timer3 configured to overflow after
 TMR3 = TMR3RL;                      // ~25ms (for SMBus low timeout detect)
 
 EIE1 |= 0x80;                       // Timer3 interrupt enable
 TMR3CN |= 0x04;                     // Start Timer3
 }
 
 //-----------------------------------------------------------------------------
 // PORT_Init
 //-----------------------------------------------------------------------------
 //
 // Return Value : None
 // Parameters   : None
 //
 // Configure the Crossbar and GPIO ports.
 //
 // P0.0   digital   open-drain    SMBus SDA
 // P0.1   digital   open-drain    SMBus SCL
 //
 // P2.1   digital   push-pull     LED
 //
 // all other port pins unused
 //
 // Note: If the SMBus is moved, the SCL and SDA sbit declarations must also
 // be adjusted.
 //
 void PORT_Init (void)
 {
 P0MDOUT = 0x00;                     // All P0 pins open-drain output
 
 P2MDOUT |= 0x02;                    // Make the LED (P2.1) a push-pull
 // output
 
 XBR0 = 0x04;                        // Enable SMBus pins
 XBR1 = 0x40;                        // Enable crossbar and weak pull-ups
 
 P0 = 0xFF;
 }
 
 //-----------------------------------------------------------------------------
 // SMBus Interrupt Service Routine (ISR)
 //-----------------------------------------------------------------------------
 //
 // SMBus ISR state machine
 // - Master only implementation - no slave or arbitration states defined
 // - All incoming data is written starting at the global pointer <pSMB_DATA_IN>
 // - All outgoing data is read from the global pointer <pSMB_DATA_OUT>
 //
 void SMBus_ISR (void) interrupt 7
 {
 bit FAIL = 0;                       // Used by the ISR to flag failed
 // transfers
 
 static char i;                      // Used by the ISR to count the
 // number of data bytes sent or
 // received
 
 static bit SEND_START = 0;          // Send a start
 
 switch (SMB0CN & 0xF0)              // Status vector
 {
 // Master Transmitter/Receiver: START condition transmitted.
 case SMB_MTSTA:
 SMB0DAT = TARGET;             // Load address of the target slave
 SMB0DAT &= 0xFE;              // Clear the LSB of the address for the
 // R/W bit
 SMB0DAT |= SMB_RW;            // Load R/W bit
 STA = 0;                      // Manually clear START bit
 i = 0;                        // Reset data byte counter
 break;
 
 // Master Transmitter: Data byte (or Slave Address) transmitted
 case SMB_MTDB:
 if (ACK)                      // Slave Address or Data Byte
 {                             // Acknowledged?
 if (SEND_START)
 {
 STA = 1;
 SEND_START = 0;
 break;
 }
 if(SMB_SENDWORDADDR)       // Are we sending the word address?
 {
 SMB_SENDWORDADDR = 0;   // Clear flag
 SMB0DAT = WORD_ADDR;    // Send word address
 
 if (SMB_RANDOMREAD)
 {
 SEND_START = 1;      // Send a START after the next ACK cycle
 SMB_RW = READ;
 }
 
 break;
 }
 
 if (SMB_RW==WRITE)         // Is this transfer a WRITE?
 {
 
 if (i < SMB_DATA_LEN)   // Is there data to send?
 {
 // send data byte
 SMB0DAT = *pSMB_DATA_OUT;
 
 // increment data out pointer
 pSMB_DATA_OUT++;
 
 // increment number of bytes sent
 i++;
 }
 else
 {
 STO = 1;              // Set STO to terminte transfer
 SMB_BUSY = 0;         // Clear software busy flag
 }
 }
 else {}                    // If this transfer is a READ,
 // then take no action. Slave
 // address was transmitted. A
 // separate 'case' is defined
 // for data byte recieved.
 }
 else                          // If slave NACK,
 {
 if(SMB_ACKPOLL)
 {
 STA = 1;                // Restart transfer
 }
 else
 {
 FAIL = 1;               // Indicate failed transfer
 }                          // and handle at end of ISR
 }
 break;
 
 // Master Receiver: byte received
 case SMB_MRDB:
 if ( i < SMB_DATA_LEN )       // Is there any data remaining?
 {
 *pSMB_DATA_IN = SMB0DAT;   // Store received byte
 pSMB_DATA_IN++;            // Increment data in pointer
 i++;                       // Increment number of bytes received
 ACK = 1;                   // Set ACK bit (may be cleared later
 // in the code)
 
 }
 
 if (i == SMB_DATA_LEN)        // This is the last byte
 {
 SMB_BUSY = 0;              // Free SMBus interface
 ACK = 0;                   // Send NACK to indicate last byte
 // of this transfer
 STO = 1;                   // Send STOP to terminate transfer
 }
 
 break;
 
 default:
 FAIL = 1;                     // Indicate failed transfer
 // and handle at end of ISR
 break;
 }
 
 if (FAIL)                           // If the transfer failed,
 {
 SMB0CF &= ~0x80;                 // Reset communication
 SMB0CF |= 0x80;
 STA = 0;
 STO = 0;
 ACK = 0;
 
 SMB_BUSY = 0;                    // Free SMBus
 
 FAIL = 0;
 }
 
 SI = 0;                             // Clear interrupt flag
 }
 
 //-----------------------------------------------------------------------------
 // Timer3 Interrupt Service Routine (ISR)
 //-----------------------------------------------------------------------------
 //
 // A Timer3 interrupt indicates an SMBus SCL low timeout.
 // The SMBus is disabled and re-enabled if a timeout occurs.
 //
 void Timer3_ISR (void) interrupt 14
 {
 SMB0CF &= ~0x80;                    // Disable SMBus
 SMB0CF |= 0x80;                     // Re-enable SMBus
 TMR3CN &= ~0x80;                    // Clear Timer3 interrupt-pending flag
 SMB_BUSY = 0;                       // Free bus
 }
 
 //-----------------------------------------------------------------------------
 // Support Functions
 //-----------------------------------------------------------------------------
 
 //-----------------------------------------------------------------------------
 // EEPROM_ByteWrite ()
 //-----------------------------------------------------------------------------
 //
 // Return Value : None
 // Parameters   :
 //   1) unsigned char addr - address to write in the EEPROM
 //                        range is full range of character: 0 to 255
 //
 //   2) unsigned char dat - data to write to the address <addr> in the EEPROM
 //                        range is full range of character: 0 to 255
 //
 // This function writes the value in <dat> to location <addr> in the EEPROM
 // then polls the EEPROM until the write is complete.
 //
 void EEPROM_ByteWrite(unsigned char addr, unsigned char dat)
 {
 while (SMB_BUSY);                   // Wait for SMBus to be free.
 SMB_BUSY = 1;                       // Claim SMBus (set to busy)
 
 // Set SMBus ISR parameters
 TARGET = EEPROM_ADDR;               // Set target slave address
 SMB_RW = WRITE;                     // Mark next transfer as a write
 SMB_SENDWORDADDR = 1;               // Send Word Address after Slave Address
 SMB_RANDOMREAD = 0;                 // Do not send a START signal after
 // the word address
 SMB_ACKPOLL = 1;                    // Enable Acknowledge Polling (The ISR
 
 | 
 |