📄 i2c.c
字号:
//2.(2071)《模拟I2C总线多主通信的通用软件包》
//通用软件包及测试程序如下:
/*********************支持多主竞争的模拟I2C软件包*******************
file name : Mult_VIIC_C51.C
writer : 张冬梅(zdm)
created : 06-30-2003
last changed: 07-30-2003
compiler : Keil C51 7.01
description : 此程序是支持多主方式的模拟IIC软件平台。包含直接面向器件的底层C子程序,包括总线启动/停止函数,发送/接收数据函数,应答函数。
version : V1.0测试版
*************************************************************/
/************************************************************
注意:
1、用户可修改SDA、SCL的口线定义;
2、用户需定义各MCU的器件从地址,注意不要与硬件IIC器件的地址重复。
3、用户需定义各MCU的优先级,数值越低优先级越高。
4、各MCU的时钟频率要一致,且Fosc<=12MHZ(标准80C51模式即12 CLOCK)。本软件包是1us机器周期,当你的系统要用高晶振频率时,要作一定的修改适当增加_nop_()的个数。
**************************************************************/
//#include "Mult_VIIC.h"
#include <reg51.h> /*头文件的包含*/
#include <intrins.h>
#define uchar unsigned char /*宏定义*/
//#define uint unsigned int
#define OK 1
#define NOK 0
/*******************用户定义**********************/
#define PREFER 3 /*MCU优先级定义,0为最高优先级,数字越大优先级越低*/
#define MYADR 0x2A /*定义本机地址,不要与硬件I2C的地址重复;*/
/*端口位定义*/
sbit SDA=P1^2; /*模拟IIC数据传送位*/
sbit SCL=P1^3; /*模拟IIC数据传送位*/
/*************************************************/
sbit BUSY=P3^3; /*握手线INT1*/
bit ack; /*应答位状态标志ack=1接收到应答;ack=0非应答*/
/***********************总线内部使用函数***********************
竞争仲裁函数
函数原型:bit Get_I2C();
功能:对竞争进行仲裁,即判断该主机可否控制I2C总线
返回:返回OK表成功,可以发动起始信号;返回NOK表失败
**************************************************************/
bit Get_I2C()
{
uchar i;
uchar pref;
EX1=0; /*关掉外部中断0*/
BUSY=1; /*冗余语句,确保不是自己拉低总线*/
if(BUSY==0) /*总线已被占用,返回失败标志*/
{
BUSY=1;
EX1=1; /*开中断*/
return(NOK) ;
}
else /*BUSY=1时对多主竞争仲裁*/
{
BUSY=0;
pref=PREFER; /*取优先级*/
while(pref!=0) /*在时间片内仲裁*/
{
pref--; /*时间片减1*/
for(i=0;i<4;i++)
{
if(SDA==1) continue;/*多次检测确保检测到高级mcu将其置0的信号*/
else
{
BUSY=1; /*总线被高优先级的mcu占用,放弃总线,返回失败标志*/
SDA=1;
EX1=1; /*开中断*/
return(NOK);
}
}
}
return(OK);/*没有高级占用总线,竞争成功,可以随后发动起始信号*/
}
}
/*************************************************************
启动总线函数
函数原型:void Start_I2C();
功能:启动I2C总线,即发送起始信号
**************************************************************/
void Start_I2C()
{
SDA=1; /*发送起始条件的数据信号*/
_nop_();
SCL=1;
_nop_();/*起始条件建立时间大于4.7us,延时*/
_nop_();
_nop_();
_nop_();
_nop_();
SDA=0; /*发送起始信号*/
_nop_();/*起始条件锁定时间大于9个机器周期*/
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
SCL=0; /*钳住I2C总线,准备发送或接收数据*/
_nop_();
_nop_();
}
/*************************************************************
结束总线函数
函数原型:void Stop_I2C();
功能:结束I2C总线,即发送起始信号
**************************************************************/
void Stop_I2C ()
{
SDA=0; /*发送结束条件的数据信号*/
_nop_(); /*发送结束条件的时钟信号*/
SCL=1; /*结束条件建立时间大于4μs*/
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
SDA=1; /*发送I2C总线结束信号*/
_nop_();
_nop_();
_nop_();
_nop_();
}
/*************************************************************
应答子函数
函数原型:void Ack_I2C(bit a);
功能:发送应答信号或非应答信号
参数:a=0输出低电平为应答信号;a=1输出高电平为非应答信号
**************************************************************/
void Ack_I2C(bit a)
{
if(a==0)SDA=0; /*发应答信号*/
else SDA=1; /*发非应答信号 */
_nop_();
_nop_();
_nop_();
SCL=1;
_nop_();
_nop_(); /*时钟低电平周期大于4μs*/
_nop_();
_nop_();
_nop_();
SCL=0; /*清时钟线,钳住I2C总线以便继续接收*/
_nop_();
_nop_();
}
/*******************************************************************
单字节发送函数
函数原型: void SendByte(uchar c);
功能:将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
此状态位进行操作.(不应答或非应答都使ack=0 假)
ack=1发送数据正常; ack=0表示被控器无应答或损坏。
********************************************************************/
bit SendByte(uchar c)
{
uchar BitCnt;
uchar CekNum;
for(BitCnt=0;BitCnt<8;BitCnt++) /*要传送的数据长度为8位*/
{
if((c<<BitCnt)&0x80) /*判断发送位*/
{
SDA=1;
while(SDA==0); /*07-22-03*/
}
else SDA=0;
_nop_();
SCL=1; /*置时钟线为高,通知被控器开始接收数据位*/
while(SCL==0); /*07-22-03*/
_nop_();
_nop_(); /*保证时钟高电平周期大于4μs*/
_nop_();
_nop_();
_nop_();
SCL=0;
}
_nop_();
_nop_();
SDA=1; /*8位发送完后释放数据线,准备接收应答位*/
for(CekNum=0;CekNum<20;CekNum++) /*重复检测应答,避免从机因应答延时而使主机没检测到误认为无应答*/
{
if(SDA==0)
{
SCL=1;
_nop_();
_nop_();
ack=1; /*ack=1接收到应答信号*/
SCL=0;
return(OK);
}
}
SCL=1;
_nop_();
_nop_();
ack=0; /*ack=0接收到非应答信号*/
SCL=0;
return(NOK);
}
/*******************************************************************
单字节接收函数
函数原型: uchar RcvByte();
功能:用来接收从器件传来的数据,并判断总线错误(不发应答信号),
发完后请用应答函数。
********************************************************************/
uchar RcvByte()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -