大家好,又见面了,我是你们的朋友全栈君。
IIC头文件
/*------------------------------------------------------------------------------ * @file I2C.H * @author Byron (from3900@gmail.com) * @version V1.0.0 * @date 05/12/2020 * @brief 51系列单片机I2C通信协议头文件 * ----------------------------------------------------------------------------- */
#ifndef __I2C_H_
#define __I2C_H_
/* includes ------------------------------------------------------------------*/
#include <reg52.h>
/* variables -----------------------------------------------------------------*/
extern bit ack; //应答标志位
/* exported functions --------------------------------------------------------*/
extern void IIC_init(); //IIC总线初始化函数
extern void IIC_Start(); //起始信号函数
extern void IIC_Stop(); //终止信号函数
extern void IIC_Ack(bit a); //应答函数
//无子地址写字节数据函数
extern void SendByte(unsigned char c);
//无子地址读字节数据函数
extern unsigned char RcvByte();
//向没有子地址器件发送字节数据函数
extern bit ISendByte(unsigned char sla, unsigned char c);
//向有子地址发送多字节数据函数
extern bit ISendStr(unsigned char sla,unsigned char suba, \
unsigned char *s,unsigned char no);
//从无子地址器件读取字节数据函数
extern bit IRcvByte(unsigned char sla, unsigned char *c);
//从有子地址器件读取多字节数据函数
extern bit IRcvStr(unsigned char sla, unsigned char suba, \
unsigned char *s, unsigned char no);
#endif
/* END OF FILE ---------------------------------------------------------------*/
IIC.c
/*------------------------------------------------------------------------------ * @file I2C.c * @author Byron (from3900@gmail.com) * @version V1.0.0 * @date 05/12/2020 * @brief 51系列单片机I2C通信协议 * --------- * @notes * ----------------------------------------------------------------------------- */
/* Includes ------------------------------------------------------------------*/
#include "I2C.H"
#include <intrins.h>
/* variables -----------------------------------------------------------------*/
sbit SCL = P3^6; //IIC模拟时钟传送位
sbit SDA = P3^7; //IIC模拟数据控制位
bit ack; //应答标志
/* function prototypes -------------------------------------------------------*/
/* functions -----------------------------------------------------------------*/
/* * @brief 延时5us * @param None * @retval None */
void Delay5us(void)
{
_nop_(); _nop_(); _nop_(); _nop_(); _nop_();
}
/* * @brief 总线初始化函数。 * 拉高SCL时钟信号; * 拉高SDA数据信号。 * @param None * @retval None */
void IIC_init()
{
SCL = 1;
_nop_();
SDA = 1;
Delay5us();
}
/* * @brief 起始信号函数。 * SCL时钟信号为高电平; * SDA数据信号拉高并至少保持4.7us,之后产生一个下降沿, 同时SDA产生的这个 * 低电平要至少保持4us; * 之后拉低SCL。 * @param None * @retval None */
void IIC_Start()
{
SCL = 1; //拉高SCL
_nop_();
SDA = 1; //拉高SDA
Delay5us(); //保证SDA建立时间>4.7us
SDA=0; //使SDA产生下降沿跳变
Delay5us(); //保持建立时间>4us
SCL=0; //拉低SCL
_nop_();
}
/* * @brief 终止信号函数。 * SDA为低电平 * SCL产生一个上升沿,同时保证维持高电平时间>4us * SDA产生一个上升沿,同时保证维持高电平时间>4.7us * @param None * @retval None */
void IIC_Stop()
{
SDA = 0; //SDA为低电平
_nop_();
SCL = 1; //SCL产生上升沿
Delay5us(); //建立时间>4us
SDA = 1; //SDA产生上升沿
Delay5us(); //建立时间>4.7us
}
/* * @brief 应答函数 * 主机接收到从器件最后一个数据字节之后,需要给从器件发送一个非应答信号, * 以使得从器件释放数据总线,以便主机发送终止信号,结束数据传送。 * @param a=0 应答,从机继续占据总线,传送数据 * a=1 非应答,从机释放总线 * @retval None */
void IIC_Ack(bit a)
{
if (a==0) SDA=0; //应答
else SDA=1; //非应答
_nop_(); //确保SDA信号已经稳定
SCL = 1;
Delay5us();
SCL = 0; //清时钟线,准备接收
Delay5us();
}
/* * @brief 发送一个Byte. * 在SCL时钟信号为高电平期间,保持发送信号SDA稳定 * 发送结束之后 SDA=1 & SCL=0 * @param c 待发送的数据或地址 * @retval 发送成功ack=1,否则ack=0 */
void SendByte(unsigned char c)
{
unsigned char BitCnt;
for (BitCnt=0; BitCnt<8; BitCnt++) //传送一个Byte即8个bit
{
SCL = 0; //保证SCL处于低电平
if ((c<<BitCnt)&0x80) SDA=1; //判断发送的位状态
else SDA=0;
_nop_();
SCL = 1; //拉高SCL, 通知从机开始接收数据bit
Delay5us();
SCL = 0; //复位SCL,为下一次发送做准备
}
_nop_();
SDA = 1; //8位发送完后释放数据线,准备接收应答位
_nop_();
SCL = 1;
Delay5us();
if (SDA==1) ack = 0; //是否接收到应答信号
else ack = 1;
SCL = 0;
_nop_();
}
/* * @brief 从从器件中读取一个Byte * 完成之后 SDA=1 & SCL=0 * @param None * @retval retc 接收到的数据 */
unsigned char RcvByte()
{
unsigned char retc = 0;
unsigned char BitCnt;
SDA = 1; //置数据线为输入方式
for (BitCnt=0; BitCnt<8; BitCnt++)
{
_nop_();
SCL = 0; //置时钟线为低,准备接收数据位
Delay5us(); //时钟低电平周期大于4.7μs
SCL = 1; //置时钟线为高使数据线上数据有效
_nop_();
retc = retc<<1;
if (SDA==1) retc = retc+1; //读数据位,接收的数据位放入retc中
_nop_();
}
SCL=0;
_nop_();
return(retc);
}
/* * @brief 向没有子地址器件发送字节数据函数 * !启用前总线已经结束 * @param sla: 器件地址 * c : 发送数据 * @retval 成功返回1,否则返回0 */
bit ISendByte(unsigned char sla, unsigned char c)
{
IIC_Start(); //启动总线
SendByte(sla); //发送器件地址
if (ack==0) return(0);
SendByte(c); //发送数据
if (ack==0) return(0);
IIC_Stop(); //结束总线
return(1);
}
/* * @brief 向有子地址器件发送多字节数据函数 * 启动总线->发送地址、子地址、数据->结束总线 * !启用前总线已经结束 * @param sla : 从器件地址 * suba: 子地址 * s :指向待发送的内容 * no :发送字节的个数 * @retval 成功返回1,否则返回0 */
bit ISendStr(unsigned char sla, unsigned char suba, \
unsigned char *s, unsigned char no)
{
unsigned char i;
IIC_Start(); //启动总线
SendByte(sla); //发送器件地址
if (ack==0) return(0);
SendByte(suba); //发送器件子地址
if (ack==0) return(0);
for (i=0; i<no; i++)
{
SendByte(*s);
if (ack==0) return(0);
s++;
}
IIC_Stop(); //结束总线
return(1);
}
/* * @brief 从无子地址器件读取字节数据函数 * 启动总线->发送地址->读取数据->结束总线 * !启用前总线已经结束 * @param sla:从器件地址 * c :读取的数据 * @retval 成功返回1,否则返回0 */
bit IRcvByte(unsigned char sla, unsigned char *c)
{
IIC_Start(); //启动总线
SendByte(sla+1); //发送器件地址
if (ack==0) return(0);
*c = RcvByte(); //读取数据0
IIC_Ack(1); //发送非就答位
IIC_Stop(); //结束总线
return(1);
}
/* * @brief 从有子地址器件读取多字节数据函数 * 启动总线->发送地址、子地址、数据->结束总线 * !启用前总线已经结束 * @param sla : 从器件地址 * suba: 子地址 * s :指向读取的内容存放区 * no :读取字节个数 * @retval 成功返回1,否则返回0 */
bit IRcvStr(unsigned char sla, unsigned char suba, \
unsigned char *s, unsigned char no)
{
unsigned char i;
IIC_Start(); //启动总线
SendByte(sla); //发送器件地址
if (ack==0) return(0);
SendByte(suba); //发送器件子地址
if (ack==0) return(0);
IIC_Start(); //启动总线
SendByte(sla); //发送器件地址
if (ack==0) return(0);
for (i=0; i<no-1; i++)
{
*s = RcvByte();
IIC_Ack(0);
s++;
}
*s = RcvByte();
IIC_Ack(1); //发送非就答位
IIC_Stop(); //结束总线
return(1);
}
/* END OF FILE ---------------------------------------------------------------*/
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/135301.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...