15届蓝桥杯嵌入式复习手把手带你学(I2C读写 EEPROM实现掉电数据不丢失)

本文详细介绍了如何在蓝桥杯嵌入式竞赛中使用I2C通信协议配合EEPROM实现数据在掉电后仍能保持不丢失的功能,包括CUBEMX工程配置、EEPROM读写函数编写以及主函数示例。
摘要由CSDN通过智能技术生成

纵观前几年蓝桥杯嵌入式赛道省赛题目,I2C出现的次数很少,但是不排除今年会出的可能性,I2C出现的应用无非就是掉电数据不丢失.下面我将从零开始教大家实现掉电数据不丢失功能。

首先我们在CUBEMX中新建工程

然后进行如下配置

 

至此,我们在CUBEMX的配置就已经完成啦!

 然后我们将大赛提供的资源包中的LCD例程中的lcd.c  lcd.h  fonts.h还有GPIO_I2C_HAL文件夹中的i2c_hal.c   i2c_hal.h 分别添加到Src和Inc文件夹中

然后打开工程,添加包含文件,然后进行编译,没有问题

由大赛提供的原理图结合EEPROM的技术文档,我们不难看出EEPROM设备的地址前七位是1010_000

最后一位如果是0,则为写操作;

若为1,则是读操作。

结合官方文档中提供的I2C连续写和连续读时序图

然后我们在i2c_hal.c中编写我们自己的EEPROM读写函数

void EEP_Write(uint8_t address, uint8_t *data, uint8_t num)
{
    I2CStart();                //I2C开始
    do
    {
        I2CSendByte(0xA0);

    } while (I2CWaitAck());    //写器件地址(写操作)
    I2CSendByte(address);      //写存储地址
    I2CWaitAck();        //上面写的是要存储的位置的第一个地址,之后每进行一次写操作,地址会自增
    for (int i = 0; i < num; i++)
    {
        I2CSendByte(data[i]);  //连续写入数据
        I2CWaitAck();          
    }

    I2CStop();
}

void EEP_Read(uint8_t address, uint8_t *str, uint8_t num)
{

    I2CStart();                   //I2C开始
    do
    {
        I2CSendByte(0xA0);        

    } while (I2CWaitAck());   //假写,目的是为了更新I2C从设备的微控制器的内部字节地址计数器, 
                              //从而自定义想要读的位置
    I2CSendByte(address);
    I2CWaitAck();
    I2CStart();
    do
    {
        I2CSendByte(0xA1);

    } while (I2CWaitAck());
    for (int i = 0; i < num; i++)
    {
        str[i] = I2CReceiveByte();//连续读数据
        I2CSendAck();
    }

    I2CSendNotAck();
    I2CStop();
}

main.c

#include "main.h"
#include "gpio.h"
#include "sys.h"
#include "lcd.h"
#include "i2c_hal.h"
#include "stdio.h"
void SystemClock_Config(void);
uint8_t str1[3] = {0x11, 0x22, 0x33};
uint8_t str2[3] = {0};
char text[30];

int main(void)
{

  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  ///
  LCD_Init();
  LCD_SetBackColor(Black);
  LCD_SetTextColor(White);
  LCD_Clear(Black);
  I2CInit(); // I2C初始化
  EEP_Write(0, str1, 3);
  HAL_Delay(20); // 写和读之间延迟一下,防止I2C时序混乱
  EEP_Read(0, str2, 3);

  while (1)
  {
    sprintf(text, "C1:%x,C2:%x,C3:%x", str2[0], str2[1], str2[2]);
    LCD_DisplayStringLine(Line0, (uint8_t *)text);
  }
}

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV3;
  RCC_OscInitStruct.PLL.PLLN = 20;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

void Error_Handler(void)
{

  __disable_irq();
  while (1)
  {
  }
}

#ifdef USE_FULL_ASSERT
/**
 * @brief  Reports the name of the source file and the source line number
 *         where the assert_param error has occurred.
 * @param  file: pointer to the source file name
 * @param  line: assert_param error line source number
 * @retval None
 */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif

最终效果如下

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值