目录
一、驱动概述
二、AT24C64简介
三、驱动编写
四、驱动应用
一、驱动概述
这是驱动篇的第一篇,所以先说明下驱动篇的作用和书写计划。之前的净化器项目已有提及,向ESP8266、SHT30这些都属于驱动设备,主芯片STM32是核心,相当于大脑,这些外部模块相当于手眼耳鼻。那STM32要如何调用这些驱动设备呢,这就需要驱动程序了,像双面胶一样,粘合这两部分。
其实驱动程序我们平时在使用个人电脑的时候也经常接触,比如我们在使用烧写器的时候直接插电脑USB首先是电脑无法识别的,需要你安装驱动程序后才能识别,这个驱动程序是烧写器厂家根据Windows的系统要求编写的,如果厂家没有写苹果系统的驱动程序,那么理论上你就不能在苹果电脑上使用烧写器了。所以,驱动程序要有比较好的移植能力,这样你在各个单片机平台之间就可以很好复用了,因为你毕竟无法预料老板想用哪款芯片做新项目。
这样一说,大家也应该基本明白了,驱动程序之间没有关联,所以这个系列就是在不断扩充品类,上下文之间没有太大关联。根据计划,我把要写的清单先列一下:EEPROM存储器AT24C64、4G、NB-Iot、LoRa、实时时钟DS1302、电能芯片HLW8032、磁编码AS5600、modbus协议、加解密算法、hp303b气压传感器、MPU6050陀螺仪、SHA204A安全认证芯片、FLASH存储器 W25Q64、以太网W5500等等,反正想到什么写什么了,或者读者有什么需要的可以留言,有条件也安排上了。
这里面LoRa是比较特殊的,因为它可以使用LoRaWAN也可以自组网,后面应该会单独开一篇LoRa自组网协议的文章。
二、AT24C64简介
下面回归本篇主题,EEPROM存储器 AT24C64,AT24CXX是个系列,后面XX代表容量,这里具体可以看手册。AT24C64_(IDCHIP(英锐芯))AT24C64中文资料_价格_PDF手册-立创电子商城
看手册不管中文版或者英文版,都要学会抓关键,像这类IIC器件的关键就是器件地址和数据地址,一般器件地址是厂家定义+引脚自定义决定的,数据地址对于这款芯片来说就是空间容量了,提炼出来就是下面这些截图了。
如上图所示,AT24C64存储空间是8192字节,转换成16进制就是0x2000,所以读写范围不要超过这个,驱动程序内要有边界保护。
如上图所示,一般来讲如果就一块AT24C64的话,地址A0A1A2都是直接接地的,根据地址脚数量可知,一条IIC总线可以挂载8个存储芯片。对于IIC,我这里都是使用模拟IIC,这样可移植性以较好。
如上图所示,AT24C64的起始器件地址是0xA0,二进制(1010 0000),其它的根据硬件电路决定。
如上图所示,读写都是差不多的,注意点是数据地址是2字节,因为存储空间是0x2000;还有一个是写的时候,如果地址重新换页了,那么要重启总线信号才能继续写数据进去,AT24C64一页是32个字节,所以代码里有部分是如下所示。
三、驱动编写
接下去是代码部分,先看下头文件部分,并不复杂。
接下来是代码部分,代码里都有注释了读写的数据地址范围,还有写数据换页时候要重启总线,然后稍微延时下,这里写代码时候稍微有点技巧,自己看代码琢磨了。
#include "drv_at24c64.h"
At24c64WorkStruct g_sAt24c64Work={0};
/*
================================================================================
描述 :初始化
输入 :
输出 :
================================================================================
*/
void at24c64_init(GPIO_TypeDef* port_sda, u16 pin_sda, GPIO_TypeDef* port_scl, u16 pin_scl)
{
I2cDriverStruct *pIIC=&g_sAt24c64Work.tag_iic;
pIIC->port_sda=port_sda;
pIIC->pin_sda=pin_sda;
pIIC->port_scl=port_scl;
pIIC->pin_scl=pin_scl;
g_sAt24c64Work.dev_addr=0xA0;//默认器件地址
IIC_GPIOInit(pIIC);
}
/*
================================================================================
描述 : 设置器件地址
输入 :
输出 :
================================================================================
*/
void at24c64_set_dev_addr(u8 dev_addr)
{
g_sAt24c64Work.dev_addr=dev_addr;
}
/*
================================================================================
描述 : 读数据
输入 :
输出 :
================================================================================
*/
u16 at24c64_read(u32 data_addr, u8 *out_buff, u16 len)
{
u8 dev_addr=g_sAt24c64Work.dev_addr;//器件地址
u16 i=0;
if(len==0 || data_addr+len>AT24C64_MAX_ADDR)//数据范围检测
return 0;
I2cDriverStruct *pIIC=&g_sAt24c64Work.tag_iic;
IIC_Start(pIIC);
IIC_WriteByte(pIIC, dev_addr );//写器件地址
IIC_WaitAck(pIIC);
IIC_WriteByte(pIIC, data_addr>>8 );
IIC_WaitAck(pIIC);
IIC_WriteByte(pIIC, data_addr ); //写数据地址
IIC_WaitAck(pIIC);
IIC_Start(pIIC);
IIC_WriteByte(pIIC, dev_addr|0x01 );//准备读
IIC_WaitAck(pIIC);
for(i=0;i<len-1;i++)//循环读取,少一个字节
{
out_buff[i]=IIC_ReadByte(pIIC);
IIC_Ack(pIIC);//ACK
}
out_buff[i]=IIC_ReadByte(pIIC);//读取最后一个字节
IIC_NAck(pIIC);//NACK
IIC_Stop(pIIC);
return len;
}
/*
================================================================================
描述 :写数据
输入 :
输出 :
================================================================================
*/
u16 at24c64_write(u32 data_addr, u8 *in_buff, u16 len)
{
u8 dev_addr=g_sAt24c64Work.dev_addr;//器件地址
u8 *pData=in_buff;
if(len==0 || data_addr+len>AT24C64_MAX_ADDR)//数据范围检测
return 0;
I2cDriverStruct *pIIC=&g_sAt24c64Work.tag_iic;
while(len>0)
{
IIC_Start(pIIC);
IIC_WriteByte(pIIC, dev_addr);//写器件地址
IIC_WaitAck(pIIC);
IIC_WriteByte(pIIC, data_addr>>8 );
IIC_WaitAck(pIIC);
IIC_WriteByte(pIIC, data_addr );//写数据地址
IIC_WaitAck(pIIC);
//继续写
while(len>0)
{
IIC_WriteByte(pIIC, *pData );
IIC_WaitAck(pIIC);
len--;
pData++;
data_addr++;
if(data_addr%32==0)//写满一页,必须重新启动总线
{
break;
}
}
IIC_Stop(pIIC);
delay_ms(5);//适当延时
}
return len;
}
四、驱动应用
应用层就是初始化,然后读写了,没什么太复杂的东西。以后还会接触一个FLASH存储器,那个需要整页先擦除才能写入,容量比较大;而EEPROM不需要这个步骤,某个地址可以直接重复写入,但是它的容量比较小,适合存储一些参数信息。