"I2C bus protocol program"
In the process of use, we must pay attention to timing and time.
i2c.c
/*
I2C.c
Host program of standard 80C51 single chip microcomputer simulating I2C bus
All rights reserved.
*/
#include “I2C.h”
//Define delay variables for macro I2C_ Delay()
unsigned char data I2C_ Delay_ t;
/*
Macro definition: I2C_ Delay()
Function: delay, analog I2C bus special
*/
#define I2C_ Delay()\
{\
I2C_ Delay_ t = (I2C_ DELAY_ VALUE);\
while ( --I2C_ Delay_ t != 0 );\
}
/*
Function: I2C_ Init()
Function: I2C bus initialization to make the bus idle
Note: at the beginning of the main() function, this function should normally be executed once
*/
void I2C_ Init()
{
I2C_ SCL = 1;
I2C_ Delay();
I2C_ SDA = 1;
I2C_ Delay();
}
/*
Function: I2C_ Start()
Function: generate the initial state of I2C bus
explain:
When SCL is at high level, I2C bus is started when SDA has falling edge
No matter what level state SDA and SCL are in, this function can always correctly generate the starting state
This function can also be used to generate a repeat start state
After this function is executed, I2C bus is busy
*/
void I2C_ Start()
{
I2C_ SDA = 1;
I2C_ Delay();
I2C_ SCL = 1;
I2C_ Delay();
I2C_ SDA = 0;
I2C_ Delay();
I2C_ SCL = 0;
I2C_ Delay();
}
/*
Function: I2C_ Write()
Function: write 1 byte of data to I2C bus
Parameters:
Dat: data to be written to the bus
*/
void I2C_ Write(char dat)
{
unsigned char t = 8;
do
{
I2C_ SDA = (bit)(dat & 0x80);
dat 《《= 1;
I2C_ SCL = 1;
I2C_ Delay();
I2C_ SCL = 0;
I2C_ Delay();
} while ( --t != 0 );
}
/*
Function: I2C_ Read()
Function: read 1 byte of data from the slave
Return: one byte of data read
*/
char I2C_ Read()
{
char dat;
unsigned char t = 8;
I2C_ SDA = 1; // Pull the SDA up before reading data
do
{
I2C_ SCL = 1;
I2C_ Delay();
dat 《《= 1;
if ( I2C_ SDA ) dat |= 0x01;
I2C_ SCL = 0;
I2C_ Delay();
} while ( --t != 0 );
return dat;
}
/*
Function: I2C_ GetAck()
Function: read slave response bit
return:
0: slave response
1: Slave non response
explain:
After receiving each byte of data, the slave will generate a reply bit
After receiving the last byte of data, the slave generally generates a non reply bit
*/
bit I2C_ GetAck()
{
bit ack;
I2C_ SDA = 1;
I2C_ Delay();
I2C_ SCL = 1;
I2C_ Delay();
ack = I2C_ SDA;
I2C_ SCL = 0;
I2C_ Delay();
return ack;
}
/*
Function: I2C_ PutAck()
Function: the host generates reply bit or non reply bit
Parameters:
ACK = 0: the host generates a response bit
ACK = 1: the host generates a non response bit
explain:
After receiving each byte of data, the host should generate a reply bit
After receiving the last byte of data, the host shall generate a non reply bit
*/
void I2C_ PutAck(bit ack)
{
I2C_ SDA = ack;
I2C_ Delay();
I2C_ SCL = 1;
I2C_ Delay();
I2C_ SCL = 0;
I2C_ Delay();
}
/*
Function: I2C_ Stop()
Function: generate the stop state of I2C bus
explain:
When SCL is at high level, stop I2C bus when SDA has a rising edge
No matter what level state SDA and SCL are in, this function can always correctly generate the stop state
After this function is executed, I2C bus is idle
*/
void I2C_ Stop()
{
unsigned int t = I2C_ STOP_ WAIT_ VALUE;
I2C_ SDA = 0;
I2C_ Delay();
I2C_ SCL = 1;
I2C_ Delay();
I2C_ SDA = 1;
I2C_ Delay();
while ( --t != 0 ); // Before the next start is generated, a certain delay shall be added
}
/*
Function: I2C_ Puts()
Function: I2C bus integrated sending function to send multiple bytes of data to the slave
Parameters:
Slaveaddr: slave address (7-Bit pure address, excluding read-write bits)
Subaddr: slave's subaddress
Submod: sub address mode, 0 - no sub address, 1 - single word node sub address, 2 - double word node sub address
*Dat: data to send
Size: number of bytes of data
return:
0: sent successfully
1: An exception occurred during sending
explain:
This function can be well adapted to all common I2C devices, whether they have sub addresses or not
When the slave has no sub address, the parameter subaddr is arbitrary, and submod should be 0
*/
bit I2C_ Puts
(
unsigned char SlaveAddr,
unsigned int SubAddr,
unsigned char SubMod,
char *dat,
unsigned int Size
)
{
//Define temporary variables
unsigned char i;
char a[3];
//Check length
if ( Size == 0 ) return 0;
//Prepare slave address
a[0] = (SlaveAddr 《《 1);
//Check subaddress mode
if ( SubMod 》 2 ) SubMod = 2;
//Determine sub address
switch ( SubMod )
{
case 0:
break;
case 1:
a[1] = (char)(SubAddr);
break;
case 2:
a[1] = (char)(SubAddr 》》 8);
a[2] = (char)(SubAddr);
break;
default:
break;
}
//Send the slave address, and then send the sub address (if any)
SubMod++;
I2C_ Start();
for ( i=0; i
{
I2C_ Write(a[i]);
if ( I2C_ GetAck() )
{
I2C_ Stop();
return 1;
}
}
//Send data
do
{
I2C_ Write(*dat++);
if ( I2C_ GetAck() ) break;
} while ( --Size != 0 );
//After sending, stop the I2C bus and return the result
I2C_ Stop();
if ( Size == 0 )
{
return 0;
}
else
{
return 1;
}
}
/*
Function: I2C_ Gets()
Function: I2C bus integrated receiving function to receive multiple bytes of data from the slave
Parameters:
Slaveaddr: slave address (7-Bit pure address, excluding read-write bits)
Subaddr: slave's subaddress
Submod: sub address mode, 0 - no sub address, 1 - single word node sub address, 2 - double word node sub address
*Dat: save the received data
Size: number of bytes of data
return:
0: received successfully
1: An exception occurred during reception
explain:
This function can be well adapted to all common I2C devices, whether they have sub addresses or not
When the slave has no sub address, the parameter subaddr is arbitrary, and submod should be 0
*/
bit I2C_ Gets
(
unsigned char SlaveAddr,
unsigned int SubAddr,
unsigned char SubMod,
char *dat,
unsigned int Size
)
{
//Define temporary variables
unsigned char i;
char a[3];
//Check length
if ( Size == 0 ) return 0;
//Prepare slave address
a[0] = (SlaveAddr 《《 1);
//Check subaddress mode
if ( SubMod 》 2 ) SubMod = 2;
//If it is a slave with sub address, the slave address and sub address shall be sent first
if ( SubMod != 0 )
{
//Determine sub address
if ( SubMod == 1 )
{
a[1] = (char)(SubAddr);
}
else
{
a[1] = (char)(SubAddr 》》 8);
a[2] = (char)(SubAddr);
}
//Send the slave address, and then send the sub address
SubMod++;
I2C_ Start();
for ( i=0; i
{
I2C_ Write(a[i]);
if ( I2C_ GetAck() )
{
I2C_ Stop();
return 1;
}
}
}
//I2C here_ Start() is a repeated start state for a slave with a child address
//For the slave without sub address, it is the normal starting state
I2C_ Start();
//Send slave address
I2C_ Write(a[0]+1);
if ( I2C_ GetAck() )
{
I2C_ Stop();
return 1;
}
//Receive data
for (;;)
{
*dat++ = I2C_ Read();
if ( --Size == 0 )
{
I2C_ PutAck(1);
break;
}
I2C_ PutAck(0);
}
//After receiving, stop the I2C bus and return the result
I2C_ Stop();
return 0;
}
i2c.h
/*
I2C.h
Host program header file of standard 80C51 single chip microcomputer simulating I2C bus
Copyright (c) 2005, Guangzhou zhouligong Single Chip Microcomputer Development Co., Ltd
All rights reserved.
This procedure is for learning reference only and does not provide any guarantee of reliability; Do not use for commercial purposes
*/
#ifndef _ I2C_ H_
#define _ I2C_ H_
#include
//Pin definition of analog I2C bus
sbit I2C_ SCL = P3^4;
sbit I2C_ SDA = P3^5;
//Define the delay value of I2C bus clock, which shall be modified according to the actual situation, with the value of 1 ~ 255
//The SCL signal period is about (I2C)_ DELAY_ Value * 4 + 15) machine cycles
#
Our other product: