IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 51单片机模拟I2C程序 -> 正文阅读

[嵌入式]51单片机模拟I2C程序

IIC即Inter-Integrated Circuit(集成电路总线),这种总线类型是由飞利浦公司研发出来的。是一种两线式串行总线,两条线可以挂多个参与通信的器件,即多机模式。一般由控制器作为主机。
IIC 有两个双向信号线:一个是数据线SDA,一个是时钟线SCL(IIC是半双工)。主从机之间的数据传输完全依靠这两个信号的配合。同时,只有主机才能进行时钟信号的生成。IIC总线式开漏引脚并联结构,因此需要在外部要添加上拉电阻。对于开漏电路外部加上拉电阻,就组成了线“与”的关系。所有接入的器件保持高点平,这条线才是高电平,而任何一个器件输出一个低电平,那这条线就会保持低电平。
??在这里插入图片描述

1、通信起始信号和停止信号:

起始信号和停止信号是两种特殊的信号。SCL为高电平期间,SDA由高电平向低电平变化产生一个下降沿,表示起始信号。SCL为高电平期间,SDA由低电平向高电平变化产生一个上升沿,表示停止信号。起始和停止信号一般是由主机产生。

2、应答/非应答信号:

当主机发送一个字节后,从机需要进行一个应答信号,以此来判断信号是否完成了传输。从机应答主机所需要的时钟仍是主机提供的,每当主机向从机发送完一个字节的数据,主机总是需要等待从机给出一个应答信号,以确认从机是否成功接收到了数据应答出现。在每一次主机完成8个数据位传输后紧跟着的时钟周期,低电平0表示应答,1表示非应答。

3、数据有效性

I2C使用SDA来传输数据,使用SCL来进行数据同步。每个时钟周期传输1位数据。在SCL时钟线为高电平时,也被称作采样时刻,此时SDA表示的数据有效,即SDA为高电平表示’1’,低电平表示‘0’,同时采样时刻SDA数据线必须保持稳定,因为在SCL高电平时,如果SDA发生动作,那么就会被判定成起始或停止信号。所以在传数据的时候,SCL为高时,SDA必须保持稳定,否则会导致此次数据传输失败。
当SCL时钟线为低电平时,SDA的数据无效,一般在这个时候是进行数据交换,为下次数据做准备。每次数据传输都以字节为单位,每次传输的字节数不受限制。

4、地址及数据方向

I2C总线上的设备,每个都有自己的独立地址。主机发起通讯时,通过SDA数据线发送设备地址来查找从机。I2C协议从机地址可以是7位或10位。在实际应用中,7位地址比较广泛,紧跟设备地址的一个数据位表示数据传输方向,它是数据的方向位(R/W),第8位或第11位。为’0’时,是主机向从机写数据;为‘1’时,是主机读取从机传输来的数据。

下面代码是51单片机的模拟I2C程序,需要注意的是51单片机的IO口是准双向IO。所以SDA引脚在数据传输过程中不需要进行方向的切换。这点需要注意。如果你的单片机GPIO有方向,一定注意切换。

代码如下:

iic.c

//iic.c

#include "reg52.h"
#include "type.h"
#include "iic.h"
#include "intrins.h"
#include "delay.h"

//#define I2CDelay() {_nop_();_nop_();}

void I2C_Start(void) //开始信号
{
	SDA_H;
	//I2CDelay();
	SCL_H;
	//I2CDelay();
	SDA_L;
	//I2CDelay();
}
void I2C_Stop(void) //停止
{
	SDA_L;
	//I2CDelay();
	SCL_H;
	//I2CDelay();
	SDA_H;
	//I2CDelay();
}


void send_ACK(bit b_ACK)     //主机应答ACK,或不应答
{
	SCL_L;
	//I2CDelay();
	if(b_ACK)                    //ACK
	{
		SDA_L;        
	}
	else                          //NOACK
	{
		SDA_H;
	}
	//I2CDelay();
	SCL_H;
	//I2CDelay();
	SCL_L;
	//I2CDelay();
}

void read_ACK(void)    //等待 24C02 回应 ACK
{
	uint8_t t=0;
	SCL_H;
	//I2CDelay();
	while((I2C_SDA==1)&&(t<200))t++;    //等待ACK,超时跳出
	SCL_L;
	//I2CDelay();
}

void I2C_init()  //I2C初始化函数,拉高 I2C_SDA 和 I2C_SCL 两条总线
{
	SDA_H;
	SCL_H;
}

void write_byte(uint8_t date)       //向24C02中写一个字节的数据
{
	uint8_t mask;
	SCL_L;
	for(mask=0x80;mask!=0;mask>>=1)    //从高位到低位依次进行
	{
		
		if((mask&date)==0)
		{
			SDA_L;
		}
		else
		{
			SDA_H;
		}
		//I2CDelay();
		SCL_H;
		//I2CDelay();
		SCL_L;
	}

}

uint8_t read_byte()   //读取一字节,从 24C02 中读取一个字节
{
	uint8_t i=0,read_data=0;
	SCL_L;
	//I2CDelay();
	SDA_H;
	//I2CDelay();
	for(i=0;i<8;i++)
	{
		SCL_H;        //I2C_SCL 拉高准备读数据
		//I2CDelay();
		read_data=(read_data<<1)|I2C_SDA; //将 I2C_SDA 中的数据读出
		SCL_L;        //I2C_SCL 拉低数据写完毕
		//I2CDelay();
	}
	return read_data;
}

void write_add(uint8_t address,uint8_t date)    //向 24C02 中写一个字节数据
{
	I2C_Start();        //起始信号
	write_byte(0XA0);    //发送写指令
	read_ACK();        //等待应答
	write_byte(address);   //发送要写入的地址
	read_ACK();            //等待应答
	write_byte(date);    //发送数据
	read_ACK();           //等待应答
	I2C_Stop();          //停止信号
}


/*void write_MultipleByte(uint8_t address,uint8_t length,uint8_t *date)    //连续地址,多数据持续写入
{ 
	while(length--)
	{
		write_add(address++,*date++);
	}
	
}*/

void write_MultipleByte(uint8_t address,uint8_t length,uint8_t *date)    //数据块写入
{ 
	I2C_Start();           
	write_byte(0XA0);      
	read_ACK();
	write_byte(address);    
	read_ACK();
	while(length--)
	{
		write_byte(*date++);
		read_ACK();
		//I2CDelay();
	}
	I2C_Stop();
}


uint8_t read_add(uint8_t address,bit ACK)  //从 24C02 中读出数据
{
	uint8_t date;
	I2C_Start();          //第一次起始信号
	write_byte(0XA0);      //发送写指令
	read_ACK();              //等待应答
	write_byte(address);     //发送要读取的地址
	read_ACK();              //等待应答
	I2C_Start();            //第二次起始信号
	write_byte(0XA1);       //发送读指令
	read_ACK();              //等待应答
	date=read_byte();      //读数据
	
	send_ACK(ACK);     //主机应答ACK或不应答
	
	I2C_Stop();          //停止信号
	
	return date;
}

void read_MultipleByte(uint8_t *temp,uint8_t address,uint8_t data_size)    //读出多个数据
{
	I2C_Start();
	write_byte(0XA0);
	read_ACK();
	write_byte(address);
	read_ACK();
	
	I2C_Start();
	write_byte(0XA1);
	read_ACK();
	
	while(data_size--)
	{
		*temp++=read_byte();
		//I2CDelay();
		send_ACK(data_size);     //主机应答ACK,当data_size = 0时,发送非应答    主机应答,则继续接受数据;不应答,即表示停止接收
	}
	
	I2C_Stop();
	
	//return temp;
}



iic.h

//iic.h - 实现相关的头文件
#include "type.h"
#ifndef __IIC_H__
#define __IIC_H__

#define  SCL_H  I2C_SCL=1
#define  SCL_L  I2C_SCL=0

#define  SDA_H  I2C_SDA=1
#define  SDA_L  I2C_SDA=0

sbit  I2C_SCL=P2^1;
sbit  I2C_SDA=P2^0;


extern void I2C_Start(void);
extern void I2C_Stop(void);
extern void read_ACK(void);
extern void I2C_init();
extern void write_byte(uint8_t date);
extern uint8_t read_byte() ;
extern void write_add(uint8_t address,uint8_t date) ;
extern uint8_t read_add(uint8_t address,bit ACK);
extern void send_ACK(bit ACK);
extern void write_MultipleByte(uint8_t address,uint8_t length,uint8_t *date);
extern void read_MultipleByte(uint8_t *temp,uint8_t address,uint8_t data_size) ;

#endif         //!__IIC_H__
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-08-06 09:59:50  更:2021-08-06 09:59:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 18:25:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码