打印
[学习资料]

基于STM32的AT21CS01 EEPROM驱动代码

[复制链接]
885|38
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
AT21CS01/ AT21CS11

        AT21CS01/11 是一种 2 引脚存储器(SI/O 信号和地),其从信号引脚获取电能,从而为集成电路供电。它提供 1024 位串行电可擦除的可编程只读存储器(Electrically-Erasable Programmable Read-Only Memory,EEPROM),该存储器划分为 128 个 8 位字。
        该器件经过了优化,可使用两点机械连接(仅将一个信号(SI/O)和 GND 连接到无电配件)在无电配件中添加配置和使用信息。部分无电配件应用示例包括模拟传感器校准数据存储、打印机墨水/墨粉盒识别以及售后市场消耗品的管理。该器件的软件寻址方案允许最多 8 个器件共享一条通用单线总线。该器件提供多种节省空间的封装选项,SI/O 线的外部上拉电压范围为 1.7V 至 3.6V(AT21CS01)/2.7V 至 4.5V(AT21CS11)。
        AT21CS01/ AT21CS11使用单线串行接口,采用 I2C 协议结构,通过单个 I/O 引脚来实现器件通信。

使用特权

评论回复
沙发
过期的塔头|  楼主 | 2022-11-30 19:22 | 只看该作者

使用特权

评论回复
板凳
过期的塔头|  楼主 | 2022-11-30 19:23 | 只看该作者

使用特权

评论回复
地板
过期的塔头|  楼主 | 2022-11-30 19:24 | 只看该作者
复位ack时序

在器件上电后或主器件复位器件(将 SI/O 线保持低电平并持续 tRESET或 tDSCHG)后,主器件必须释放SI/O 线,该线随后将通过外部上拉电阻拉为高电平。之后,主器件必须再等待一段最小 tRRT 时间,然后才能请求从器件获取发现响应应答。

使用特权

评论回复
5
过期的塔头|  楼主 | 2022-11-30 19:25 | 只看该作者
在发现响应应答序列中,首先是主器件将 SI/O 线驱动为低电平,这将启动 AT21CS01/11 内部时序电路。主器件必须继续将此线驱动为低电平并持续 tDRR。
        在 tDRR 时间内,AT21CS01/11 将以并发的方式将 SI/O 驱动为低电平来进行响应。器件会继续将 SI/O 线驱动为低电平,总时长为 tDACK。主器件应从 tDRR 开始的 tMSDR 后对 SI/O 线的状态进行采样。按照定义,最小 tDACK 时间应比最大 tMSDR 时间长,从而确保主器件始终能够正确地从 SI/O 线上采样到低于 VIL 的电压。在 tDACK 时间过后,AT21CS01/11 将释放 SI/O 线,该线随后通过外部上拉电阻拉为高电平。

使用特权

评论回复
6
过期的塔头|  楼主 | 2022-11-30 19:26 | 只看该作者
代码:
Ack_t AT21CS01_Reset(void)
{
    u8 res = 0;

    AT21CS01_PowerOn();
        delay_us(20);
        /*for(int i = 0; i < 70 ; i++)*/delay_ms(100);
       
    AT21CS01_IO_L();
    delay_us(400);        //RESET
    AT21CS01_IO_H();
    delay_us(10);        //T_RRT
    AT21CS01_IO_L();
    delay_us(1);        //T_MSDR  2~6us
    AT21CS01_IO_Input();
        delay_us(1);
    res = GPIO_ReadInputDataBit(AT21CS01_IO_PORT, AT21CS01_IO_PIN);        //read ACK
    AT21CS01_IO_Output();
    AT21CS01_IO_H();
    return res ? NACK : ACK;        //read 1 -> NACK
}

使用特权

评论回复
7
过期的塔头|  楼主 | 2022-11-30 19:28 | 只看该作者
发送时序

主机逻辑0发送波形

使用特权

评论回复
8
过期的塔头|  楼主 | 2022-11-30 19:29 | 只看该作者
主机逻辑1发送波形

使用特权

评论回复
9
过期的塔头|  楼主 | 2022-11-30 19:31 | 只看该作者
代码:
Ack_t AT21CS01_SendByte(u8 data)
{
    u8 i = 0, res = 0;

    AT21CS01_IO_Output();
    for(; i < 8; i++)
    {
        if(data & 0x80)        //高位先发,高位为1
        {
            if(SPEED_MODE == HIGH_SPEED)        //高速模式
            {
                AT21CS01_IO_L();
                delay_us(TLOW_1_HighSpeed);                //发送逻辑1中的低电平
                AT21CS01_IO_H();
                delay_us(THIGH_1_HighSpeed);        //发送逻辑1中的高电平
            }
            else                                                        //标速模式
            {
                AT21CS01_IO_L();
                delay_us(TLOW_1_StandardSpeed);        //发送逻辑1中的低电平
                AT21CS01_IO_H();
                delay_us(THIGH_1_StandardSpeed);//发送逻辑1中的高电平
            }
        }
        else                                                                //高位先发,高位为0
        {
            if(SPEED_MODE == HIGH_SPEED)        //高速模式
            {
                AT21CS01_IO_L();
                delay_us(TLOW_0_HighSpeed);        //发送逻辑0中的低电平
                AT21CS01_IO_H();
                delay_us(THIGH_0_HighSpeed);        //发送逻辑0中的高电平
            }
            else                                                                //标速模式
            {
                AT21CS01_IO_L();
                delay_us(TLOW_0_StandardSpeed);        //发送逻辑0中的低电平
                AT21CS01_IO_H();
                delay_us(THIGH_0_StandardSpeed);        //发送逻辑0中的高电平
            }
        }
        data <<= 1;
    }
    AT21CS01_IO_L();        //拉低准备接收ACK
    if(SPEED_MODE == HIGH_SPEED)
    {
        delay_us(TWACK_HighSpeed);
    }
    else
    {
        delay_us(TWACK_StandardSpeed);
    }
    AT21CS01_IO_Input();
    __nop();
    res = GPIO_ReadInputDataBit(AT21CS01_IO_PORT, AT21CS01_IO_PIN);        //read ACK
    AT21CS01_IO_Output();
    AT21CS01_IO_H();        //释放ACK结束
    if(SPEED_MODE == HIGH_SPEED)
    {
        delay_us(TWACKHIGH_HighSpeed);
    }
    else
    {
        delay_us(TWACKHIGH_StandardSpeed);
    }
    return res ? NACK : ACK;
}

使用特权

评论回复
10
过期的塔头|  楼主 | 2022-11-30 19:33 | 只看该作者
接收时序

从机逻辑0反馈波形

使用特权

评论回复
11
过期的塔头|  楼主 | 2022-11-30 19:35 | 只看该作者
从机逻辑1反馈波形

使用特权

评论回复
12
过期的塔头|  楼主 | 2022-11-30 19:38 | 只看该作者
代码:
u8 AT21CS01_ReadByte(Ack_t ack)
{
    u8 i = 0, res = 0;

    AT21CS01_IO_Output();
    for(; i < 8; i++)
    {
        res <<= 1;
        AT21CS01_IO_L();
        if(SPEED_MODE == HIGH_SPEED)
        {
            delay_us(TRD_HighSpeed);
        }
        else
        {
            delay_us(TRD_StandardSpeed);
        }
        AT21CS01_IO_Input();
                delay_us(1);        //上拉时间
        res |= GPIO_ReadInputDataBit(AT21CS01_IO_PORT, AT21CS01_IO_PIN);
        AT21CS01_IO_Output();
        AT21CS01_IO_H();
        if(SPEED_MODE == HIGH_SPEED)
        {
            delay_us(TRDHIGH_HighSpeed);
        }
        else
        {
            delay_us(TRDHIGH_StandardSpeed);
        }
    }
    if(SPEED_MODE == HIGH_SPEED)
    {
        if(ack == ACK)
        {
            MACK_HighSpeed();
        }
        else//if(ack == NACK)
        {
            MNACK_HighSpeed();
        }
    }
    else
    {
        if(ack == ACK)
        {
            MACK_StandardSpeed();
        }
        else//if(ack == NACK)
        {
            MNACK_StandardSpeed();
        }
    }
    return res;
}

使用特权

评论回复
13
过期的塔头|  楼主 | 2022-11-30 19:40 | 只看该作者
连续发送/接收示例
//连续发送
void AT21CS01_SendData(u8* data, u16 len)
{
    while(len--)
    {
        AT21CS01_SendByte(*data);
        data++;
    }
}
//连续接收
void AT21CS01_ReadData(u8* buffer, u16 len)
{
    int i = 0;
    for( ; i < len - 1; i++)
    {
        buffer[i] = AT21CS01_ReadByte(ACK);
    }
    buffer[i] = AT21CS01_ReadByte(NACK);
}

使用特权

评论回复
14
过期的塔头|  楼主 | 2022-11-30 19:41 | 只看该作者
EEPROM访问

        EEPROM区有多种读写方式,下面以常用的随机地址连续读取和页写操作为例。

使用特权

评论回复
15
过期的塔头|  楼主 | 2022-11-30 19:42 | 只看该作者
EEPROM读取

        随机读操作以与字节写操作相同的方式开始,也就是将新的 EEPROM 存储器地址装入地址指针。但是并不发送字节写操作的数据字节和停止条件,而是将重复的启动条件发送到器件。这一序列称为“虚拟写入”。在发送了“虚拟写入”的器件地址和存储器地址字节之后,AT21CS01/11 将返回 ACK 响应。主器件随后即可启动当前地址读操作(以新的启动条件开始),以从 EEPROM 读取数据。

使用特权

评论回复
16
过期的塔头|  楼主 | 2022-11-30 19:43 | 只看该作者

使用特权

评论回复
17
过期的塔头|  楼主 | 2022-11-30 19:43 | 只看该作者
代码:
void EEPROMRead(u8* buffer, u8 addr, u8 len)
{
    DELAY_HTSS();
    AT21CS01_SendByte(EEPROM_ACCESS | WRITE);//dummy write
    AT21CS01_SendByte(addr);
    delay_us(800);
    AT21CS01_SendByte(EEPROM_ACCESS | READ);
    AT21CS01_ReadData(buffer, len);
    DELAY_HTSS();
}

使用特权

评论回复
18
过期的塔头|  楼主 | 2022-11-30 19:45 | 只看该作者
EEPROM页写

        页写操作允许在一个写周期内最多写入 8 个字节,前提是所有字节都在存储器阵列的同一行(地址位 A6到 A3 相同)。此外,还支持不足 8 字节的部分页写操作。
        接收到每个数据字节后,EEPROM 都将以 ACK 进行响应。在发送了所有数据字节后,器件需要一个停止条件来开始写周期。但是,由于停止条件定义为空位帧(SI/O 拉为高电平),因此主器件无需驱动 SI/O线即可实现这一点。如果在任何其他时间发送停止条件,则写操作将中止。在停止条件完成后,内部自计时写周期将开始。SI/O 引脚在整个 tWR 周期内必须通过外部上拉电阻上拉到高电平。因此,在有多个从器件的环境下,如果有任何器件处于内部写周期,则不应尝试与总线上的其他单线器件通信。

使用特权

评论回复
19
过期的塔头|  楼主 | 2022-11-30 19:46 | 只看该作者
     接收到每个数据字节后,存储器地址的低三位在内部递增。高地址位不会递增,器件将保持存储器页位置。无论实际写入的字节数如何,页写操作都仅限于在单个物理页内写入字节。当递增的字地址达到页边界时,地址计数器将“计满返回”到当前页的开头。但是应避免创建“计满返回”,因为页中先前装入的数据可能会被意外更改。在经过了最大 tWR 时间之后,主器件可能会开始新的总线事务。

使用特权

评论回复
20
过期的塔头|  楼主 | 2022-11-30 19:47 | 只看该作者
代码:
Ack_t EEPROMWritePage(u8* data, u8 addr, u16 len)
{
    int i = 0;
    Ack_t ack = ACK;

    DELAY_HTSS();
    ack &= AT21CS01_SendByte(EEPROM_ACCESS | WRITE);
    ack &= AT21CS01_SendByte(addr);
    for(i = 0; i < len; i++)
    {
        ack &= AT21CS01_SendByte(data[i]);
    }
    DELAY_HTSS();
    delay_ms(5);        //t_WR
    return ack;
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

78

主题

923

帖子

0

粉丝