📄 8051 smb.c
字号:
// WRITE_BUF OP_CODEs are received. Note that the SMBus is stalled until the
// OP_CODE is decoded.
switch (OP_CODE & 0x0F){ // Decode OP_CODE
// OP_CODE = READ_ADC - Perform an ADC conversion, and place data in
// output buffer.
// Read only ADC high byte.
case READ_ADC:
SI = 0; // Free the bus
AA = 0; // Take slave 'offline'
ADCINT = 0; // Clear ADC interrupt flag.
ADBUSY = 1; // Start conversion.
while (!ADCINT); // Wait for conversion to finish.
WORD = ADC0H; // Put data in output buffer.
AA = 1; // Put slave back 'online'
VALID_OP = 0; // Look for a new OP_CODE
break;
// OP_CODE = WRITE_DAC - Wait for a valid data byte, and write it to high
// byte of DAC0.
case WRITE_DAC:
SI = 0; // Free the bus
DATA_READY = 0; // Wait for valid data.
while (!DATA_READY); //
DAC0L = 0; // DAC low byte
DAC0H = WORD; // DAC high byte
VALID_OP = 0; // Look for new OP_CODE
SI = 0; // Free bus when finished.
break;
// OP_CODE = WRITE_BUF - Wait for valid data byte, then place data in
// DATA_BUF array. Index data according to upper 4 bits of OP_CODE.
case WRITE_BUF:
SI = 0; // Free the bus
index = (OP_CODE & 0xF0); // Use upper 4 bits as array index.
DATA_READY = 0; // Wait for valid data.
while (!DATA_READY); //
DATA_BUF[index] = WORD; // Store data in array.
VALID_OP = 0; // Look for new OP_CODE
SI = 0; // Free the bus when finished.
break;
// OP_CODE = READ_BUF - Read DATA_BUF array and place byte in output buffer.
// Array index determined by upper 4 bits of OP_CODE.
case READ_BUF:
index = (OP_CODE & 0xF0); // Use upper 4 bits as array index.
WORD = DATA_BUF[index]; // Place indexed data in output buffer.
VALID_OP = 0; // Look for new OP_CODE
SI = 0; // Free the bus when finished.
break;
}
if (LOST){ // If LOST is set, the device has recently
COMMAND = LOST_COMMAND; // lost an arbitration. Load saved values
WORD = LOST_WORD; // back into transfer variables, and retry
OP_CODE = LOST_CODE; // transfer.
LOST = 0;
STO = 0;
STA = 1;
}
}
}
//------------------------------------------------------------------------------------
// SMBus Interrupt Service Routine
//------------------------------------------------------------------------------------
void SMBUS_ISR (void) interrupt 7
{
switch (SMB0STA){ // Status code for the SMBus
// (SMB0STA register)
// Master Transmitter/Receiver: START condition transmitted.
// Load SMB0DAT with slave device address. Mask out R/W bit since all transfers
// start with an OP_CODE write.
case SMB_START:
SMB0DAT = (COMMAND & 0xFE); // Load address of the slave to be accessed.
// Mask out R/W bit because first transfer
// will always be a write of the OP_CODE.
STA = 0; // Manually clear STA bit
SI = 0; // Clear interrupt flag
break;
// Master Transmitter/Receiver: Repeated START condition transmitted.
// This state only occurs during a READ, after the OP_CODE has been sent. Load
// device address + READ into SMB0DAT.
case SMB_RP_START:
SMB0DAT = COMMAND;
STA = 0; // Manually clear START bit.
SI = 0;
break;
// Master Transmitter: Slave address + WRITE transmitted. ACK received.
// Load OP_CODE into SMB0DAT.
case SMB_MTADDACK:
SMB0DAT = OP_CODE;
SI = 0; // Clear interrupt flag
break;
// Master Transmitter: Slave address + WRITE transmitted. NACK received.
// The slave is not responding. Use ACK polling to retry.
case SMB_MTADDNACK:
STO = 1;
STA = 1;
SI = 0; // Clear interrupt flag
break;
// Master Transmitter: Data byte transmitted. ACK received.
// Check OP_CODE - If it is a READ code, send repeated START to begin
// read. If it is a WRITE code, load WORD into SMB0DAT for transfer.
// If it is not a valid code, then either 1) data has been transmitted
// and the transfer is finished, or 2) there is an error. In either case,
// send STOP and end transfer.
case SMB_MTDBACK:
switch (OP_CODE & 0x0F){ // Check only lower 4 bits.
// OP_CODE is a READ. Send repeated START.
case READ_BUF:
case READ_ADC:
OP_CODE = 0; // Current OP_CODE no longer useful
STO = 0;
STA = 1;
break;
// OP_CODE is a WRITE. Load output data into SMB0DAT.
case WRITE_BUF:
case WRITE_DAC:
SMB0DAT = WORD;
OP_CODE = 0; // Clear OP_CODE so transfer ends the next
break; // time this state occurs
// (after data is sent).
default: // No valid OP_CODE. End transfer.
STO = 1;
SM_BUSY = 0;
break;
}
SI = 0;
break;
// Master Transmitter: Data byte transmitter. NACK received.
// Use ACK polling to retry transfer.
case SMB_MTDBNACK:
STO = 1;
STA = 1;
SI = 0; // Clear interrupt flag
break;
// Master Transmitter: Arbitration lost.
case SMB_MTARBLOST:
LOST_COMMAND = COMMAND; //
LOST_WORD = WORD; // Store variables for use when bus is free.
LOST_CODE = OP_CODE; //
LOST = 1; // Set flag to retry transfer
// when bus is free.
SI = 0; // Clear interrupt flag
break;
// Master Receiver: Slave address + READ transmitted. ACK received.
// Set to transmit NACK after next transfer since it will be the
// last (only) byte.
case SMB_MRADDACK:
AA = 0; // NACK sent during acknowledge cycle.
SI = 0;
break;
// Master Receiver: Slave address + READ transmitted. NACK received.
// Slave not responding. Send repeated START to try again.
case SMB_MRADDNACK:
STO = 0;
STA = 1;
SI = 0;
break;
// Master Receiver: Data byte received. ACK transmitted.
// State should not occur because AA is cleared in previous state.
// Send STOP if state does occur.
case SMB_MRDBACK:
STO = 1;
SM_BUSY = 0;
SI = 0;
break;
// Master Receiver: Data byte received. NACK transmitted.
// Read operation has completed. Read data register and send STOP.
case SMB_MRDBNACK:
WORD = SMB0DAT;
STO = 1;
SM_BUSY = 0;
AA = 1; // Set AA for next transfer
SI = 0;
break;
// Slave Receiver: Arbitration lost, general call address received.
// Set LOST flag to retry transfer when bus is free. Fall through.
case SMB_SRGARBLOST:
// Slave Receiver: Arbitration lost, own slave address + WRITE received.
// Set LOST flag to retry transfer when bus is free.
// Set STO bit to get out of master mode.
case SMB_SROARBLOST:
LOST_COMMAND = COMMAND; //
LOST_WORD = WORD; // Store variables for use when bus is free.
LOST_CODE = OP_CODE; //
LOST = 1; // Retry transfer when bus is free.
SI = 0;
break;
// Slave Receiver: Slave address + WRITE received. ACK transmitted.
// Fall through.
case SMB_SROADACK:
// Slave Receiver: General call address received. ACK transmitted.
case SMB_SRGADACK:
SI = 0;
break;
// Slave Receiver: Data byte received after addressed by general
// call address + WRITE.
// ACK transmitted. Fall through.
case SMB_SRGDBACK:
// Slave Receiver: Data byte received after addressed by own
// slave address + WRITE.
// ACK transmitted.
// Take action depending on OP_CODE or data received.
case SMB_SRODBACK:
if (!VALID_OP){ // if VALID_OP=0, this byte is an OP_CODE.
OP_CODE = SMB0DAT; // Store OP_CODE
VALID_OP = 1; // Next byte is not an OP_CODE
} else {
DATA_READY = 1; // Valid data has been received. Process
// in OP_CODE handler.
WORD = SMB0DAT;
SI = 0;
}
break;
// Slave Receiver: Data byte received while addressed as slave.
// NACK transmitted. Should not occur since AA will not be cleared
// as slave. Fall through to next state.
case SMB_SRODBNACK:
// Slave Receiver: Data byte received while addressed by general call.
// NACK transmitted.
// Should not occur since AA will not be cleared as slave.
case SMB_SRGDBNACK:
AA = 1;
SI = 0;
break;
// Slave Receiver: STOP or repeated START received while addressed as slave.
case SMB_SRSTOP:
SI = 0;
break;
// Slave Transmitter: Own slave address + READ received. ACK transmitted.
// Load SMB0DAT with data to be output.
case SMB_STOADACK:
SMB0DAT = WORD;
SI = 0;
break;
// Slave Transmitter: Arbitration lost as master. Own address + READ received.
// ACK transmitted.
case SMB_STOARBLOST:
LOST_COMMAND = COMMAND; //
LOST_WORD = WORD; // Store variables for use when bus
LOST_CODE = OP_CODE; // is free.
LOST = 1; // Retry when bus is free.
SI = 0;
break;
// Slave Transmitter: Data byte transmitted. ACK received. Fall through.
case SMB_STDBACK:
// Slave Transmitter: Data byte transmitted. NACK received. Fall through.
case SMB_STDBNACK:
// Slave Transmitter: Last data byte transmitted. ACK received.
// No action necessary.
case SMB_STDBLAST:
SI = 0;
break;
// All other status codes invalid. Reset communication.
default:
STO = 1;
SM_BUSY = 0;
break;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -