按下不同按键k1-k4,分别实现计数,清零,保存数据,恢复数据的功能(I2C和24C02芯片)

2023-12-23 06:15:45

代码:

#include "reg52.h"	

sbit SCL=P1^1; // 数据线sda和时钟线scl
sbit SDA=P1^2;

sbit k1=P2^0; // 单独定义四个按键
sbit k2=P2^1;
sbit k3=P2^2;
sbit k4=P2^3;	


unsigned char num=0; // 实现计数的变量
unsigned char dis[4]; // 保存数据
unsigned char seg[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; // 0-9
unsigned char bit_code[4] ={0x7f,0xbf,0xdf,0xef}; // 数码管的位码


// 延时函数
void delay(unsigned int i){
	while(i--);	
}

// 起始信号
void I2C_Start(){
	SDA=1; 	delay(5);
	SCL=1;	delay(5); 
	SDA=0;	delay(5);

	SCL=0;	delay(5);
}
          
// 终止信号                                                                         
void I2C_Stop(){
	SCL=0;  delay(5);

	SDA=0;	delay(5);
	SCL=1;	delay(5);
	SDA=1;	delay(5);
}

// 应答位
void I2C_ACK(){ 
	unsigned char i = 0;
	SCL = 0; delay(5);
	SDA = 0; delay(5);
	SCL = 1; delay(5);
	
	// SDA处于非应答的状态,等待其应答,超过指定时间,默认应答了
	while((SDA == 1) && (i < 100)) i++; 	
	SCL = 0; delay(5);
	SDA = 1; delay(5);
}

// 发送数据:把一个字节的自定义数据发送给总线SDA
void I2C_Send_Byte(unsigned char dat){
	unsigned char i;	
	for(i = 0; i < 8; i++){ // 1字节8位
		SCL = 0; delay(5); // SDA数据在SCL为0的期间可以更换
		dat <<= 1;		 // 这里dat最高位溢出了
		SDA = CY; 		delay(5); // 将最近的一位溢出给SDA
		SCL = 1;		delay(5);
	}
	I2C_ACK();
}

// 读取数据:从SDA数据线上读取一个字节的数据
unsigned char I2C_Read_Byte(){
	unsigned char i, dat = 0;
	SCL = 0; delay(5); // 在SCL为0期间,让SDA变为1,这样才能读取数据
	SDA = 1; delay(5);
	for(i = 0; i < 8; i++){ // 1字节8位
		SCL=1; delay(5);
		dat = (dat<<1) | SDA;
		SCL=0; delay(5);
	}
	return dat;		
}


void AT24C02_Write(unsigned char addr,unsigned char dat){
	I2C_Start();
	I2C_Send_Byte(0xa0);
	I2C_Send_Byte(addr);
	I2C_Send_Byte(dat);	
	I2C_Stop();
}

// 主器件的读、写操作
unsigned char AT24C02_Read(unsigned char addr){
	unsigned char dat;
	I2C_Start();
	I2C_Send_Byte(0xa0); // 读取指定从器件
	I2C_Send_Byte(addr); // 读取指定从器件的片内地址
	
	I2C_Start(); // 这个是必须的,重新启动
	I2C_Send_Byte(0xa1); // R 主器件接收从器件的数据
	dat = I2C_Read_Byte(); 
	I2C_Stop();
	return dat;	
}

// 不同按键实现不同功能
void key_in() 
{
	if(k1==0){
		delay(1000);  
		if(k1==0){
			num++; // 1. 自增
			if(num>255) num=0;
		}
		while(!k1); // 一直按着按钮,会卡在这个循环
	}

	if(k2==0){
		delay(1000);  
		if(k2==0){
			num=0; // 2. 清零
		}
		while(!k2); // 按键低电平有效,防抖动
	}

	if(k3==0){
		delay(1000);  
		if(k3==0){ // 3. 保存数据
			AT24C02_Write(0,num);   
		}
		while(!k3); // 按键低电平有效,防抖动
	}

	if(k4==0){
		delay(1000); 
		if(k4==0){ // 4. 恢复数据
			num=AT24C02_Read(0);	 
		}
		while(!k4); // 按键低电平有效,防抖动
	}

}

// 实现每个数码管对应的位码显示对应的数字  千 百 十 个 
void data_process() {
	dis[0]=seg[num/1000];
	dis[1]=seg[num%1000/100];
	dis[2]=seg[num%100/10];
	dis[3]=seg[num%10];
}

// 显示led灯
void led_show(){
		unsigned char i;
		for(i = 0; i < 4; i++){
		 P3=bit_code[i]; // 位码
		 P0=dis[i];      // 段码
		 delay(100); P0=0x00; delay(100); // 清除数码管的余晖效应
	  }	
}


void main(){	
	while(1){
		key_in();	 
		data_process(); 
		led_show();
	}		
}

仿真和视频演示:

仿真?????视频

原理介绍:

????????I2C(Inter Interface Circuit)全称为芯片间总线,是目前使用广泛的芯片间串行扩展总线。

????????目前世界上采用I2C总线有两个规范,荷兰飞利浦公司和日本索尼公司,现多采用飞利浦公司I2C总线技术规范,已成为电子行业认可的总线标准。采用I2C技术单片机以及外围器件种类很多,已广泛用于各类电子产品、家用电器及通信设备中。

????????I2C串行总线只有两条信号线,一条是数据线SDA,另一条是时钟线SCL。SDA和SCL是双向的,I2C总线上各器件数据线都接到SDA线上,各器件时钟线均接到SCL线上。

????????带有I2C接口单片机可直接与I2C总线接口的各种扩展器件(如存储器、I/O芯片、A/D、D/A、键盘、显示器、日历/时钟)连接。由于I2C总线采用纯软件寻址方法,无需片选线连接,大大简化总线数量。

?????????I2C串行总线运行由主器件控制。主器件是指启动数据的发送(发出起始信号)、发出时钟信号、传送结束时发出终止信号的器件,通常由单片机来担当。从器件可以是存储器、LED或LCD驱动器、A/D或D/A转换器、时钟/日历器件等,从器件须带有I2C串行总线接口。

????????I2C总线空闲时,SDA和SCL两条线均为高。连接到总线上器件输出级必须是漏级或集电极开路,只要有一器件任意时刻输出低电平,都将使总线上信号变低,即各器件SDA及SCL都是“线与” 关系。由于各器件输出为漏级开路,故须通过上拉电阻接正电源(见图10-6中两个电阻),以保证SDA和SCL在空闲时被上拉为高电平。SCL线上时钟信号对SDA线上各器件间数据传输起同步控制作用。SDA线上数据起始、终止及数据的有效性均要根据SCL线上的时钟信号来判断。

????????在标准I2C普通模式下,数据传输速率为100kbit/s,高速模式下可达400kbit/s。总线上扩展器件数量不是由电流负载决定的,而是由电容负载确定。I2C总线每个器件接口都有一定等效电容,连接器件越多,电容值就越大,这会造成信号传输延迟。总线上允许器件数以器件电容量不超过400pF(通过驱动扩展可达4 000pF)为宜,据此可计算出总线长度及连接器件数量。每个I2C总线器件都有唯一地址,扩展器件时也要受器件地址数目限制。

????????I2C总线应用系统允许多主器件,由哪一个主器件来控制总线要通过总线仲裁来决定。如何进行总线仲裁,读者可查阅I2C总线仲裁协议。但是在实际应用中,经常遇到的是以单一单片机为主器件,其他外围接口器件为从器件的情况。

1.数据位的有效性规定

????????I2C总线数据传送时,每一数据位传送都与时钟脉冲相对应。时钟脉冲为高电平期间,数据线上数据须保持稳定,在I2C总线上,只有在时钟线为低电平期间,数据线上电平状态才允许变化

2.起始信号和终止信号

????????由I2C总线协议,总线上数据信号传送由起始信号(S)开始、由终止信号(P)结束。起始信号和终止信号都由主机发出,在起始信号产生后,总线就处于占用状态;在终止信号产生后,总线就处于空闲状态。

(1)起始信号(S)。在SCL线为高期间,SDA线由高电平向低电平的变化表示起始信号,只有在起始信号以后,其他命令才有效。

(2)终止信号(P)。在SCL线为高期间,SDA线由低电平向高电平的变化表示终止信号。随着终止信号出现,所有外部操作都结束。

3.I2C总线上数据传送的应答

????????I2C总线数据传送时,传送字节数没有限制,但每字节须为8位长。数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随1位应答位(即1帧共有9位)

????????I2C总线在传送每1字节数据后都须有应答信号A,应答信号在第9个时钟位上出现,与应答信号对应的时钟信号由主器件产生。这时发方须在这一时钟位上使SDA线处于高电平状态,以便收方在这一位上送出低电平应答信号A。

????????由于某种原因收方不对主器件寻址信号应答时,例如收方正在进行其他处理而无法接收总线上数据时,必须释放总线,将数据线置为高电平,而由主器件产生一个终止信号以结束总线的数据传送。

????????当主器件接收来自从机数据时,接收到最后一个数据字节后,须给从器件发送一个非应答信号(A),使从机释放数据总线,以便主机发送一终止信号,从而结束数据传送。*

4.I2C总线上的数据帧格式

????????I2C总线上传送数据信号即包括真正的数据信号,也包括地址信号。

I2C总线规定,在起始信号后必须传送一从器件地址(7位),第8位是数据传送的方向位(R/W),用“0”表示主器件发送数据(W),“1”表示主器件接收数据(R)。**

????????每次数据传送总是由主器件产生的终止信号结束。但是,若主器件希望继续占用总线进行新的数据传送,则可不产生终止信号,马上再次发出起始信号对另一从器件进行寻址。因此,在总线一次数据传送过程中,可有以下几种组合方式:

(1)主器件向从器件发送n字节的数据,数据传送方向在整个传送过程中不变,数据传送格式:

其中:字节1~字节n为主机写入从器件的n字节的数据。格式中阴影部分表示主器件向从机发送数据,无阴影部分表示从器件向主器件发送,以下同。上述格式中的“从器件地址”为7位,紧接其后的“1”和“0”表示主器件的读/写方向,“1”-读,“0”-写。

(2)主器件读出来自从机的n字节。除第1个寻址字节由主机发出,n字节都由从器件发送,主器件接收,数据传送格式如下:

其中:字节1~字节n为从器件被读出的n字节数据。主器件发送终止信号前应发送非应答信号,向从器件表明读操作要结束。

(3)主器件的读、写操作。在一次数据传送过程中,主器件先发送1字节数据,然后再接收1字节数据,此时起始信号和从器件地址都被重新产生一次,但两次读写的方向位正好相反。数据传送格式如下:

????????格式中的“Sr”表示重新产生的起始信号,“从器件地址r”表示重新产生的从器件地址。

????????由上可见,无论哪种方式,起始信号、终止信号和从器件地址均由主器件发送,数据字节传送方向则由主器件发出的寻址字节中的方向位规定,每个字节传送都须有应答位(A或A)相随。*

5.寻址字节

????????在上面介绍的数据帧格式中,均有7位从器件地址和紧跟其后的1位读/写方向位,即寻址字节。I2C总线的寻址采用软件寻址,主器件在发送完起始信号后,立即发送寻址字节来寻址被控的从器件,寻址字节格式如下:

7位从器件地址为“DA3、DA2、DA1、DA0”和“A2、A1、A0”,其中“DA3、DA2、DA1、DA0”为器件地址,即器件固有地址编码,出厂时就已给定。“A2、A1、A0”为引脚地址,由器件“A2、A1、A0”为引脚地址,由器件引脚A2、A1、A0在电路中接高电平或接地决定。

????????数据方向位(R/W)规定了总线上的单片机(主器件)与从器件数据传送方向。R/W=1,表示主器件接收(读)。R/W*=0,表示主器件发送(写)**

6.数据传送格式

????????I2C总线每传送一位数据都与一个时钟脉冲对应,传送的每一帧数据均为一字节。但启动I2C总线后传送的字节数没有限制,只要求每传送一个字节后,对方回答一个应答位。在时钟线为高电平期间,数据线的状态就是要传送的数据。

????????数据线上数据改变须在时钟线为低电平间完成。在数据传输期间,只要时钟线为高电平,数据线都必须稳定,否则数据线上任何变化都当作起始或终止信号。

AT24C02芯片介绍

(1)封装与引脚

????????AT24C02的封装形式有双列直插(DIP)8脚式和贴片8脚式两种,无论何种封装,其引脚功能都是一样的。AT24C02的DIP形式引脚如图10-16所示,引脚功能见表10-5。

(2)存储单元的寻址

AT24C02存储容量为256B,分为32页,每页8B。有两种寻址方式:芯片寻址和片内子地址寻址。

① 芯片寻址。AT24C02芯片地址固定为1 010,它是I2C总线器件的特征编码,其地址控制字的格式为1 010 A2A1A0 R/W 。A2A1A0引脚接高、低电平后得到确定的3位编码,与1 010形成7位编码,即为该器件的地址码。由于A2A1A0共有8种组合,故系统最多可外接8片AT24C02,R/W*是对芯片的读/写控制位。*

② 片内子地址寻址。在确定了AT24C02芯片的7位地址码后,片内的存储空间可用1字节的地址码进行寻址,寻址范围为00H~FFH,即可对片内的256个单元进行读/写操作。

(3)写操作

AT24C02有两种写入方式,字节写入与页写入。

① 字节写入方式。单片机(主器件)先发送启动信号和1字节的控制字,从器件发出应答信号后,单片机再发送1字节的存储单元子地址(AT24C02内部单元的地址码),单片机收到AT24C02应答后,再发送8位数据和1位终止信号。

② 页写入方式。单片机先发送启动信号和1字节控制字,再发送1字节存储器起始单元地址,上述几个字节都得到AT24C02应答后,就可发送最多1页的数据,并顺序存放在已指定的起始地址开始的相继单元,最后以终止信号结束。

(4)读操作

????????AT24C02读操作也有两种方式,即指定地址读和指定地址连续读。

① 指定地址读方式。单片机发送启动信号后,先发送含有芯片地址的写操作控制字,AT24C02应答后,单片机再发送1字节的指定单元地址,AT24C02应答后再发送1个含有芯片地址读操作控制字,此时如AT24C02应答,被访问单元的数据就会按SCL信号同步出现在SDA线上,供单片机读取。

② 指定地址连续读方式。指定地址连续读方式是单片机收到每个字节数据后要做出应答,只有AT24C02检测到应答信号后,其内部的地址寄存器就自动加1指向下一个单元,并顺序将指向单元的数据送到SDA线上。当需要结束读操作时,单片机接收到数据后,在需要应答的时刻发送一个非应答信号,接着再发送一个终止信号即可。

文章来源:https://blog.csdn.net/hdz_wiz_csdn/article/details/135161847
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。