当前位置: 首页 > article >正文

51单片机个人学习笔记11(AT24C02-I2C总线)

前言

本篇文章属于STC89C52单片机(以下简称单片机)的学习笔记,来源于B站教学视频。下面是这位up主的视频链接。本文为个人学习笔记,只能做参考,细节方面建议观看视频,肯定受益匪浅。

[1-1] 课程简介_哔哩哔哩_bilibili

一、存储器介绍

存储器介绍

易失性存储器/RAM(random access memory 随机存储器):掉电会丢失

SRAM:静态RAM速度较快

DRAM:速度不如静态RAM

非易失性存储器/ROM(read only memory 只读存储器):掉电不会丢失

Mask ROM:掩膜ROM,不能写入,只能读取

PROM:可编程ROM,只能写入一次

EPROM:可擦除可编程ROM,紫外线照射30分钟才能擦除数据

EEPROM:电可擦除可编程ROM,可以通过电来迅速擦除


存储器的简化模型

烧录一词的由来:通过烧穿二极管来实现导通

二、AT24C02介绍

 引脚及应用电路

内部结构框图 

三、I2C总线

1.I2C总线介绍

2.I2C电路规范

 单片机的弱上拉模式

要输出低电平0时,闭合开关,无电阻经过,驱动能力较强

要输出高电平1时,断开开关,有电阻经过,驱动能力较弱

开漏输出

把上拉电阻去掉 

输出低电平时,闭合开关即可

输出高电平时,断开开关,IO口处于一个浮空的状态

 3.I2C时序结构

起始位与终止位

发送一个字节 

 接受一个字节

 从机应答

I2C数据帧 

发送

 接受

复合格式 

AT24C02数据帧 

四、实例一(AT24C02数据存储)

I2C.c

#include <REGX52.H>

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

/**
  * @brief  I2C开始 
  * @param  无
  * @retval  无
  */
void I2C_Start(void)
{
	I2C_SDA=1;
	I2C_SCL=1;
	I2C_SDA=0;
	I2C_SCL=0;
}

/**
  * @brief  I2C停止
  * @param  无
  * @retval  无
  */
void I2C_Stop(void)
{
	I2C_SDA=0;
	I2C_SCL=1;
	I2C_SDA=1;
}

/**
  * @brief  I2C发送一个字节
  * @param  Byte 要发送的字节
  * @retval  无
  */
void I2C_SendByte(unsigned char Byte)
{
	unsigned char i;
	for (i=0;i<8;i++)
	{
		I2C_SDA=Byte&(0x80>>i);
		I2C_SCL=1;
		I2C_SCL=0;
	}
}

/**
  * @brief  I2C接受一个字节
  * @param  无
  * @retval  接受到的一个字节数据
  */
unsigned char I2C_ReceiveByte(void)
{
	unsigned char i,Byte=0x00;
	
	I2C_SDA=1;
	
	for (i=0;i<8;i++)
	{
		I2C_SCL=1;
		if(I2C_SDA){Byte|=(0x80>>i);}
		I2C_SCL=0;
	}

	return Byte;
}

/**
  * @brief  I2C发送应答
  * @param  AckBit 应答位,0为应答,1为非应答
  * @retval  无
  */
void I2C_SendAck(unsigned char AckBit)
{
	I2C_SDA=AckBit;
	I2C_SCL=1;
	I2C_SCL=0;
}

/**
  * @brief  I2C接受应答
  * @param  无
  * @retval  接受到的应答位
  */
unsigned char I2C_ReceiveAck(void)
{
	unsigned char Ackbit;
	I2C_SDA=1;
	I2C_SCL=1;
	Ackbit=I2C_SDA;
	I2C_SCL=0;
	return Ackbit;
}




 AT24C02.c   --继承I2C的字节帧形成数据帧

#include <REGX52.H>
#include "I2C.h"
 
