📄 i2c.c
字号:
#include <pic.h>#include "delay.h"#include "i2c.h"/* * I2C functions for HI-TECH PIC C - master mode only *//* * TIMING - see Philips Sem. 80C51-based 8-bit ucontrollers, * or e.g. Philips PCF8574 data sheet *//* * Send stop condition * - data low-high while clock high */voidi2c_Stop(void){ /* assume SCL is high on entry */ SCL_DIR = I2C_OUTPUT; SDA = 0; /* ensure the data is low first */ SDA_DIR = I2C_OUTPUT; DelayUs(I2C_TM_DATA_SU); SCL_DIR = I2C_INPUT; /* float clock high */ DelayUs(I2C_TM_STOP_SU); SDA = 1; /* the low->high data transistion */ DelayUs(I2C_TM_BUS_FREE); /* bus free time before next start */ return;}/* * Send (re)start condition * - ensure data is high then issue a start condition * - see also i2c_Start() macro */voidi2c_Restart(void){ SCL = 0; /* ensure clock is low */ SCL_DIR = I2C_OUTPUT; SDA = 1; /* ensure data is high */ DelayUs(I2C_TM_DATA_SU); SCL_DIR = I2C_INPUT; /* clock pulse high */ DelayUs(I2C_TM_SCL_HIGH); SDA = 0; SDA_DIR = I2C_OUTPUT; /* the high->low transition */ DelayUs(I2C_TM_START_HD); return;}/* * Send a byte to the slave * - returns true on error */unsigned chari2c_SendByte(unsigned char byte){ signed char i; for(i=7; i>=0; i--) { SCL_DIR = I2C_OUTPUT; /* drive clock low */ /* data hold time = 0, send data now */ SDA = ((byte>>i) & 0x01); /* bit to send */ SDA_DIR = I2C_OUTPUT; DelayUs(I2C_TM_DATA_SU); SCL_DIR = I2C_INPUT; /* float clock high */ if(i2c_WaitForSCL()) /* wait for clock release */ return TRUE; /* bus error */ DelayUs(I2C_TM_SCL_HIGH); /* clock high time */ } return FALSE;}/* * send an address and data direction to the slave * - 7-bit address (lsb ignored) * - direction (FALSE = write ) */unsigned chari2c_SendAddress(unsigned char address, unsigned char rw){ return i2c_SendByte(address | (rw?1:0));}/* * Check for an acknowledge * - returns ack or ~ack, or ERROR if a bus error */signed chari2c_ReadAcknowledge(void){ unsigned char ack; SCL_DIR = I2C_OUTPUT; SDA_DIR = I2C_INPUT; /* disable data line - listen for ack */ DelayUs(I2C_TM_SCL_TO_DATA); /* SCL low to data out valid */ SCL_DIR = I2C_INPUT; /* float clock high */ DelayUs(I2C_TM_DATA_SU); ack = SDA; /* read the acknowledge */ /* wait for slave to release clock line after processing byte */ if(i2c_WaitForSCL()) return I2C_ERROR; return ack;}/* * Read a byte from the slave * - returns the byte, or I2C_ERROR if a bus error */inti2c_ReadByte(void){ unsigned char i; unsigned char byte = 0; for(i=0; i<8; i++) { SCL_DIR = I2C_OUTPUT; DelayUs(I2C_TM_SCL_LOW); /* min clock low period */ SDA_DIR = I2C_INPUT; /* release data line */ SCL_DIR = I2C_INPUT; /* float clock high */ if(i2c_WaitForSCL()) return I2C_ERROR; DelayUs(I2C_TM_SCL_HIGH); byte = byte << 1; /* read the next bit */ byte |= SDA; } return (int)byte;}/* * Send an (~)acknowledge to the slave * - status of I2C_LAST implies this is the last byte to be sent */voidi2c_SendAcknowledge(unsigned char status){ SCL_DIR = I2C_OUTPUT; SDA = status?0:1; /* drive line low -> more to come */ SDA_DIR = I2C_OUTPUT; DelayUs(I2C_TM_DATA_SU); SCL_DIR = I2C_INPUT; /* float clock high */ DelayUs(I2C_TM_SCL_HIGH); return;}/* * Send a byte to the slave and acknowledges the transfer * - returns I2C_ERROR, ack or ~ack */signed chari2c_PutByte(unsigned char data){ if(i2c_SendByte(data)) return I2C_ERROR; return i2c_ReadAcknowledge(); /* returns ack, ~ack */}/* * Get a byte from the slave and acknowledges the transfer * - returns true on I2C_ERROR or byte */inti2c_GetByte(unsigned char more){ int byte; if((byte = i2c_ReadByte()) == I2C_ERROR) return I2C_ERROR; i2c_SendAcknowledge(more); return byte;}/* * Send an array of bytes to the slave and acknowledges the transfer * - returns number of bytes not successfully transmitted */inti2c_PutString(const unsigned char *str, unsigned char length){ signed char error; while(length) { if((error = i2c_PutByte(*str)) == I2C_ERROR) return -(int)length; /* bus error */ else if(error) return (int)length; /* non acknowledge */ str++; length--; } return FALSE; /* everything OK */}/* * Reads number bytes from the slave, stores them at str and acknowledges the transfer * - returns number of bytes not successfully read in */unsigned chari2c_GetString(unsigned char *str, unsigned char number){ int byte; while(number) { if((byte = i2c_GetByte(number-1)) == I2C_ERROR) return number; /* bus error */ else *str = (unsigned char)byte; str++; number--; } return FALSE; /* everything OK */}/* * Opens communication with a device at address. mode * indicates I2C_READ or I2C_WRITE. * - returns TRUE if address is not acknowledged */unsigned chari2c_Open(unsigned char address, unsigned char mode){ i2c_Start(); i2c_SendAddress(address, mode); if(i2c_ReadAcknowledge()) return TRUE; return FALSE;} /* * wait for the clock line to be released by slow slaves * - returns TRUE if SCL was not released after the * time out period. * - returns FALSE if and when SCL released */unsigned chari2c_WaitForSCL(void){ /* SCL_DIR should be input here */ if(!SCL) { DelayUs(I2C_TM_SCL_TMO); /* if the clock is still low -> bus error */ if(!SCL) return TRUE; } return FALSE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -