C51单片机模拟I2C总线驱动程序设计
/********************************** I2C总线驱动 ******************************** 模块名:I2C总线驱动 型号:I2C 功能描述: 此模块包括发送数据及接收数据,应答位发送,并提供了几个直接面对器件的操作 函数,能很方便的与用户程序进行连接并扩展。需要注意的是,函数是采用延时方法产 生 SCL 脉冲,对高晶振频率要做一定的修改!!在写E2PROM的时候一定要延时!!! 说明: 1us机器周期,晶振频率要小于12MHz 返回 1 则操作成功,返回 0 则操作失败。 sla 为器件从地址,suba 为器件子地址。 *******************************************************************************/ #include "AT89X52.h" #include <intrins.h> #define SomeNOP(); {_nop_();_nop_();_nop_();_nop_();_nop_();} //定义空指令 sbit SDA = P1^; //模拟I2C数据传输位 sbit SCL = P1^; //模拟I2C时钟控制位 bit bdata I2C_Ack; //应答标志位 /************************************ I2C_Start ********************************* 函数名:void I2C_Start() 入口: 出口: 功能描述:启动I2C总线,即发送I2C初始条件 解释: 在I2C总线协议中规定的起始位格式是:在SCL高电平期间,SDA发生从高到低的电平跳变.它与其它数据格式的区别在于,协议中规定有效的数据必须在SCL的高电平期间保持不变,只有在SCL的低电平期间才能发生跳变.所以这一有别与其它格式的数据才能做为起始位. 调用函数: 全局变量: *******************************************************************************/ void I2C_Start() { SDA = ; //发送起始条件的数据信号 _Nop(); SCL = ; SomeNOP(); //起始条件建立时间大于4.7us,延时 SDA = ; //发送起始信号 SomeNOP(); //起始条件建立时间大于4us,延时 SCL = ; //钳住I2C总线准备发送或接收数据 /******解释:I2C总线在空闲状态下都是被上拉为高电平的,所以当它们处于低电平时就表示忙的状态.***/ _nop_(); _nop_(); } /************************************ I2C_Stop ********************************* 函数名:void I2C_Stop() 入口: 出口: 功能描述:结束I2C总线,即发送I2C结束条件 解释: 同起始条件的格式类似,结束条件的格式是在SCL高电平期间,SDA由低电平向高电平跳变. 调用函数: 全局变量: *******************************************************************************/ void I2C_Stop() { SDA = ; //发送结束条件的数据信号 _Nop(); SCL = ; //发送结束条件的时钟信号 SomeNOP(); //结束条件建立时间大于4us,延时 SDA = ; //发送I2C总线结束信号 SomeNOP(); } /************************************ I2C_CheckAck ***************************** 函数名:bit I2C_CheckAck(void) 入口: 出口:0(无应答),1(有应答) 功能描述: 检验I2C总线应答信号,有应答则返回1,否则返回0,超时值取255. 解释: I2C总线协议中规定传输的每个字节之后必须跟一个应答位,所以从器件在接收到每个 字节之后必须反馈一个应答信号给主控制器,而主控制器就需要检测从器件回传的应答信号, 根据其信息做出相应的处理.另外,主从之别是相对的,接收数据的即为从,发送数据的及为主. 再看看应答信号的格式:在由发送器产生的时钟响应周期里,发送器先释放SDA(置高),然后由 接受器将SDA拉低,并在这个时钟脉冲周期的高电平期间保持稳定的低电平.即表示从器件做 出了应答. 调用函数:void I2C_Stop() 全局变量: *******************************************************************************/ bit I2C_CheckAck(void) { uchar errtime = ; // 因故障接收方无 Ack,超时值为255 SDA = ; //发送器先释放SDA SomeNOP(); SCL = ; SomeNOP(); //时钟电平周期大于 4 us while(SDA) //判断SDA是否被拉低 { errtime--; ) { I2C_Stop(); ); } } SCL = ; _nop_(); ); } /************************************ I2C_SendB ******************************** 函数名:void I2C_SendB(uchar c) 入口:uchar 型数据 出口: 功能描述: 字节数据传送函数,将数据 c 发送出去,可以是地址,也可以是数据,发完后等待 应答,并对 此状态位进行操作 注意: 在传送数据时,数据(SDA)的改变只能发生在SCL的低电平期间,在SCL的高电平期间保持不变 调用函数:bit I2C_CheckAck() 全局变量:I2C_Ack *******************************************************************************/ void I2C_SendB(uchar c) { uchar BitCnt; ; BitCnt<; BitCnt++) //要传送的数据长度为8位 { if((c<<BitCnt)&0x80) //判断发送位(从高位起发送) { SDA = ; } else { SDA = ; } _nop_(); _nop_(); SCL = ; //置时钟线为高通知被控器开始接收数据位 SomeNOP(); //保证时钟高电平周期大于 4us SCL = ; } _nop_(); _nop_(); I2C_Ack = I2C_CheckAck(); //检验应答信号,作为发送方,所以要检测接收器反馈的应答信号. _nop_(); _nop_(); } /************************************ I2C_RcvB ********************************* 函数名:uchar I2C_RcvB() 入口: 出口:uchar型数据 功能描述: 接收从器件传来的数据,并判断总线错误(不发应答信号),收完后需要调用应答函数。 调用函数: 全局变量: *******************************************************************************/ uchar I2C_RcvB() { uchar retc; uchar BitCnt; //位 retc = ; SDA = ; //置数据总线为输入方式,作为接收方要释放SDA. ;BitCnt<;BitCnt++) { _nop_(); SCL = ; //置时钟线为低准备接收数据位 SomeNOP(); //时钟低电平周期大于4.7us SCL = ; //置时钟线为高使数据有效 _nop_(); _nop_(); retc = retc<<; ) { retc = retc + ;//读数据位,接收的数据放入retc中 } _nop_(); _nop_(); } SCL = ; _nop_(); _nop_(); return(retc); } /************************************ I2C_Ackn ********************************* 函数名:void I2C_Ackn(bit a) 入口:0或1 出口: 功能描述: 主控制器进行应答信号(可以是应答或非应答信号) 说明: 作为接收方的时候,必须根据当前自己的状态向发送器反馈应答信号 调用函数: 全局变量: *******************************************************************************/ void I2C_Ackn(bit a) { ) //在此发送应答或非应答信号 { SDA = ; } else { SDA = ; } SomeNOP(); SCL = ; SomeNOP(); //时钟电平周期大于 4 us SCL = ; //清时钟线钳住I2C总线以便继续接收 _nop_(); _nop_(); } /******************************** I2C_ISendB *********************************** 函数名:bit I2C_ISendB(uchar sla, uchar suba, uchar c) 入口:从器件地址 sla,子地址 suba, 发送字节 c 出口:0(操作有误),1(操作成功) 功能描述: 从启动总线到发送地址、数据,结束总线的全过程, 如果返回1,表示操作成功,否则操作有误。 调用函数:I2C_Start(),I2C_SendB(uchar c),I2C_Stop() 全局变量:I2C_Ack *******************************************************************************/ bit I2C_ISendB(uchar sla, uchar suba, uchar c) { I2C_Start(); //启动总线 I2C_SendB(sla); //发送器件地址 if(!I2C_Ack) { ); } I2C_SendB(suba); //发送器件子地址 if(!I2C_Ack) { ); } I2C_SendB(c); //发送数据 if(!I2C_Ack) { ); } I2C_Stop(); //结束总线 ); } /********************************** I2C_IRcvB ********************************** 函数名:bit I2C_IRcvB(uchar sla, uchar suba, uchar *c) 入口:从器件地址 sla, 子地址 suba, 收到的数据在 c 出口:1(操作成功),0(操作有误) 功能描述:从启动总线到发送地址、读数据,结束总线的全过程。 调用函数: I2CS_tart(), I2C_SendB(uchar c), I2C_RcvB(), I2C_Ackn(bit a), I2C_Stop() 全局变量:I2C_Ack 创建者:陈曦 日期:2005-5-15 修改者: 日期: *******************************************************************************/ bit I2C_IRcvB(uchar sla, uchar suba, uchar *c) { I2C_Start(); //启动总线 I2C_SendB(sla); if(!I2C_Ack) { ); } I2C_SendB(suba); //发送器件子地址 if(!I2C_Ack) { ); } I2C_Start(); //重复起始条件 I2C_SendB(sla+); //发送读操作的地址 if(!I2C_Ack) { ); } *c = I2C_RcvB(); //读取数据 I2C_Ackn(); //发送非应答位 I2C_Stop(); //结束总线 ); }
C51单片机模拟I2C总线驱动程序设计的更多相关文章
- 51单片机模拟I2C总线的C语言实现
电路原理图 EEPROM为ATMEL公司的AT24C01A.单片机为ATMEL公司的AT89C51. 软件说明 C语言为Franklin C V3.2.将源程序另存为testi2c.c,用命令 C ...
- 51单片机 | 基于I2C总线的秒表模拟应用
———————————————————————————————————————————— 参考地址: http://blog.csdn.net/junyeer/article/details/4648 ...
- i2c总线驱动,总线设备(适配器),从设备,从设备驱动的注册以及匹配
常用链接 我的随笔 我的评论 我的参与 最新评论 我的标签 随笔分类 ARM裸机(13) C(8) C++(8) GNU-ARM汇编 Linux驱动(24) Linux应用编程(5) Makefile ...
- I2C总线驱动框架详解
一.I2C子系统总体架构 1.三大组成部分 (1)I2C核心(i2c-core):I2C核心提供了I2C总线驱动(适配器)和设备驱动的注册.注销方法,I2C通信方法(”algorithm”)上层的,与 ...
- STM32F4XX中断方式通过IO模拟I2C总线Master模式
STM32的I2C硬核为了规避NXP的知识产权,使得I2C用起来经常出问题,因此ST公司推出了CPAL库,CPAL库在中断方式工作下仅支持无子地址 的器件,无法做到中断方式完成读写大部分I2C器件.同 ...
- I2C裸机驱动程序设计
① I2C(Inter-Integrated Circuit)总线是由飞利浦公司开发的两线式串行总线,用于连接微控制器及其外围设备 ② I2C总线有两根双向信号线 (1)SDA:Serial Data ...
- gpio模拟I2C,驱动pcf8574T
一.pcf8574T介绍 查看pcf8574T的数据手册, A表示读或写,当A为1的时候表示读,当A为0的时候表示写.现把地址控制线,即A2.A1.A0全部接地,可以得到读控制指令为0x41,写控制指 ...
- 利用C51单片机模拟SPI进行双机通信
SPI协议简述 SPI,是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口.由Motorola首创.SPI接口主要应用在 EEPROM,FLASH,实时时 ...
- I2C总线完全版——I2C总线的结构、工作时序与模拟编程
I2C总线的结构.工作时序与模拟编程 I2C总线的结构.工作时序与模拟编程I2C总线(Inter Integrated Circuit)是飞利浦公司于上个世纪80年代开发的一种"电路板级&q ...
随机推荐
- XJOI网上同步训练DAY1 T2
思路:似曾相识?...见http://www.cnblogs.com/qzqzgfy/p/5266874.html 一看时限还是4s!,于是就开开心心地打了70%的分,就是用容斥原理,就可以n^3解决 ...
- Keil C51怎样将子程序段定位在固定的地址位?
以下2问题均要用C51解决1.怎样将1个子程序段定位在1个固定的地址位置?例如将 INT BCD2HEX(INT XX)定位在1000H2.如何在EEPROM 中固定的位置存放1字符串?如在200H处 ...
- windows phone中三种解析XML的方法
需求如下, 项目需要将一段xml字符串中的信息提取出来 <?xml version=""1.0"" encoding=""UTF-8& ...
- (heap)239. Sliding Window Maximum
题目: Given an array nums, there is a sliding window of size k which is moving from the very left of t ...
- C5-信号量与PV操作(iOS篇-细说信号量)
一.概述 信号量这种同步机制的概念. P, V操作(Dijkstra提出)的定义 github地址(iOS中的信号量是以1开始定义): https://github.com/sixleaves/sem ...
- c++中可以对类中私有成员中的静态变量初始化吗?
转载http://www.cnblogs.com/carbs/archive/2012/04/04/2431992.html 问题:我看的书上写的对私有部分的访问可以是公共部分的成员函数,也可以是友员 ...
- qt model/view 架构自定义模型之QFileSystemModel
# -*- coding: utf-8 -*- # python:2.x #QFileSystemModel """ Qt 内置了两种模型:QStandardItemM ...
- c++之 printf 打印内容
该代码全部在Visual Studio 2015中编写,有关VS2015的安装流程后期在写相关的博文 首先让我们来输出一下hello, world! 1.首先新建一个main.cpp的文件,然后在该文 ...
- python学习之路-8 面向对象之进阶
上篇内容回顾和补充 面向对象三大特性 封装 继承 多态 在python中没有多态的概念 变量的类型允许为多种数据类型称之为多态 # c#/java中的多态 # 伪代码 def func(int arg ...
- 【剑指offer】替换字符串中的空格
转载请注明出处:http://blog.csdn.net/ns_code/article/details/25002199 剑指offer上的第四道题目,在九度OJ上測试通过,但还是有些问题.由于是用 ...