雅特力AT32F421 IIC读写EEPROM AT24C64

【注意】

        我在一开始由于第一次使用雅特力芯片,以为时钟脚和数据脚初始化为推挽输出也能用,但是这个芯片需要初始化为IIC复用功能,希望读者不要犯这个错误。

【硬件介绍】 

        AT24C64相信大家都不陌生,在学习51的时候相信大家都学过,在这边我就不多赘述了。直接点上代码。

【代码】

这是时钟脚和数据脚的初始化

文件名 at24c64.c 

//引脚初始化
void IIC_Init(void)
{
    gpio_init_type gpio_initstructure;
 
    /* i2c periph clock enable */     
    crm_periph_clock_enable(CRM_GPIOF_PERIPH_CLOCK, TRUE);

    /* gpio configuration */
    gpio_initstructure.gpio_out_type       = GPIO_OUTPUT_OPEN_DRAIN;
    gpio_initstructure.gpio_pull           = GPIO_PULL_UP;
    gpio_initstructure.gpio_mode           = GPIO_MODE_MUX;
    gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;

    /* configure i2c pins: scl */
    gpio_initstructure.gpio_pins = GPIO_PINS_6;
    gpio_init(GPIOF, &gpio_initstructure);
    gpio_pin_mux_config(GPIOF, GPIO_PINS_SOURCE6, GPIO_MUX_0);

    /* configure i2c pins: sda */
    gpio_initstructure.gpio_pins = GPIO_PINS_7;
    gpio_init(GPIOF, &gpio_initstructure);
    gpio_pin_mux_config(GPIOF, GPIO_PINS_SOURCE7, GPIO_MUX_0);
}
//at24c64.c 
 
#define SDAT_SET                   gpio_bits_set(GPIOF, GPIO_PINS_7)
#define SDAT_CLR                   gpio_bits_reset(GPIOF, GPIO_PINS_7)
#define TST_SDAT                   (gpio_input_data_bit_read(GPIOF, GPIO_PINS_7))

#define SCLK_SET                   gpio_bits_set(GPIOF, GPIO_PINS_6)
#define SCLK_CLR                    gpio_bits_reset(GPIOF, GPIO_PINS_6)
uchar i2c_i, i2c_cnt;

void SDA_Input_Mode()
{
         
    gpio_init_type gpio_initstructure;
    crm_periph_clock_enable(CRM_GPIOF_PERIPH_CLOCK, TRUE);
    
    gpio_initstructure.gpio_pins = GPIO_PINS_7;     
    gpio_initstructure.gpio_pull           = GPIO_PULL_UP;
    gpio_initstructure.gpio_mode           = GPIO_MODE_INPUT;
    gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
           
    gpio_init(GPIOF, &gpio_initstructure);
}

void SDA_Output_Mode()
{   
    gpio_init_type gpio_initstructure;
    crm_periph_clock_enable(CRM_GPIOF_PERIPH_CLOCK, TRUE);
    
    gpio_initstructure.gpio_pins = GPIO_PINS_7;
    gpio_initstructure.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
    gpio_initstructure.gpio_pull           = GPIO_PULL_NONE;
    gpio_initstructure.gpio_mode           = GPIO_MODE_OUTPUT;
    gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
           
    gpio_init(GPIOF, &gpio_initstructure);
}

void SCL_Output_Mode()
{
    gpio_init_type gpio_initstructure;
    crm_periph_clock_enable(CRM_GPIOF_PERIPH_CLOCK, TRUE);
    
    gpio_initstructure.gpio_pins = GPIO_PINS_6;
    gpio_initstructure.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
    gpio_initstructure.gpio_pull           = GPIO_PULL_NONE;
    gpio_initstructure.gpio_mode           = GPIO_MODE_OUTPUT;
    gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
           
    gpio_init(GPIOF, &gpio_initstructure);
}

 

void I2c_Delay(void)
{
  delayInUs(5);
}
 
void Start(void)
{
    SDA_Output_Mode();
    SCL_Output_Mode();
    SCLK_SET;
    SDAT_SET;
    I2c_Delay();
    SDAT_CLR;
    I2c_Delay();
    SCLK_CLR;
}

void Stop(void)
{
	SCLK_SET;
    SDAT_CLR;
    I2c_Delay();
    SDAT_SET;
}

void Ack(void)
{
	SDAT_CLR;
	SCLK_SET;
	I2c_Delay();
	SCLK_CLR;
}

void NoAck(void)
{
	SDAT_SET;
	SCLK_SET;
	I2c_Delay();
	SCLK_CLR;
}