// SLAVE ADDRESS+W为0xA0,SLAVE ADDRESS+R为0xA1
#define AT24C02_ADDRESS_READ		0xA0
#define AT24C02_ADDRESS_WRITE		0xA1
 
/**
  * @brief  AT24C02写入一个字节
  * @param  WordAddress 要写入字节的地址
  * @param  Data 要写入的数据
  * @retval 无
  */
void AT24C02_WriteByte(unsigned char WordAddress,Data)
{
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS_READ);
	I2C_ReceiveAck();
	I2C_SendByte(WordAddress);
	I2C_ReceiveAck();
	I2C_SendByte(Data);
	I2C_ReceiveAck();
	I2C_Stop();
}
 
/**
  * @brief  AT24C02读取一个字节
  * @param  WordAddress 要读出字节的地址
  * @retval 读出的数据
  */
unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{
	unsigned char Data;
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS_READ);
	I2C_ReceiveAck();
	I2C_SendByte(WordAddress);
	I2C_ReceiveAck();
	I2C_Start();
	// 读地址
	I2C_SendByte(AT24C02_ADDRESS_WRITE);
	I2C_ReceiveAck();
	Data=I2C_ReceiveByte();
	I2C_SendAck(1);
	I2C_Stop();
	return Data;
}

 注意:调用AT24C02_WriteByte时要延时5ms,让数据有充分的时间写入

五、实例二(秒表(定时器扫描按键数码管)) 

在定时器的中断函数中调用按键扫描和数码管扫描的函数,实现定时器的复用

Key.c 

#include <REGX52.H>
#include "Delay.h"

unsigned char Key_KeyNum;

unsigned char Key()
{
	unsigned char Temp=0;
	Temp=Key_KeyNum;
	Key_KeyNum=0;
	return Temp;
}

unsigned char Key_GetState()
{
	unsigned char KeyNumber=0;
	if(P3_1==0){KeyNumber=1;}
	if(P3_0==0){KeyNumber=2;}
	if(P3_2==0){KeyNumber=3;}
	if(P3_3==0){KeyNumber=4;}
	return KeyNumber;
}

void Key_Loop(void)
{
	static unsigned char NowState,LastState;
	LastState=NowState;
	NowState=Key_GetState();
	//Last=1,Now=0检测的是松手,Last=0,Now=1检测的是按下
	if (LastState==1 && NowState==0)
	{
		Key_KeyNum=1;
	}
	if (LastState==2 && NowState==0)
	{
		Key_KeyNum=2;
	}
	if (LastState==3 && NowState==0)
	{
		Key_KeyNum=3;
	}
	if (LastState==4 && NowState==0)
	{
		Key_KeyNum=4;
	}
}

 Nixie.c

#include <REGX52.H>
#include "Delay.h"

unsigned char Nixie_Buf[9]={0,10,10,10,10,10,10,10,10};

unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00,0x40};

void Nixie_SetBuf(unsigned char Location,Number)
{
	Nixie_Buf[Location]=Number;
}

void Nixie_Scan(unsigned char Location,Number)
{
	P0=0x00;
	switch(Location)
	{
		case 1:P2_4=1;P2_3=1;P2_2=1;break;
		case 2:P2_4=1;P2_3=1;P2_2=0;break;
		case 3:P2_4=1;P2_3=0;P2_2=1;break;
		case 4:P2_4=1;P2_3=0;P2_2=0;break;
		case 5:P2_4=0;P2_3=1;P2_2=1;break;
		case 6:P2_4=0;P2_3=1;P2_2=0;break;
		case 7:P2_4=0;P2_3=0;P2_2=1;break;
		case 8:P2_4=0;P2_3=0;P2_2=0;break;
	}
	P0=NixieTable[Number];
}

void Nixie_Loop(void)
{
	static unsigned char i=1;
	Nixie_Scan(i,Nixie_Buf[i]);
	i++;
	if(i>8){i=1;}
}

 main.c

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

unsigned char KeyNum;
unsigned char Temp;
unsigned char Min,Sec,MiniSec;
unsigned char RunFlag;

