STM32F1与STM32CubeIDE编程实例-设备驱动-EEPROM-AT24C256驱动 EEPROM-AT24C256驱动 1、EEPROM与AT24C256介绍 EEPROM(电可擦除可编程只读存储器)是用户可修改的只读存储器(ROM),可以通过施加高于正常电压的电压反复擦除和重新编程(写入)。 与 EPROM 芯片不同,EEPROM 不需要从计算机中取出即可进行修改。 但是,EEPROM 芯片必须整体擦除和重新编程,而不是选择性地擦除和重新编程。 它还具有有限的寿命——也就是说,它可以重新编程的次数被限制在数万或数十万次。 在计算机使用过程中经常重新编程的 EEPROM 中,EEPROM 的寿命可能是一个重要的设计考虑因素。
一种特殊形式的 EEPROM 是闪存,它使用正常的 PC 电压进行擦除和重新编程。
AT24C128/256 提供 131,072/262,144 位串行电可擦除可编程只读存储器 (EEPROM),组织为 16,384/32,768 个字,每个字为 8 位。 该设备的级联功能允许多达 4 个设备共享一个公共的两线总线。 该器件针对许多工业和商业应用进行了优化,在这些应用中,低功率和低电压操作是必不可少的。 这些器件采用节省空间的 8 引线 JEDEC PDIP、8 引线 JEDEC SOIC、8 引线 EIAJSOIC、8 引线 MAP (24C128)、8 引线 TSSOP、8 引线 SOIC 阵列封装和 8 焊球 dBGA2 封装 . 此外,整个系列提供 2.7V(2.7V 至 5.5V)和 1.8V(1.8V 至 3.6V)版本。
关于AT24Cxx的驱动在前面的文章做了详细的描述,请参考:
2、AT24C256配置 开发环境搭建、系统时钟配置、调试配置及串口配置,请参考:
2.1 AT24C256的I2C配置
各项设置完成后,保存并生成代码。
3、AT24C256驱动实现 3.1 基本定义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #ifndef \_AT24CXX\_H #define \_AT24CXX\_H #include "i2c.h" #ifdef \_\_cplusplus extern "C" { #endif #include <stdbool.h> #include <stdint.h> #include <stddef.h> typedef struct { uint16\_t id; I2C_HandleTypeDef\* i2c_handle; uint16\_t size_kb; uint8\_t device_address; uint16\_t p_size; // 页面大小 bool is_locked; }at24cxx\_t; // 初始化 bool at24cxx\_init(at24cxx\_t\* device); // 判断设备是否已经连接 bool at24cxx\_is\_connected(at24cxx\_t\* device); // 在指定地址写数据 bool at24cxx\_write(at24cxx\_t\* device,uint16\_t address, uint8\_t \*data, size\_t len, uint32\_t timeout); // 从指定地址读数据 bool at24cxx\_read(at24cxx\_t\* device,uint16\_t address, uint8\_t \*data, size\_t len, uint32\_t timeout); // 芯片擦除 bool at24cxx\_erase\_chip(at24cxx\_t\* device); #ifdef \_\_cplusplus } #endif #endif
3.2 驱动功能实现 3.2.1 导入相关头文件 1 2 3 4 5 // at24cxx.c #include "at24cxx.h" #include "main.h" #include "i2c.h"
3.2.2 设备初始化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 bool at24cxx\_init(at24cxx\_t \*device) { switch (device->size_kb) { case 1: case 2: device->p_size = 8; break; case 4: case 8: case 16: device->p_size = 16; break; default: device->p_size = 32; } device->is_locked = false; return true; }
3.2.2 判断设备是否连接 1 2 3 4 5 6 7 8 9 // at24cxx.c bool at24cxx\_is\_connected(at24cxx\_t \*device) { if (HAL\_I2C\_IsDeviceReady(device->i2c_handle, device->device_address, 2, 100) == HAL_OK) return true; else return false; }
函数HAL_I2C_IsDeviceReady用于判断I2C设备是否已经连接。如果已经连接,则返回true;否则,返回false。
3.2.3 写数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 // at24cxx.c bool at24cxx\_write(at24cxx\_t \*device, uint16\_t address, uint8\_t \*data, size\_t len, uint32\_t timeout) { if (device->is_locked) return false; device->is_locked = true; uint16\_t w; uint32\_t startTime = HAL\_GetTick(); uint16\_t dev_address, mem_address, mem_add_size; mem_add_size = I2C_MEMADD_SIZE_8BIT; while (1) { w = device->p_size - (device->device_address % device->p_size); if (w > len) { w = len; } if (device->size_kb == 1 || device->size_kb == 2) { dev_address = device->device_address; mem_address = address; } else if (device->size_kb == 4) { dev_address = device->device_address | ((address & 0x0100) >> 7); mem_address = (address & 0xff); } else if (device->size_kb == 8) { dev_address = device->device_address | ((address & 0x0300) >> 7); mem_address = (address & 0xff); } else if (device->size_kb == 16) { dev_address = device->device_address | ((address & 0x0700) >> 7); mem_address = (address & 0xff); } else { dev_address = device->device_address; mem_address = address; mem_add_size = I2C_MEMADD_SIZE_16BIT; } if (HAL\_I2C\_Mem\_Write(device->i2c_handle, dev_address, mem_address, mem_add_size, data, w, 100) == HAL_OK) { HAL\_Delay(10); len -= w; data += w; address += w; if (len == 0) { device->is_locked = false; return true; } if (HAL\_GetTick() - startTime >= timeout) { device->is_locked = false; return false; } } else { device->is_locked = false; return false; } } }
在上面代码中,主要步骤如下:
1)通过储存页面大小和写入地址计算储存地址偏移值。
2)使用HAL_I2C_Mem_Write函数写数据,并计算超时。
3)重复1)和第2)步,直到指定数据长度写完。
3.2.3 读取数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 // at24cxx.c bool at24cxx\_read(at24cxx\_t \*device, uint16\_t address, uint8\_t \*data, size\_t len, uint32\_t timeout) { if (device->is_locked) return false; device->is_locked = true; uint16\_t dev_address, mem_address, mem_add_size; mem_add_size = I2C_MEMADD_SIZE_8BIT; if (device->size_kb == 1 || device->size_kb == 2) { dev_address = device->device_address; mem_address = address; } else if (device->size_kb == 4) { dev_address = device->device_address | ((address & 0x0100) >> 7); mem_address = (address & 0xff); } else if (device->size_kb == 8) { dev_address = device->device_address | ((address & 0x0300) >> 7); mem_address = (address & 0xff); } else if (device->size_kb == 16) { dev_address = device->device_address | ((address & 0x0700) >> 7); mem_address = (address & 0xff); } else { dev_address = device->device_address; mem_address = address; mem_add_size = I2C_MEMADD_SIZE_16BIT; } if (HAL\_I2C\_Mem\_Read(device->i2c_handle, dev_address, mem_address, mem_add_size, data, len, timeout) == HAL_OK) { device->is_locked = false; return true; } else { device->is_locked = false; return false; } }
3.2.4 储存擦除 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // at24cxx.c bool at24cxx\_erase\_chip(at24cxx\_t \*device) { const uint8\_t eraseData[32] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF\ , 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; uint32\_t bytes = 0; while (bytes < (device->size_kb\* 128)) { if (at24cxx\_write(device, bytes, (uint8\_t\*) eraseData, sizeof(eraseData), 100) == false) return false; bytes += sizeof(eraseData); } return true; }
3.2.5 主程序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 // main.c /\* USER CODE END Header \*/ /\* Includes ------------------------------------------------------------------\*/ #include "main.h" #include "i2c.h" #include "usart.h" #include "gpio.h" /\* Private includes ----------------------------------------------------------\*/ #include "AT24CXX/at24cxx.h" #include <stdio.h> /\* USER CODE END Includes \*/ /\* Private typedef -----------------------------------------------------------\*/ /\* USER CODE BEGIN PTD \*/ /\* USER CODE END PTD \*/ /\* Private define ------------------------------------------------------------\*/ /\* USER CODE BEGIN PD \*/ /\* USER CODE END PD \*/ /\* Private macro -------------------------------------------------------------\*/ /\* USER CODE BEGIN PM \*/ /\* USER CODE END PM \*/ /\* Private variables ---------------------------------------------------------\*/ /\* USER CODE BEGIN PV \*/ bool writeStatus = false; bool readStatus = false; bool eraseStatus = false; uint8\_t wData[] = "Hello World 123"; uint8\_t rData[25]; /\* USER CODE END PV \*/ /\* Private function prototypes -----------------------------------------------\*/ void SystemClock\_Config(void); /\* USER CODE BEGIN PFP \*/ /\* USER CODE END PFP \*/ /\* Private user code ---------------------------------------------------------\*/ /\* USER CODE BEGIN 0 \*/ at24cxx\_t at24cxx; /\* USER CODE END 0 \*/ /\*\* \* @brief The application entry point. \* @retval int \*/ int main(void) { /\* USER CODE BEGIN 1 \*/ /\* USER CODE END 1 \*/ /\* MCU Configuration--------------------------------------------------------\*/ /\* Reset of all peripherals, Initializes the Flash interface and the Systick. \*/ HAL\_Init(); /\* USER CODE BEGIN Init \*/ /\* USER CODE END Init \*/ /\* Configure the system clock \*/ SystemClock\_Config(); /\* USER CODE BEGIN SysInit \*/ /\* USER CODE END SysInit \*/ /\* Initialize all configured peripherals \*/ MX\_GPIO\_Init(); MX\_I2C1\_Init(); MX\_USART1\_UART\_Init(); /\* USER CODE BEGIN 2 \*/ printf("AT24C256 EPPROM DEMO \r\n"); at24cxx.i2c_handle = &hi2c1; at24cxx.id = 1; at24cxx.device_address = 0xA0; at24cxx.size_kb = 256; // 256Kb at24cxx\_init(&at24cxx); if(at24cxx\_is\_connected(&at24cxx)){ if(at24cxx\_erase\_chip(&at24cxx)){ printf("at24c256 erased\r\n"); }else{ printf("at24c256 erase failed\r\n"); } if(at24cxx\_write(&at24cxx,MEM_ADDR, wData, 15, 100)){ printf("write data:%s\r\n",wData); }else{ printf("write data@0x00 failed\r\n"); } if(at24cxx\_read(&at24cxx, MEM_ADDR, rData, 15, 100)){ printf("read data from@0x00:%s\r\n ",rData); }else{ printf("read data failed\r\n"); } }else{ printf("at24c256 not connected\r\n"); } /\* USER CODE END 2 \*/ /\* Infinite loop \*/ /\* USER CODE BEGIN WHILE \*/ while (1) { /\* USER CODE END WHILE \*/ /\* USER CODE BEGIN 3 \*/ } /\* USER CODE END 3 \*/ }
4、运行结果
文章来源: https://iotsmart.blog.csdn.net/article/details/125238855
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!