void I2c_Write_Byte(uchar wbyte)
{
    for(i2c_i = 8; i2c_i > 0; i2c_i--)
    {
        if((wbyte & 0x80) == 0x80)
        {
            SDAT_SET;
        }
        else
        {
            SDAT_CLR;
        }
        SCLK_SET;
        I2c_Delay();
        SCLK_CLR;
        wbyte <<= 1;
		I2c_Delay();
    }
    I2c_Delay();
    Ack();
}

uchar I2c_Read_Byte(void)
{
    uchar rbyte;
	rbyte = 0;
    SDA_Input_Mode();
    for(i2c_i = 0; i2c_i < 8; i2c_i++)
    {
	    SCLK_SET;
        rbyte <<= 1;
        if(TST_SDAT)
        {
            rbyte |= 0x01;
        }
		I2c_Delay();
        SCLK_CLR;
        I2c_Delay();
    }
    SDA_Output_Mode();
    return rbyte;
}

void I2c_Write_Data(uint addr, uchar wrbyte)
{
    Start();
    I2c_Write_Byte(0xa0);
    I2c_Write_Byte(addr >> 8);
    I2c_Write_Byte(addr & 0xff);
    I2c_Write_Byte(wrbyte);
    Stop();
    delayInMs(6);
}

uchar I2c_Read_Data(uint addr)
{
    Start();
    I2c_Write_Byte(0xa0);
    I2c_Write_Byte(addr >> 8);
    I2c_Write_Byte(addr & 0xff);
    Start();
    I2c_Write_Byte(0xa1);
    i2c_cnt = I2c_Read_Byte();
    NoAck();
    Stop();
    return i2c_cnt;
}


void I2c_Write_Page(uint addr, uchar cnt, uchar *datapointer)
{
    Start();
    I2c_Write_Byte(0xa0);
    I2c_Write_Byte(addr >> 8);
    I2c_Write_Byte(addr & 0xff);
    for(i2c_cnt = 0; i2c_cnt < cnt; i2c_cnt++)
    {
        I2c_Write_Byte(*datapointer);
        datapointer++;
    }
    Stop();
    delayInMs(5);
}

void I2c_Read_Page(uint addr, uchar cnt, uchar *datapointer)
{
    Start(); 
    I2c_Write_Byte(0xa0);
    I2c_Write_Byte(addr >> 8);
    I2c_Write_Byte(addr & 0xff);
    Start();
    I2c_Write_Byte(0xa1);
	cnt -= 1;
    for(i2c_cnt = cnt; i2c_cnt > 0; i2c_cnt--)
    {
    	*datapointer = I2c_Read_Byte();
    	Ack();
    	datapointer++;
    }
    *datapointer = I2c_Read_Byte();
    NoAck();
    Stop();
}

void I2c_Write_Word(uint addr, uint wWord)
{
	uchar tmpArr[2];

	tmpArr[0] = (uchar)wWord;
	tmpArr[1] = (uchar)wWord >> 8;

	I2c_Write_Page(addr, 2, tmpArr);
}

uint I2c_Read_Word(uint addr)
{
	uchar tmpArr[2];
	uint rWord;
	
	I2c_Read_Page(addr, 2, tmpArr);
	rWord = tmpArr[1];
	rWord = (rWord << 8) | tmpArr[0];

	return rWord;
}

 文件名 at24c64.h

#ifndef __AT24C64_H__
#define __AT24C64_H__
 
 

uchar I2c_Read_Data(uint addr);
void I2c_Write_Data(uint addr, uchar wrbyte);
void I2c_Write_Word(uint addr, uint wWord);
uint I2c_Read_Word(uint addr);
void I2c_Write_Page(uint addr, uchar cnt, uchar *datapointer);
void I2c_Read_Page(uint addr, uchar cnt, uchar *datapointer);

#endif 

以上是本文全部内容,驱动代码都是测试正确的,需要的读者可以直接用,但是还是建议自己多实践才能真正理解。

