蓝桥杯学习笔记 单片机CT107D AT24C02数据读写

一.AT24C02的使用
1.AT24C02基本介绍
  • AT24C02是一种可以实现掉电不丢失的存储器,可用于保存单片机运行时想要永久保存的数据信息
  • 存储介质:E2PROM
  • 通讯接口:I2C总线
2.CT107D中AT24C02引脚 介绍

图中A0 A1 A2决定着设备在iic中的地址 

设备地址

由原理图并结合数据手册可是可知在CT107D中 读的地址为0xa1,写的地址为0xa0 scl为P2^0,sda为P2^1(在iic.c中补全)

3.AT24C02数据帧
①字节写

 由手册可知,字节写操作如下:

  • 主机(MCU)发送start信号
  • 主机(MCU)发送设备地址并接收应答(write为低电平)
  • 主机(MCU)发送数据要送往的地址并接收应答
  • 主机(MCU)发送数据并接收应答
  • 主机发送(MCU)发送stop信号
void Write_24C02(unsigned char addr,unsigned char dat)
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(addr);
	I2CWaitAck();
	I2CSendByte(dat);
	I2CWaitAck();
	I2CStop();
}

注意: 数据写入指令发送后需要等待一段时间(不少于50ms)才能进行下一次字节写,否则会造成写入失败(若不是连续写可不注意)

② 页写

一般来说,CT107D上的AT24C02一个地址位只能写一个8位数据,如果想存储16位(或以上)的数据,除了多次写入外,也可进行也写的操作 

对照手册我们可以得知大致步骤: 

  • 主机(MCU)发送start信号
  • 主机(MCU)发送设备地址并接收应答(write为低电平)
  • 主机(MCU)发送数据要送往的地址并接收应答
  • 主机(MCU)发送每一位数据并接收应答,直到最后一个数据
  • 在接受最后一个应答信号后,发送stop信号

unsigned int temp    //以发送无符号整型为例
void AT24C02_PageWrite()
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(0x01);
	I2CWaitAck();
	I2CSendByte((temp)>>8);//发送高8位
	I2CWaitAck();
	I2CSendByte((temp));//发送低8位
	I2CWaitAck();
	I2CStop();
}

 

③随机读 

随机读并不是指在所有的地址中随机挑一个地址进行读取,而是按照给定的地址读取其中的数据。

由数据手册可知,在进行读操作之前先要进行一次“伪写”的操作:

  • 主机(MCU)发送start信号
  • 主机(MCU)发送设备地址并接收应答(write置低电平`)
  • 主机(MCU)发送要读取的地址并接收应答

之后便开始正式读取数据

  • 主机(MCU)发送start信号
  • 主机(MCU)发送设备地址并接收应答(read置高电平)
  • MCU接收数据并向AT24C02发送应答信号"1"(此时AT24C02作为主机接收应答信号)
  •  主机(MCU)发送STOP信号
unsigned char Read_24C02(unsigned char addr)
{
	unsigned char temp=0;
	I2CStart();            //伪写操作
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(addr);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	temp=I2CReceiveByte();
	I2CSendAck(1);
	I2CStop();
	return temp;
}
④顺序读

对照手册可知,顺序读可发送在随机读 和当前地址读之后,与上述两个不同的时,在接受第一个数据后发送应答信号(0),继续接受下一个数据,直到接受到最后一个数据,发送非应答信号(1),并发送stop信号

unsigned int temp
void AT24C02_SequentialRead()
{    
    unsigned char LSB,MSB;
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(0x01);
	I2CWaitAck();
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	MSB=I2CReceiveByte();//接受高8位
	I2CSendAck(0);
	LSB=I2CReceiveByte();//接受低8位
	I2CSendAck(1);
	I2CStop();
	temp=(MSB<<8)|LSB;复原16位数据
}

 

 

注:代码为新驱动代码,详情请参考这篇文章:

蓝桥杯学习笔记 单片机CT107D 新驱动代码的使用.-CSDN博客

二.练习

这里借用一些小蜜蜂老师的题目

代码参考:

main.c

#include <REGX52.H>
#include "iic.h"
code unsigned char SMG_NoDot[] =
{
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83, 0xc6,0xa1,0x86,0x8e};
unsigned char data1=0,data2=0,data3=0;
void Delay_SMG(unsigned int t)
{
	while(t--);
}
void Select_HC573(unsigned char channel,unsigned char dat)
{
	switch(channel)
	{
		case 4:
			P2=(P2&0x1f)|0x80;
		break;
		case 5:
			P2=(P2&0x1f)|0xa0;
		break;
		case 6:
			P2=(P2&0x1f)|0xc0;
		break;
		case 7:
			P2=(P2&0x1f)|0xe0;
		break;
		case 0:
			P2=(P2&0x1f)|0x00;
		break;
	}
	P0=dat;
	P2=(P2&0x1f)|0x00;
}
void SMG_Display(unsigned char pos,unsigned char dat)
{
	Select_HC573(6,0x01<<(pos-1));
	Select_HC573(7,dat);
	Delay_SMG(500);
	Select_HC573(6,0x01<<(pos-1));
	Select_HC573(7,0xff);
}
void SMG_Dynamic()
{
	SMG_Display(1,SMG_NoDot[data1/10]);
	SMG_Display(2,SMG_NoDot[data1%10]);
	SMG_Display(3,0xbf);
	SMG_Display(4,SMG_NoDot[data2/10]);
	SMG_Display(5,SMG_NoDot[data2%10]);
	SMG_Display(6,0xbf);
	SMG_Display(7,SMG_NoDot[data3/10]);
	SMG_Display(8,SMG_NoDot[data3%10]);
}
unsigned char Read_24C02(unsigned char addr)
{
	unsigned char temp=0;
	I2CStart();                                //伪写操作
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(addr);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	temp=I2CReceiveByte();
	I2CSendAck(1);
	I2CStop();
	return temp;
}
void Write_24C02(unsigned char addr,unsigned char dat)
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(addr);
	I2CWaitAck();
	I2CSendByte(dat);
	I2CWaitAck();
	I2CStop();
}
void Scan_Key()
{
	if(P3_3==0)
	{
		Delay_SMG(100);
		if(P3_3==0)
		{
			data1++;
			if(data1>13)
			{
				data1=0;
			}
			Write_24C02(0x00,data1);//因为不是连续写入可以不延时
			
		}
		while(P3_3==0)
		{
			SMG_Dynamic();
		}
	}
	if(P3_2==0)
	{
		Delay_SMG(100);
		if(P3_2==0)
		{
			data2++;
				if(data2>13)
			{
				data2=0;
			}
			Write_24C02(0x01,data2);
		}
		while(P3_2==0)
		{
			SMG_Dynamic();
		}
	}
	if(P3_1==0)
	{
		Delay_SMG(100);
		if(P3_1==0)
		{
			data3++;
				if(data3>13)
			{
				data3=0;
			}
			Write_24C02(0x02,data3);
		}
		while(P3_1==0)
		{
			SMG_Dynamic();
		}
	}
}
void Sys_Init()
{
	Select_HC573(4,0xff);
	Select_HC573(5,0x00);
//数据清零
//	Write_24C02(0x00,0);
//	Delay_SMG(1500);//延时,防止数据写入失败
//	Write_24C02(0x01,0);
//	Delay_SMG(1500);
//	Write_24C02(0x02,0);
//	Delay_SMG(1500);
	data1= Read_24C02(0x00);
	data2= Read_24C02(0x01);
	data3= Read_24C02(0x02);
}
void main()
{
	Sys_Init();
	while(1)
	{
		SMG_Dynamic();
		Scan_Key();
	}
}

 iic.h

#ifndef __IIC_H
#define __IIC_H

static void I2C_Delay(unsigned char n);
void I2CStart(void);
void I2CStop(void);
void I2CSendByte(unsigned char byt);
unsigned char I2CReceiveByte(void);
unsigned char I2CWaitAck(void);
void I2CSendAck(unsigned char ackbit);

#endif

iic.c

/*	#   I2C代码片段说明
	1. 	本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
	2. 	参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
		中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include <REGX52.H>
#include "intrins.h"//可使用nop代码
#define DELAY_TIME	5
sbit sda=P2^1;//对照原理图进行补全
sbit scl=P2^0;
//
static void I2C_Delay(unsigned char n)
{
    do
    {
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();		
    }
    while(n--);      	
}

//
void I2CStart(void)
{
    sda = 1;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 0;
	I2C_Delay(DELAY_TIME);
    scl = 0;    
}

//
void I2CStop(void)
{
    sda = 0;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 1;
	I2C_Delay(DELAY_TIME);
}

//
void I2CSendByte(unsigned char byt)
{
    unsigned char i;
	
    for(i=0; i<8; i++){
        scl = 0;
		I2C_Delay(DELAY_TIME);
        if(byt & 0x80){
            sda = 1;
        }
        else{
            sda = 0;
        }
		I2C_Delay(DELAY_TIME);
        scl = 1;
        byt <<= 1;
		I2C_Delay(DELAY_TIME);
    }
	
    scl = 0;  
}

//
unsigned char I2CReceiveByte(void)
{
	unsigned char da;
	unsigned char i;
	for(i=0;i<8;i++){   
		scl = 1;
		I2C_Delay(DELAY_TIME);
		da <<= 1;
		if(sda) 
			da |= 0x01;
		scl = 0;
		I2C_Delay(DELAY_TIME);
	}
	return da;    
}

//
unsigned char I2CWaitAck(void)
{
	unsigned char ackbit;
	
    scl = 1;
	I2C_Delay(DELAY_TIME);
    ackbit = sda; 
    scl = 0;
	I2C_Delay(DELAY_TIME);
	
	return ackbit;
}

//
void I2CSendAck(unsigned char ackbit)
{
    scl = 0;
    sda = ackbit; 
	I2C_Delay(DELAY_TIME);
    scl = 1;
	I2C_Delay(DELAY_TIME);
    scl = 0; 
	sda = 1;
	I2C_Delay(DELAY_TIME);
}

  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值