STM8 的MCU有四个供电单元
【STM8-SO8】08-STM8L001J3的点灯
STM8单片机如何实现Bootloader
基于STM8的DALI (数字可寻址调光协议)
开源基于STM32的STM8脱机编程器
【ST MCU实战经验】之STM8中UART奇偶校验的使用方法
【思修电子STM8集合贴】龙顺宇STM8理论/实战视频/书籍/软件/
初次尝试STM8S001J3
分享STM8 风驰光盘的资料,是完整的(包括原理图+例程+PDF注释)
基于STM8的实验代码汇总分享
微信公众号
手机版
/*==========================================================================================================
函数名称: 设置I2C总线为标准/快速模式和占空比
函数功能: 本函数用于设置I2C总线为标准/快速模式和占空比操作的函数。
函数入口参数:Model ----------------- 标准/快速模式和占空比, ON(快速模式)/ OFF(标准模式)。
函数返回值: 没有
调用函数: 1.
备注: 1.
==========================================================================================================*/
void CommI2cBusModeDuty (unsigned char Model)
{
#if (defined(_IAR_EW_AVR_))
#elif ((defined(_IAR_EW_MCS51_)) || (defined(_KEIL_UV_MCS51_)))
#elif ( defined(_IAR_EW_STM8_) \
|| defined(_COSMIC_STM8_) ) // “......_STM8 编译器”条件编译开始
#ifdef _USE_STM8_FWLIB_ // “使用 STM8 FWLib 的库文件”条件编译开始
#else // “_USE_STM8_FWLIB_”
I2CCR1 &= (u8)(~((1<<i2cEN ) )); // 禁止I2C模块,用以设置 I2CTRISER。
if (Model == ON) // 快速模式:占空比=Tlow/Thigh=2/1
{
I2CCCRH = (u8)( ((0<<i2cDUTY )| // 快速模式下的占空比=0:Tlow/Thigh=2/1,1:Tlow/Thigh=16/9。
(1<<i2cSFM )| // 标准/快速模式选择位=快速模式
cI2c0BrCcrF21H )); // 置I2C比特率高位寄存器的数值,注:只有禁用I2C模块时,才能设置。
I2CCCRL = (u8)( cI2c0BrCcrF21L); // 置I2C比特率低位寄存器的数值,注:只有禁用I2C模块时,才能设置。
I2CTRISER = (u8)( ((((cSysCpuClk / 1000000UL) * 3UL) / 10UL) + 1));
// 快速模式:最大上升时间=300ns,注:只有禁用I2C模块时,才能设置。
}
else // 标准模式:占空比=Tlow/Thigh=1/1
{
I2CCCRH = (u8)( ((0<<i2cDUTY )| // 快速模式下的占空比=0:Tlow/Thigh=2/1,1:Tlow/Thigh=16/9。
(0<<i2cSFM )| // 标准/快速模式选择位=标准模式
cI2c0BrCcrS11H )); // 置I2C比特率高位寄存器的数值,注:只有禁用I2C模块时,才能设置。
I2CCCRL = (u8)( cI2c0BrCcrS11L); // 置I2C比特率低位寄存器的数值,注:只有禁用I2C模块时,才能设置。
I2CTRISER = (u8)( ((cSysCpuClk / 1000000UL) + 1));// 标准模式:最大上升时间=1000ns,注:只有禁用I2C模块时,才能设置。
}
I2CCR1 |= (u8)( ((1<<i2cEN ) )); // 使能I2C模块
#endif // “_USE_STM8_FWLIB_”
#else
#error 错误:
#endif // “PreMcuIs__......”
}
#ifdef PreCommI2cUseSingleMasterMode // “I2C总线工作于单主机方式”的条件编译
/*==========================================================================================================
函数名称: I2C总线工作于单主机方式,重新启动I2C总线前一个通讯收发作业
函数功能: 本函数用于I2C总线工作于单主机方式,重新启动I2C总线前一个通讯收发作业操作的函数。
函数入口参数:gbitI2c.Txd ------------- “正在进行发送数据作业”标志。
gbitI2c.Rxd ------------- “正在进行接收数据作业”标志。
函数返回值: 没有
函数出口参数:gucvI2cEvent ---------- I2C总线的状态码变量,出口值= cI2cAllNoState(没有相关的状态信息) 。
gstvI2c.TxBuf[0] ------ 每次发送数据缓冲区数组变量,出口值=要发送的地址。
gstvI2c.ErrNum -------- I2C总线的通讯收发作业发生错误次数值变量,出口值=0。
gstvI2c.RxCnt --------- 每次接收数据个数计数器变量,出口值=0。
调用函数: 1.
备注: 1.调用本函数将触发两线串行总线接口TWI中断请求和向I2C总线发出 START 信号(起始条件)。
==========================================================================================================*/
static void CommI2cBusAgain (void)
{
#if cI2cTxBufSize < 256
register unsigned char i; // 循环变量
#else
register unsigned int i;
#endif
unsigned char temp; // 临时变量
CommI2cDataStru *pI2c; // 指向I2C总线通讯收发数据处理变量的指针
pI2c = &gstvI2c; // 取I2C总线通讯收发数据处理变量的首个地址
MFHI2cBusModSwRst( ); // 软件复位I2C模块,释放I2C总线
gucvI2cEvent = cI2cAllNoState; // 置I2C总线的状态码 = 没有相关的状态信息
if ( (gbitI2c.Txd == SET) // 如果是先发送若干地址然后再进行发送数据作业?
&& (gbitI2c.Rxd == SET) )
{
pI2c->TxBuf[0] &= (u8)(~BIT0); // 设置数据传送方向为写入数据
}
pI2c->RxCnt = 0x00; // I2C总线每次接收数据个数计数器清0
pI2c->ErrNum = 0x00; // I2C总线的通讯收发作业发生错误次数值清0
MFHI2cFlgEventClr( ); // 清0I2C总线事件中断标志位
MFHI2cIntEventOne( ); // 使能I2C总线事件中断、错误中断,禁止缓冲中断
MFHI2cBusNackStar( ); // 发出 START 信号(起始条件),没有 ACK 脉冲
}
/*==========================================================================================================
函数名称: 启动I2C总线应用中断方式发送数据
函数功能: 本函数用于启动I2C总线使用中断方式,进行通讯发送数据作业操作的函数。
函数入口参数:Object ------------------ 要发送数据的的目标设备地址值。
*pData ------------------ 指向首个要发送数据在SRAM中的地址指针。
Length ------------------ 要发送数据的数据总长度。
函数返回值: 没有
函数出口参数:gbitI2c.Busy ------------ I2C总线〖忙〗,出口值=置位。
gbitI2c.Txd ------------- “正在进行发送数据作业”标志,出口值=置位。
gbitI2c.Rxd ------------- “正在进行接收数据作业”标志,出口值=清位。
gucvI2cEvent ------------ I2C总线的状态码变量,出口值= cI2cAllNoState(没有相关的状态信息) 。
gstvI2c.TxSize ---------- 每次发送数据个数大小变量,出口值=Length + cI2cAddrNum。
gstvI2c.TxCnt ----------- 每次发送数据个数计数器变量,出口值=0。
gstvI2c.TxBuf[] --------- 每次发送数据缓冲区数组变量,出口值=要发送的数据。
gstvI2c.Cycle ----------- 重新启动通讯收发作业圈数,出口值=0。
gstvI2c.ErrNum ---------- 通讯收发作业发生错误次数,出口值=0。
调用函数: 1.
备注: 1.注意:调用本函数之前,必须确定I2C总线在空闲状态。即必须先调用
“unsigned char CommI2cBusBusy(void)”函数,来检查I2C总线的工作状态,
只有I2C总线处于空闲状态,才允许调用本函数。
2.调用本函数将触发两线串行总线接口TWI中断请求和向I2C总线发出 START 信号(起始条件)。
==========================================================================================================*/
#if cI2cTxBufSize < 256
void CommI2cTxWithData (unsigned char Object, unsigned char *pData, unsigned char Length)
#else
void CommI2cTxWithData (unsigned char Object, unsigned char *pData, unsigned int Length)
#endif
{
#if cI2cTxBufSize < 256
register unsigned char i; // 循环变量
#else
register unsigned int i;
#endif
unsigned char temp; // 临时变量
CommI2cDataStru *pI2c; // 指向I2C总线通讯收发数据处理变量的指针
pI2c = &gstvI2c; // 取I2C总线通讯收发数据处理变量的首个地址
#ifdef PreCommI2cWithRedundantCode // “使用冗余程序代码”条件编译开始
if ( (Length >= (cI2cTxBufSize - 1))
|| (Length == 0) )
{
return;
}
#endif // “PreCommI2cWithRedundantCode”
MFHI2cBusModSwRst( ); // 软件复位I2C模块,释放I2C总线
// while(CommI2cBusBusy( )); // 等待直到对TWI下一个收发作业准备就绪为止
gbitI2c.Busy = SET; // 置“I2C总线〖忙〗”标志
gbitI2c.Txd = SET; // 置“正在进行发送数据作业”标志
gbitI2c.Rxd = CLEAR; // 清除“正在进行接收数据作业”标志
gbitI2c.OverS = SET; // 置“通讯任务时间超时”标志
gucvI2cEvent = cI2cAllNoState; // 置I2C总线的状态码 = 没有相关的状态信息
pI2c->OverS = RtcGetSecByte(cI2cOverSec);// 启动通讯任务时间计时秒表
// pI2c->Object = Object; // 复制目标设备地址到每次发送数据的目标设备地址中
// pI2c->Object &= (u8)(~BIT0); // 设置数据传送方向为写入数据
// pUsart->pTxData = pData; // 保存要发送的数据序列的地址指针
MemCopySramToSram(&Object, pI2c->TxBuf, cI2cAddrNum); // 复制目标设备地址到发送数据缓冲区中
pI2c->TxBuf[0] &= (u8)(~BIT0); // 设置数据传送方向为写入数据
MemCopySramToSram(pData, &pI2c->TxBuf[cI2cAddrNum], Length);
// 复制发送的数据序列到发送数据缓冲区中
pI2c->TxSize = Length + cI2cAddrNum; // 置每次发送数据个数大小值
pI2c->TxCnt = 0x00; // 每次发送数据计数器值清0
pI2c->Cycle = 0x00; // 重新启动通讯收发作业圈数清0
pI2c->ErrNum = 0x00; // I2C总线的通讯收发作业发生错误次数清0
MFHI2cFlgEventClr( ); // 清0I2C总线事件中断标志位
MFHI2cIntEventOne( ); // 使能I2C总线事件中断、错误中断,禁止缓冲中断
MFHI2cBusNackStar( ); // 发出 START 信号(起始条件),没有 ACK 脉冲
}
/*==========================================================================================================
函数名称: 启动I2C总线应用中断方式接收数据
函数功能: 本函数用于启动I2C总线使用中断方式,进行通讯接收数据作业操作的函数。
函数入口参数:Object ------------------ 要接收数据的的目标设备地址值。
Length ------------------ 要接收数据的数据总长度。
函数返回值: 没有
函数出口参数:gbitI2c.Busy ------------ I2C总线〖忙〗,出口值=置位。
gbitI2c.Txd ------------- “正在进行发送数据作业”标志,出口值=清位。
gbitI2c.Rxd ------------- “正在进行接收数据作业”标志,出口值=置位。
gucvI2cEvent ------------ I2C总线的状态码变量,出口值= cI2cAllNoState(没有相关的状态信息) 。
gstvI2c.TxSize ---------- 每次发送数据个数大小变量,出口值=cI2cAddrNum。
gstvI2c.TxCnt ----------- 每次发送数据个数计数器变量,出口值=0。
gstvI2c.TxBuf[] --------- 每次发送数据缓冲区数组变量,出口值=要发送的数据。
gstvI2c.Cycle ----------- 重新启动通讯收发作业圈数,出口值=0。
gstvI2c.ErrNum ---------- 通讯收发作业发生错误次数,出口值=0。
gstvI2c.RxSize ---------- 每次接收数据个数大小变量,出口值=Length。
gstvI2c.RxCnt ----------- 每次接收数据个数计数器变量,出口值=0。
调用函数: 1.
备注: 1.注意:调用本函数之前,必须确定I2C总线在空闲状态。即必须先调用
“unsigned char CommI2cBusBusy(void)”函数,来检查I2C总线的工作状态,
只有I2C总线处于空闲状态,才允许调用本函数。
2.调用本函数将触发两线串行总线接口TWI中断请求和向I2C总线发出 START 信号(起始条件)。
==========================================================================================================*/
#if cI2cRxBufSize < 256
void CommI2cRxWithData (unsigned char Object, unsigned char Length)
#else
void CommI2cRxWithData (unsigned char Object, unsigned int Length)
#endif
{
#if cI2cRxBufSize < 256
register unsigned char i; // 循环变量
#else
register unsigned int i;
#endif
unsigned char temp; // 临时变量
CommI2cDataStru *pI2c; // 指向I2C总线通讯收发数据处理变量的指针
pI2c = &gstvI2c; // 取I2C总线通讯收发数据处理变量的首个地址
#ifdef PreCommI2cWithRedundantCode // “使用冗余程序代码”条件编译开始
if ( (Length > cI2cRxBufSize) ) // 检查要接收数据的总个数是否超过缓冲区长度?
{
Length = cI2cRxBufSize; // 截断要接收数据的总个数
}
#endif // “PreCommI2cWithRedundantCode”
MFHI2cBusModSwRst( ); // 软件复位I2C模块,释放I2C总线
// while(CommI2cBusBusy( )); // 等待直到对TWI下一个收发作业准备就绪为止
gbitI2c.Busy = SET; // 置“I2C总线〖忙〗”标志
gbitI2c.Txd = CLEAR; // 清除“正在进行发送数据作业”标志
gbitI2c.Rxd = SET; // 置“正在进行发送数据作业”标志
gbitI2c.OverS = SET; // 置“通讯任务时间超时”标志
gucvI2cEvent = cI2cAllNoState; // 置I2C总线的状态码 = 没有相关的状态信息
pI2c->OverS = RtcGetSecByte(cI2cOverSec);// 启动通讯任务时间计时秒表
MemCopySramToSram(&Object, pI2c->TxBuf, cI2cAddrNum); // 复制目标设备地址到发送数据缓冲区中
pI2c->TxBuf[0] |= (u8)( BIT0); // 设置数据传送方向为接收数据
pI2c->TxSize = cI2cAddrNum; // 置每次发送数据个数大小值
pI2c->TxCnt = 0x00; // 每次发送数据计数器值清0
pI2c->Cycle = 0x00; // 重新启动通讯收发作业圈数清0
pI2c->ErrNum = 0x00; // I2C总线的通讯收发作业发生错误次数清0
pI2c->RxSize = Length; // 置I2C总线每次接收数据个数大小的值
pI2c->RxCnt = 0x00; // I2C总线每次接收数据个数计数器清0
MFHI2cFlgEventClr( ); // 清0I2C总线事件中断标志位
MFHI2cIntEventOne( ); // 使能I2C总线事件中断、错误中断,禁止缓冲中断
MFHI2cBusNackStar( ); // 发出 START 信号(起始条件),没有 ACK 脉冲
}
/*==========================================================================================================
函数名称: 启动I2C总线应用中断方式先发送若干地址然后再进行发送数据作业的函数。
函数功能: 本函数用于启动I2C总线使用中断方式,进行通讯先发送若干地址然后再进行发送数据作业操作的函数。
函数入口参数:Object ------------------ 要发送数据的的目标设备地址值。
*pAddr ------------------ 指向首个要发送地址在SRAM中的地址指针。
LenAddr ----------------- 要发送地址的地址总长度。
*pData ------------------ 指向首个要发送数据在SRAM中的地址指针。
Length ------------------ 要发送数据的数据总长度。
函数返回值: 没有
函数出口参数:gbitI2c.Busy ------------ I2C总线〖忙〗,出口值=置位。
gbitI2c.Txd ------------- “正在进行发送数据作业”标志,出口值=置位。
gbitI2c.Rxd ------------- “正在进行接收数据作业”标志,出口值=清位。
gucvI2cEvent ------------ I2C总线的状态码变量,出口值= cI2cAllNoState(没有相关的状态信息) 。
gstvI2c.TxSize ---------- 每次发送数据个数大小变量,出口值=LenAddr + Length + cI2cAddrNum。
gstvI2c.TxCnt ----------- 每次发送数据个数计数器变量,出口值=0。
gstvI2c.TxBuf[] --------- 每次发送数据缓冲区数组变量,出口值=要发送的地址和数据。
gstvI2c.Cycle ----------- 重新启动通讯收发作业圈数,出口值=0。
gstvI2c.ErrNum ---------- 通讯收发作业发生错误次数,出口值=0。
调用函数: 1.
备注: 1.注意:调用本函数之前,必须确定I2C总线在空闲状态。即必须先调用
“unsigned char CommI2cBusBusy(void)”函数,来检查I2C总线的工作状态,
只有I2C总线处于空闲状态,才允许调用本函数。
2.调用本函数将触发两线串行总线接口TWI中断请求和向I2C总线发出 START 信号(起始条件)。
==========================================================================================================*/
#if cI2cTxBufSize < 256
void CommI2cTxWithAddr (unsigned char Object, unsigned char *pAddr, unsigned char LenAddr, unsigned char *pData, unsigned char Length)
#else
void CommI2cTxWithAddr (unsigned char Object, unsigned char *pAddr, unsigned char LenAddr, unsigned char *pData, unsigned int Length)
#endif
{
#if cI2cTxBufSize < 256
register unsigned char i; // 循环变量
#else
register unsigned int i;
#endif
unsigned char temp; // 临时变量
CommI2cDataStru *pI2c; // 指向I2C总线通讯收发数据处理变量的指针
pI2c = &gstvI2c; // 取I2C总线通讯收发数据处理变量的首个地址
#ifdef PreCommI2cWithRedundantCode // “使用冗余程序代码”条件编译开始
if ( ((LenAddr + Length) > (cI2cTxBufSize - 1)) // 检查要接收数据的总个数是否超过缓冲区长度?
|| (LenAddr == 0) )
{
return;
}
#endif // “PreCommI2cWithRedundantCode”
MFHI2cBusModSwRst( ); // 软件复位I2C模块,释放I2C总线
// while(CommI2cBusBusy( )); // 等待直到对TWI下一个收发作业准备就绪为止
gbitI2c.Busy = SET; // 置“I2C总线〖忙〗”标志
gbitI2c.Txd = SET; // 置“正在进行发送数据作业”标志
gbitI2c.Rxd = CLEAR; // 清除“正在进行接收数据作业”标志
gbitI2c.OverS = SET; // 置“通讯任务时间超时”标志
gucvI2cEvent = cI2cAllNoState; // 置I2C总线的状态码 = 没有相关的状态信息
pI2c->OverS = RtcGetSecByte(cI2cOverSec);// 启动通讯任务时间计时秒表
// pI2c->Object = Object; // 复制目标设备地址到每次发送数据的目标设备地址中
// pI2c->Object &= (u8)(~BIT0); // 设置数据传送方向为写入数据
// pUsart->pTxData = pData; // 保存要发送的数据序列的地址指针
MemCopySramToSram(&Object, pI2c->TxBuf, cI2cAddrNum); // 复制目标设备地址到发送数据缓冲区中
pI2c->TxBuf[0] &= (u8)(~BIT0); // 设置数据传送方向为写入数据
MemCopySramToSram(pAddr, &pI2c->TxBuf[cI2cAddrNum], LenAddr);
// 复制发送的地址序列到发送数据缓冲区中
MemCopySramToSram(pData, &pI2c->TxBuf[LenAddr + cI2cAddrNum], Length);
// 复制发送的数据序列到发送数据缓冲区中
pI2c->TxSize = LenAddr + Length + cI2cAddrNum;
// 置每次发送数据个数大小值
pI2c->TxCnt = 0x00; // 每次发送数据计数器值清0
pI2c->Cycle = 0x00; // 重新启动通讯收发作业圈数清0
pI2c->ErrNum = 0x00; // I2C总线的通讯收发作业发生错误次数清0
MFHI2cFlgEventClr( ); // 清0I2C总线事件中断标志位
MFHI2cIntEventOne( ); // 使能I2C总线事件中断、错误中断,禁止缓冲中断
MFHI2cBusNackStar( ); // 发出 START 信号(起始条件),没有 ACK 脉冲
}
/*==========================================================================================================
函数名称: 启动I2C总线应用中断方式先发送若干地址然后再进行接收数据作业的函数。
函数功能: 本函数用于启动I2C总线使用中断方式,进行通讯先发送若干地址然后再进行接收数据作业操作的函数。
函数入口参数:Object ------------------ 要接收数据的的目标设备地址值。
*pAddr ------------------ 指向首个要发送地址在SRAM中的地址指针。
LenAddr ----------------- 要发送地址的地址总长度。
Length ------------------ 要接收数据的数据总长度。
函数返回值: 没有
函数出口参数:gbitI2c.Busy ------------ I2C总线〖忙〗,出口值=置位。
gbitI2c.Txd ------------- “正在进行发送数据作业”标志,出口值=置位。
gbitI2c.Rxd ------------- “正在进行接收数据作业”标志,出口值=置位。
gucvI2cEvent ------------ I2C总线的状态码变量,出口值= cI2cAllNoState(没有相关的状态信息) 。
gstvI2c.TxSize ---------- 每次发送数据个数大小变量,出口值=LenAddr + cI2cAddrNum。
gstvI2c.TxCnt ----------- 每次发送数据个数计数器变量,出口值=0。
gstvI2c.TxBuf[] --------- 每次发送数据缓冲区数组变量,出口值=要发送的地址。
gstvI2c.Cycle ----------- 重新启动通讯收发作业圈数,出口值=0。
gstvI2c.ErrNum ---------- 通讯收发作业发生错误次数,出口值=0。
gstvI2c.RxSize ---------- 每次接收数据个数大小变量,出口值=Length。
gstvI2c.RxCnt ----------- 每次接收数据个数计数器变量,出口值=0。
调用函数: 1.
备注: 1.注意:调用本函数之前,必须确定I2C总线在空闲状态。即必须先调用
“unsigned char CommI2cBusBusy(void)”函数,来检查I2C总线的工作状态,
只有I2C总线处于空闲状态,才允许调用本函数。
2.调用本函数将触发两线串行总线接口TWI中断请求和向I2C总线发出 START 信号(起始条件)。
==========================================================================================================*/
#if cI2cTxBufSize < 256
#if cI2cRxBufSize < 256
void CommI2cRxWithAddr (unsigned char Object, unsigned char *pAddr, unsigned char LenAddr, unsigned char Length)
#else
void CommI2cRxWithAddr (unsigned char Object, unsigned char *pAddr, unsigned char LenAddr, unsigned int Length)
#endif
#else
#if cI2cRxBufSize < 256
void CommI2cRxWithAddr (unsigned char Object, unsigned char *pAddr, unsigned int LenAddr, unsigned char Length)
#else
void CommI2cRxWithAddr (unsigned char Object, unsigned char *pAddr, unsigned int LenAddr, unsigned int Length)
#endif
#endif
{
#if cI2cTxBufSize < 256
register unsigned char i; // 循环变量
#else
register unsigned int i;
#endif
unsigned char temp; // 临时变量
CommI2cDataStru *pI2c; // 指向I2C总线通讯收发数据处理变量的指针
pI2c = &gstvI2c; // 取I2C总线通讯收发数据处理变量的首个地址
#ifdef PreCommI2cWithRedundantCode // “使用冗余程序代码”条件编译开始
if ( (LenAddr >= (cI2cTxBufSize - 1))
|| (LenAddr == 0) )
{
return;
}
if ( (Length > cI2cRxBufSize) ) // 检查要接收数据的总个数是否超过缓冲区长度?
{
Length = cI2cRxBufSize; // 截断要接收数据的总个数
}
#endif // “PreCommI2cWithRedundantCode”
MFHI2cBusModSwRst( ); // 软件复位I2C模块,释放I2C总线
// while(CommI2cBusBusy( )); // 等待直到对TWI下一个收发作业准备就绪为止
gbitI2c.Busy = SET; // 置“I2C总线〖忙〗”标志
gbitI2c.Txd = SET; // 置“正在进行发送数据作业”标志
gbitI2c.Rxd = SET; // 置“正在进行接收数据作业”标志
gbitI2c.OverS = SET; // 置“通讯任务时间超时”标志
gucvI2cEvent = cI2cAllNoState; // 置I2C总线的状态码 = 没有相关的状态信息
pI2c->OverS = RtcGetSecByte(cI2cOverSec);// 启动通讯任务时间计时秒表
// pI2c->Object = Object; // 复制目标设备地址到每次发送数据的目标设备地址中
// pI2c->Object &= (u8)(~BIT0); // 设置数据传送方向为写入数据
// pUsart->pTxData = pData; // 保存要发送的数据序列的地址指针
MemCopySramToSram(&Object, pI2c->TxBuf, cI2cAddrNum); // 复制目标设备地址到发送数据缓冲区中
pI2c->TxBuf[0] &= (u8)(~BIT0); // 设置数据传送方向为写入数据
MemCopySramToSram(pAddr, &pI2c->TxBuf[cI2cAddrNum], LenAddr);
// 复制发送的地址序列到发送数据缓冲区中
pI2c->TxSize = LenAddr + cI2cAddrNum; // 置每次发送数据个数大小值
pI2c->TxCnt = 0x00; // 每次发送数据计数器值清0
pI2c->Cycle = 0x00; // 重新启动通讯收发作业圈数清0
pI2c->ErrNum = 0x00; // I2C总线的通讯收发作业发生错误次数清0
pI2c->RxSize = Length; // 置I2C总线每次接收数据个数大小的值
pI2c->RxCnt = 0x00; // I2C总线每次接收数据个数计数器清0
MFHI2cFlgEventClr( ); // 清0I2C总线事件中断标志位
MFHI2cIntEventOne( ); // 使能I2C总线事件中断、错误中断,禁止缓冲中断
MFHI2cBusNackStar( ); // 发出 START 信号(起始条件),没有 ACK 脉冲
}
/*==========================================================================================================
函数名称: I2C总线工作于单主机方式,使用中断进行接收和发送数据的中断服务程序。
函数功能: 本函数用于I2C总线工作于单主机方式,使用中断进行接收和发送数据的中断服务程序。
函数入口参数:gbitI2c.Rxd ------------- “正在进行接收数据作业”标志。
gstvI2c.TxSize ---------- 每次发送数据个数大小变量。
gstvI2c.TxCnt ----------- 每次发送数据个数计数器变量。
gstvI2c.TxBuf[] --------- 每次发送数据缓冲区数组变量。
gstvI2c.RxSize ---------- 每次接收数据个数大小变量。
函数返回值: 没有
函数出口参数:gbitI2c.Busy ------------ I2C总线〖忙〗,出口值=清位(可能)。
gbitI2c.Error ----------- 通讯收发作业发生错误,出口值=置位(可能)。
gucvI2cEvent ------------ I2C总线的状态码变量,出口值= 不确定。
gstvI2c.TxCnt ----------- 每次发送数据个数计数器变量,出口值=gstvI2c.TxCnt。
gstvI2c.ErrNum ---------- 通讯收发作业发生错误次数,出口值=不确定。
gstvI2c.RxCnt ----------- 每次接收数据个数计数器变量,出口值=gstvI2c.RxSize。
gstvI2c.RxBuf[] --------- 每次接收数据缓冲区变量,出口值=从I2C总线上接收到的数据。
调用函数: 1.
备注: 1.注意:本函数需在I2C总线中断请求的中断向量函数中调用。
在调用之前需对该中断向量进行初始化,使能该中断。
2.全部完成通讯收发作业后,本函数将禁止I2C总线中断。
==========================================================================================================*/
#if ( defined(_IAR_EW_AVR_) \
|| defined(_IAR_EW_STM8_) )
#pragma vector = int_I2C_vector
INTERRUPT_KEY void CommI2c_isr (void)
#elif (defined(_KEIL_UV_MCS51_) )
void CommI2c_isr (void) INTERRUPT_KEY int_I2C_vector using 0
#elif ( defined(_COSMIC_STM8_) )
INTERRUPT_KEY void CommI2c_isr (void)
#else
void CommI2cIsr(void);
#endif // “_IAR_EW_......”
#if (defined(_IAR_EW_AVR_))
{
#if ((cI2cTxBufSize < 256) && (cI2cRxBufSize < 256))
register unsigned char cnt; // USART每次发送数据个数计数器变量
#else
register unsigned int cnt;
#endif
unsigned char temp; // 临时变量
CommI2cDataStru *pI2c; // 指向I2C总线通讯收发数据处理变量的指针
pI2c = &gstvI2c; // 取I2C总线通讯收发数据处理变量的首个地址
switch (TWSR & cI2cTwsrMask) // 判断已屏蔽非状态位的 TWI 状态寄存器状态位值?
{
case cI2cAllStart: // START 信号已发送
case cI2cAllRepStart: // 重复 START 信号已发送
{
pI2c->TxCnt = 0x00; // 每次发送数据计数器值清0
}
case cI2cMtxAddrAck: // SLA+W 已发送,接收到 ACK
case cI2cMtxDataAck: // 数据已发送,接收到 ACK
{
cnt = pI2c->TxCnt; // 取I2C总线每次发送数据个数计数器变量
if (cnt >= pI2c->TxSize) // 检查是否己完成发送通讯任务的全部数据?
{ // 是,在最后一个字节之后发出 STOP 信号
if (gbitI2c.Rxd == SET) // 检查是否为读取I2C总线数据?
{
pI2c->TxBuf[0] |= (u8)( BIT0); // 设置数据传送方向为接收数据
MFHI2cBusNackReps( ); // 发出重复 START 信号(重新开始条件),没有 ACK 脉冲
}
else
{
gbitI2c.Busy = CLEAR; // 清除“I2C总线〖忙〗”标志
gbitI2c.OverS = CLEAR; // 清除“通讯任务时间超时”标志
MFHI2cIntEventOff( ); // 禁止I2C总线事件中断
MFHI2cBusNackStop( ); // 发出 STOP 信号(结束条件),没有 ACK 脉冲
}
}
else
{
I2CDR = pI2c->TxBuf[cnt]; // 从发送缓冲区中将发送数据写入到I2C总线
cnt++; // I2C总线每次发送数据个数计数器+1
pI2c->TxCnt = cnt; // 返回I2C总线每次发送数据个数计数器值
// 通过先读 I2CSR1,然后写入 I2CDR,来清0发送结束、发送数据寄存器空标志
MFHI2cIntEventClr( ); // 进入中断后,在中断句柄中,清0I2C总线事件中断标志位(在中断服务程序中)
}
break;
}
case cI2cMrxDataAck: // 接收到数据,ACK 已返回
{
cnt = pI2c->RxCnt; // 取I2C总线每次接收数据个数计数器变量
pI2c->RxBuf[cnt] = I2CDR; // 复制I2C总线读取到的字节到接收数据缓冲区中
cnt++; // I2C总线每次接收数据个数计数器+1
pI2c->RxCnt = cnt; // 返回I2C总线每次接收数据个数计数器值
}
case cI2cMrxAddrAck: // SLA+R 已发送,接收到 ACK
{
cnt = pI2c->RxCnt; // 取I2C总线每次接收数据个数计数器变量
if (cnt < (pI2c->RxSize - 1)) // 检查是否完成需要读取的数据长度?
{
MFHI2cBusRdataAck( ); // 在接收之后发出 ACK 脉冲
}
else // 在最后一个字节数据接收之后发出 NOT ACK
{
MFHI2cBusRdatNack( ); // 在接收之后发出 NOT ACK
}
break;
}
case cI2cMrxDataNack: // 接收到数据,NOT ACK 已返回
{
cnt = pI2c->RxCnt; // 取I2C总线每次接收数据个数计数器变量
pI2c->RxBuf[cnt] = I2CDR; // 复制I2C总线读取到的字节到接收数据缓冲区中
gbitI2c.Busy = CLEAR; // 清除“I2C总线〖忙〗”标志
gbitI2c.OverS = CLEAR; // 清除“通讯任务时间超时”标志
MFHI2cIntEventOff( ); // 禁止I2C总线事件中断
MFHI2cBusNackStop( ); // 发出 STOP 信号(结束条件),没有 ACK 脉冲
break;
}
case cI2cAllArbLost: // SLA+W 或数据的仲裁失败
{
if (pI2c->ErrNum > cI2cErrorMax) // 检查通讯收发作业发生错误次数是否大于最大值?
{
gbitI2c.Error = SET; // 置“通讯收发作业发生错误”标志
MFHI2cInnEventMem( ); // 存储I2C总线的事件和状态存储器值
MFHI2cIntEventOff( ); // 禁止I2C总线事件中断
}
else
{
pI2c->ErrNum++; // I2C总线的通讯收发作业发生错误次数值+1
MFHI2cBusNackReps( ); // 发出 START 或重复的 START 信号(起始条件),没有 ACK 脉冲
}
break;
}
case cI2cMtxAddrNack: // SLA+W 已发送,接收到 NOT ACK
case cI2cMrxAddrNack: // SLA+R 已发送,接收到 NOT ACK
case cI2cMtxDataNack: // 数据已发送,接收到 NOT ACK
case cI2cAllNoState: // 没有相关的状态信息; TWINT = "0"
case cI2cAllBusError: // 由于非法的 START 信号或 STOP 信号引起的总线错误
default:
{
gbitI2c.Error = SET; // 置“通讯收发作业发生错误”标志
MFHI2cInnEventMem( ); // 存储I2C总线的事件和状态存储器值
MFHI2cIntEventOff( ); // 禁止I2C总线事件中断
}
}
INTERRUPT_RETURN( );
}
#elif ((defined(_IAR_EW_MCS51_)) || (defined(_KEIL_UV_MCS51_)))
#elif ( defined(_IAR_EW_STM8_) \
|| defined(_COSMIC_STM8_) ) // “......_STM8 编译器”条件编译开始
{
#if ((cI2cTxBufSize < 256) && (cI2cRxBufSize < 256))
register unsigned char cnt; // USART每次发送数据个数计数器变量
#else
register unsigned int cnt;
#endif
unsigned char temp; // 临时变量
CommI2cDataStru *pI2c; // 指向I2C总线通讯收发数据处理变量的指针
temp = I2CSR2; // 取I2C状态寄存器2值
if (temp & cI2cEvtSr2Mask) // 判断已屏蔽非状态位的I2C状态寄存器2值?
{
pI2c = &gstvI2c; // 取I2C总线通讯收发数据处理变量的首个地址
switch (temp & cI2cEvtSr2Mask) // 判断已屏蔽非状态位的 TWI 状态寄存器状态位值?
{
case cI2cAllArbLost: // 仲裁失败【I2CSR2】
{
if (pI2c->ErrNum > cI2cErrorMax) // 检查通讯收发作业发生错误次数是否大于最大值?
{
gbitI2c.Error = SET; // 置“通讯收发作业发生错误”标志
MFHI2cInnEventMem( ); // 存储I2C总线的事件和状态存储器值
MFHI2cIntEventOff( ); // 禁止I2C总线事件中断
MFHI2cBusNackStop( ); // 发出 STOP 信号(结束条件),没有 ACK 脉冲
}
else
{
pI2c->ErrNum++; // I2C总线的通讯收发作业发生错误次数值+1
MFHI2cBusNackReps( ); // 发出 START 或重复的 START 信号(起始条件),没有 ACK 脉冲
}
break;
}
// case cI2cMasterNack: // SLA 已发送,接收到 NOT ACK;或者数据已发送/接收到数据,接收到 NOT ACK/NOT ACK 已返回【I2CSR2】
// case cI2cAllNoState: // 没有相关的状态信息; TWINT = "0"
// case cI2cAllBusError: // 由于非法的 START 信号或 STOP 信号引起的总线错误
default:
{
gbitI2c.Error = SET; // 置“通讯收发作业发生错误”标志
MFHI2cInnEventMem( ); // 存储I2C总线的事件和状态存储器值
MFHI2cIntEventOff( ); // 禁止I2C总线事件中断
MFHI2cBusNackStop( ); // 发出 STOP 信号(结束条件),没有 ACK 脉冲
}
}
}
else // I2C总线没有错误
{
// 通过先读 I2CSR1,然后再读 I2CSR3,来清0地址已被发送(主模式)/地址匹配(从模式)标志
temp = I2CSR1; // 取I2C状态寄存器1值
if ((I2CSR3 & (u8)( (1<<i2cRXTX ))) == (u8)( (1<<i2cRXTX )))
{ // 检查I2C总线是否为发送数据?
temp |= (u8)( BIT5); // 是,
}
pI2c = &gstvI2c; // 取I2C总线通讯收发数据处理变量的首个地址
switch (temp) // 判断I2C状态寄存器1+I2C状态寄存器3值?
{
case cI2cAllStart: // START 信号已发送
case cI2cAllRepStart: // 重复 START 信号已发送
{
pI2c->TxCnt = 0x00; // 每次发送数据计数器值清0
}
case cI2cMtxAddrAck: // SLA+W 已发送,接收到 ACK
{
// if (temp == cI2cMtxAddrAck)
// {
MFHI2cIntEventOnn( ); // 使能缓冲中断
// }
}
case cI2cMtxDataAck: // 数据已发送,接收到 ACK
case cI2cMtxDataAckWait: // 数据已发送,接收到 ACK,且没有写新的数据到 I2CDR
{
cnt = pI2c->TxCnt; // 取I2C总线每次发送数据个数计数器变量
if (cnt >= pI2c->TxSize) // 检查是否己完成发送通讯任务的全部数据?
{ // 是,在最后一个字节之后发出 STOP 信号
if (gbitI2c.Rxd == SET) // 检查是否为读取I2C总线数据?
{
MFHI2cBusNackReps( ); // 发出重复 START 信号(重新开始条件),没有 ACK 脉冲
pI2c->TxBuf[0] |= (u8)( BIT0); // 设置数据传送方向为接收数据
// 通过先读 I2CSR1,然后写入 I2CDR,来清0发送数据寄存器空,字节发送结束,起始位(主模式)标志
// MFHI2cIntEventClr( ); // 进入中断后,在中断句柄中,清0I2C总线事件中断标志位(在中断服务程序中)
I2CDR = pI2c->TxBuf[0]; // 从发送缓冲区中将发送数据写入到I2C总线
MFHI2cIntEventOff( ); // 禁止I2C总线事件中断
MFHI2cIntEventOne( ); // 使能I2C总线事件中断、错误中断,禁止缓冲中断
}
else
{
gbitI2c.Busy = CLEAR; // 清除“I2C总线〖忙〗”标志
gbitI2c.OverS = CLEAR; // 清除“通讯任务时间超时”标志
MFHI2cIntEventOff( ); // 禁止I2C总线事件中断
MFHI2cBusNackStop( ); // 发出 STOP 信号(结束条件),没有 ACK 脉冲
}
}
else
{
// 通过先读 I2CSR1,然后写入 I2CDR,来清0发送数据寄存器空,字节发送结束,起始位(主模式)标志
// MFHI2cIntEventClr( ); // 进入中断后,在中断句柄中,清0I2C总线事件中断标志位(在中断服务程序中)
I2CDR = pI2c->TxBuf[cnt]; // 从发送缓冲区中将发送数据写入到I2C总线
cnt++; // I2C总线每次发送数据个数计数器+1
pI2c->TxCnt = cnt; // 返回I2C总线每次发送数据个数计数器值
}
break;
}
case cI2cMrxDataAck: // 接收到数据,ACK 已返回
case cI2cMrxDataAckWait: // 接收到数据,ACK 已返回,且 I2CDR 中的数据没有被读取
{
cnt = pI2c->RxCnt; // 取I2C总线每次接收数据个数计数器变量
// 通过先读 I2CSR1,然后读取 I2CDR,来清0接收数据寄存器非空标志
// MFHI2cIntEventClr( ); // 进入中断后,在中断句柄中,清0I2C总线事件中断标志位(在中断服务程序中)
pI2c->RxBuf[cnt] = I2CDR; // 复制I2C总线读取到的字节到接收数据缓冲区中
cnt++; // I2C总线每次接收数据个数计数器+1
pI2c->RxCnt = cnt; // 返回I2C总线每次接收数据个数计数器值
cnt = pI2c->RxCnt; // 取I2C总线每次接收数据个数计数器变量
if (cnt >= pI2c->RxSize) // 检查是否完成需要读取的数据长度?
{
gbitI2c.Busy = CLEAR; // 清除“I2C总线〖忙〗”标志
gbitI2c.OverS = CLEAR; // 清除“通讯任务时间超时”标志
MFHI2cIntEventOff( ); // 禁止I2C总线事件中断
}
else if (cnt >= (pI2c->RxSize - 1)) // 在最后一个字节数据接收之后发出 NOT ACK
{
MFHI2cBusRdatNack( ); // 在接收之后发出 NOT ACK
MFHI2cBusNackStop( ); // 发出 STOP 信号(结束条件),没有 ACK 脉冲
}
else
{
MFHI2cBusRdataAck( ); // 在接收之后发出 ACK 脉冲
}
break;
}
case cI2cMrxAddrAck: // SLA+R 已发送,接收到 ACK
{
MFHI2cBusRdataAck( ); // 在接收之后发出 ACK 脉冲
MFHI2cIntEventOnn( ); // 使能缓冲中断
break;
}
default:
{
gbitI2c.Error = SET; // 置“通讯收发作业发生错误”标志
MFHI2cInnEventMem( ); // 存储I2C总线的事件和状态存储器值
MFHI2cIntEventOff( ); // 禁止I2C总线事件中断
MFHI2cBusNackStop( ); // 发出 STOP 信号(结束条件),没有 ACK 脉冲
}
}
}
(void)temp; // 用以阻止编译器产生[temp]未使用的警告消息
INTERRUPT_RETURN( );
}
#else
#error 错误:
#endif // “PreMcuIs__......”
#endif // “I2C总线工作于单主机方式”条件编译结束
/*==========================================================================================================
函数功能: 本函数是I2C总线通信接收和发送作业不间断循环调用运行函数。
备注: ▲.注意:本函数为消息任务队列函数,要在主函数中不间断循环调用运行。
▲.当I2C总线工作于从机方式时,I2C总线中断总是处于使能状态,以便
I2C总线处于随时接收数据状态。
==========================================================================================================*/
void CommI2cCircleFunc (void)
{
#ifdef DEBUG
unsigned char i; // 循环计数器变量
unsigned char j;
unsigned char hex_data[2];
unsigned char *ptr;
#endif
unsigned char i; // 循环计数器变量
CommI2cDataStru *pI2c; // 指向I2C总线通讯收发数据处理变量的指针
pI2c = &gstvI2c; // 取I2C总线通讯收发数据处理变量的首个地址
#ifdef PreCommI2cUseSingleMasterMode // “I2C总线工作于单主机方式”的条件编译
if ( (gbitI2c.Error == SET) // 如果I2C总线通讯收发作业发生错误,
&& ( ! CommI2cBusBusy( )) ) // 且I2C总线收发器处于空闲状态?
{
if (pI2c->Cycle > cI2cErrorMax) // 检查重新启动收发作业错误次数是否大于最大值?
{
pI2c->Cycle = 0x00; // I2C总线的重新启动收发作业发生错误次数清0
gbitI2c.Error = CLEAR; // 清除“通讯收发作业发生错误”标志
gbitI2c.Busy = CLEAR; // 清除“I2C总线〖忙〗”标志
#ifdef _SYSTEM_ERROR_MANAGE_H_
sys_error_type |= SYS_ERROR_TYPE_IS_GENERAL; // 置【普通】错误类型消息任务标志位
sys_error_value = SYS_ERROR_COMM_I2CBUS ; // 置“I2C总线通信收发作业”错误代码值
#endif
}
else
{
pI2c->Cycle++; // I2C的重新启动收发作业发生错误次数值+1
gbitI2c.Error = CLEAR; // 清除“通讯收发作业发生错误”标志
CommI2cBusAgain( ); // 重新启动I2C总线前一个通讯收发作业操作
}
}
// 通讯任务时间超时计时处理,用以处理I2C总线直处于“BUSY”状态。
if (gbitI2c.OverS == SET)
{
if (RtcSecByteOverflow(pI2c->OverS)) // 如果通讯任务时间计时秒表时间已溢出?
{
I2CCR2 = (u8)( ((0<<i2cSTART)| // 禁止 START 信号(起始条件)
(0<<i2cSTOP )|(0<<i2cACKEN)| // 禁止 STOP 信号(停止条件),使能 ACK 应答
(0<<i2cPOS )|(1<<i2cRST ) ));// 应答的位置=当前字节,复位I2C模块
CLKPECR1 &= (u8)(~((1<<clkI2C ))); // 禁止I2C外设时钟
I2CCR1 = (u8)( ((0<<i2cEN )|(0<<i2cGCEN )| // 禁止I2C模块,禁止广播呼叫
(0<<i2cCKTEN) )); // 禁止时钟延展
MFH_PIN_CFG_OUTH_I2cScl; // 设置I2C时钟引脚为推挽输出,并为H电平(释放 SCL)
MFH_PIN_CFG_OUTH_I2cSda; // 设置I2C数据引脚为推挽输出,并为H电平(释放 SDA)
for (i=0; i<9; i++) // 发送 9 个 SCL 时钟脉冲;在此过程中,SDA 为高电平,以复位从设备
{
DelayUs(1);
MFH_PIN_OUT_CLRL_I2cScl;
DelayUs(1);
MFH_PIN_OUT_SETH_I2cScl;
}
CLKPECR1 |= (u8)( ((1<<clkI2C ))); // 使能I2C外设时钟
CommI2cInit( ); // 重新初始化I2C总线
}
}
#endif // “PreCommI2cUseSingleMasterMode”
}
#ifdef __cplusplus
} // extern "C" 链接指示符作用域结束
#endif
/*
************************************************************************************************************
本C语言源程序文件到此结束
************************************************************************************************************
*/
两线串行总线接口(I2C)
------------------------------------------------------------------------------------------------*/
// I2CCR1(I2C_CR1)——— I2C控制寄存器1
#define i2cEN 0 // I2C启动/停止使能位
#define i2cGCEN 6 // 广播呼叫使能位
#define i2cCKTEN 7 // 时钟延展禁止位
// I2CCR2(I2C_CR2)——— I2C控制寄存器2
#define i2cSTART 0 // 起始位状态
#define i2cSTOP 1 // 结束位状态
#define i2cACKEN 2 // 应答使能位
#define i2cPOS 3 // 应答的位置
#define i2cRST 7 // 软件复位
// I2CARL(I2C_OARL)——— I2C(从机)地址低位寄存器
#define i2cADD0 0 // I2C从机地址位0
#define i2cADD1 1 // I2C从机地址位1
#define i2cADD2 2 // I2C从机地址位2
#define i2cADD3 3 // I2C从机地址位3
#define i2cADD4 4 // I2C从机地址位4
#define i2cADD5 5 // I2C从机地址位5
#define i2cADD6 6 // I2C从机地址位6
#define i2cADD7 7 // I2C从机地址位7
#define i2cADD17 1 // I2C从机地址位1~7
// I2CARH(I2C_OARH)——— I2C(从机)地址高位寄存器
#define i2cADD8 1 // I2C从机地址位8
#define i2cADD9 2 // I2C从机地址位9
#define i2cCFG 6 // 地址模式配置
#define i2cMODE 7 // 寻址模式
#define i2cADD89 1 // I2C从机地址位8~9
// I2CSR1(I2C_SR1)——— I2C状态寄存器1
#define i2cSTAF 0 // 起始位(主模式)
#define i2cADDTR 1 // 地址已被发送(主模式)/地址匹配(从模式)
#define i2cTXC 2 // 字节发送结束
#define i2cADD10 3 // 10位头序列已发送(主模式)
#define i2cSTODF 4 // 停止条件检测位(从模式)
#define i2cRXNE 6 // 接收数据寄存器非空
#define i2cDRE 7 // 发送数据寄存器空
// I2CSR2(I2C_SR2)——— I2C状态寄存器2
#define i2cBERR 0 // 总线错误
#define i2cARLO 1 // 仲裁失败(主模式)
#define i2cACKF 2 // 应答失败
#define i2cOVF 3 // 溢出标志位
#define i2cWUF 5 // 从停机(Halt)模式唤醒标志
// I2CSR3(I2C_SR3)——— I2C状态寄存器3
#define i2cMSF 0 // 主/从机模式标志位
#define i2cBSY 1 // 总线忙标志
#define i2cRXTX 2 // 接收器/发送器,0:接收,1:发送
#define i2cGCF 4 // 广播呼叫头序列(从模式)
// I2CICR(I2C_ITR)——— I2C中断控制寄存器
#define i2cERRIE 0 // 错误中断使能位
#define i2cEVTIE 1 // 事件中断使能位
#define i2cBUFIE 2 // 缓冲中断使能位
// I2CCCRL(I2C_CCRL)——— I2C时钟控制低位寄存器
#define i2cCS0 0 // 预分频器时钟选择位0
#define i2cCS1 1 // 预分频器时钟选择位1
#define i2cCS2 2 // 预分频器时钟选择位2
#define i2cCS3 3 // 预分频器时钟选择位3
#define i2cCS4 4 // 预分频器时钟选择位4
#define i2cCS5 5 // 预分频器时钟选择位5
#define i2cCS6 6 // 预分频器时钟选择位6
#define i2cCS7 7 // 预分频器时钟选择位7
// I2CCCRH (I2C_CCRH)——— I2C时钟控制高位寄存器
#define i2cCS8 0 // 预分频器选择控制位8
#define i2cCS9 1 // 预分频器选择控制位9
#define i2cCSA 2 // 预分频器选择控制位10
#define i2cCSB 3 // 预分频器选择控制位11
#define i2cDUTY 6 // 快速模式下的占空比
#define i2cSFM 7 // 标准/快速模式选择位
__IO_REG8_BIT(I2CCR2 , 0x5211, __READ_WRITE, __BITS_I2C_CR2 );// I2C控制寄存器2
__IO_REG8_BIT(I2CFR , 0x5212, __READ_WRITE, __BITS_I2C_FREQR );// I2C频率寄存器
__IO_REG8_BIT(I2CARL , 0x5213, __READ_WRITE, __BITS_I2C_OARL );// I2C(从机)地址低位寄存器
__IO_REG8_BIT(I2CARH , 0x5214, __READ_WRITE, __BITS_I2C_OARH );// I2C(从机)地址高位寄存器
__IO_REG8 (I2CDR , 0x5216, __READ_WRITE );// I2C数据寄存器
__IO_REG8_BIT(I2CSR1 , 0x5217, __READ, __BITS_I2C_SR1 );// I2C状态寄存器1
__IO_REG8_BIT(I2CSR2 , 0x5218, __READ_WRITE, __BITS_I2C_SR2 );// I2C状态寄存器2
__IO_REG8_BIT(I2CSR3 , 0x5219, __READ, __BITS_I2C_SR3 );// I2C状态寄存器3
__IO_REG8_BIT(I2CICR , 0x521A, __READ_WRITE, __BITS_I2C_ITR );// I2C中断控制寄存器
__IO_REG8 (I2CCCRL , 0x521B, __READ_WRITE );// I2C比特率低位寄存器
__IO_REG8_BIT(I2CCCRH , 0x521C, __READ_WRITE, __BITS_I2C_CCRH );// I2C比特率高位寄存器
__IO_REG8_BIT(I2CTRISER , 0x521D, __READ_WRITE, __BITS_I2C_TRISER );// I2CTRISE寄存器
__IO_REG8 (I2CPECR , 0x521E, __READ_WRITE );// I2C包错误检查寄存器