### 关于AT24C64 IIC库函数读写示例代码 对于基于不同MCU平台上的AT24C64 EEPROM的操作,可以利用各自的标准库或硬件IIC模块实现其读写功能。 #### STM32F4系列下的AT24C64单次/连续读写操作 针对STM32F4系列微控制器而言,可以通过标准库中的`HAL_I2C_Master_Transmit()` 和 `HAL_I2C_Master_Receive()` 函数完成对AT24C64设备的数据传输过程[^1]。下面给出一段简单的例子用于说明如何执行一次性的数据写入以及从指定地址处获取多个字节: ```c #include "stm32f4xx_hal.h" // 假设已经初始化好I2C句柄hi2c1, 并定义好了相应的参数配置. #define AT24C64_ADDRESS (0xA0 << 1) // 设备7位地址左移一位得到8位格式. void WriteToAT24C64(uint16_t MemAddress, uint8_t* pData, uint16_t Size){ HAL_StatusTypeDef status; /* 发送起始条件并发送器件地址 */ status = HAL_I2C_Mem_Write(&hi2c1, AT24C64_ADDRESS, MemAddress, I2C_MEMADD_SIZE_16BIT, pData, Size, 100); } uint8_t ReadFromAT24C64(uint16_t MemAddress, uint8_t *pData, uint16_t Size){ HAL_StatusTypeDef status; /* 发送起始条件并发送器件地址 */ status = HAL_I2C_Mem_Read(&hi2c1, AT24C64_ADDRESS, MemAddress, I2C_MEMADD_SIZE_16BIT, pData, Size, 100); return status; } ``` 这段代码展示了基本的写入和读取方法,其中包含了内存地址指针传递给目标芯片以便定位具体存储位置的功能。 #### 特力AT32F421IIC读写EEPROM AT24C64实例 当涉及到特力AT32F421 MCU时,则会依赖特定版本SDK所提供的API来进行通信控制[^2]。以下是简化版的读写流程示意: ```c #include "at32f4xx_iic.h" #include "at32f4xx_rcc.h" /* 定义全局变量 */ static i2c_handle_type DefHandle; void AT24C64_Init(void){ // 初始化IIC外设... } void AT24C64_WriteByte(uint16_t Addr,uint8_t Data){ uint8_t buffer[2]; buffer[0]=(Addr>>8)&0xFF; //高字节 buffer[1]=Addr&0XFF; //低字节 i2c_start_send(DefHandle.Instance, AT24C64_ADDRESS_WRITE); i2c_write_data(DefHandle.Instance,&buffer[0],sizeof(buffer)); i2c_write_data(DefHandle.Instance,&Data,sizeof(Data)); i2c_stop(); } uint8_t AT24C64_ReadByte(uint16_t Addr){ uint8_t data=0; uint8_t addr_buffer[2]; addr_buffer[0]=(Addr>>8)&0xFF; //高字节 addr_buffer[1]=Addr&0XFF; //低字节 i2c_start_send(DefHandle.Instance, AT24C64_ADDRESS_WRITE); i2c_write_data(DefHandle.Instance,&addr_buffer[0], sizeof(addr_buffer)); i2c_start_send(DefHandle.Instance, AT24C64_ADDRESS_READ); i2c_read_data(DefHandle.Instance,&data,1,I2C_NO_STOP); i2c_stop(); return data; } ``` 上述片段体现了通过设置不同的寄存器值来启动停止信号、传送命令序列等细节处理方式。 #### HC32F460硬件IIC驱动AT24C64案例分享 HC32F460作为另一款高性能ARM Cortex-M4内核处理器同样支持使用内置的硬件IIC接口与外部串行EEPROM交互工作[^3]。下面是部分核心逻辑摘录: ```c #include "hc32f460_iic.h" #define SLAVE_ADDR_AT24C64 ((uint8_t)(0xA0 >> 1)) // 注意这里的地址右移了一位! void AT24C64_Write(uint16_t u16MemAdd, const uint8_t *pu8Buf, uint16_t u16Len){ uint8_t au8WriteBuff[3]; au8WriteBuff[0] = (u16MemAdd & 0xFF00)>>8; au8WriteBuff[1] = u16MemAdd & 0x00FF; memcpy(&(au8WriteBuff[2]), pu8Buf, u16Len); M4_I2Cx->START(); // 开启总线访问 while(I2C_GetFlagStatus(M4_I2Cx, I2C_FLAG_SB)==RESET){};//等待开始标志置位 I2C_Send7bitAddress(M4_I2Cx,SLAVE_ADDR_AT24C64,I2C_Direction_Transmitter);//发地址 ... } uint8_t AT24C64_Read(uint16_t u16MemAdd, uint8_t *pu8Buf, uint16_t u16Len){ uint8_t au8ReadBuff[2]; au8ReadBuff[0] = (u16MemAdd & 0xFF00)>>8; au8ReadBuff[1] = u16MemAdd & 0x00FF; M4_I2Cx->START(); while(I2C_GetFlagStatus(M4_I2Cx, I2C_FLAG_SB)== RESET){} I2C_Send7bitAddress(M4_I2Cx,SLAVE_ADDR_AT24C64,I2C_Direction_Transmitter); ... } ``` 这些代码段揭示了如何运用HC32特有的指令集去构建完整的事务链路,并确保每次请求都能被正确解析和响应。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值