Detailed Configuration of an Intelligent Lock System Based on STM32: A Case Study of AT24C04 (Part 1)

1. The Relationship Between I²C Timing and AT24Cxx Driver

AT24Cxx (24C02/04/08/16…) is an EEPROM storage chip that communicates with the MCU via the I²C bus.The essence of I²C is:

Using two wires (SCL, SDA) to read and write data according to a fixed timing.

Signal Line Meaning
SCL Clock line, controlled by the master (MCU)
SDA Data line, where the data is transmitted

I²C is a typical “timing protocol” that must adhere to strict rules such as start signal, stop signal, acknowledgment, and data validity.

2. Key I²C Timing Review

Detailed Configuration of an Intelligent Lock System Based on STM32: A Case Study of AT24C04 (Part 1)

The core operations of I²C include:

  1. Start Condition (START)

  • SCL = High

  • SDA transitions from high to low

  • Stop Condition (STOP)

    • SCL = High

    • SDA transitions from low to high

  • Acknowledgment (ACK)

    • The receiver pulls SDA low (0) to indicate ACK

    • Releasing SDA (1) indicates NACK

  • Data Transmission

    • SDA must remain stable when SCL = High

    • Data changes can only occur when SCL = Low

    3. Detailed Explanation of Functions

    1) IIC Start Signal:<span><span>iic_star()</span></span>

    void iic_star(void){SCL_L;  SDA_H;   SCL_H;timer5_delay_us(5);SDA_L;timer5_delay_us(5);SCL_L;}

    Function Description

    <span>iic_star()</span> is used to generate the I²C Start Signal (START).

    The standard definition of the START condition is:

    When SCL is high, SDA transitions from high to low.

    This is the only legal way to start according to I²C specifications; all communication must begin with START.

    Line-by-Line Analysis

    <span>SCL_L;</span>

    • Pull the clock line low first.

    • Why? Because only when SCL is low can SDA change levels without being interpreted as a START/STOP signal.This is understandable, right?

    <span>SDA_H;</span>

    • Pull SDA high first (ensuring it is in a stable “high to low” transition state)

    • This is to create the falling edge later.

    <span>SCL_H;</span>

    • Now pull the clock line high.

    • This is the key preparation state for I²C START.

    <span>SDA_L;</span> (The Main Event)

    • When SCL = High, let SDA transition from high to low

    • Complete the Start Signal (START)

    <span>SCL_L;</span>

    • Immediately pull SCL low after the start signal is completed, so that subsequent data transmission can begin.

    Summary

    <span>iic_star()</span> generates the START condition strictly according to the I²C protocol.

    The essence of the start signal: SDA generates a falling edge when SCL is high.

    2) IIC Stop Signal:<span><span>iic_stop()</span></span>

    Original Code

    void iic_stop(void){SCL_L;SDA_H;SCL_H;timer5_delay_us(5);SDA_H;timer5_delay_us(5);}

    STOP Condition Definition:

    When SCL is high, SDA transitions from low to high, which is STOP.

    Line-by-Line Analysis:

    1. Preparation: Pull SCL low, pull SDA high

    2. SCL goes high → Preparing for STOP

    3. SDA ensures transition from low to high → STOP is generated

    STOP is the end signal of communication, and AT24Cxx will start its internal write cycle after STOP (during write operations).

    For the following receive ACK/NACK signals and send ACK/NACK signals, remember this sentence

    Receive ACK/NACK Signal

    The master will send a bit of data on the next clock after receiving a byte, where data 0 indicates ACK and data 1 indicates NACK.

    Send ACK/NACK Signal

    The master will receive a bit of data on the next clock after sending a data byte, where data 0 indicates ACK and data 1 indicates NACK

    3) Send ACK/NACK:<span><span>iic_send_ack(u8 ack)</span></span>

    void iic_send_ack(u8 ack){SCL_L;     timer5_delay_us(3);    ack ? (SDA_H) : (SDA_L);timer5_delay_us(2);SCL_H;      timer5_delay_us(5);SCL_L;}

    Concept Explanation

    • ACK = 0: Reception successful

    • NACK = 1: Indicates no need to continue receiving (usually used for the last byte)

    Explanation

    In I²C:

    ACK SDA Level
    0 Pulled low (valid acknowledgment)
    1 Released to high (no acknowledgment)

    After the master sends a byte, it waits for the slave to acknowledge; after the master reads a byte, it must send ACK/NACK.

    4) Read Slave ACK:<span><span>iic_get_ack()</span></span>

    u8 iic_get_ack(void){    u8 ack;SCL_L;      SDA_H;SCL_L;      timer5_delay_us(5);SCL_H;timer5_delay_us(5);if(SDA_READ_INT)    {        ack = 1;    }else    {        ack = 0;    }SCL_L;    return ack;}

    Explanation

    • Read whether the slave pulls SDA low.

    • The master must configure SDA as input (high impedance), so first <span>SDA_H</span>.

    • If SDA=0 → ACK

    • If SDA=1 → NACK

    After writing to AT24Cxx, it will be in an internal busy state, and ACK will be crucial.

    5) Send 1 Byte:<span><span>iic_send_byte()</span></span>

    void iic_send_byte(u8 data){    u8 i;for(i=0;i<8;i++)    {        SCL_L;        timer5_delay_us(3);if(data & 0x80)        {            SDA_H;        }else        {            SDA_L;        }        timer5_delay_us(2);        SCL_L;        timer5_delay_us(5);data = data << 1;    }SCL_L;}

    Explanation

    The process complies with the basic rules of I²C:

    Data bits must be stable before the rising edge of SCL and remain unchanged during the high period.

    Loop 8 times, sending each bit of data from high to low.

    6) Receive 1 Byte:<span><span>iic_read_byte()</span></span>

    u8 iic_read_byte(void){    u8 i;    u8 data;SCL_L;       SDA_H;for(i=0;i<8;i++)    {        SCL_L;        timer5_delay_us(5);        SCL_H;        timer5_delay_us(5);        data = data << 1;        if(SDA_READ_INT)        {            data |= 0x01;        }}SCL_L;    return data;}

    Explanation

    • SDA is set to input (high impedance)

    • The master reads SDA when SCL is high

    • Read 8 bits to form a byte

    After reading, the master must send ACK or NACK (see previous functions).

    In the next section, we will use the functions we encapsulated above to write the low-level driver for AT24C02.

    Leave a Comment