KEIL C51 IIC程序设计


前言

使用的单片机型号为STC15F2K60S2,程序的测试对象为DS3231时钟模块。基本所有51内核的单片机都可以直接使用。


IIC程序设计

个人理解IIC通信就是6类基本函数的排列组合:开始函数、停止函数、发送应答/应答非、接收应答/应答非、接收字节数据、发送字节数据。因一般不对应答信号进行处理,所以会把发送应答/应答非、接收应答/应答非合并为发送应答,即只有5类基础函数。只要不用处理应答信号,上面两种方式都可以正常使用。下面会分别列举上面两种IIC通信方式实例,希望对各位的学习和理解有所帮助。
学习参考资料:

http://sumcu.suda.edu.cn/_upload/article/files/74/e5/d4eb93de45808d71ad8aad542ede/a3cb5873-aaf4-4af0-9e5f-521793fbba46.pdf
https://blog.csdn.net/helloworld573/article/details/105629235
https://blog.csdn.net/zzm260270267/article/details/51258349

设计思路在代码中以注释的方式给出,可以复制下来在本地查看。
代码移植流程:

1.修改头文件(.c文件中),<STC15F2K60S2.h>换成自己的头文件即可。
2.修改引脚(.c文件中)
3.修改延时函数(.c文件中),直接修改函数体中的内容即可

接收、发送应答分开的IIC通信

.c文件

#include <STC15F2K60S2.h>
#include "IIC.h"
#include "intrins.h"//引入_nop_()函数,用于软件延时

//开始信号:时钟线SCL为高电平的条件下,数据线SDA有一个 下降沿。
//结束信号:时钟线SCL为高电平的条件下,数据线SDA有一个 上升沿。
//应答信号:应答是一个低电平信号。
/* 注:
*读取数据线时,需要先释放总线,即 SDA = 1;
*为了提高程序结构的严谨性和简洁性,这里限定IIC基础操作结束时SCL电平
		*开始信号:SCL = 0
		*结束信号:SCL = 1
		*应答信号:SCL = 0
		*发送数据:SCL = 0
		*接受数据:SCL = 0
*默认Device_Addr是从设备写地址,(Device_Addr+1)为从设备读地址。
*理论上说接收数据时,主机发送应答;发送数据时,主机接收应答。但是由于无需对从机应答进行处理,所以这里全部用的是主机发送应答。
*/

sbit IIC_SDA = P4^6;        //声明IIC总线的数据线接在单片机的P4.6端口。
sbit IIC_SCL = P4^5;        //声明IIC总线的时钟线接在单片机的P4.5端口。

/****************************************
*函数功能:延时函数,此处设置延时为10us
*参数:		
			无
*返回值:	
			无
****************************************/
void delay_IIC(void)
{
    
    
    unsigned char Number = 8;
    while (Number--){
    
    
        _nop_();
        _nop_();
    }
}
/****************************************
*函数功能:IIC开始信号
*参数:		
			无
*返回值:	
			无
****************************************/
void IIC_start(void)
{
    
    
	IIC_SDA = 1;
	
	IIC_SCL = 1;delay_IIC();

	IIC_SDA = 0;delay_IIC();

	IIC_SCL = 0;delay_IIC();		//拉低时钟线
	
}
/****************************************
*函数功能:IIC结束信号
*参数:		
			无
*返回值:	
			无
****************************************/
void IIC_stop(void)
{
    
    
	IIC_SDA = 0;delay_IIC();
	
	IIC_SCL = 1;delay_IIC();
	
	IIC_SDA = 1;delay_IIC();
}

/****************************************
*函数功能:IIC 主机接收 应答信号
*参数:	
			无
*返回值:	
			0------从机发送 应答
			1------从机发送 非应答
****************************************/
unsigned char IIC_Rack(void)
{
    
    
	unsigned char Ack;
	IIC_SDA = 1;delay_IIC();//释放数据线
	
	IIC_SCL = 1;delay_IIC();
	
	Ack = IIC_SDA;delay_IIC();
	
	IIC_SCL = 0;delay_IIC();
	
    return Ack;
}
/****************************************
*函数功能:IIC 主机发送 应答信号
*参数:	
			Ack = 0 ,主机发送 应答
			Ack = 1 ,主机发送 非应答
*返回值:	
			无
****************************************/
void IIC_Tack(unsigned char Ack)
{
    
    
	
	
	IIC_SDA = Ack;delay_IIC();//发送应答或非应答
	
	IIC_SCL = 1;delay_IIC();
	
	IIC_SCL = 0;delay_IIC();
}

/****************************************
*函数功能:IIC 发送 一字节数据
*参数:		
			Data------等待发送的数据
*返回值:	
			无
****************************************/
void IIC_write_byte(unsigned char Data)
{
    
    
	unsigned char i;
	for(i = 0;i < 8;i++)	//有8位数据
	{
    
    
		if(Data & 0x80){
    
    	//发送高位数据
			IIC_SDA = 1;
		}else{
    
    
			IIC_SDA = 0;
		}delay_IIC();
		
		IIC_SCL = 1;delay_IIC();
		
		IIC_SCL = 0;delay_IIC();
		//Data <<= 1;
		Data = Data << 1;
	}
}
/****************************************
*函数功能:IIC 接收 一字节数据
*参数:		
			无
*返回值:	
			接收的一字节数据
****************************************/
unsigned char IIC_recv_byte(void)
{
    
    
    unsigned char i;
    unsigned char Data;
	IIC_SDA = 1;		//先释放数据线,再读取数据
    for(i=0;i<8;i++)
    {
    
    
        IIC_SCL = 1;delay_IIC();
        Data = Data << 1; delay_IIC();
        if(IIC_SDA){
    
    
            Data |= 0x01;
		}
        IIC_SCL = 0;delay_IIC();
    }
    return Data;
}
/****************************************
*函数功能:向从机某一地址单元写入一字节数据
*参数:		
			Device_Addr       ----------从设备地址(写)
			Write_Addr        ----------待写入的地址
			Data              ----------待写入的数据
*返回值:	
			无
****************************************/
void IIC_write_single_byte(unsigned char Device_Addr,unsigned char Write_Addr,unsigned char Data)
{
    
    
    IIC_start();
	
    IIC_write_byte(Device_Addr);
    IIC_Rack();//接收从机应答信号,但不进行处理
	
    IIC_write_byte(Write_Addr);
    IIC_Rack();
	
    IIC_write_byte(Data);
	IIC_Rack();
	
    IIC_stop();
}
/****************************************
*函数功能:获取从机某一地址单元的一字节数据
*参数:		
			Device_Addr ----------从设备地址(写)
			Recv_Addr   ----------待读取的地址
*返回值:	
			接收到的一字节数据
****************************************/
unsigned char IIC_recv_single_byte(unsigned char Device_Addr,unsigned char Recv_Addr)
{
    
    
    unsigned char Data;

    IIC_start();

    IIC_write_byte(Device_Addr);//设备地址(写)。
    IIC_Rack();

    IIC_write_byte(Recv_Addr);
    IIC_Rack();

    IIC_start();

    IIC_write_byte(Device_Addr + 1);//设备地址(读)。
    IIC_Rack();

    Data = IIC_recv_byte();
	IIC_Tack(1);//若想连续读,就不断发送应答信号,否则发送应答非

    IIC_stop();				//产生停止符号。
    return Data;			//返回读取的一个字节数据。
}
/****************************************
*函数功能:连续写入从机地址单元
*参数:		
			Device_Addr ----------从设备地址(写)
			Write_Addr  ----------待写入的首地址
			Data		----------用于保存数据的数组名或指针
			Length		----------指定读取数据的长度
*返回值:	
			无
****************************************/
void IIC_write_bytes(unsigned char Device_Addr,unsigned char Write_Addr,unsigned char *Data, unsigned char Length)
{
    
    
	unsigned char i;
	
    IIC_start();
	
    IIC_write_byte(Device_Addr);
    IIC_Rack();
	
    IIC_write_byte(Write_Addr);
	IIC_Rack();

	for(i = 0; i < Length; i++){
    
    
		IIC_write_byte(*(Data + i));
		IIC_Rack();
	}
	
    IIC_stop();
}
/****************************************
*函数功能:连续读取从机地址单元
*参数:		
			Device_Addr ----------从设备地址(写)
			Recv_Addr   ----------待写入的首地址
			Data		----------待写入数据的数组名或指针
			Length		----------指定写入数据的长度
*返回值:	
			无
****************************************/
void IIC_recv_bytes(unsigned char Device_Addr,unsigned char Recv_Addr,unsigned char *Data, unsigned char Length)
{
    
    
	unsigned char i;
    IIC_start();

    IIC_write_byte(Device_Addr);//写入设备地址(写)。
    IIC_Rack();

    IIC_write_byte(Recv_Addr);
    IIC_Rack();

    IIC_start();

    IIC_write_byte(Device_Addr + 1);//写入设备地址(读)。
    IIC_Rack();
	
	for(i = 0; i < Length; i++){
    
    
		*(Data + i) = IIC_recv_byte();
		IIC_Tack(0);
	}
	
    IIC_stop();				//产生停止符号。
}


.h文件

#ifndef _IIC_H_
#define _IIC_H_
//--------------------------------------------
/*IIC基础函数*/
void delay_IIC(void);
void IIC_start(void);
void IIC_stop(void);
unsigned char IIC_Rack(void);
void IIC_Tack(unsigned char Ack);
void IIC_write_byte(unsigned char Data);
unsigned char IIC_recv_byte(void);

//--------------------------------------------
/*接收/发送 单 字节数据*/
void IIC_write_single_byte(unsigned char Device_Addr,unsigned char Write_Addr,unsigned char Data);
unsigned char IIC_recv_single_byte(unsigned char Device_Addr,unsigned char Recv_Addr);

//--------------------------------------------
/*接收/发送 多 字节数据*/
void IIC_write_bytes(unsigned char Device_Addr,unsigned char Write_Addr,unsigned char *Data, unsigned char Length);
void IIC_recv_bytes(unsigned char Device_Addr,unsigned char Recv_Addr,unsigned char *Data, unsigned char Length);

#endif

只发送应答的IIC通信

.c文件

#include <STC15F2K60S2.h>
#include "IIC.h"
#include "intrins.h"//引入_nop_()函数,用于软件延时

//开始信号:时钟线SCL为高电平的条件下,数据线SDA有一个 下降沿。
//结束信号:时钟线SCL为高电平的条件下,数据线SDA有一个 上升沿。
//应答信号:应答是一个低电平信号。
/* 注:
*读取数据线时,需要先释放总线,即 SDA = 1;
*为了提高程序结构的严谨性和简洁性,这里限定IIC基础操作结束时SCL电平
		*开始信号:SCL = 0
		*结束信号:SCL = 1
		*应答信号:SCL = 0
		*发送数据:SCL = 0
		*接受数据:SCL = 0
*默认Device_Addr是从设备写地址,(Device_Addr+1)为从设备读地址。
*理论上说接收数据时,主机发送应答;发送数据时,主机接收应答。但是由于无需对从机应答进行处理,所以这里全部用的是主机发送应答。
*/

sbit IIC_SDA = P4^6;        //声明IIC总线的数据线接在单片机的P4.6端口。
sbit IIC_SCL = P4^5;        //声明IIC总线的时钟线接在单片机的P4.5端口。

/****************************************
*函数功能:延时函数,此处设置延时为10us
*参数:		
			无
*返回值:	
			无
****************************************/
void delay_IIC(void)
{
    
    
    unsigned char Number = 8;
    while (Number--){
    
    
        _nop_();
        _nop_();
    }
}
/****************************************
*函数功能:IIC开始信号
*参数:		
			无
*返回值:	
			无
****************************************/
void IIC_start(void)
{
    
    
	IIC_SDA = 1;
	
	IIC_SCL = 1;delay_IIC();

	IIC_SDA = 0;delay_IIC();

	IIC_SCL = 0;delay_IIC();		//拉低时钟线
	
}
/****************************************
*函数功能:IIC结束信号
*参数:		
			无
*返回值:	
			无
****************************************/
void IIC_stop(void)
{
    
    
	IIC_SDA = 0;delay_IIC();
	
	IIC_SCL = 1;delay_IIC();
	
	IIC_SDA = 1;delay_IIC();
}

/****************************************
*函数功能:IIC 主机发送 应答信号
*参数:	
			无
*返回值:	
			无
****************************************/
void IIC_Ack(void)
{
    
    
	
	
	IIC_SDA = 0;delay_IIC();
	
	IIC_SCL = 1;delay_IIC();
	
	IIC_SCL = 0;delay_IIC();
}

/****************************************
*函数功能:IIC 发送 一字节数据
*参数:		
			Data------等待发送的数据
*返回值:	
			无
****************************************/
void IIC_write_byte(unsigned char Data)
{
    
    
	unsigned char i;
	for(i = 0;i < 8;i++)	//有8位数据
	{
    
    
		if(Data & 0x80){
    
    	//发送高位数据
			IIC_SDA = 1;
		}else{
    
    
			IIC_SDA = 0;
		}delay_IIC();
		
		IIC_SCL = 1;delay_IIC();
		
		IIC_SCL = 0;delay_IIC();
		//Data <<= 1;
		Data = Data << 1;
	}
}
/****************************************
*函数功能:IIC 接收 一字节数据
*参数:		
			无
*返回值:	
			接收的一字节数据
****************************************/
unsigned char IIC_recv_byte(void)
{
    
    
    unsigned char i;
    unsigned char Data;
	IIC_SDA = 1;		//先释放数据线,再读取数据
    for(i=0;i<8;i++)
    {
    
    
        IIC_SCL = 1;delay_IIC();
        Data = Data << 1; delay_IIC();
        if(IIC_SDA){
    
    
            Data |= 0x01;
		}
        IIC_SCL = 0;delay_IIC();
    }
    return Data;
}
/****************************************
*函数功能:向从机某一地址单元写入一字节地址
*参数:		
			Device_Addr       ----------从设备地址(写)
			Write_Addr        ----------待写入的地址
			Data              ----------待写入的数据
*返回值:	
			无
****************************************/
void IIC_write_single_byte(unsigned char Device_Addr,unsigned char Write_Addr,unsigned char Data)
{
    
    
    IIC_start();
	
    IIC_write_byte(Device_Addr);
    IIC_Ack();
	
    IIC_write_byte(Write_Addr);
    IIC_Ack();
	
    IIC_write_byte(Data);
	IIC_Ack();
	
    IIC_stop();
}
/****************************************
*函数功能:获取从机某一地址单元的一字节数据
*参数:		
			Device_Addr ----------从设备地址(写)
			Recv_Addr   ----------待读取的地址
*返回值:	
			接收到的一字节数据
****************************************/
unsigned char IIC_recv_single_byte(unsigned char Device_Addr,unsigned char Recv_Addr)
{
    
    
    unsigned char Data;

    IIC_start();

    IIC_write_byte(Device_Addr);//设备地址(写)。
    IIC_Ack();

    IIC_write_byte(Recv_Addr);
    IIC_Ack();

    IIC_start();

    IIC_write_byte(Device_Addr + 1);//设备地址(读)。
    IIC_Ack();

    Data = IIC_recv_byte();
	IIC_Ack();

    IIC_stop();				//产生停止符号。
    return Data;			//返回读取的一个字节数据。
}
/****************************************
*函数功能:连续写入从机地址单元
*参数:		
			Device_Addr ----------从设备地址(写)
			Write_Addr  ----------待写入的首地址
			Data		----------用于保存数据的数组名或指针
			Length		----------指定读取数据的长度
*返回值:	
			无
****************************************/
void IIC_write_bytes(unsigned char Device_Addr,unsigned char Write_Addr,unsigned char *Data, unsigned char Length)
{
    
    
	unsigned char i;
	
    IIC_start();
	
    IIC_write_byte(Device_Addr);
	IIC_Ack();
	
    IIC_write_byte(Write_Addr);
	IIC_Ack();

	for(i = 0; i < Length; i++){
    
    
		IIC_write_byte(*(Data + i));
		IIC_Ack();
	}
	
    IIC_stop();
}
/****************************************
*函数功能:连续写入从机地址单元
*参数:		
			Device_Addr ----------从设备地址(写)
			Recv_Addr   ----------待写入的首地址
			Data		----------待写入数据的数组名或指针
			Length		----------指定写入数据的长度
*返回值:	
			无
****************************************/
void IIC_recv_bytes(unsigned char Device_Addr,unsigned char Recv_Addr,unsigned char *Data, unsigned char Length)
{
    
    
	unsigned char i;
    IIC_start();

    IIC_write_byte(Device_Addr);//写入设备地址(写)。
    IIC_Ack();

    IIC_write_byte(Recv_Addr);
    IIC_Ack();

    IIC_start();

    IIC_write_byte(Device_Addr + 1);//写入设备地址(读)。
    IIC_Ack();
	
	for(i = 0; i < Length; i++){
    
    
		*(Data + i) = IIC_recv_byte();
		IIC_Ack();
	}
	
    IIC_stop();				//产生停止符号。
}

.h文件

#ifndef _IIC_H_
#define _IIC_H_
//--------------------------------------------
/*IIC基础函数*/
void delay_IIC(void);
void IIC_start(void);
void IIC_stop(void);
void IIC_Ack(void);
void IIC_write_byte(unsigned char Data);
unsigned char IIC_recv_byte(void);

//--------------------------------------------
/*接收/发送 单 字节数据*/
void IIC_write_single_byte(unsigned char Device_Addr,unsigned char Write_Addr,unsigned char Data);
unsigned char IIC_recv_single_byte(unsigned char Device_Addr,unsigned char Recv_Addr);

//--------------------------------------------
/*接收/发送 多 字节数据*/
void IIC_write_bytes(unsigned char Device_Addr,unsigned char Write_Addr,unsigned char *Data, unsigned char Length);
void IIC_recv_bytes(unsigned char Device_Addr,unsigned char Recv_Addr,unsigned char *Data, unsigned char Length);

#endif

猜你喜欢

转载自blog.csdn.net/m0_54346266/article/details/128591014
今日推荐