stm32下的IIC实现EEPROM代码-stm32G431RBT6(蓝桥杯嵌入式)

目录

    1.当前地址读取

     2.随机地址读取

     3.顺序读取

     4.字节写入

     5.页写入


手册中总共有五种EEPROM的读和写的方式

在开始写程序前,需要知道它的设备地址:

 可以看到设备地址是:1010xxxx即0xa?.

 在原理图中可以看见:E123都接gnd了,所以A012都是0,所以设备地址就是1010000x(二进制),最后一位x是在读和写的时候配置的。

    1.当前地址读取:

 从这个图上看到:读的时候READ是高电平,所以设备地址是:0xa1。

按照图片写代码:

void eeprom_current_read(unsigned char data) //当前地址读,读的是上次访问的地址加1
{

	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	
	data=I2CReceiveByte();
	I2CSendNotAck();
	I2CStop();
}

根据图片我们就可以发现DATA是八位的数据,所以最大就是256,所以用unsigned char。 

当前地址读:
内部地址计数器保存着上次访问时最后一个地址加1的值。只要芯片有电,该地址就一直保存。
当读到最后页的最后字节,地址会回转到0。但是在实际操作中,这个没有实现,读出来的是混乱的数字。这个还不清楚为什么?
 

     2.随机地址读取:

 同样根据图片写代码:

unsigned char eeprom_random_read(unsigned char adress) 
{
   unsigned char data;
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	
	I2CSendByte(adress);
	I2CWaitAck();
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	data=I2CReceiveByte();
	I2CSendNotAck();
	I2CStop();
	return data;
}

 程序验证是正确的。可以自己选一个地址读取该处的数据。

     3.顺序读取:

 可以通过当前地址读或顺序读开启,然后读就行了

void eeprom_sequential_read(unsigned char adress,unsigned char *data,unsigned char num)  //写一个数据给这个地址
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	
	I2CSendByte(adress);
	I2CWaitAck();
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	while(num--)
	{
		*data++=I2CReceiveByte();
		if(num)
				I2CSendAck();	
		else
				I2CSendNotAck();
	
	}
	I2CStop();
}

测试可以运行,可以读取任意个数数据 

     4.字节写入:

void eeprom_byte_write(unsigned char adress,unsigned char data)  //写一个数据给这个地址
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	
  I2CSendByte(adress);
	I2CWaitAck();
	I2CSendByte(data);
	I2CWaitAck();
	I2CStop();
}

 可以实现

     5.页写入:

* 表示数据量不要超过1kbit

24C02器件按8字节/页执行页写,24C04/08/16器 件按16字节/页执行页写,24C32/64器 件
按32字节/页执行页写。
每次写完内部自动加1,高位地址位不变,维持在当前页内。当内部产生的字地址达到该页边界地址时,随后的数据将写入该页的页首。如果超过8个(24C02) 或16个(24C04/08/16) 或32个
(24C32/64)数据传送给了EEPROM,字地址将回转到该页的首字节,先前的字节将会被覆盖。

上面时网上的解释,但是我实际测试发现,超过8个数据的话后面的就不会写入了,也不会覆盖先前字节。

void eeprom_page_write(unsigned char adress,unsigned char *data,unsigned char num) 
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	
  I2CSendByte(adress);
	I2CWaitAck();
	while(num--)
	{
	I2CSendByte(*data++);
	I2CWaitAck();
	}
	I2CStop();
}

其他代码:

IIC.c:

#include "i2c.h"

#define DELAY_TIME	20


/**
  * @brief SDA线输入模式配置
  * @param None
  * @retval None
  */
void SDA_Input_Mode()
{
    GPIO_InitTypeDef GPIO_InitStructure = {0};

    GPIO_InitStructure.Pin = GPIO_PIN_7;
    GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
    GPIO_InitStructure.Pull = GPIO_PULLUP;
    GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
}

/**
  * @brief SDA线输出模式配置
  * @param None
  * @retval None
  */
void SDA_Output_Mode()
{
    GPIO_InitTypeDef GPIO_InitStructure = {0};

    GPIO_InitStructure.Pin = GPIO_PIN_7;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStructure.Pull = GPIO_NOPULL;
    GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
}

/**
  * @brief SDA线输出一个位
  * @param val 输出的数据
  * @retval None
  */
void SDA_Output( uint16_t val )
{
    if ( val )
    {
        GPIOB->BSRR |= GPIO_PIN_7;
    }
    else
    {
        GPIOB->BRR |= GPIO_PIN_7;
    }
}

/**
  * @brief SCL线输出一个位
  * @param val 输出的数据
  * @retval None
  */
void SCL_Output( uint16_t val )
{
    if ( val )
    {
        GPIOB->BSRR |= GPIO_PIN_6;
    }
    else
    {
        GPIOB->BRR |= GPIO_PIN_6;
    }
}

/**
  * @brief SDA输入一位
  * @param None
  * @retval GPIO读入一位
  */
uint8_t SDA_Input(void)
{
	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7) == GPIO_PIN_SET){
		return 1;
	}else{
		return 0;
	}
}


/**
  * @brief I2C的短暂延时
  * @param None
  * @retval None
  */
static void delay1(unsigned int n)
{
    uint32_t i;
    for ( i = 0; i < n; ++i);
}

/**
  * @brief I2C起始信号
  * @param None
  * @retval None
  */
void I2CStart(void)
{
    SDA_Output(1);
    delay1(DELAY_TIME);
    SCL_Output(1);
    delay1(DELAY_TIME);
    SDA_Output(0);
    delay1(DELAY_TIME);
    SCL_Output(0);
    delay1(DELAY_TIME);
}

/**
  * @brief I2C结束信号
  * @param None
  * @retval None
  */
void I2CStop(void)
{
    SCL_Output(0);
    delay1(DELAY_TIME);
    SDA_Output(0);
    delay1(DELAY_TIME);
    SCL_Output(1);
    delay1(DELAY_TIME);
    SDA_Output(1);
    delay1(DELAY_TIME);

}

/**
  * @brief I2C等待确认信号
  * @param None
  * @retval None
  */
unsigned char I2CWaitAck(void)
{
    unsigned short cErrTime = 5;
    SDA_Input_Mode();
    delay1(DELAY_TIME);
    SCL_Output(1);
    delay1(DELAY_TIME);
    while(SDA_Input())
    {
        cErrTime--;
        delay1(DELAY_TIME);
        if (0 == cErrTime)
        {
            SDA_Output_Mode();
            I2CStop();
            return ERROR;
        }
    }
    SDA_Output_Mode();
    SCL_Output(0);
    delay1(DELAY_TIME);
    return SUCCESS;
}

/**
  * @brief I2C发送确认信号
  * @param None
  * @retval None
  */
void I2CSendAck(void)
{
    SDA_Output(0);
    delay1(DELAY_TIME);
    delay1(DELAY_TIME);
    SCL_Output(1);
    delay1(DELAY_TIME);
    SCL_Output(0);
    delay1(DELAY_TIME);

}

/**
  * @brief I2C发送非确认信号
  * @param None
  * @retval None
  */
void I2CSendNotAck(void)
{
    SDA_Output(1);
    delay1(DELAY_TIME);
    delay1(DELAY_TIME);
    SCL_Output(1);
    delay1(DELAY_TIME);
    SCL_Output(0);
    delay1(DELAY_TIME);

}

/**
  * @brief I2C发送一个字节
  * @param cSendByte 需要发送的字节
  * @retval None
  */
void I2CSendByte(unsigned char cSendByte)
{
    unsigned char  i = 8;
    while (i--)
    {
        SCL_Output(0);
        delay1(DELAY_TIME);
        SDA_Output(cSendByte & 0x80);
        delay1(DELAY_TIME);
        cSendByte += cSendByte;
        delay1(DELAY_TIME);
        SCL_Output(1);
        delay1(DELAY_TIME);
    }
    SCL_Output(0);
    delay1(DELAY_TIME);
}

/**
  * @brief I2C接收一个字节
  * @param None
  * @retval 接收到的字节
  */
unsigned char I2CReceiveByte(void)
{
    unsigned char i = 8;
    unsigned char cR_Byte = 0;
    SDA_Input_Mode();
    while (i--)
    {
        cR_Byte += cR_Byte;
        SCL_Output(0);
        delay1(DELAY_TIME);
        delay1(DELAY_TIME);
        SCL_Output(1);
        delay1(DELAY_TIME);
        cR_Byte |=  SDA_Input();
    }
    SCL_Output(0);
    delay1(DELAY_TIME);
    SDA_Output_Mode();
    return cR_Byte;
}

//
void I2CInit(void)
{
		GPIO_InitTypeDef GPIO_InitStructure = {0};

    GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_6;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStructure.Pull = GPIO_PULLUP;
    GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
}

 IIC.h:

#ifndef __I2C_H
#define __I2C_H

#include "main.h"

void I2CStart(void);
void I2CStop(void);
unsigned char I2CWaitAck(void);
void I2CSendAck(void);
void I2CSendNotAck(void);
void I2CSendByte(unsigned char cSendByte);
unsigned char I2CReceiveByte(void);
void I2CInit(void);

#endif

main函数初始化;

MX_GPIO_Init();
MX_TIM3_Init();
I2CInit();

需要注意I2CInit()函数中没有时钟使能,因为MX_GPIO_Init()中有,所以记得放在它的下面才能初始化成功。 

总结:

有人说EEPROM经不起快速的连续读写,所以在读和写之间加入20ms的delay,我没有试过。

还有一些问题没有解决。


寄掉了,昨天只能写入八个数据,今天发现可以随便页写,几个数据都行,一开始字节写第9位置以及后面都写不进去,突然想写多少个写多少个,懵圈了,咱也不知道,咱也不敢问,我没有在读和写之间加延时,不会是这个的问题吧?


试了一下,还真的是延时的问题,不能写完之后立马读,不然就是读出255................................


写的很好的eeprom,还有16位数如何读取和写入

共用体实现浮点数、负数的存储(非常好用,快关注,比上面方便多了)

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值