void main()
{
	Timer0_Init();
	while(1)
	{
		KeyNum=Key();
		if(KeyNum==1)
		{
			RunFlag=!RunFlag;
		}
		if(KeyNum==2)
		{
			Min=0;
			Sec=0;
			MiniSec=0;
		}
		if(KeyNum==3)
		{
			AT24C02_WriteByte(0,Min);
			Delay(5);
			AT24C02_WriteByte(1,Sec);
			Delay(5);
			AT24C02_WriteByte(2,MiniSec);
			Delay(5);
		}
		if(KeyNum==4)
		{
			Min=AT24C02_ReadByte(0);
			Sec=AT24C02_ReadByte(1);
			MiniSec=AT24C02_ReadByte(2);
		}
		Nixie_SetBuf(1,Min/10);
		Nixie_SetBuf(2,Min%10);
		Nixie_SetBuf(3,11);
		Nixie_SetBuf(4,Sec/10);
		Nixie_SetBuf(5,Sec%10);
		Nixie_SetBuf(6,11);
		Nixie_SetBuf(7,MiniSec/10);
		Nixie_SetBuf(8,MiniSec%10);
	}
}

void Sec_Loop()
{
	if (RunFlag)
	{
		MiniSec++;
		if (MiniSec>=100)
		{
			MiniSec=0;
			Sec++;
			if (Sec>=60)
			{
				Sec=0;
				Min++;
				if (Min>=100)
				{
					Min=0;
				}
			}
		}
	}
}

void Timer0_Rountine() interrupt 1
{
	static unsigned int T0Count1,T0Count2,T0Count3;
	TH0=0xFC;   	    
	TL0=0x66;		   
	T0Count1++;
	if (T0Count1==20)       
	{
		T0Count1=0;
		Key_Loop();
	}
	T0Count2++;
	if (T0Count2==2)       
	{
		T0Count2=0;
		Nixie_Loop();
	}
	T0Count3++;
	if (T0Count3==10)
	{
		T0Count3=0;
		Sec_Loop();
	}
}


http://www.kler.cn/news/295213.html

相关文章:

  • 十一、C语言:字符串函数
  • ECCV`24 | 蚂蚁集团开源风格控制新SOTA!StyleTokenizer:零样本精确控制图像生成
  • chapter06 面向对象基础 知识点Note
  • 【鸿蒙开发】03 HarmonyNext开发中使用本地数据库进行数据存储
  • Python 中读取 Excel 表格数据
  • JAVA读写Excel(jxl,poi,easyExcel)
  • HTML 字符实体
  • iPhone手机清理软件:照片清理功能全解析
  • 基于springboot+vue+uniapp的“共享书角”图书借还管理系统小程序
  • 蓝桥杯嵌入式国三备赛经验分享
  • BAT脚本实现基础爬虫功能
  • 上海亚商投顾:深成指、创业板指均涨超1%,华为产业链反复活跃
  • 深入解析 Node.js:基础知识、环境搭建与核心模块详解
  • 文法—语法推导树例题
  • 面对Redis数据量庞大时的应对策略
  • 物联网之流水LED灯、正常流水灯、反复流水灯、移动流水灯
  • SprinBoot+Vue餐饮连锁店管理系统的设计与实现
  • 网络编程day03(网络体系结构、调试命令、TCP/IP对比)
  • el-table 单元格,双击编辑
  • some electronic products
  • isxdigit函数讲解 <ctype.h>头文件函数
  • Sysbench性能测试工具的安装与使用
  • Kettle使用命令pan/kitchen执行任务时传参问题
  • Node.js学习记录(一)
  • MySQL中常见的存储引擎有什么?
  • python操作数据对象方法和高阶函数
  • 19章 泛型(编程练习题)
  • windows C++-并行编程-将使用缩减变量的 OpenMP 循环转换为使用并发运行时
  • 经验笔记:负载均衡
  • Hive的优势与使用场景