C8051F I2C(SMBus)程序
/********************************************************************************************************
// This example supports in 100kHz void SMBus_Init(void); void Check_SDA(void); void SMBus_Write(uint wrDAdr,uchar Data1,uchar Data2,uchar Num); void SMBus_Read(uint wrDAdr,uchar *Data,uchar Num); /*Hardware Environment:DVK501 && F320+ EX*/
void Timer1_Init(void); void Timer3_Init(void); void Enb_Interrupt(void); void SMBus_ISR(void); void Timer3_ISR(void); // 16-bit SFR declarations sfr16 TMR3RL = 0x92; // Timer3 reload registers sfr16 TMR3 = 0x94; // Timer3 counter registers sbit SDA = P1^0; // SMBus on P1.0 sbit SCL = P1^1; // and P1.1 void SMBus_Init(void) { XBR0 |= 0x07; // Enable SMBus pins P1MDOUT = 0x00; // All P1 pins open-drain output P1 = 0xFF; 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(); Timer3_Init(); } 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.
CKCON |= 0x08; // Timer1 clock source = SYSCLK
CKCON |= 0x01; CKCON &= ~0x0A; // Timer1 clock source = SYSCLK / 4
TMOD = 0x20; // Timer1 in 8-bit auto-reload mode // Timer1 configured to overflow at 1/3 the rate defined by SMB_FREQUENCY TH1 = -(SYSCLK/SMB_FREQUENCY/SCALE/3); TL1 = TH1; // Init Timer1 TR1 = 1; // Timer1 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): // 1/.025 = 40 EIE1 |= 0x80; // Timer3 interrupt enable TMR3CN |= 0x04; // Start Timer3 } void Enb_Interrupt(void) { EIE1 |= 0x01; // Enable the SMBus interrupt EA = 1; // Global interrupt enable }
/********************************************************************************************************
//----------------------------------------------------------------------------- // Global CONSTANTS //-----------------------------------------------------------------------------
// Status vector - top 4 bits only
// End status vector definition //----------------------------------------------------------------------------- // Global VARIABLES //----------------------------------------------------------------------------- unsigned char SMBus_DATA_IN[3]; // Global holder for SMBus data // All receive data is written here unsigned char SMBus_DATA_OUT[2]; // Global holder for SMBus data. // All transmit data is read from here unsigned char COMMAND,num[2]; // Target SMBus slave address bit SMBus_BUSY; // Software flag to indicate when the // SMB_Read() or SMB_Write() functions // have claimed the SMBus bit SMBus_WR; // SMBus READ or WRITE, 0 is READ, 1 is WRITE //----------------------------------------------------------------------------- // Check_SDA //----------------------------------------------------------------------------- // If slave is holding SDA low because of an improper SMBus reset or error void Check_SDA(void) { uchar i; // Dummy variable counters 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 } } //----------------------------------------------------------------------------- // wrDAdr:I2C address // dat:I2C data //----------------------------------------------------------------------------- void SMBus_Write(uint wrDAdr,uchar Data1,uchar Data2,uchar Num) { while(SMBus_BUSY); // Wait for SMBus to be free. SMBus_BUSY = 1; // Claim SMBus (set to busy) COMMAND = wrDAdr; SMBus_DATA_OUT[0] = Data1; SMBus_DATA_OUT[1] = Data2; num[0] = Num; SMBus_WR = 0; STO = 0; STA = 1; // Start transfer while(SMBus_BUSY); // Wait for SMBus to be free. } //----------------------------------------------------------------------------- // wrDAdr:I2C address //----------------------------------------------------------------------------- void SMBus_Read(uint wrDAdr,uchar *Data,uchar Num) { uchar i; while(SMBus_BUSY); // Wait for bus to be free. SMBus_BUSY = 1; // Claim SMBus (set to busy) COMMAND = wrDAdr; num[1] = Num; SMBus_WR = 1; STO = 0; STA = 1; // Start transfer while(SMBus_BUSY); // Wait for transfer to complete for(i=0;i<Num;i++) Data[i] = SMBus_DATA_IN[i]; } void SMBus_ISR(void) interrupt 7 { bit FAIL = 0; // Used by the ISR to flag failed transfers static uchar sent_byte_counter,rec_byte_counter; if (ARBLOST == 0) // Check for errors { // Normal operation switch (SMB0CN & 0xF0) // Status vector { // Master Transmitter/Receiver: START condition transmitted. case SMBus_MTSTA: { SMB0DAT = COMMAND; // Load address of the target slave STA = 0; // Manually clear START bit sent_byte_counter = 1; rec_byte_counter = 1; break; } // Master Transmitter: Data byte transmitted case SMBus_MTDB: { if (ACK) // Slave ACK? { if (SMBus_WR == WRITE) // If this transfer is a WRITE, { if (sent_byte_counter <= num[0]) { // send data byte SMB0DAT = SMBus_DATA_OUT[sent_byte_counter-1]; sent_byte_counter++; } else { STO = 1; // Set STO to terminate transfer SMBus_BUSY = 0; // And free SMBus interface } } } else // If slave NACK, { STO = 1; // Send STOP condition, followed STA = 1; // By a START } break; } // Master Receiver: byte received case SMBus_MRDB: { if (rec_byte_counter < num[1]) { SMBus_DATA_IN[rec_byte_counter-1] = SMB0DAT; // Store received byte ACK = 1; // Send ACK to indicate byte received rec_byte_counter++; // Increment the byte counter } else { SMBus_DATA_IN[rec_byte_counter-1] = SMB0DAT; // Store received byte SMBus_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; } } // end switch } else { // ARBLOST = 1, error occurred... abort transmission FAIL = 1; } // end ARBLOST if if (FAIL) // If the transfer failed, { SMB0CF &= ~0x80; // Reset communication SMB0CF |= 0x80; STA = 0; STO = 0; ACK = 0; SMBus_BUSY = 0; // Free SMBus } SI = 0; // Clear interrupt flag } void Timer3_ISR(void) interrupt 14 { SMB0CF &= ~0x80; // Disable SMBus SMB0CF |= 0x80; // Re-enable SMBus TMR3CN &= ~0x80; // Clear Timer3 interrupt-pending flag STA = 0; SMBus_BUSY = 0; // Free SMBus }
|
---|