📄 iic.c
字号:
/*
*********************************************************************************************************************
* I2C BUS LOW LEVEL FUNCTIONS
*
* Description: Low level IIC functions
* File: iic.c
* Software: Keil C (C51) compiler, 8.0x version under uVision3 IDE
* Programmer: Vinay Kumar Kondaparthi
* Hardware: P89V51RD2 8 Bit Microcontroller
* Date: 3rd May 2009
* Version: 1.0
*
*********************************************************************************************************************
*/
#include "t89c51rd2.h"
#include "intrins.h"
#include "iic.h"
/*
*********************************************************************************************************************
* LOCAL DEFINITIONS
*********************************************************************************************************************
*/
#define HIGH 1
#define LOW 0
#define Delay5Us {_nop_();_nop_();_nop_();_nop_();_nop_();} //for 12MHz xtal, generic 8051
/*
*********************************************************************************************************************
* IIC START CONDITION GENERATION
* Function: Generate an I2C bus start condition
* Argument: none
* Return: none
* Note: Hardware-dependent for direct I/O operation on SDA and SCL required.
* Delay5Us is a macro assuming the system clock (xtal) is 12MHz or less for 12-clock 8051
*********************************************************************************************************************
*/
void i2c_Start(void)
{
SDA = HIGH;
SCL = HIGH;
Delay5Us;
SDA = LOW;
Delay5Us;
SCL = LOW;
}
/*
*********************************************************************************************************************
* IIC STOP CONDITION GENERATION
* Function: Generate an I2C stop condition
* Argument: none
* Return: none
* Note: Hardware-dependent for direct I/O operation on SDA and SCL required.
* Delay5Us is a macro assuming the system clock (xtal) is 12MHz or less for 12-clock 8051
*********************************************************************************************************************
*/
void i2c_Stop(void)
{
SDA = LOW;
SCL = HIGH;
Delay5Us;
SDA = HIGH;
Delay5Us;
}
/*
*********************************************************************************************************************
* IIC ACK CONDITION GENERATION
* Function: This function is called to generate an ACK or noACK.
* Argument: 'reply' ACK if an acknowledge is required, i.e. SDA pulled low
* noACK if an acknowledge not required, i.e. SDA pulled high
* Return: none
* Warning: The argument reply of type 'bit', which is KEIL C specific
* Note: ACK and noACK constants defined under iic.h, public constants
* Hardware-dependent for direct I/O operation on SDA and SCL required.
* Delay5Us is a macro assuming the system clock (xtal) is 12MHz or less for 12-clock 8051
*********************************************************************************************************************
*/
void i2c_Ack(bit reply)
{
(reply==ACK)?(SDA=LOW):(SDA=HIGH);
_nop_();_nop_();_nop_();
SCL = HIGH;
Delay5Us;
SCL=LOW;
_nop_();_nop_();
}
/*
*********************************************************************************************************************
* IIC LOW LEVEL SEND BYTE FUNCTION
* Function: This function is called to write a byte to the i2c bus in MBS first.
* The function caller(master) sends a byte, and in the 9th bit, waits for an ACK or noACK
* from the slave. The slave may reply either ACK or noACK.
* Waiting for ACK signal is NOT infinite to avoid program hang-up.
* Statement 'while((SDA==HIGH)&&(i++<0x80))' employed for ACK waiting with timeout
* Argument: 'c' the byte to send
* Return: ACK if the slave does acknowledge
* noACK if the slave didn't acknowledge
* ACK and noACK defined under iic.h, public constants
* WARNING : the type 'bit' is KEIL C specific
* Note: Hardware-dependent for direct I/O operation on SDA and SCL required.
* Delay5Us is a macro assuming the system clock (xtal) is 12MHz or less for 12-clock 8051
*********************************************************************************************************************
*/
bit i2c_SendByte(unsigned char c)
{
unsigned char i;
for(i=0;i<8;i++)
{
((c<<i)&0x80)? (SDA = HIGH):(SDA = LOW);
_nop_();
SCL = HIGH;
Delay5Us; //for data on SDA to be valid for at least 4.7usec
SCL = LOW;
}
i=0;
SDA = HIGH; //release data line to read ACK/noACK signal from slave
SCL = HIGH; //take clock line high for a stable data line read
while((SDA==HIGH)&&(i++<0x80));
(SDA==LOW)? (i = ACK):(i = noACK);
SCL = LOW;
_nop_();_nop_();
return (i);
}
/*
*********************************************************************************************************************
* IIC LOW LEVEL READ BYTE FUNCTION
* Function: This function is called to read a byte from the i2c bus.
* Argument: none
* Return: The byte read from the IIC bus
* Note: Hardware-dependent for direct I/O operation on SDA and SCL required.
* Delay5Us is a macro assuming the system clock (xtal) is 12MHz or less for 12-clock 8051
*********************************************************************************************************************
*/
unsigned char i2c_RcvByte(void)
{
unsigned char val=0;
unsigned char i;
SDA = HIGH; //release data line for input
for(i=0; i<8; i++) //bit counter from 0 to 7 (inclusive)
{
SCL = LOW;
Delay5Us;
SCL = HIGH;
_nop_();_nop_();
val = val<<1;
if (SDA==HIGH) val = val|1;
}
SCL = LOW;
_nop_();_nop_();
return (val);
}
/*
*********************************************************************************************************************
* SEQUENTIAL WRITE BYTES
* Function: This function is called to sequentially write an array/string of a certain length
* to an iic slave. STOP bit is not generated at the end of every byte written except
* the last byte.
* Argument: 'device' iic device address, e.g. 0xA0 for 24LC02 EEPROM, 0xA2 for PCF8563 RTC etc
* 'addrh' internal address's high byte, if any. If address is 8-bit,
* this should be passed a NONE defined under iic.h
* 'addrl' internal address's low address byte.
* '*s' pointer to the array/string to write
* 'length' length of the array or string to write
* Return: 'noACK' if any of the iic write action passes a bus collision error
* 'ACK' if all of the iic write action successful
* WARNING : the type 'bit' is KEIL C specific
* Note: Example:
* s[0] = 0x00; s[1] = 0x12;
* i2c_SeqWr(0xA2, NONE, 0x00, &s[0], 2); //This is to initialize PCF8563 rtc
*********************************************************************************************************************
*/
bit i2c_SeqWr(unsigned char device, unsigned char addrh, unsigned char addrl, unsigned char *s, unsigned char length)
{
unsigned char i;
i2c_Start();
if(i2c_SendByte(device)==noACK) return (noACK);
if(addrh!=NONE)
{
if(i2c_SendByte(addrh)==noACK) return (noACK);
}
if(i2c_SendByte(addrl)==noACK) return (noACK);
for (i=0;i<length;i++)
{
if(i2c_SendByte(*s)==noACK) return (noACK);
s++;
}
i2c_Stop();
return (ACK);
}
/*
*********************************************************************************************************************
* SEQUENTIAL READ BYTES
* Function: This function is called to sequentially read an array/string of a certain length
* from an iic slave.
* Argument: 'device' iic device address, e.g. 0xA0 for 24LC02 EEPROM, 0xA2 for PCF8563 RTC etc
* 'addrh' internal address's high byte, if any. If address is 8-bit,
* this should be passed a NONE defined under iic.h
* 'addrl' intermal address's low address byte.
* '*s' pointer to the array/string to read
* 'length' length of the array or string to write
* Return: 'noACK' if any of the iic write action passes a bus collision error
* 'ACK' if all of the iic write action successful
* WARNING : the type 'bit' is KEIL C specific. Array/string passed to *s should be large enough to hold the
* total data length.
* Note:
*********************************************************************************************************************
*/
bit i2c_SeqRd(unsigned char device, unsigned char addrh, unsigned char addrl, unsigned char *s, unsigned char length)
{
unsigned char i;
i2c_Start();
if(i2c_SendByte(device)==noACK) return (noACK);
if(addrh!=NONE)
{
if(i2c_SendByte(addrh)==noACK) return (noACK);
}
if(i2c_SendByte(addrl)==noACK) return (noACK);
i2c_Start();
//RTC_ADDR+1 = 1010 001R/W, R/W = 1 for READ, R/W = 0 for WRITE
if(i2c_SendByte(device+1)==noACK) return (noACK);
for(i=0; i<length-1; i++)
{
*s = i2c_RcvByte();
i2c_Ack(ACK);
s++;
}
*s = i2c_RcvByte();
i2c_Ack(noACK);
i2c_Stop();
return (ACK);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -