概述
文章目录
- 前言
- IIC程序设计
- 接收、发送应答分开的IIC通信
- .c文件
- .h文件
- 只发送应答的IIC通信
- .c文件
- .h文件
前言
使用的单片机型号为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
最后
以上就是善良小猫咪为你收集整理的KEIL C51 IIC程序设计的全部内容,希望文章能够帮你解决KEIL C51 IIC程序设计所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复