当前位置: 首页 > news >正文

STM32存储左右互搏 I2C总线FATS读写EEPROM ZD24C1MA

STM32存储左右互搏 I2C总线FATS读写EEPROM ZD24C1MA

在较低容量存储领域,EEPROM是常用的存储介质,可以通过直接或者文件操作方式进行读写。不同容量的EEPROM的地址对应位数不同,在发送字节的格式上有所区别。EEPROM是非快速访问存储,因为EEPROM按页进行组织,在连续操作模式,当跨页时访问地址不是跳到下一页到开始,而是跳到当前页的首地址,因此跨页时要重新指定起始地址。而在控制端发送写操作I2C数据后还需要有等待EEPROM内部操作完成的时间才能进行下一次操作。ZD24C1MA是1M bit / 128K Byte容量的EEPROM,ZD24C1MA的管脚定义为:
在这里插入图片描述
这里介绍STM32 通过文件系统FATS访问EEPROM ZD24C1MA的例程。采用STM32CUBEIDE开发平台,以STM32F401CCU6芯片为例,通过STM32 I2C硬件电路实现读写操作,通过UART串口进行控制。

STM32工程配置

首先建立基本工程并设置时钟:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
配置硬件I2C接口,在这里插入图片描述
在这里插入图片描述
配置UART1作为通讯串口:
在这里插入图片描述
在这里插入图片描述
对FATS文件系统进行配置:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
保存并生成初始工程代码:
在这里插入图片描述

STM32工程代码

代码里用到的微秒延时函数参考: STM32 HAL us delay(微秒延时)的指令延时实现方式及优化

ZD24C1MA的设备默认访问地址为0xA0, ZD24C1MA的存储单元地址访问略为特殊,17位地址分为两部分,最高位的1位放置于I2C设备默认访问地址的第1位,I2C设备默认访问地址第0位仍然为读写控制位,由于采用硬件I2C控制,库函数自行通过识别调用的是发送还是接收函数对第0位进行发送前设置,因此,不管是调用库函数的I2C写操作还是读操作,提供的地址相同。17位地址的低16位通过在发送设备地址后的作为跟随的第一,二个字节发送。

建立ZD24C1MA.h库头文件

#ifndef INC_ZD24C1MA_H_
#define INC_ZD24C1MA_H_#include "main.h"void PY_Delay_us_t(uint32_t Delay);
void ZD24C1MA_Read(uint32_t addr, uint8_t * data, uint32_t len);
void ZD24C1MA_Write(uint32_t addr, uint8_t * data, uint32_t len);#endif

建立ZD24C1MA.c库源文件:


#include <string.h>
#include <ZD24C1MA.h>#define Page_Size 256
#define Delay_Param 5
extern I2C_HandleTypeDef hi2c1;
extern uint8_t ZD24C1MA_Default_I2C_Addr ;void ZD24C1MA_Read(uint32_t addr, uint8_t * data, uint32_t len)
{uint8_t ZD24C1MA_I2C_Addr;ZD24C1MA_I2C_Addr = ZD24C1MA_Default_I2C_Addr | ((addr>>16)<<1); //highest 1-bit access address placed into I2C addressuint8_t RA[2];RA[0] = (addr & 0xFF00)>>8; //high 8-bit access address placed into I2C first dataRA[1] =addr & 0x00FF; //low 8-bit access address placed into I2C first dataHAL_I2C_Master_Transmit(&hi2c1, ZD24C1MA_I2C_Addr, &RA[0], 2, 2700); //Write address for readHAL_I2C_Master_Receive(&hi2c1, ZD24C1MA_I2C_Addr, data, len, 2700); //Read data}void ZD24C1MA_Write(uint32_t addr, uint8_t * data, uint32_t len)
{uint8_t ZD24C1MA_I2C_Addr;uint32_t addr_page = addr/Page_Size;uint32_t addr_index = addr%Page_Size;uint32_t TLEN;uint8_t TAD[Page_Size+2];uint32_t i=0;if(len<=(Page_Size-addr_index)){TAD[0] = (addr & 0xFF00) >> 8;TAD[1] = addr & 0x00FF ;memcpy(TAD+2, data, len);ZD24C1MA_I2C_Addr = ZD24C1MA_Default_I2C_Addr | ((addr>>16)<<1); //highest 1-bit access address placed into I2C addressHAL_I2C_Master_Transmit(&hi2c1, ZD24C1MA_I2C_Addr, TAD, len+2, 2700);  //Write dataPY_Delay_us_t(Delay_Param*1000);}else{TAD[0] = (addr & 0xFF00) >> 8;TAD[1] = addr & 0x00FF ;memcpy(TAD+2, data, (Page_Size-addr_index));ZD24C1MA_I2C_Addr = ZD24C1MA_Default_I2C_Addr | ((addr>>16)<<1); //highest 1-bit access address placed into I2C addressHAL_I2C_Master_Transmit(&hi2c1, ZD24C1MA_I2C_Addr, TAD, (Page_Size-addr_index)+2, 2700);  //Write dataPY_Delay_us_t(Delay_Param*1000);TLEN = (len-(Page_Size-addr_index));while( TLEN >= Page_Size ){addr_page += 1;TAD[0] = ((addr_page*Page_Size) & 0xFF00 ) >> 8;TAD[1] = (addr_page*Page_Size) & 0x00FF ;memcpy(TAD+2, data + (Page_Size-addr_index) + i*Page_Size, Page_Size);ZD24C1MA_I2C_Addr = ZD24C1MA_Default_I2C_Addr | (((addr_page*Page_Size)>>16)<<1); //highest 1-bit access address placed into I2C addressHAL_I2C_Master_Transmit(&hi2c1, ZD24C1MA_I2C_Addr, TAD, Page_Size+2, 2700);  //Write dataHAL_Delay(Delay_Param);i++;TLEN -= Page_Size;PY_Delay_us_t(Delay_Param*1000);}if(TLEN>0){addr_page += 1;TAD[0] = ((addr_page*Page_Size) & 0xFF00 ) >> 8;TAD[1] = (addr_page*Page_Size) & 0x00FF ;memcpy(TAD+2, data + (Page_Size-addr_index) + i*Page_Size, TLEN);ZD24C1MA_I2C_Addr = ZD24C1MA_Default_I2C_Addr | (((addr_page*Page_Size)>>16)<<1); //highest 1-bit access address placed into I2C addressHAL_I2C_Master_Transmit(&hi2c1, ZD24C1MA_I2C_Addr, TAD, TLEN+2, 2700);  //Write dataPY_Delay_us_t(Delay_Param*1000);}}}

对ffconf.h添加包含信息:
在这里插入图片描述

#include "main.h"
#include "stm32f4xx_hal.h"
#include "ZD24C1MA.h"

修改user_diskio.c,对文件操作函数与底层I2C读写提供连接:

/* USER CODE BEGIN Header */
/********************************************************************************* @file    user_diskio.c* @brief   This file includes a diskio driver skeleton to be completed by the user.******************************************************************************* @attention** Copyright (c) 2023 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************//* USER CODE END Header */#ifdef USE_OBSOLETE_USER_CODE_SECTION_0
/** Warning: the user section 0 is no more in use (starting from CubeMx version 4.16.0)* To be suppressed in the future.* Kept to ensure backward compatibility with previous CubeMx versions when* migrating projects.* User code previously added there should be copied in the new user sections before* the section contents can be deleted.*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
#endif/* USER CODE BEGIN DECL *//* Includes ------------------------------------------------------------------*/
#include <string.h>
#include "ff_gen_drv.h"/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*//* Private variables ---------------------------------------------------------*/
/* Disk status */
static volatile DSTATUS Stat = STA_NOINIT;/* USER CODE END DECL *//* Private function prototypes -----------------------------------------------*/
DSTATUS USER_initialize (BYTE pdrv);
DSTATUS USER_status (BYTE pdrv);
DRESULT USER_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count);
#if _USE_WRITE == 1DRESULT USER_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count);
#endif /* _USE_WRITE == 1 */
#if _USE_IOCTL == 1DRESULT USER_ioctl (BYTE pdrv, BYTE cmd, void *buff);
#endif /* _USE_IOCTL == 1 */Diskio_drvTypeDef  USER_Driver =
{USER_initialize,USER_status,USER_read,
#if  _USE_WRITEUSER_write,
#endif  /* _USE_WRITE == 1 */
#if  _USE_IOCTL == 1USER_ioctl,
#endif /* _USE_IOCTL == 1 */
};/* Private functions ---------------------------------------------------------*//*** @brief  Initializes a Drive* @param  pdrv: Physical drive number (0..)* @retval DSTATUS: Operation status*/
DSTATUS USER_initialize (BYTE pdrv           /* Physical drive nmuber to identify the drive */
)
{/* USER CODE BEGIN INIT *//**************************SELF DEFINITION PART************/extern uint8_t ZD24C1MA_Default_I2C_Addr ;ZD24C1MA_Default_I2C_Addr =  0xA0; //Pin A2=A1=0return RES_OK;/**********************************************************//*Stat = STA_NOINIT;return Stat;*//* USER CODE END INIT */
}/*** @brief  Gets Disk Status* @param  pdrv: Physical drive number (0..)* @retval DSTATUS: Operation status*/
DSTATUS USER_status (BYTE pdrv       /* Physical drive number to identify the drive */
)
{/* USER CODE BEGIN STATUS *//**************************SELF DEFINITION PART************/switch (pdrv){case 0 :return RES_OK;case 1 :return RES_OK;case 2 :return RES_OK;default:return STA_NOINIT;}/**********************************************************//*Stat = STA_NOINIT;return Stat;*//* USER CODE END STATUS */
}/*** @brief  Reads Sector(s)* @param  pdrv: Physical drive number (0..)* @param  *buff: Data buffer to store read data* @param  sector: Sector address (LBA)* @param  count: Number of sectors to read (1..128)* @retval DRESULT: Operation result*/
DRESULT USER_read (BYTE pdrv,      /* Physical drive nmuber to identify the drive */BYTE *buff,     /* Data buffer to store read data */DWORD sector,   /* Sector address in LBA */UINT count      /* Number of sectors to read */
)
{/* USER CODE BEGIN READ *//**************************SELF DEFINITION PART************/uint16_t len;if( !count ){return RES_PARERR;  /*count status*/}switch (pdrv){case 0:sector <<= 9; //Convert sector number to byte addresslen = count*512;ZD24C1MA_Read(sector, buff, len);return RES_OK;default:return RES_ERROR;}/**********************************************************//*return RES_OK;*//* USER CODE END READ */
}/*** @brief  Writes Sector(s)* @param  pdrv: Physical drive number (0..)* @param  *buff: Data to be written* @param  sector: Sector address (LBA)* @param  count: Number of sectors to write (1..128)* @retval DRESULT: Operation result*/
#if _USE_WRITE == 1
DRESULT USER_write (BYTE pdrv,          /* Physical drive nmuber to identify the drive */const BYTE *buff,   /* Data to be written */DWORD sector,       /* Sector address in LBA */UINT count          /* Number of sectors to write */
)
{/* USER CODE BEGIN WRITE *//* USER CODE HERE *//**************************SELF DEFINITION PART************/uint16_t len;if( !count ){return RES_PARERR;  /*count status*/}switch (pdrv){case 0:sector <<= 9; //Convert sector number to byte addresslen = count*512;ZD24C1MA_Write(sector, (uint8_t *)buff,len);return RES_OK;default:return RES_ERROR;}/*********************************************************//*return RES_OK;*//* USER CODE END WRITE */
}
#endif /* _USE_WRITE == 1 *//*** @brief  I/O control operation* @param  pdrv: Physical drive number (0..)* @param  cmd: Control code* @param  *buff: Buffer to send/receive control data* @retval DRESULT: Operation result*/
#if _USE_IOCTL == 1
DRESULT USER_ioctl (BYTE pdrv,      /* Physical drive nmuber (0..) */BYTE cmd,       /* Control code */void *buff      /* Buffer to send/receive control data */
)
{/* USER CODE BEGIN IOCTL *//**************************SELF DEFINITION PART************/#define user_sector_byte_size 512DRESULT res;switch(cmd){case CTRL_SYNC:res=RES_OK;break;case GET_SECTOR_SIZE:*(WORD*)buff = user_sector_byte_size;res = RES_OK;break;case GET_BLOCK_SIZE:*(WORD*)buff = 4096/user_sector_byte_size;res = RES_OK;break;case GET_SECTOR_COUNT:*(DWORD*)buff = (128*1024/512);res = RES_OK;break;default:res = RES_PARERR;break;}return res;/**********************************************************//*DRESULT res = RES_ERROR;return res;*//* USER CODE END IOCTL */
}
#endif /* _USE_IOCTL == 1 */

然后在main.c里根据串口输入命令(16进制单字节)实现如下功能:
0x01. 读取EEPROM ID
0x02. 装载FATS文件系统
0x03: 创建/打开文件并从头位置写入数据
0x04: 打开文件并从头位置读入数据
0x05: 创建/打开文件并从特定位置写入数据
0x06: 打开文件并从特定位置读入数据
完整的代码实现如下:

/* USER CODE BEGIN Header */
/********************************************************************************* @file           : main.c* @brief          : Main program body******************************************************************************* @attention** Copyright (c) 2023 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
//Written by Pegasus Yu in 2023
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "fatfs.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "usart.h"
#include "string.h"
#include "ZD24C1MA.h"
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
__IO float usDelayBase;
void PY_usDelayTest(void)
{__IO uint32_t firstms, secondms;__IO uint32_t counter = 0;firstms = HAL_GetTick()+1;secondms = firstms+1;while(uwTick!=firstms) ;while(uwTick!=secondms) counter++;usDelayBase = ((float)counter)/1000;
}void PY_Delay_us_t(uint32_t Delay)
{__IO uint32_t delayReg;__IO uint32_t usNum = (uint32_t)(Delay*usDelayBase);delayReg = 0;while(delayReg!=usNum) delayReg++;
}void PY_usDelayOptimize(void)
{__IO uint32_t firstms, secondms;__IO float coe = 1.0;firstms = HAL_GetTick();PY_Delay_us_t(1000000) ;secondms = HAL_GetTick();coe = ((float)1000)/(secondms-firstms);usDelayBase = coe*usDelayBase;
}void PY_Delay_us(uint32_t Delay)
{__IO uint32_t delayReg;__IO uint32_t msNum = Delay/1000;__IO uint32_t usNum = (uint32_t)((Delay%1000)*usDelayBase);if(msNum>0) HAL_Delay(msNum);delayReg = 0;while(delayReg!=usNum) delayReg++;
}
/* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;
DMA_HandleTypeDef hdma_i2c1_tx;UART_HandleTypeDef huart1;/* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_I2C1_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t cmd=0;          //for status control
uint8_t URX;uint8_t ZD24C1MA_Default_I2C_Addr =  0xA0; //Pin A2=A1=0
uint32_t ZD24C1MA_Access_Addr = 0;   //EEPROM ZD24C1MA access address (17-bit)uint8_t EEPROM_mount_status = 0; //EEPROM fats mount status indication (0: unmount; 1: mount)
uint8_t FATS_Buff[_MAX_SS]; //Buffer for f_mkfs() operationFRESULT retEEPROM;
FIL file;
FATFS *fs;UINT bytesread;
UINT byteswritten;
uint8_t rBuffer[20];      //Buffer for read
uint8_t WBuffer[20] ={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; //Buffer for write#define user_sector_byte_size 512
uint8_t eeprombuffer[user_sector_byte_size];extern char USERPath[4];char * console;
/* USER CODE END 0 *//*** @brief  The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 */EEPROM_mount_status = 0;uint32_t EEPROM_Read_Size;extern char USERPath[4];char * dpath = "0:"; //Disk Pathfor(uint8_t i=0; i<4; i++){USERPath[i] = *(dpath+i);}const TCHAR* filepath = "0:test.txt";char cchar[256];console = cchar;/* 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_DMA_Init();MX_I2C1_Init();MX_USART1_UART_Init();MX_FATFS_Init();/* USER CODE BEGIN 2 */PY_usDelayTest();PY_usDelayOptimize();HAL_UART_Receive_IT(&huart1, &URX, 1);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){if(cmd==1) //Read ID{cmd = 0;printf("EEPROM ID=ZD24C1MAT\r\n\r\n");}else if(cmd==2) //EEPROM File System Mount{cmd = 0;retEEPROM=f_mount(&USERFatFS, (TCHAR const*)USERPath, 1);if (retEEPROM != FR_OK){printf("File system mount failure: %d\r\n", retEEPROM);if(retEEPROM==FR_NO_FILESYSTEM){printf("No file system. Now to format......\r\n");retEEPROM = f_mkfs((TCHAR const*)USERPath, FM_FAT, 1024, FATS_Buff, sizeof(FATS_Buff)); //EEPROM formattingif(retEEPROM == FR_OK){printf("EEPROM formatting success!\r\n");}else{printf("EEPROM formatting failure!\r\n");}}}else{EEPROM_mount_status = 1;printf("File system mount success\r\n");}}else if(cmd==3) //File creation and write{cmd = 0;if(EEPROM_mount_status==0){printf( "\r\nEEPROM File system not mounted: %d\r\n",retEEPROM);}else{retEEPROM = f_open( &file, filepath, FA_CREATE_ALWAYS | FA_WRITE );  //Open or create fileif(retEEPROM == FR_OK){printf( "\r\nFile open or creation successful\r\n");retEEPROM = f_write( &file, (const void *)WBuffer, sizeof(WBuffer), &byteswritten); //Write dataif(retEEPROM == FR_OK){printf("\r\nFile write successful\r\n");}else{printf("\r\nFile write error: %d\r\n",retEEPROM);}f_close(&file);   //Close file}else{printf("\r\nFile open or creation error %d\r\n",retEEPROM);}}}else if(cmd==4) //File read{cmd = 0;if(EEPROM_mount_status==0){printf("\r\nEEPROM File system not mounted: %d\r\n",retEEPROM);}else{retEEPROM = f_open( &file, filepath, FA_OPEN_EXISTING | FA_READ); //Open fileif(retEEPROM == FR_OK){printf("\r\nFile open successful\r\n");retEEPROM = f_read( &file, (void *)rBuffer, sizeof(rBuffer), &bytesread); //Read dataif(retEEPROM == FR_OK){printf("\r\nFile read successful\r\n");PY_Delay_us_t(200000);EEPROM_Read_Size = sizeof(rBuffer);for(uint16_t i = 0;i < EEPROM_Read_Size;i++){printf("%d ", rBuffer[i]);}printf("\r\n");}else{printf("\r\nFile read error: %d\r\n", retEEPROM);}f_close(&file); //Close file}else{printf("\r\nFile open error: %d\r\n", retEEPROM);}}}else if(cmd==5) //File locating write{cmd = 0;if(EEPROM_mount_status==0){printf("\r\nEEPROM File system not mounted: %d\r\n",retEEPROM);}else{retEEPROM = f_open( &file, filepath, FA_CREATE_ALWAYS | FA_WRITE);  //Open or create fileif(retEEPROM == FR_OK){printf("\r\nFile open or creation successful\r\n");retEEPROM=f_lseek( &file, f_tell(&file) + sizeof(WBuffer) ); //move file operation pointer, f_tell(&file) gets file head locatingif(retEEPROM == FR_OK){retEEPROM = f_write( &file, (const void *)WBuffer, sizeof(WBuffer), &byteswritten);if(retEEPROM == FR_OK){printf("\r\nFile locating write successful\r\n");}else{printf("\r\nFile locating write error: %d\r\n", retEEPROM);}}else{printf("\r\nFile pointer error: %d\r\n",retEEPROM);}f_close(&file);   //Close file}else{printf("\r\nFile open or creation error %d\r\n",retEEPROM);}}}else if(cmd==6) //File locating read{cmd = 0;if(EEPROM_mount_status==0){printf("\r\nEEPROM File system not mounted: %d\r\n",retEEPROM);}else{retEEPROM = f_open(&file, filepath, FA_OPEN_EXISTING | FA_READ); //Open fileif(retEEPROM == FR_OK){printf("\r\nFile open successful\r\n");retEEPROM =  f_lseek(&file,f_tell(&file)+ sizeof(WBuffer)/2); //move file operation pointer, f_tell(&file) gets file head locatingif(retEEPROM == FR_OK){retEEPROM = f_read( &file, (void *)rBuffer, sizeof(rBuffer), &bytesread);if(retEEPROM == FR_OK){printf("\r\nFile locating read successful\r\n");PY_Delay_us_t(200000);EEPROM_Read_Size = sizeof(rBuffer);for(uint16_t i = 0;i < EEPROM_Read_Size;i++){printf("%d ",rBuffer[i]);}printf("\r\n");}else{printf("\r\nFile locating read error: %d\r\n",retEEPROM);}}else{printf("\r\nFile pointer error: %d\r\n",retEEPROM);}f_close(&file);}else{printf("\r\nFile open error: %d\r\n",retEEPROM);}}}PY_Delay_us_t(100);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}/*** @brief System Clock Configuration* @retval None*/
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};/** Configure the main internal regulator output voltage*/__HAL_RCC_PWR_CLK_ENABLE();__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/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 = 25;RCC_OscInitStruct.PLL.PLLN = 336;RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;RCC_OscInitStruct.PLL.PLLQ = 7;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks*/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_DIV2;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK){Error_Handler();}
}/*** @brief I2C1 Initialization Function* @param None* @retval None*/
static void MX_I2C1_Init(void)
{/* USER CODE BEGIN I2C1_Init 0 *//* USER CODE END I2C1_Init 0 *//* USER CODE BEGIN I2C1_Init 1 *//* USER CODE END I2C1_Init 1 */hi2c1.Instance = I2C1;hi2c1.Init.ClockSpeed = 400000;hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;hi2c1.Init.OwnAddress1 = 0;hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;hi2c1.Init.OwnAddress2 = 0;hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;if (HAL_I2C_Init(&hi2c1) != HAL_OK){Error_Handler();}/* USER CODE BEGIN I2C1_Init 2 *//* USER CODE END I2C1_Init 2 */}/*** @brief USART1 Initialization Function* @param None* @retval None*/
static void MX_USART1_UART_Init(void)
{/* USER CODE BEGIN USART1_Init 0 *//* USER CODE END USART1_Init 0 *//* USER CODE BEGIN USART1_Init 1 *//* USER CODE END USART1_Init 1 */huart1.Instance = USART1;huart1.Init.BaudRate = 115200;huart1.Init.WordLength = UART_WORDLENGTH_8B;huart1.Init.StopBits = UART_STOPBITS_1;huart1.Init.Parity = UART_PARITY_NONE;huart1.Init.Mode = UART_MODE_TX_RX;huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;huart1.Init.OverSampling = UART_OVERSAMPLING_16;if (HAL_UART_Init(&huart1) != HAL_OK){Error_Handler();}/* USER CODE BEGIN USART1_Init 2 *//* USER CODE END USART1_Init 2 */}/*** Enable DMA controller clock*/
static void MX_DMA_Init(void)
{/* DMA controller clock enable */__HAL_RCC_DMA1_CLK_ENABLE();/* DMA interrupt init *//* DMA1_Stream6_IRQn interrupt configuration */HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 0, 0);HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn);}/*** @brief GPIO Initialization Function* @param None* @retval None*/
static void MX_GPIO_Init(void)
{
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 *//* GPIO Ports Clock Enable */__HAL_RCC_GPIOH_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart==&huart1){cmd = URX;HAL_UART_Receive_IT(&huart1, &URX, 1);}}
/* USER CODE END 4 *//*** @brief  This function is executed in case of error occurrence.* @retval None*/
void Error_Handler(void)
{/* USER CODE BEGIN Error_Handler_Debug *//* User can add his own implementation to report the HAL error return state */__disable_irq();while (1){}/* USER CODE END Error_Handler_Debug */
}#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 /* USE_FULL_ASSERT */#endif /* USE_FULL_ASSERT */

STM32例程测试

串口指令0x01测试效果如下:
在这里插入图片描述
串口指令0x02测试效果如下:
在这里插入图片描述
串口指令0x03测试效果如下:
在这里插入图片描述
串口指令0x04测试效果如下:
在这里插入图片描述
串口指令0x05测试效果如下:
在这里插入图片描述
串口指令0x06测试效果如下:
在这里插入图片描述

STM32例程下载

STM32F401CCU6 I2C总线FATS读写EEPROM ZD24C1MA例程下载

–End–

相关文章:

STM32存储左右互搏 I2C总线FATS读写EEPROM ZD24C1MA

STM32存储左右互搏 I2C总线FATS读写EEPROM ZD24C1MA 在较低容量存储领域&#xff0c;EEPROM是常用的存储介质&#xff0c;可以通过直接或者文件操作方式进行读写。不同容量的EEPROM的地址对应位数不同&#xff0c;在发送字节的格式上有所区别。EEPROM是非快速访问存储&#xf…...

微服务—远程调用(RestTemplate)

在微服务的所有框架中&#xff0c;SpringCloud脱颖而出&#xff0c;它是目前国内使用的最广泛的微服务框架 &#xff08;官网地址&#xff09;&#xff0c;它集成了各种微服务功能组件&#xff0c;并基于SpringBoot实现了这些组件的自动装配&#xff0c;从而提供了良好的开箱…...

Fine tune简介

目录 Intro Related work Example .1 重新训练 .2 使用新的数据集进行fine tune .3 修改net结构 References 移学习不是一种算法而是一种机器学习思想,应用到深度学习就是微调(Fine-tune)。通过修改预训练网络模型结构(如修改样本类别输出个数),选择性载入预训练网络…...

centos nginx配置ipv4和ipv6的地址都可以访问同一个网站

标题centos nginx配置ipv4和ipv6的地址都可以访问同一个网站 在 Nginx 中配置使 IPv4 和 IPv6 地址都可以访问同一个网站相对简单。只需要确保 Nginx 配置文件正确地配置了监听 IPv4 和 IPv6 地址的监听器即可。 打开你的 Nginx 配置文件&#xff0c;通常位于 /etc/nginx/nginx…...

高教杯数学建模2020C题总结

&#x1f9e1;1. 前言&#x1f9e1; 跟队友花了三天模拟2020C题&#xff0c;现在整理一下一些数据处理的代码&#xff0c;以及在模拟中没有解决的问题。方便以后回溯笔记。 &#x1f9e1;2. 数据处理&#x1f9e1; 2.1 导入数据&#xff0c;并做相关预处理 import pandas a…...

Swagger

目录 简介 使用方式&#xff1a; 常用注解 简介 使用Swagger你只需要按照他的规范去定义接口及接口相关信息再通过Swagger衍生出来的一系列项目和工具&#xff0c;就可以做到生成各种格式的接口文档&#xff0c;以及在线接口调试页面等等。 官网&#xff1a;https://swagger…...

Android 13像Settings一样获取热点和网络共享

一.背景 由于客户定制的Settings里面需要获取到热点和网络共享状态,所以需要实现此功能。 目录 一.背景 二.前提条件 三.调用api 二.前提条件 首先应用肯定要是系统应用,并且导入framework.jar包,具体可以参考: Android 应用自动开启辅助(无障碍)功能并使用辅助(无障碍…...

操作系统搭建相关知识

文章目录 系统篇netstat命令systemctl命令Systemd系统资源分类&#xff08;12类&#xff09; 网络篇ifconfig命令操作系统配置动态IP脚本dhcp服务的安装与配置防火墙相关知识 操作系统常用配置文件 系统篇 netstat命令 netstat指路 systemctl命令 常用于重启系统的每个服务…...

【校招VIP】前端校招考点之vue底层特性

考点介绍&#xff1a; 大家在面试途中遇到的相对多的问题&#xff0c;也是难点的问题&#xff0c;一般都有vue底层原理。对于只会用但是不懂的小白来说真是太痛苦了&#xff0c;仅仅能说出来 一些 数据劫持&#xff0c;双向数据绑定&#xff0c;虚拟dom树的名词来说远远不够。 …...

vue3+vite配置vantUI主题

❓在项目中统一配置UI主题色&#xff0c;各个组件配色统一修改 vantUI按需安装 参考vantUI文档 创建vantVar.less文件夹进行样式编写 vantVar.less :root:root{//导航--van-nav-bar-height: 44px;//按钮--van-button-primary-color: #ffffff;--van-button-primary-backgr…...

C++基础语法——继承

1.继承是什么&#xff1f; 继承是一种面向对象编程的概念&#xff0c;它允许一个类&#xff08;称为子类或派生类&#xff09;从另一个类&#xff08;称为基类或父类&#xff09;继承属性和方法。继承使得子类能够使用基类已有的代码&#xff0c;并且可以在此基础上进行扩展或修…...

vim配置之spf13-vim

文章目录 vim配置:spf13-vim什么是spf13-vim安装*nix and os x安装 spf13-vim使用技巧或快捷键spf13的vim默认没有启用剪切板,需要在vimrc中设置 vim配置:spf13-vim 什么是spf13-vim 官网&#xff1a;http://vim.spf13.com/ 它是一个完全跨平台发布&#xff0c;保持vim的感觉…...

Azure如何启用网络观察应用程序

文章目录 基础概念介绍实操 基础概念介绍 Azure中的网络观察应用程序是一种用于监视和诊断Azure网络的工具。它提供了一种集中管理和监控网络流量、连接性和性能的方式。网络观察应用程序能够提供网络流量分析、连接监视、性能监视和故障诊断等功能&#xff0c;用于帮助管理员…...

分步注册方式 编写驱动

作业&#xff1a;通过分步注册方式&#xff0c;编写LED灯驱动&#xff1a;&#xff08;驱动文件mycdev.c 测试文件test.c 头文件head.h) mycdev.c #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/io.h> …...

repmgr出现双主,并且时间线分叉,删除了最新的时间线节点

遇到的问题如下&#xff1a; 2023-08-17 20:24:21.566 CST [1556001] LOG: database system was interrupted; last known up at 2023-08-17 20:21:41 CST 2023-08-17 20:24:21.770 CST [1556001] LOG: restored log file "00000009.history" from archive cp: 无法…...

ThinkPHP中实现IP地址定位

在网站开发中&#xff0c;我们经常需要获取用户的地理位置信息以提供个性化的服务。一种常见的方法是通过IP地址定位。在本文中&#xff0c;我们将介绍如何在ThinkPHP框架中实现IP地址定位。 一、IP地址定位的基本原理 IP地址是Internet上的设备在网络中的标识符。每个设备都有…...

使用Python批量将Word文件转为PDF文件

说明&#xff1a;在使用Minio服务器时&#xff0c;无法对word文件预览&#xff0c;如果有需要的话&#xff0c;可以将word文件转为pdf文件&#xff0c;再存储到Minio中&#xff0c;本文介绍如何批量将word文件&#xff0c;转为pdf格式的文件&#xff1b; 安装库 首先&#xff…...

XDR解决方案成为了新的安全趋势

和当今指数倍增长的安全数据相比&#xff0c;安全人才的短缺带来了潜在的风险。几乎所有的公司&#xff0c;无论规模大小&#xff0c;在安全资源能力上都有限&#xff0c;需要过滤各种告警才能将分析量保持在可接受范围。但这样一来&#xff0c;潜在的威胁线索就可能被埋没&…...

001-Nacos 服务注册

目录 Nacos介绍注册中心架构面临问题源码分析实例注册-接口实例注册-入口实例注册-创建一个(Nacos)Service实例注册-注册(Nacos)Service Nacos 介绍 Dynamic Naming and Configuration Service 动态的命名和配置服务 反正可以实现注册中心的功能 注册中心架构 服务提供者 …...

71 # 协商缓存的配置:通过内容

对比&#xff08;协商&#xff09;缓存 比较一下再去决定是用缓存还是重新获取数据&#xff0c;这样会减少网络请求&#xff0c;提高性能。 对比缓存的工作原理 客户端第一次请求服务器的时候&#xff0c;服务器会把数据进行缓存&#xff0c;同时会生成一个缓存标识符&#…...

谷歌浏览器插件

项目中有时候会用到插件 sync-cookie-extension1.0.0&#xff1a;开发环境同步测试 cookie 至 localhost&#xff0c;便于本地请求服务携带 cookie 参考地址&#xff1a;https://juejin.cn/post/7139354571712757767 里面有源码下载下来&#xff0c;加在到扩展即可使用FeHelp…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例&#xff1a;使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例&#xff1a;使用OpenAI GPT-3进…...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出&#xff1a;JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中&#xff0c;随机数的生成看似简单&#xff0c;却隐藏着许多玄机。无论是生成密码、加密密钥&#xff0c;还是创建安全令牌&#xff0c;随机数的质量直接关系到系统的安全性。Jav…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...