这是我最近工程中的I2C程序,工作模式参考了意法半导体的I2C中断模式例程,你参考一下吧!
由于是工程中的一部分,有些东西对你可能没用,但你可以参考一下。
该工程项目S105B-1024中,主器件:ADP2013V1-08(使用STM8S105),从器件:YB125003,DS1307;
主器件每100ms读取从器件寄存器,项目产品在重型车间运行1个多月未停机,所有数据正常。
/*******************************************************************************
// STM8系列MCU的I2C主模式程序(直接运行,无中断)
//
// 输出函数:
// extern void I2CM_Init(void);
// 模块初始化
// extern void I2CM_RunTimeOut(void);
// 模块超时计数
// extern uchar I2CM_Write(uchar SlaveAddr,uchar RegAddr,uchar NumByte,uchar *DataBuf);
// I2C主器件向从器件写入数据函数
// extern uchar I2CM_Read(uchar SlaveAddr,uchar RegAddr,uchar NumByte,uchar *DataBuf);
// I2C主器件从从器件读取数据函数
// extern uchar I2CM_RandomRead(uchar SlaveAddr, uchar NumByte, uchar *DataBuf);
// I2C主器件直接读取从器件(不指定寄存器地址)函数(内部使用)
//
// 说明:
// 1、当发生超时错误后,EState保存第一次错误现场状态;
// 2、所有有返回结果的函数,返回0:操作失败;返回1:操作成功;
//
// 注意:
// 1、部分MCU在默认情况下,PB4、PB5端口的复用为ADC输入,若强行启动I2C,SR3的BUSY为恒为1
// 若要将I2C的SDA、SCL连接到PB4、PB5上,需要使用STTools将复用设置给为I2C
//
// 调试:
// 1、在独立项目中,主器件:ADP2013V1-08,从器件:YB125003、DS1307
// 读写操作成功:2013-10-25
// 2、在项目S105B-1024中,主器件:ADP2013V1-08,从器件:YB125003、DS1307
// 读写操作成功:2013-10-25
*******************************************************************************/
#ifndef __STM8I2CMaster
#define __STM8I2CMaster
#include "iostm8s105k4.h"
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
#ifndef ulong
#define ulong unsigned long
#endif
/** @addtogroup I2C_Registers_Bits_Definition
* @{
*/
#define I2C_CR2POS ((uchar)0x08) /*!< Acknowledge */
#define I2C_CR2ACK ((uchar)0x04) /*!< Acknowledge Enable */
#define I2C_CR2STOP ((uchar)0x02) /*!< Stop Generation */
#define I2C_CR2START ((uchar)0x01) /*!< Start Generation */
#define I2C_SR1RXNE ((uchar)0x40) /*!< Data Register not Empty (receivers) */
#define I2C_SR1BTF ((uchar)0x04) /*!< Byte Transfer Finished */
#define I2C_SR1ADDR ((uchar)0x02) /*!< Address sent (master mode)/matched (slave mode) */
#define I2C_SR1SB ((uchar)0x01) /*!< Start Bit (Master mode) */
#define I2C_SR3BUSY ((uchar)0x02) /*!< Bus Busy */
#define INI_00 00
// Write states 0x
#define SB_01 01
#define ADDR_03 03
#define BTF_04 04
#define REGADDR_05 05
#define STOP_06 06
// Read states 1x
#define SB_11 11
#define ADDR_13 13
#define BTF_14 14
#define BTF_15 15
#define RXNE_16 16
#define RXNE_17 17
#define STOP_18 18
#define I2C_TOUT 20
#define I2C_BECount 300
uchar STATE = 0;
uchar EState = 0;
uint ETCount = 0;
uint EBusy = 0;
extern void I2CM_Init(void);
extern void I2CM_RunTimeOut(void);
extern uchar I2CM_GetLastError(void);
extern uchar I2CM_Write(uchar SlaveAddr,uchar RegAddr,uchar NumByte,uchar *DataBuf);
extern uchar I2CM_Read(uchar SlaveAddr,uchar RegAddr,uchar NumByte,uchar *DataBuf);
extern uchar I2CM_RandomRead(uchar SlaveAddr, uchar NumByte, uchar *DataBuf);
static void SetSTATE(uchar iState);
void I2CM_Init( void )
{
CLK_PCKENR1 |= 0x01; // 打开f(MASTER)与外设I2C的连接
//define SDA, SCL outputs 可以不需要设置
PB_DDR_DDR4 = 1; // 设置为输出
PB_CR1_C14 = 1; // 设置为推挽
PB_CR2_C24 = 0;
PB_DDR_DDR5 = 1; // 设置为输出
PB_CR1_C15 = 1; // 设置为推挽
PB_CR2_C25 = 0;
I2C_CR1_PE = 0;
I2C_FREQR = 8; // input clock to I2C - 16MHz
I2C_CCRH = 0x00; // standard mode, duty 1/1 bus speed 100kHz
I2C_CCRL = 0xA0; // CCR= 40 - (SCLhi must be at least 4000+1000=5000ns!)
I2C_TRISER = 5; // 1000ns/(125ns) + 1 (maximum 1000ns)
I2C_OARH |= 0x40;
I2C_OARL = 0xA0; // own address A0;
//I2C_ITR = 7; // enable Event & error interrupts
I2C_CR2 |= 0x04; // ACK=1, Ack enable
I2C_CR1 &= ~0x80; // Stretch enable
I2C_CR1_PE = 1;
SetSTATE(INI_00);
}
/******************************************************************************
I2C主模式写入函数
参数:
uchar SlaveAddr, 从器件地址
uchar RegAddr, 从器件寄存器地址
uchar NumByte, 要写入的数据字节数
uchar *DataBuf 要写入的数据
输出:
0:写入失败
1:写入成功
*******************************************************************************/
uchar I2CM_Write(uchar SlaveAddr,uchar RegAddr,uchar NumByte,uchar *DataBuf)
{
uchar i;
SetSTATE(INI_00);
if (!EBusy){EBusy = 1;}
/*--------------- BUSY? -> STOP request ---------------------*/
if ((I2C_SR3 & I2C_SR3BUSY)||I2C_CR2_SWRST)
{
return 0;
}
/*--------------- Start communication -----------------------*/
I2C_CR2 |= I2C_CR2START; // START=1, generate start
SetSTATE(SB_01);
while((!EState)&&(!(I2C_SR1 & I2C_CR2START))); // wait for start bit detection (SB)
/*------------------ Address send ---------------------------*/
I2C_DR = SlaveAddr<<1; // Send 7-bit device address & Write (R/W = 1/0)
SetSTATE(ADDR_03);
while((!EState)&&(!(I2C_SR1 & I2C_SR1ADDR))); // Wait for address ACK (ADDR)
I2C_SR1;
I2C_SR3;
/*--------------- Register/Command send ----------------------*/
I2C_DR = RegAddr; // 发送寄存器地址
SetSTATE(REGADDR_05);
while((!EState)&&(!(I2C_SR1 & I2C_CR2ACK))); // Wait for address ACK
/*------------------- Data Write --------------------------*/
for(i=0;i<NumByte;i++) // 发送数据(如果有数据)
{
I2C_SR3;
I2C_DR = *(DataBuf+i); // Reading next data byte
SetSTATE(BTF_04);
while((!EState)&&(!(I2C_SR1 & I2C_CR2ACK)));
}
/*--------------- Stop -----------------------*/
SetSTATE(STOP_06);
I2C_CR2 |= I2C_CR2STOP; //产生停止位
while((!EState)&&(I2C_CR2 & I2C_CR2STOP)); // Wait until stop is performed (STOPF = 1)
/*--------------- All Data Writed -----------------------*/
SetSTATE(INI_00);
if (EBusy){EBusy = 0;}
return !EState;
}
/******************************************************************************
I2C主模式从指定寄存器开始读取函数
参数:
uchar SlaveAddr, 从器件地址
uchar RegAddr, 从器件寄存器地址
uchar NumByte, 要写入的数据字节数
uchar *DataBuf 要写入的数据
输出:
0:读取失败
1:读取成功
*******************************************************************************/
uchar I2CM_Read(uchar SlaveAddr,uchar RegAddr,uchar NumByte,uchar *DataBuf)
{
if (I2CM_Write(SlaveAddr,RegAddr,0,DataBuf)) // 从器件寄存器地址指针移动到目标位置
{
return I2CM_RandomRead(SlaveAddr,NumByte,DataBuf);
}
else
{return 0;}
}
/******************************************************************************
I2C主模式直接读取函数
参数:
uchar SlaveAddr, 从器件地址
uchar NumByte, 要写入的数据字节数
uchar *DataBuf 要写入的数据
输出:
0:读取失败
1:读取成功
*******************************************************************************/
uchar I2CM_RandomRead(uchar SlaveAddr, uchar NumByte, uchar *DataBuf)
{
SetSTATE(INI_00);
if (!EBusy){EBusy = 0;}
/*--------------- BUSY? -> STOP request ---------------------*/
if ((I2C_SR3 & I2C_SR3BUSY)||I2C_CR2_SWRST)
{
return 0;
}
I2C_CR2 |= I2C_CR2ACK; // ACK=1, Ack enable
/*--------------- Start communication -----------------------*/
I2C_CR2 |= I2C_CR2START; // START=1, generate start
SetSTATE(SB_11);
while((!EState)&&(!(I2C_SR1 & I2C_CR2START))); // wait for start bit detection (SB)
/*------------------ Address send ---------------------------*/
I2C_DR = (uchar)(SlaveAddr << 1) | 1; // Send 7-bit device address & Write (R/W = 1/0)
SetSTATE(ADDR_13);
while((!EState)&&(!(I2C_SR1 & I2C_SR1ADDR))); // Wait for address ACK (ADDR)
/*------------------- Data Receive --------------------------*/
if (NumByte > 2)
// *** more than 2 bytes are received? ***
{
I2C_SR3; // ADDR clearing sequence
while(NumByte > 3 ) // not last three bytes?
{
SetSTATE(BTF_14);
while((!EState)&&((I2C_SR1 & I2C_SR1BTF) == 0)); // Wait for BTF
*DataBuf++ = I2C_DR; // Reading next data byte
--NumByte; // Decrease Numbyte to reade by 1
}
SetSTATE(BTF_14); //last three bytes should be read
while((!EState)&&((I2C_SR1 & I2C_SR1BTF) == 0)); // Wait for BTF
I2C_CR2 &=~I2C_CR2ACK; // Clear ACK
*DataBuf++ = I2C_DR; // Read 1st byte
I2C_CR2 |= I2C_CR2STOP; // Generate stop here (STOP=1)
*DataBuf++ = I2C_DR; // Read 2nd byte
SetSTATE(RXNE_16);
while((!EState)&&((I2C_SR1 & I2C_SR1RXNE)==0)); // Wait for RXNE
*DataBuf++ = I2C_DR; /// Read 3rd Data byte
SetSTATE(STOP_18);
}
else
{
if(NumByte == 2)
// *** just 2 bytes are received? ***
{
I2C_CR2 |= I2C_CR2POS; // Set POS bit (NACK at next received byte)
I2C_SR3; // Clear ADDR Flag
I2C_CR2 &=~I2C_CR2ACK; // Clear ACK
SetSTATE(BTF_15);
while((!EState)&&((I2C_SR1 & I2C_SR1BTF) == 0)); // Wait for BTF
I2C_CR2 |= I2C_CR2STOP; // Generate stop here (STOP=1)
*DataBuf++ = I2C_DR; // Read 1st Data byte
*DataBuf = I2C_DR; // Read 2nd Data byte
SetSTATE(STOP_18);
}
else
// *** only 1 byte is received ***
{
I2C_CR2 &=~I2C_CR2ACK;; // Clear ACK
I2C_SR3; // Clear ADDR Flag
I2C_CR2 |= I2C_CR2STOP; // generate stop here (STOP=1)
SetSTATE(RXNE_17);
while((!EState)&&((I2C_SR1 & I2C_SR1RXNE) == 0)); // test EV7, wait for RxNE
*DataBuf = I2C_DR; // Read Data byte
SetSTATE(STOP_18);
}
}
/*--------------- All Data Received -----------------------*/
while((!EState)&&(I2C_CR2 & I2C_CR2STOP)); // Wait until stop is performed (STOPF = 1)
I2C_CR2 &=~I2C_CR2POS; // return POS to default state (POS=0)
SetSTATE(INI_00);
if (EBusy){EBusy = 0;}
return !EState;
}
/******************************************************************************
I2C主模式工作状态设置函数
参数:
uchar iState I2C当前工作状态
说明:
1、当前如果错误状态(EState)不为0,所有设置无效
*******************************************************************************/
void SetSTATE(uchar iState)
{
if (!EState)
{
STATE = iState;
EState = 0;
if (STATE)
{ETCount = 1;}
else
{ETCount = 0;}
}
}
/******************************************************************************
I2C主模式超时计数函数
说明:
1、该函数必须放在100us定时器中断事件中运行,保证每个I2C操作计算超时;
2、以下状态,超时不计数;
A、当错误状态(EState)不为0;
B、当I2C工作状态(STATE)为0;
C、计数器(ETCount)为0;
3、当第一次发生超时,将I2C当前工作状态(STATE)保存到错误状态(EState)中;
*******************************************************************************/
void I2CM_RunTimeOut(void)
{
if (I2C_CR2_SWRST)
{I2C_CR2_SWRST = 0;}
if ((!EState)&&STATE&&ETCount&&(++ETCount>I2C_TOUT))
{
ETCount = 0;
EState = STATE;
}
if (EBusy&&(++EBusy>20))
{
I2C_SR3;
I2C_CR2 |= I2C_CR2ACK;
I2C_CR2 |= I2C_CR2START;
I2C_DR = EBusy;
I2C_CR2 |= I2C_CR2STOP;
I2C_CR2_SWRST = 1;
EBusy = 0;
}
}
uchar I2CM_GetLastError(void)
{
uchar iResult;
iResult = EState;
EState = 0;
return iResult;
}
#endif //__STM8I2CMaster |