51单片机IIC通信协议

51单片机IIC通信协议/*——————————————————————————*@fileI2C.H*@authorByron(from3900@gmail.com)*@versionV1.0.0*@date05/12/2020*@brief51系列单片机I2C通信协议头文件*——————————————-

大家好,又见面了,我是你们的朋友全栈君。

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 ---------------------------------------------------------------*/
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/135301.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • telnet 命令使用方法详解,telnet命令怎么用?[通俗易懂]

    telnet 命令使用方法详解,telnet命令怎么用?[通俗易懂]什么是Telnet?对于Telnet的认识,不同的人持有不同的观点,可以把Telnet当成一种通信协议,但是对于入侵者而言,Telnet只是一种远程登录的工具。一旦入侵者与远程主机建立了Telnet

    2022年8月2日
    28
  • Linux LAMP架构介绍及配置「建议收藏」

    Linux LAMP架构介绍及配置「建议收藏」LinuxLAMP架构介绍及配置一、LAMPLAMP平台概述LAMP架构是目前成熟的企业网站应用模式之一,指的是协同工作的一整台系统和相关软件,能够提供动态web站点服务及其应用开发环境LAMP是一个缩写词,具体包括Linux操作系统,Apache网站服务器,MySQL数据库服务器,PHP(或perl,Python)网页编程语言LAMP各组件主要作用(平台)Linux:作为LAMP架构的基础,提供用于支撑Web站点的操作系统,能够与其他三个组件提供更好的稳定性,兼容性(AMP组件也

    2022年10月16日
    0
  • 游戏开发怎么做(游戏开发流程详解)

    本文来自作者goto先生在GitChat上分享「如何开发一款游戏:游戏开发流程及所需工具」,「阅读原文」查看交流实录。「文末高能」编辑|哈比游戏作为娱乐生活的一个方面,参与其中的人越来越多,而大部分参与其中的人都是以玩家的身份。他们热爱一款游戏,或是被游戏的故事情节、炫丽的场景、动听的音乐所艳羡,亦或是被游戏中角色扮演、炫酷的技能、有趣的任务所吸引,然而他们中的大多数可能并不了解如此

    2022年4月17日
    61
  • MIPS五级流水线_工业级CPU报价

    MIPS五级流水线_工业级CPU报价一、流水线CPU流水线CPU就是指将一条分解为多步,在同一周期内进行多条指令的同时执行。MIPS五级流水线就是将指令分为:取指(IF),译码(ID),执行(EX),访存(MEM),写回(WB)五个阶段。举个例子:比如第二条指令lui$t2,0x2100在流水线CPU中执行的就是可以看到在200-300ns的周期里,IF阶段取到0x00400004处的指令,300-400ns,这条指令到了ID阶段,而IF阶段执行下一条指令。400-500ns,执行这条指令,ALU的结果为0x2100

    2022年8月21日
    6
  • ubuntu16.04安装教程_刚安装ETC不能马上使用吗

    ubuntu16.04安装教程_刚安装ETC不能马上使用吗Ubuntu的安装与使用1、请参考:https://jingyan.baidu.com/album/ca00d56c2b5257e99febcf41.html?picindex=29注意网络连接选

    2022年8月1日
    2
  • android 课程格子源码,课程格子Android客户端产品体验报告[通俗易懂]

    android 课程格子源码,课程格子Android客户端产品体验报告[通俗易懂]概览手机:魅族MX3操作系统:FlymeOS3.5.2(A19220)体验产品:课程格子Android客户端软件版本:6.1需求分析目标人群:在校大学生使用场景:大学生课前查看课程,课堂做笔记,课下在BBS灌水。用户需求:课程导入便利,显示准确,操作便捷,功能新颖有趣。产品分析1.信息架构2.页面视图A.课程格子菜单栏放在顶部,按钮也并不大,在子页面中也都是同样的设计,没有分出导航栏或状态栏(…

    2022年10月4日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号