蓝桥杯学习总结——EEPROM(AT24C02),PCF8951

EEPROM和PCF8951这两个外设都是基于I2C通信与单片机通信的,这里就不展开对I2C协议的讲解,感兴趣可以看看其他的大佬对于I2C的讲解,这里我们讲解如何用I2c来通信。I2C的底层代码会在比赛时提供,我们只需在底层文件中加EEPROM和PCF8951有关代码。

AT24C02

基础知识

AT24C02是一种可以实现掉电不丢失的存储器,可用于保存单片机运行时想要永久保存的数据信息

EEPROM有2k存储空间,可以存256个字节,可支持一次写入8个字节,一个内存地址可写入一个字节

代码部分

1.写AT24C02函数

1)编程思路

可以根据芯片手册写出写AT24C02函数

步骤:

1.写操作   IIC_SendByte(0xa0);

2.确定要写入的地址   IIC_SendByte(addr);

3.写入数据   IIC_SendByte(dat);

每发送一个字节数据时要启动I2C总线,同理发完数据时,也要关闭I2C总线。每次发送数据时I2C都要等待一次应答。

//写AT24C02
void vWrite_EEPROM(u8 add, u8 dat)
{
	IIC_Start();			//I2C总线启动
	IIC_SendByte(0xa0);		//AT24C02硬件地址,最低位为读写控制位,0-写。1-读
	IIC_WaitAck();			//I2C等待应答
	IIC_SendByte(add);		//I2C发送要存储数据地址
	IIC_WaitAck();			//I2C等待应答
	IIC_SendByte(dat);		//I2C发送要存储的数据
	IIC_WaitAck();			//I2C等待应答
	IIC_Stop();				//I2C总线停止发送
	vDelay_Ms(5);			//延时5ms,延长两次写的间隔,不然写入数据会出错,也可能损坏EEPROM
}

2)在main中如何调用函数


//开机次数统计
u8 start_times;
void vEEPROM_Process()
{
	start_times = ucRead_EEPROM(0x20);	 /*AT24C02的地址范围是0x00~0xff*/
	vWrite_EEPROM(0x20,++start_times);
}

//数码管操作函数
void vSMG_Process()
{
	smg_buf[0]=smg_code[start_times/10];
	smg_buf[1]=smg_code[start_times%10];
	smg_buf[2]=0x00;
	smg_buf[3]=0x00;
	smg_buf[4]=0x00;
	smg_buf[5]=0x00;
	smg_buf[6]=0x00;
	smg_buf[7]=0x00;
}

void main(void)
{
	vSystem_Init();
	vEEPROM_Process();
	vTimer2_Init();
	while(1)
	{
		vSMG_Process();
	}
}


//中断服务程序
void vTimer2_ISR() interrupt 12     	//中断入口
{
	vSMG_Display();
}

2.读ATC24C02函数

在数据手册中同样也可以找到读ATC24C02函数的一个流程

步骤:

1.写操作   IIC_SendByte(0xa0);

2.确定要写入的地址   IIC_SendByte(addr);

3.写入数据   IIC_SendByte(dat);

读数据操作与写时类似,但是在接收I2C数据时要发送应答1,表示成功接收到数据

//读AT24C02
u8 ucRead_EEPROM(u8 add)
{
	u8 dat;						//定义接收数据变量
	IIC_Start();				//I2C总线启动
	IIC_SendByte(0xa0);			//AT24C02硬件地址,写
	IIC_WaitAck();				/I2C等待应答
	IIC_SendByte(add);			//I2C发送要读取数据地址
	IIC_WaitAck();				//I2C等待应答
	
	IIC_Start();				//发送重复起始信号,以便从写模式切换到读模式
	IIC_SendByte(0xa1);			//AT24C02硬件地址,读
	IIC_WaitAck();				//I2C等待应答
	dat=IIC_RecByte();			//从I2C总线接收一个字节的数据
	IIC_SendAck(1);				//发送应答信号,表示已经成功接收到数据,1表示发送应答
	IIC_Stop();					I2C总线停止发送
	
	return dat;
}

 3.小技巧

        如果我们要读写不同数据或者多位数据时该如何做

//EEPROM处理函数
u16 u16_write = 1234;
u16 u16_read = 0;

float float_write = 3.1415;
float float_read = 0;

s8 minus_write = -23;
s8 minus_read = 0;

