【51】I2C总线和AT24C02的使用、关于主函数void main和int main的思考

本文以AT24C02为例,介绍了I2C总线协议的使用方法。先阐述I2C总线的电路规范、时序结构和数据帧,接着介绍AT24C02芯片及数据帧。给出了I2C开始/停止、发送/接收数据等功能的程序示例,最后对51单片机主函数void main和int main进行了思考。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、I2C总线介绍

1. 电路规范

2. 时序结构

3. I2C数据帧

二、 AT24C02

1. 芯片介绍

2. 数据帧

三、程序示例

1. I2C开始/停止

2. 主机发送/接收数据

3. 主机发送/接收应答

四、关于主函数void main和int main的思考


本文参考资料:江协科技——[12-1] AT24C02(I2C总线)_bilibili

        在使用51的过程中,常会用到诸如OLED、AT24C02(EEPROM)等通讯协议较复杂的外设,据此,Philips公司开发了一种通用数据总线“I2C总线(Inter IC BUS)”,下文将以AT24C02为例,介绍该总线协议的使用方法

一、I2C总线介绍

通信线: SCL (Serial Clock)、SDA (Serial Data);特性:同步、半双工,带数据应答

1. 电路规范

f8ed40632d764d8eb377a809a69e8556.png

注:

1. 上拉电阻:通过电阻与一个固定的高电平VCC相接,使其电压在空闲状态保持在VCC电平电阻阻值与上下拉能力反相关,故强上拉的电阻阻值较小(强上拉一般在1K~5.6K,弱上拉至少是10K或更大阻值。

推荐参考文章:最全讲解上下拉电阻 - 知乎

2. SCL和SDA配置为开漏输出模式:使得不必在每个设备都接电源及上拉电阻,进而减小电路干扰;对SCL和SDA各添一个总的上拉电阻,使得挂载在总线上的所有设备都能在同一时间收到相同的信号,因此实现总线上多设备的挂载和使用

2. 时序结构

        1). 起始条件:SCL高电平期间,SDA从高电平切换到低电平
        2). 终止条件:SCL高电平期间,SDA从低电平切换到高电平

        3). 主机发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位在前),然后拉高SCL,从机在SCL高电平期间读取数据位(因此SCL高电平期间SDA不允许有数据变化),依次循环上述过程8次,即可发送一个字节。

        4). 主机接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线.上(高位在前),然后拉高SCL,主机将在SCL高电平期间读取数据位(同样SCL高电平期间SDA不允许有数据变化),依次循环上述过程8次,即可接收一个字节。【注意:主机在接收之前,需要释放SDA】

        5). 主机发送应答:在接收完一个字节之后,主机在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答。

        6). 主机接收应答:在发送完一个字节之后,主机在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答。【注意:主机在接收之前,需要释放SDA】

        即:主 ==> 从,从应答;从 ==> 主,主应答(主机接收完字节后,从机释放总线,主机接过总线后发送应答;而当主机发送完字节后,主机先释放总线,从机接过总线,通过总线向主机发送应答)

        注意:上文中的 “主机发送/接收应答” 一般简称为:SA(Send Acknowledge 发送应答)、RA(Receive Acknowledge 接收应答),下文统一使用简称

3. I2C数据帧

主机发送数据帧内容:起始信号包含写标志的从机地址 → 接收应答(从机给)→【发送字节接收应答(从机给)(若发送n字节则循环n次)】→ 终止信号

主机接收数据帧内容:起始信号包含读标志的从机地址接收应答(从机给,表示收到)→【读取字节 → 发送应答(主机发)(若接收n字节则循环n次)】→ 终止信号

二、 AT24C02

1. 芯片介绍

fc4ff9862f6d4e2d9506ff971b0430be.png

7d978ba8a8834b1592121000e51bc2ed.png

2. 数据帧

芯片手册原图:

601e6958c87e4e1a8921596f6d880384.png

12ab2cafcde24c18bd12e5946087413d.png

三、程序示例

        根据I2C时序图,可以知道I2C总线协议需要实现:开始/停止、发送/接收数据、发送/接收应答的功能,据此编写单片机程序,其中为了提高代码可读性,采用 "sbit" 关键字声明位寄存器,用 #define语句对已定义的寄存器再定义。

语法:#define <易懂的名字>     <寄存器> sbit <易懂的名字> = <位寄存器>,示例如下:

#define MATRIX LED     P0
sbit I2C_SCL=P2^1;
sbit I2C_SDA=P2^0;

sbit和sfr的区别:

  • sfr (Special Function Register 特殊功能寄存器声明)
  • sbit (Special Bit 特殊位声明)

例:

sfr P0= 0x80;         //声明P0口寄存器,物理地址为0x80
sbit P0_1 = 0x81;  或  sbit P0_1 = P0^1;         //声明P0寄存器的第1位

1. I2C开始/停止

实现函数
5f3ac4a0f4e442c5b372c0807ac12e31.png3790bca83ffa4ed6a1bf77de3ee67983.png

 这里的SDA置1/0:保证SCL变化之前SDA的状态

2. 主机发送/接收数据

 8a7d5b9d10654ad296f4e7ba3afe293d.png0547e6ae6f244ced8aaab07e9bdaecd1.png

 右图 SDA 置1:主机释放SDA,将控制权交给从机

3. 主机发送/接收应答

 0e1e2bf457264b6f8592e974a8ebac1e.png12ce8311e4cc4e2d9191242da7db290f.png

利用上述各I2C功能函数,可以实现使用AT24C02芯片存储数据 :

137edf67116f456c87add23538afc15f.png9256b39706504e21a1ac1d2412de67c5.png

 

最后,我们在主程序中调用AT24C02相关函数,实现数据存储与读取的相关功能:

#include <REGX52.H>
#include "LCD1602.h"
#include "Key.h"
#include "AT24C02.h"
#include "Delay.h"

unsigned char KeyNum;
unsigned int Num;

void main()
{
	LCD_Init();
	LCD_ShowNum(1,1,Num,5);
	while(1)
	{
		KeyNum=Key();
		if(KeyNum==1)	//K1按键,Num自增
		{
			Num++;
			LCD_ShowNum(1,1,Num,5);
		}
		if(KeyNum==2)	//K2按键,Num自减
		{
			Num--;
			LCD_ShowNum(1,1,Num,5);
		}
		if(KeyNum==3)	//K3按键,向AT24C02写入数据
		{
			AT24C02_WriteByte(0,Num%256);
			Delay(5); // AT24C02芯片的最大写入耗时5ms,故此处延时5ms,下同
			AT24C02_WriteByte(1,Num/256);
			Delay(5);
			LCD_ShowString(2,1,"Write OK");
			Delay(1000);
			LCD_ShowString(2,1,"        ");
		}
		if(KeyNum==4)	//K4按键,从AT24C02读取数据
		{
			Num=AT24C02_ReadByte(0);
			Num|=AT24C02_ReadByte(1)<<8;
			LCD_ShowNum(1,1,Num,5);
			LCD_ShowString(2,1,"Read OK ");
			Delay(1000);
			LCD_ShowString(2,1,"        ");
		}
	}
}

四、关于主函数void main和int main的思考:

        上文沿用的,51单片机开发(C51语言)常用的主函数形式:void main() { <函数体> }  并不是标准的C语言语法,但单片机的编译器(Keil)支持这种操作,这种写法也常见于很多资料中,而在C语言中标准的主函数形式 :int main(){ <函数体> } 也同样可用,且具有保证程序在不同编译器上都能够正常工作的优点;个人理解其原因在于:C++Primer第五版中文版(Page28)明确指出,main()函数的返回类型必须是int类型,即整数类型,而有些编译器会对其他语法作出适配,并且对C51语言来说,采用void关键字能更直观地体现其主函数无需返回值的特点,等效于没有return语句的int类型,但仍需明确其与标准语法的区别。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zosea231

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值