s16 minus_s16_write = -1234;
s16 minus_s16_read = 0;

u8 str_write[11]={"hello world"};
u8 str_read[11];
void vEEPROM_Process()
{
	u8 i = 0;
	
	/***************写入u16类型的数据**************/
	vWrite_EEPROM(0x00,u16_write>>8);
	vWrite_EEPROM(0x01,u16_write);
	u16_read = (ucRead_EEPROM(0x00)<<8)+ucRead_EEPROM(0x01);
	
	/***************写入float类型的数据,保留小数点后四位**************/
	vWrite_EEPROM(0x03,(u16)(float_write*1000)/256);
	vWrite_EEPROM(0x04,(u16)(float_write*1000)%256);
	float_read = (ucRead_EEPROM(0x03)*256+ucRead_EEPROM(0x04))/1000.0f;
	
	/***************写入负数,在数字电路中的存储形式是补码**************/
	/***************例如-23,其最高位为符号位1(表示负数),23的二进制10111,反码1110 1000,补码1110 1001 -> 0xE9**************/
	
	//	if(minus_write<0)
	//	{
	//		vWrite_EEPROM(0x06,'-');
	//		vWrite_EEPROM(0x07,-minus_write);
	//	}
	//	if(ucRead_EEPROM(0x06)=='-')
	//	{
	//		minus_read = 0 - ucRead_EEPROM(0x07);
	//	}
	
	vWrite_EEPROM(0x06,minus_write);
	minus_read = ucRead_EEPROM(0x06);	
	
	vWrite_EEPROM(0x08,minus_s16_write>>8);						//取出高8位
	vWrite_EEPROM(0x09,minus_s16_write);						//取出低8位
	minus_s16_read = (ucRead_EEPROM(0x08)<<8)+ucRead_EEPROM(0x09);
		
	/***************写入字符串,字符以ASCII码存储**************/
	for(i=0;i<sizeof(str_write);i++)
	{
		vWrite_EEPROM(0x10+i,str_write[i]);
	}
	for(i=0;i<sizeof(str_write);i++)
	{
		str_read[i]=ucRead_EEPROM(0x10+i);
	}
}

其实关于读写AT24C02方法还有好几种这里就不一一举例,如果感兴趣的话可以看其他大佬的一个方法

PCF8951

AD-DA芯片基本知识

ADC:模拟信号转化为数字信号,特定电压转换为二进制

DAC:数字信号转化为模拟信号,通过二进制让芯片输出特定的电压

在蓝桥杯所给I2C.c底层文件中修改添加读取ADC和DAC转换函数

ADC—DAC编程

1.读取ADC函数流程 

//读ADC函数
u8 Read_ADC(u8 chnl)
{
    u8 ADC_Val = 0;                   //接受读取对应通道的值
        
    I2CStart();                       //I2c初始化
    I2CSendByte(0x90);                //51向PCF8591写数据
    I2CWaitAck();                     //等待应答
    I2CSendByte(chnl);                //读取chnl通道
    I2CWaitAck();                      /等待应答
    
    I2CStart();                       //I2c初始化
    I2CSendByte(0x91);                //PCF8591向51写数据
    I2CWaitAck();                     //等待应答
    ADC_Val = I2CReceiveByte();       //返回读取的值
    I2CSendAck(1);                    //发送非应答
    I2CStop();                        //总线停止发送数据
    
    return ADC_Val;                   /返回数据
}
1)ADC值通道

采样通道0控制字:0100 0000(0x40

采样通道1(光敏电阻)控制字:0100 0001(0x41

采样通道3(旋转电位器)控制字:0100 0003(0x43

2)ADC值的转换


由于PCF8591是一个8位的ADC,所以读取到的值范围是0~255,但是比赛一般不会要求直接返回0~255的数据,一般要求返回的是电压,所以需要进行数据的转换。

将AD值(0~255)转换为实际电压(0~5),先成100,再除以51。先乘100的原因是把直接除51时的小数转换成整数,方便在数码管上显示。

将AD值转换为0~99的数值,直接除2.57

//ADC采样
u8 cnt_adc;
u8 ch0,ch1,ch3;
u16 ch3_volt;
u8 ch3_0_99,ch3_1_5;
void vADC_Process()
{
	if(cnt_adc>=10)
	{
		cnt_adc=0;
		ucRead_ADC(0x41);
		ch1 = ucRead_ADC(0x41);			//光敏电阻的AD值 - 通道1
		ucRead_ADC(0x43);
		ch3 = ucRead_ADC(0x43);			//旋转电位器的AD值 - 通道3
		
		ch3_volt = ch3*100/51;			// 0~255 --> 0~500
		ch3_0_99 = ch3/2.57f;			// 0~255 --> 0~99
		ch3_1_5 = ch3/51.1f + 1;
	}
}
3)在main主函数如何调用

u8 ADC_count;                    //在定时器中刷新读取
u8 ch1;                          //获取对应通道的值
/*PCF8951操作函数*/
void ADCorDAC_Loop()
{
	if(ADC_count >= 10)           // 10ms中刷新读取一次
	{
		ADC_count = 0;            //每次读取刷新重置ADC_count 为0
		ch1 = Read_ADC(0x41);     //获取0x41通道光敏电阻的值
	}

}

void T2Init() interrupt 12
{
	Count_Key++;
	T_Count++;
	Nixie_Display();
    ADC_count++;                //在定时器二中计时10ms
}

最后在mian,while中不断调取 ADCOrDAC_Loop函数。

2.写DAC流程

//写DAC
void Wirte_DAC(u8 Data)
{
	I2CStart();				   //I2c初始化
	I2CSendByte(0x90);         //51向PCF8591写数据
	I2CWaitAck();              //等待应答
	
	I2CSendByte(0x40);		   //通道选择无所谓,只要前面是0x4,启用DAC
	I2CWaitAck();			    //等待应答
		
	I2CSendByte(Data);			//发送数据
	I2CWaitAck();				//等待应答
	I2CStop();					//总线停止发送
}

在main中调用使用DAC函数

u8 DAC_count;

/*PCF8951操作函数*/
void ADCorDAC_Loop()
{
	if(DAC_count >= 2)                   //在定时器中计时2ms
	{
		static u8 dac_val=0;            
		DAC_count = 0;                    //每次读取刷新时间到了,将DAC_count清零
		Wirte_DAC(dac_val++);               //输出DAC值
	}
}



void T2Init() interrupt 12
{
	Count_Key++;
	T_Count++;
	Nixie_Display();
	DAC_count++;                    //在定时器2中计时刷新	
}

最后在mian,while中不断调取 ADCOrDAC_Loop函数。

  • 19
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
EEPROM存储器AT24C02驱动是一种用于控制和操作AT24C02 EEPROM芯片的软件程序。AT24C02是一种2K位串行电路编程只读存储器(EEPROM),能够以字节为单位进行读写操作。下面是一个简单的EEPROM存储器AT24C02驱动的实现示例: 首先,需要确定与AT24C02芯片通信的硬件接口。一般来说,AT24C02芯片使用I2C(TWI)总线进行通信。因此,需要确保控制器上的I2C总线控制器(如I2C模块)已正确配置和初始化。 其次,需要实现与AT24C02芯片通信的相关函数,如写入数据、读取数据等。这些函数可以通过在控制器上通过I2C总线传输控制字节和数据字节来执行相关的EEPROM操作。 例如,实现写入数据的函数,可以按照以下步骤进行: 1. 通过发出启动条件向AT24C02芯片发送设备地址。设备地址应包括芯片的固定地址和A0、A1和A2引脚的状态,用来识别芯片的物理位置。 2. 发送一个字节的内存地址,确定要写入数据的EEPROM存储器地址。 3. 发送要写入的数据字节。 4. 等待写操作完成,可以通过轮询芯片或等待I2C总线中断来检查。 5. 发送停止位,结束写操作。 同样,读取数据的函数也可以按照类似的步骤进行实现,只不过在发送内存地址之后需要切换到读操作模式,并在读取数据后保存数据字节。 在驱动程序的应用中,可以使用这些函数来存储和检索数据。通过提供适当的地址,可以将数据写入或读取到AT24C02芯片的特定地址中。此外,除了基本的读写功能之外,还可以实现其他操作,如块写入、页写入等。 总之,EEPROM存储器AT24C02驱动程序通过I2C总线控制器与AT24C02芯片进行通信,实现了对EEPROM芯片的读写操作。驱动程序应提供适当的函数来进行数据存储和检索,并可以根据应用需求扩展其他功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值