/*************************************************************************** @file power_data.c @brief @attention Created on: 2025-05-12 Author: YL Monitor Software group @description 功率部件的数据缓存处理模块 ****************************************************************************/ /************************ Includes *************************/ /************************ 宏指令 *************************/ #include “power_data.h” /************************ Private types *************************/ /************************ Private constants *************************/ /************************ 功能结构体 *************************/ typedef enum{ CACHE_L1_LOADING = 0xA1,/正在加载数据/ CACHE_L1_READY = 0xA2,/数据就绪/ CACHE_L1_SENT = 0xA2,/数据已上传至LEVEL2/ }ENUM_CACHE_L1_STATUS; typedef enum{ CACHE_L2_SENDING = 0x55,/数据待上传/ CACHE_L2_SENT = 0xAA,/数据已上传/ }ENUM_CACHE_L2_STATUS; /************************ Private macros *************************/ /************************ Private variables *************************/ /************************ 私有变量 ************************/ #if !SERIAL1_DMARx_ENABLE //禁用DMA1读取 0 / 一级数据缓存:用于功率部件接收数据的实时缓存 */ uint8_t power1_data_cache_L1[POWER_DEVICE_DATA_SIZE] = {0}; static SemaphoreHandle_t mutex_RW_Power1_L1 = NULL; /* 一级缓存当前数据写入位置 */ static uint16_t power1_L1_wPos = 0; /* 一级数据缓存状态 */ static uint16_t power1_L1_status = CACHE_L1_LOADING; #endif #if !SERIAL2_DMARx_ENABLE //禁用DMA2读取 0 /* 一级数据缓存:用于功率部件接收数据的实时缓存 / uint8_t power2_data_cache_L1[POWER_DEVICE_DATA_SIZE] = {0}; static SemaphoreHandle_t mutex_RW_Power2_L1 = NULL; / 一级缓存当前数据写入位置 / static uint16_t power2_L1_wPos = 0; / 一级数据缓存状态 */ static uint16_t power2_L1_status = CACHE_L1_LOADING; #endif /* 二级数据缓存:用于系统状态监控 */ static uint8_t power1_data_cache_L2[POWER_DEVICE_DATA_SIZE] = {0}; static uint8_t power2_data_cache_L2[POWER_DEVICE_DATA_SIZE] = {0}; static SemaphoreHandle_t mutex_RW_Power1_L2 = NULL; static SemaphoreHandle_t mutex_RW_Power2_L2 = NULL; /* 二级数据缓存状态 */ static uint8_t power1_L2_status = CACHE_L2_SENDING; static uint8_t power2_L2_status = CACHE_L2_SENDING; /************************ Functions *************************/ /************************ 功能函数 *************************/ /************************************************************ @funName : MD_SwInitPowerData @Input : NULL @Output : @Description : 数据缓存模块软件资源初始化 @Athor : YL Software Group @Version : V0.0.0 @Data : 2025/5/12 ************************************************************/ void MD_SwInitPowerData(void) { #if !SERIAL1_DMARx_ENABLE if(NULL == mutex_RW_Power1_L1) { mutex_RW_Power1_L1 = xSemaphoreCreateBinary(); / 数据读写互斥量创建失败 */ if(NULL == mutex_RW_Power1_L1) { } else { /* 释放数据读写互斥量 */ xSemaphoreGive(mutex_RW_Power1_L1); } } #endif #if SERIAL2_DMARx_ENABLE #else if(NULL == mutex_RW_Power2_L1) { mutex_RW_Power2_L1 = xSemaphoreCreateBinary(); /* 数据读写互斥量创建失败 */ if(NULL == mutex_RW_Power2_L1) { } else { /* 释放数据读写互斥量 */ xSemaphoreGive(mutex_RW_Power2_L1); } } #endif if(NULL == mutex_RW_Power1_L2) { mutex_RW_Power1_L2 = xSemaphoreCreateBinary(); /* 数据读写互斥量创建失败 */ if(NULL == mutex_RW_Power1_L2) { } else { /* 释放数据读写互斥量 */ xSemaphoreGive(mutex_RW_Power1_L2); } } if(NULL == mutex_RW_Power2_L2) { mutex_RW_Power2_L2 = xSemaphoreCreateBinary(); /* 数据读写互斥量创建失败 */ if(NULL == mutex_RW_Power2_L2) { } else { /* 释放数据读写互斥量 */ xSemaphoreGive(mutex_RW_Power2_L2); } } } /************************************************************ @funName : MD_UpdatePowerL2 @Input : device-功率部件序号 @Output : @Description : 更新功率部件二级缓存数据 @Athor : YL Software Group @Version : V0.0.0 @Data : 2025/5/12 *************************************************************/ void MD_UpdatePowerL2(const uint8_t device) { switch(device) { case POWER_DEVICE_1: { #if SERIAL1_DMARx_ENABLE if(BSP_GetRecvSize4Serial1() >= POWER_DEVICE_DATA_SIZE) { uint8_t rbuf[POWER_DEVICE_DATA_SIZE] = {0}; uint16_t rlen = 0; BSP_Recv4Serial1(rbuf, &rlen); if(rlen >= POWER_DEVICE_DATA_SIZE){ portBASE_TYPE xRecvWoken = pdFALSE; xSemaphoreTakeFromISR(mutex_RW_Power1_L2, &xRecvWoken); portYIELD_FROM_ISR(xRecvWoken); memcpy((uint8_t*)power1_data_cache_L2, (uint8_t*)rbuf, POWER_DEVICE_DATA_SIZE); power1_L2_status = CACHE_L2_SENDING;/* 待发送 */ xRecvWoken = pdFALSE; xSemaphoreGiveFromISR(mutex_RW_Power1_L2, &xRecvWoken); portYIELD_FROM_ISR(xRecvWoken); } } #else if(CACHE_L1_READY == power1_L1_status) { portBASE_TYPE xRecvWoken = pdFALSE; xSemaphoreTakeFromISR(mutex_RW_Power1_L2, &xRecvWoken); portYIELD_FROM_ISR(xRecvWoken); memcpy((uint8_t*)power1_data_cache_L2, (uint8_t*)power1_data_cache_L1, POWER_DEVICE_DATA_SIZE); power1_L1_status = CACHE_L1_SENT; power1_L2_status = CACHE_L2_SENDING;/* 待发送 */ xRecvWoken = pdFALSE; xSemaphoreGiveFromISR(mutex_RW_Power1_L2, &xRecvWoken); portYIELD_FROM_ISR(xRecvWoken); } #endif }break; case POWER_DEVICE_2: { #if SERIAL2_DMARx_ENABLE if(BSP_GetRecvSize4Serial2() >= POWER_DEVICE_DATA_SIZE) { uint8_t rbuf[POWER_DEVICE_DATA_SIZE] = {0}; uint16_t rlen = 0; BSP_Recv4Serial2(rbuf, &rlen); if(rlen >= POWER_DEVICE_DATA_SIZE){ portBASE_TYPE xRecvWoken = pdFALSE; xSemaphoreTakeFromISR(mutex_RW_Power2_L2, &xRecvWoken); portYIELD_FROM_ISR(xRecvWoken); memcpy((uint8_t*)power2_data_cache_L2, (uint8_t*)rbuf, POWER_DEVICE_DATA_SIZE); power2_L2_status = CACHE_L2_SENDING;/* 待发送 */ xRecvWoken = pdFALSE; xSemaphoreGiveFromISR(mutex_RW_Power2_L2, &xRecvWoken); portYIELD_FROM_ISR(xRecvWoken); } } #else if(CACHE_L1_READY == power2_L1_status) { portBASE_TYPE xRecvWoken = pdFALSE; xSemaphoreTakeFromISR(mutex_RW_Power2_L2, &xRecvWoken); portYIELD_FROM_ISR(xRecvWoken); memcpy((uint8_t*)power2_data_cache_L2, (uint8_t*)power2_data_cache_L1, POWER_DEVICE_DATA_SIZE); power1_L1_status = CACHE_L1_SENT; power2_L2_status = CACHE_L2_SENDING;/* 待发送 */ xRecvWoken = pdFALSE; xSemaphoreGiveFromISR(mutex_RW_Power2_L2, &xRecvWoken); portYIELD_FROM_ISR(xRecvWoken); } #endif }break; } } /************************************************************ @funName : MD_UpdatePowerL1 @Input : device-功率部件序号 bFirst-是否为第一个数据 wbuf-数据 wlen-数据长度 @Output : @Description : 更新功率部件一级缓存数据 @Athor : YL Software Group @Version : V0.0.0 @Data : 2025/5/12 ************************************************************/ //static uint8_t byte = 0; void MD_UpdatePowerL1(const uint8_t device, const bool bFirst, const uint8_t wbuf, const uint16_t wlen) { uint16_t len = wlen; if(wlen <= 0) { return; } switch(device) { case POWER_DEVICE_1: { #if SERIAL1_DMARx_ENABLE #else if(bFirst) { power1_L1_status = CACHE_L1_LOADING; power1_L1_wPos = 0; memset((uint8_t*)power1_data_cache_L1, 0, POWER_DEVICE_DATA_SIZE); } if(len > POWER_DEVICE_DATA_SIZE - power1_L1_wPos) { len = POWER_DEVICE_DATA_SIZE - power1_L1_wPos; } portBASE_TYPE xRecvWoken = pdFALSE; xSemaphoreTakeFromISR(mutex_RW_Power1_L1, &xRecvWoken); portYIELD_FROM_ISR(xRecvWoken); memcpy((uint8_t*)&power1_data_cache_L1[power1_L1_wPos], wbuf, len); power1_L1_wPos += len; xRecvWoken = pdFALSE; xSemaphoreGiveFromISR(mutex_RW_Power1_L1, &xRecvWoken); portYIELD_FROM_ISR(xRecvWoken); if(POWER_DEVICE_DATA_SIZE <= power1_L1_wPos) { power1_L1_status = CACHE_L1_READY; } #endif }break; case POWER_DEVICE_2: { #if SERIAL2_DMARx_ENABLE #else if(bFirst) { power2_L1_status = CACHE_L1_LOADING; power2_L1_wPos = 0; memset((uint8_t*)power2_data_cache_L1, 0, POWER_DEVICE_DATA_SIZE); } if(len > POWER_DEVICE_DATA_SIZE - power2_L1_wPos) { len = POWER_DEVICE_DATA_SIZE - power2_L1_wPos; } portBASE_TYPE xRecvWoken = pdFALSE; xSemaphoreTakeFromISR(mutex_RW_Power2_L1, &xRecvWoken); portYIELD_FROM_ISR(xRecvWoken); memcpy((uint8_t*)&power2_data_cache_L1[power2_L1_wPos], wbuf, len); power2_L1_wPos += len; xRecvWoken = pdFALSE; xSemaphoreGiveFromISR(mutex_RW_Power2_L1, &xRecvWoken); portYIELD_FROM_ISR(xRecvWoken); if(POWER_DEVICE_DATA_SIZE <= power2_L1_wPos) { power2_L1_status = CACHE_L1_READY; } #endif }break; } } /功率部件一级缓存数据/ /************************************************************ @funName : MD_ReadPowerL2 @Input : device-功率部件序号 rbuf-数据输出缓存 pos-数据读取位置 rlen-数据读取长度 @Output : @Description : 获取功率部件二级缓存数据 @Athor : YL Software Group @Version : V0.0.0 @Data : 2025/5/13 *************************************************************/ bool MD_ReadPowerL2(const uint8_t device, uint8_t *rbuf, const uint16_t pos, const uint16_t rlen) { if(rlen > POWER_DEVICE_DATA_SIZE || pos >= POWER_DEVICE_DATA_SIZE || POWER_DEVICE_DATA_SIZE - pos < rlen) { return false; } switch(device) { case POWER_DEVICE_1: { xSemaphoreTake(mutex_RW_Power1_L2, portMAX_DELAY); memcpy(rbuf, (uint8_t*)&power1_data_cache_L2[pos], rlen); xSemaphoreGive(mutex_RW_Power1_L2); }break; case POWER_DEVICE_2: { xSemaphoreTake(mutex_RW_Power2_L2, portMAX_DELAY); memcpy(rbuf, (uint8_t*)&power2_data_cache_L2[pos], rlen); xSemaphoreGive(mutex_RW_Power2_L2); }break; } return true; } /************************************************************ @funName : MD_GetPowerL2 @Input : device-功率部件序号 rbuf-数据缓存地址 @Output : @Description : 获取功率部件二级缓存地址 @Athor : YL Software Group @Version : V0.0.0 @Data : 2025/5/13 ***********************************************************/ uint8_t MD_GetPowerL2(const uint8_t device) { uint8_t addr = NULL; switch(device) { case POWER_DEVICE_1: { xSemaphoreTake(mutex_RW_Power1_L2, portMAX_DELAY); if(CACHE_L2_SENDING != power1_L2_status) { addr = NULL; } else { power1_L2_status = CACHE_L2_SENT; addr = power1_data_cache_L2; } xSemaphoreGive(mutex_RW_Power1_L2); }break; case POWER_DEVICE_2: { xSemaphoreTake(mutex_RW_Power2_L2, portMAX_DELAY); if(CACHE_L2_SENDING != power2_L2_status) { addr = NULL; } else{ power2_L2_status = CACHE_L2_SENT; addr = power2_data_cache_L2; } xSemaphoreGive(mutex_RW_Power1_L2); }break; } return addr; } /************************ End of file / /************************************************** @file fw_data.h @brief This file contains the macros & function about real data for framework & App. @attention Created on: 2025-05-30 Author: YL Monitor Software group @description ****************************************************************************/ /*************************************************************************** * @file fw_data.h * @brief This file contains the macros & function about real data for framework & App. * **************************************************************************** * @attention * * Created on: 2025-05-30 * Author: YL Monitor Software group * **************************************************************************** * @description * * * ****************************************************************************/ #ifndef __FW_DATA_H_ #define __FW_DATA_H_ #ifdef __cplusplus extern "C" { #endif /************************ Includes *************************/ #include "main.h" /************************ Exportd types ********************/ typedef struct{ uint8_t byte_H; uint8_t byte_L; }Power_Bits16; typedef struct{ uint8_t byte0; uint8_t byte1; uint8_t byte2; uint8_t byte3; }Power_Bits32; /* 功率部件系统参数 */ typedef struct{ /* word 0 */ Power_Bits16 Reserved0; //0-预留 /* word 1 */ Power_Bits16 SYSCTRL; //1-系统控制 /* word 2 */ Power_Bits16 Flag; //2-系统状态标志 /* word 3 */ Power_Bits16 ProtectHard_PROHARD; //3-硬件保护标志 /* word 4 */ Power_Bits16 ProtectSoft_PROSOFT; //4-软件保护标志 /* word 5 */ Power_Bits16 ProtectDrive_PRODRIVE; //5-驱动保护标志 /* word 6 */ Power_Bits16 ProtectComm_PROCOMM; //6-通信保护标志 /* word 7 */ Power_Bits16 INVCTRL; //7-逆变器控制 /* word 8 */ Power_Bits16 Reserved8; //预留 /* word 9 */ Power_Bits16 Reserved9; //预留 /* word 10 */ Power_Bits16 Reserved10; //预留 /* word 11-12 */ Power_Bits32 GPADAT; //GPIO0~31状态 /* word 13-14*/ Power_Bits32 GPBDAT; //GPIO32~63状态 /* word 15-16 */ Power_Bits32 GPCDAT; //GPIO64~87状态 /* word 17 */ Power_Bits16 Reserved17; //预留 /* word 18 */ Power_Bits16 Reserved18; //预留 /* word 19 */ Power_Bits16 Reserved19; //预留 /* word 20 */ Power_Bits16 OSC_CLK_FRQ; //外部晶振频率 /* word 21 */ Power_Bits16 SYS_CLK_FRQ; //系统时钟频率 /* word 22 */ Power_Bits16 SYS_TICK; //定时器时钟基准 /* word 23 */ Power_Bits16 SET_F_PWM; //开关频率 /* word 24 */ Power_Bits16 Reserved24; //预留 /* word 25 */ Power_Bits16 SysMode; //工作模式 /* word 26 */ Power_Bits16 SysState; //工作状态 /* word 27 */ Power_Bits16 SysStartMode; //启动方式 /* word 28*/ Power_Bits16 SysStartStopControl; //启停控制指令来源 /* word 29*/ Power_Bits16 SysCommandSource; //系统频率指令来源 /* word 30*/ Power_Bits16 ModID; //模块编号 /* word 31*/ Power_Bits16 SETUP_UOUT; //电压设定值 /* word 32*/ Power_Bits16 SETUP_IOUT; //电流设定值 /* word 33*/ Power_Bits16 SETUP_FREQ; //频率设定值 /* word 34*/ Power_Bits16 SOFTSTART_TIME; //软件起动时间 /* word 35*/ Power_Bits16 STEP_UOUT; //电压步长 /* word 36*/ Power_Bits16 STEP_IOUT; //电流步长 /* word 37*/ Power_Bits16 STEP_FREQ; //频率步长 /* word 38 */ Power_Bits16 STEP_ANGLE; //相角步长 /* word 39 */ Power_Bits16 POINTCYCLE; //周波点数 /* word 40 */ Power_Bits16 REF_UOUT; //电压给定值 /* word 41 */ Power_Bits16 REF_IOUT; //电流给定值 /* word 42 */ Power_Bits16 REF_FREQ; //频率给定值 /* word 43 */ Power_Bits16 REF_ANGLE; //实时相角 /* word 44 */ Power_Bits16 KPWMA; //A相调制系数 /* word 45 */ Power_Bits16 KPWMB; //B相调制系数 /* word 46 */ Power_Bits16 KPWMC; //C相调制系数 /* word 47 */ Power_Bits16 Effective_Uin; //输入电压有效值 /* word 48 */ Power_Bits16 Effective_Iin; //输入电流有效值 /* word 49 */ Power_Bits16 Effective_Udc; //直流母线电压有效值 /* word 50 */ Power_Bits16 Effective_Uout1; //A相输出电压有效值 /* word 51 */ Power_Bits16 Effective_Uout2; //B相输出电压有效值 /* word 52 */ Power_Bits16 Effective_Uout3; //C相输出电压有效值 /* word 53 */ Power_Bits16 Effective_Iout1; //A相输出电流有效值 /* word 54 */ Power_Bits16 Effective_Iout2; //B相输出电流有效值 /* word 55 */ Power_Bits16 Effective_Iout3; //C相输出电流有效值 /* word 56 */ Power_Bits16 Effective_IL1; //A相电感电流有效值 /* word 57 */ Power_Bits16 Effective_IL2; //B相电感电流有效值 /* word 58 */ Power_Bits16 Effective_IL3; //C相电感电流有效值 /* word 59 */ Power_Bits16 Effective_UinC; //备用电源电压有效值 /* word 60 */ Power_Bits16 Effective_UoutSet; //输出电压设定值(模拟) /* word 61 */ Power_Bits16 Effective_IoutSet; //输出电流设定值(模拟) /* word 62 */ Power_Bits16 Reserved62; //预留 /* word 63 */ Power_Bits16 Effective_FreqSet; //输出电压频率设定值(模拟) /* word 64 */ Power_Bits16 PIDU1_hReference; //PIDU1给定值 /* word 65 */ Power_Bits16 PIDI1_hPresentFeedback; //PIDI1反馈值 /* word 66 */ Power_Bits16 PIDI1_hReference; //PIDI1输出值 /* word 67 */ Power_Bits16 PIDU1_hKp_Gain; //PIDU1参数kp /* word 68*/ Power_Bits16 PIDU1_hKi_Gain; //PIDU1参数ki /* word 69*/ Power_Bits16 PIDU1_hKd_Gain; //PIDU1参数kd /* word 70*/ Power_Bits32 PIDU1_wLower_Limit_Integral; //PIDU1积分下限值 /* word 71*/ Power_Bits32 PIDU1_wUpper_Limit_Integral; //PIDU1积分上限值 /* word 72*/ Power_Bits16 PIDU1_hLower_Limit_Output; //PIDU1输出下限值 /* word 73*/ Power_Bits16 PIDU1_hUpper_Limit_Output; //PIDU1输出上限值 /* word 74*/ Power_Bits16 PIDU2_hReference; //PIDU2给定值 /* word 75*/ Power_Bits16 PIDU2_hPresentFeedback; //PIDU2反馈值 /* word 76*/ Power_Bits16 PIDI2_hReference; //PIDI2输出值 /* word 77*/ Power_Bits16 PIDU2_hKp_Gain; //PIDU2参数kp /* word 78*/ Power_Bits16 PIDU2_hKi_Gain; //PIDU2参数ki /* word 79*/ Power_Bits16 PIDU2_hKd_Gain; //PIDU2参数kd /* word 80*/ Power_Bits32 PIDU2_wLower_Limit_Integral; //PIDU2积分下限值 /* word 81*/ Power_Bits32 PIDU2_wUpper_Limit_Integral; //PIDU2积分上限值 /* word 82*/ Power_Bits16 PIDU2_hLower_Limit_Output; //PIDU2输出下限值 /* word 83*/ Power_Bits16 PIDU2_hUpper_Limit_Output; //PIDU2输出上限值 /* word 84 */ Power_Bits16 PIDI1hReference; //PIDI1给定值 /* word 85 */ Power_Bits16 PIDI1hPresentFeedback; //PIDI1反馈值 /* word 86 */ Power_Bits16 iParkUref_Ds; //PIDI1输出值 /* word 87 */ Power_Bits16 PIDI1_hKp_Gain; //PIDI1参数kp /* word 88*/ Power_Bits16 PIDI1_hKi_Gain; //PIDI1参数ki /* word 89*/ Power_Bits16 PIDI1_hKd_Gain; //PIDI1参数kd /* word 90*/ Power_Bits32 PIDI1_wLower_Limit_Integral; //PIDI1积分下限值 /* word 91*/ Power_Bits32 PIDI1_wUpper_Limit_Integral; //PIDI1积分上限值 /* word 92*/ Power_Bits16 PIDI1_hLower_Limit_Output; //PIDI1输出下限值 /* word 93*/ Power_Bits16 PIDI1_hUpper_Limit_Output; //PIDI1输出上限值 /* word 94 */ Power_Bits16 PIDI2hReference; //PIDI2给定值 /* word 95 */ Power_Bits16 PIDI2_hPresentFeedback; //PIDI2反馈值 /* word 96 */ Power_Bits16 iParkUref_Qs; //输出值 /* word 97 */ Power_Bits16 PIDI2_hKp_Gain; //PIDI2参数kp /* word 98*/ Power_Bits16 PIDI2_hKi_Gain; //PIDI2参数ki /* word 99*/ Power_Bits16 PIDI2_hKd_Gain; //PIDI2参数kd /* word 100*/ Power_Bits32 PIDI2_wLower_Limit_Integral; //PIDI2积分下限值 /* word 101*/ Power_Bits32 PIDI2_wUpper_Limit_Integral; //PIDI2积分上限值 /* word 102*/ Power_Bits16 PIDI2_hLower_Limit_Output; //PIDI2输出下限值 /* word 103*/ Power_Bits16 PIDI2_hUpper_Limit_Output; //PIDI2输出上限值 /* word 104 */ Power_Bits16 PIDPARA_hReference; //PIDPARA给定值 /* word 105 */ Power_Bits16 PIDPARA_hPresentFeedback; //PIDPARA反馈值 /* word 106 */ Power_Bits16 Reserved106; //PIDPARA输出值 /* word 107 */ Power_Bits16 PIDPARA_hKp_Gain; //PIDPARA参数kp /* word 108*/ Power_Bits16 PIDPARA_hKi_Gain; //PIDPARA参数ki /* word 109*/ Power_Bits16 PIDPARA_hKd_Gain; //PIDPARA参数kd /* word 110*/ Power_Bits32 PIDPARA_wLower_Limit_Integral;//PIDPARA积分下限值 /* word 111*/ Power_Bits32 PIDPARA_wUpper_Limit_Integral;//PIDPARA积分上限值 /* word 112*/ Power_Bits16 PIDPARA_hLower_Limit_Output; //PIDPARA输出下限值 /* word 113*/ Power_Bits16 PIDPARA_hUpper_Limit_Output; //PIDPARA输出上限值 /* word 114 */ Power_Bits16 PIDPLL_hReference; //PIDPLL给定值 /* word 115 */ Power_Bits16 PIDPLL_hPresentFeedback; //PIDPLL反馈值 /* word 116 */ Power_Bits16 Reserved116; //PIDPLL输出值 /* word 117 */ Power_Bits16 PIDPLL_hKp_Gain; //PIDPLL参数kp /* word 118*/ Power_Bits16 PIDPLL_hKi_Gain; //PIDPLL参数ki /* word 119*/ Power_Bits16 PIDPLL_hKd_Gain; //PIDPLL参数kd /* word 120*/ Power_Bits32 PIDPLL_wLower_Limit_Integral; //PIDPLL积分下限值 /* word 121*/ Power_Bits32 PIDPLL_wUpper_Limit_Integral; //PIDPLL积分上限值 /* word 122*/ Power_Bits16 PIDPLL_hLower_Limit_Output; //PIDPLL输出下限值 /* word 123*/ Power_Bits16 PIDPLL_hUpper_Limit_Output; //PIDPLL输出上限值 /* word 124 */ Power_Bits16 Reserved124; //输出变压器变比 /* word 125 */ Power_Bits16 Reserved125; //变压器等效电抗 /* word 126 */ Power_Bits16 Reserved126; //变压器等效电阻 /* word 127 */ Power_Bits16 Reserved127; //预留 /* word 128 */ Power_Bits16 FdOverUin_ValLimitHi; //输入过压保护值 /* word 129 */ Power_Bits16 FdUnderUin_ValLimitHi; //输入欠压保护值 /* word 130 */ Power_Bits16 FdOverIin_ValLimitHi; //输入过流保护值 /* word 131 */ Power_Bits16 FdOverUo1_ValLimitHi; //输出过压保护值 /* word 132 */ Power_Bits16 FdOverIo1_ValLimitHi; //输出过流保护值 /* word 133 */ Power_Bits16 FdOverIL1_ValLimitHi; //电感过流保护值 /* word 134 */ Power_Bits16 Reserved134; //短路保护电压动作值 /* word 135 */ Power_Bits16 Reserved135; //短路保护电流动作值 /* word 136 */ Power_Bits16 Reserved136; //短路保护电压返回值 /* word 137 */ Power_Bits16 Reserved137; //短路保护电流返回值 /* word 138 */ Power_Bits16 Reserved138; //短路运行时间 /* word 139 */ Power_Bits16 Reserved139; //110%过载保护限值 /* word 140 */ Power_Bits16 Reserved140; //110%过载保护时间 /* word 141 */ Power_Bits16 Reserved141; //110%过载保护倒计时 /* word 142 */ Power_Bits16 Reserved142; //120%过载保护限值 /* word 143 */ Power_Bits16 Reserved143; //120%过载保护时间 /* word 144 */ Power_Bits16 Reserved144; //120%过载保护倒计时 /* word 145 预留*/ Power_Bits16 Reserved145; /* word 146 AD结果寄存器数据(CH0)*/ Power_Bits16 AdcRegs_ADCRESULT0; /* word 147 */ Power_Bits16 AdcRegs_ADCRESULT1; //AD结果寄存器数据(CH1) /* word 148 */ Power_Bits16 AdcRegs_ADCRESULT2; //AD结果寄存器数据(CH2) /* word 149 */ Power_Bits16 AdcRegs_ADCRESULT3; //AD结果寄存器数据(CH3) /* word 150 */ Power_Bits16 AdcRegs_ADCRESULT4; //AD结果寄存器数据(CH4) /* word 151 */ Power_Bits16 AdcRegs_ADCRESULT5; //AD结果寄存器数据(CH5) /* word 152 */ Power_Bits16 AdcRegs_ADCRESULT6; //AD结果寄存器数据(CH6) /* word 153 */ Power_Bits16 AdcRegs_ADCRESULT7; //AD结果寄存器数据(CH7) /* word 154 */ Power_Bits16 AdcRegs_ADCRESULT8; //AD结果寄存器数据(CH8) /* word 155 */ Power_Bits16 AdcRegs_ADCRESULT9; //AD结果寄存器数据(CH9) /* word 156 */ Power_Bits16 AdcRegs_ADCRESULT10; //AD结果寄存器数据(CH10) /* word 157 */ Power_Bits16 AdcRegs_ADCRESULT11; //AD结果寄存器数据(CH11) /* word 158 */ Power_Bits16 AdcRegs_ADCRESULT12; //AD结果寄存器数据(CH12) /* word 159 */ Power_Bits16 AdcRegs_ADCRESULT13; //AD结果寄存器数据(CH13) /* word 160 */ Power_Bits16 AdcRegs_ADCRESULT14; //AD结果寄存器数据(CH14) /* word 161 */ Power_Bits16 AdcRegs_ADCRESULT15; //AD结果寄存器数据(CH15) /* word 162 预留*/ Power_Bits16 Reserved162; /* word 163 预留*/ Power_Bits16 Reserved163; /* word 164 预留*/ Power_Bits16 Reserved164; /* word 165 预留*/ Power_Bits16 Reserved165; /* word 166 预留*/ Power_Bits16 Reserved166; /* word 167 预留*/ Power_Bits16 Reserved167; /* word 168 预留*/ Power_Bits16 Reserved168; /* word 169预留 */ Power_Bits16 Reserved169; /* word 170 预留*/ Power_Bits16 Reserved170; /* word 171 预留*/ Power_Bits16 Reserved171; /* word 172 预留*/ Power_Bits16 Reserved172; /* word 173 预留*/ Power_Bits16 Reserved173; /* word 174 预留*/ Power_Bits16 Reserved174; /* word 175 预留*/ Power_Bits16 Reserved175; /* word 176 预留*/ Power_Bits16 Reserved176; /* word 177 预留*/ Power_Bits16 Reserved177; /* word 178 预留*/ Power_Bits16 Reserved178; /* word 179 预留*/ Power_Bits16 Reserved179; /* word 180 输入电压传感器采样范围*/ Power_Bits16 PEAK_UIN_SENSOR; /* word 181 输入电流传感器采样范围*/ Power_Bits16 PEAK_IIN_SENSOR; /* word 182 输出电压传感器采样范围*/ Power_Bits16 PEAK_UO_SENSOR; /* word 183 输出电流传感器采样范围*/ Power_Bits16 PEAK_IO_SENSOR; /* word 184 电感电流传感器采样范围*/ Power_Bits16 PEAK_IL_SENSOR; /* word 185 预留*/ Power_Bits16 Reserved185; /* word 186 预留*/ Power_Bits16 Reserved186; /* word 187 预留*/ Power_Bits16 Reserved187; /* word 188 预留*/ Power_Bits16 Reserved188; /* word 189 预留*/ Power_Bits16 Reserved189; /* word 190 通道选择*/ Power_Bits16 ChannelSelect; /* word 191 预留*/ Power_Bits16 Reserved191; /* word 192 预留*/ Power_Bits16 Reserved192; /* word 193 地址偏移量*/ Power_Bits16 AddressOffset; /* word 194 预留*/ Power_Bits16 Reserved194; /* word 195 预留*/ Power_Bits16 Reserved195; /* word 196 预留*/ Power_Bits16 Reserved196; /* word 197 预留*/ Power_Bits16 Reserved197; /* word 198 预留*/ Power_Bits16 Reserved198; /* word 199 网络通讯协议控制*/ Power_Bits16 Modbus_Control_ModbusCtrl; }Power_System_Type; STM32F105 power_data.c程序的二级缓存的400字节的数据准确的映射给fw_data.h程序中的Power_System_Type结构体中,然后去调用结构体的某一个数据,需要频繁访问结构体中的某个字段,可以将其缓存到局部变量中,减少多次访问互斥锁的开销,用标准库写出详细代码和注释,优化的建议也写入代码中,别单独提出来
时间: 2025-06-05 18:05:09 浏览: 21
<think>我们有一个需求:将power_data.c中的400字节的二级缓存数据映射到fw_data.h中的Power_System_Type结构体。同时,为了优化频繁访问字段的性能,我们建议将频繁访问的字段缓存到局部变量中,以减少互斥锁的开销(因为直接访问结构体可能需要加锁以保证数据一致性,而缓存到局部变量后,就可以在局部使用而不需要频繁加锁)。步骤:1.确保Power_System_Type结构体的总大小为400字节,或者我们明确知道这400字节的数据布局与Power_System_Type结构体完全匹配。2.使用memcpy将二级缓存数据直接复制到Power_System_Type结构体实例中。3.对于频繁访问的字段,在访问之前,先通过一次加锁操作将整个结构体复制到局部变量(或者仅复制频繁访问的字段),然后使用局部变量进行操作,最后如果需要回写,再在锁的保护下更新。注意:由于涉及并发访问,我们需要使用互斥锁来保护共享数据(即全局的Power_System_Type结构体实例)。但是,如果只是读取,而且数据不需要实时更新,我们可以采用复制到局部变量的方式,这样在读取期间就不需要一直持有锁。我们假设:-有一个全局的Power_System_Type类型的变量:global_power_system-有一个互斥锁:power_mutex在fw_data.h中定义结构体和全局变量(示例):typedefstruct{//假设结构体有多个成员,总大小为400字节//例如:uint32_tvoltage;uint32_tcurrent;//...其他字段}Power_System_Type;externPower_System_Typeglobal_power_system;externpthread_mutex_tpower_mutex;//假设使用pthread互斥锁在power_data.c中,我们有二级缓存数据,我们假设它是一个uint8_t数组,大小为400字节。具体实现:步骤1:将二级缓存数据映射到结构体我们可以通过memcpy将400字节的数据直接复制到global_power_system中。但要注意,我们需要保证结构体的内存布局与缓存数据的内存布局完全一致(包括字节对齐、填充等)。如果布局不一致,则不能直接复制,而需要逐个字段赋值。但是根据要求,我们假设布局一致。步骤2:在更新全局结构体时,我们需要加锁。同时,对于读取,如果读取多个字段需要保证一致性,则也要加锁。但是频繁加锁解锁会影响性能,所以对于频繁读取的字段,我们建议将整个结构体或部分字段复制到局部变量。示例代码:更新全局结构体(当二级缓存数据更新时):voidupdate_power_system_from_cache(uint8_t*cache_data){pthread_mutex_lock(&power_mutex);memcpy(&global_power_system,cache_data,sizeof(Power_System_Type));pthread_mutex_unlock(&power_mutex);}读取全局结构体中的字段,并优化频繁访问:假设我们需要频繁访问voltage和current字段,我们可以这样做:voidprocess_power_data(){Power_System_Typelocal_power;//局部变量//加锁复制全局结构体到局部变量pthread_mutex_lock(&power_mutex);local_power=global_power_system;//这里复制了整个结构体pthread_mutex_unlock(&power_mutex);//现在我们可以无锁地使用local_power中的字段uint32_tvol=local_power.voltage;uint32_tcur=local_power.current;//...使用vol和cur进行计算等操作//注意:如果在使用过程中全局结构体被更新,这里不会反映出来,因为我们复制了局部副本}优化:如果结构体很大(400字节),而我们只需要几个字段,则可以只复制需要的字段,这样减少复制开销。voidprocess_power_data(){uint32_tvol,cur;pthread_mutex_lock(&power_mutex);vol=global_power_system.voltage;cur=global_power_system.current;pthread_mutex_unlock(&power_mutex);//然后使用vol和cur}但是,如果我们需要访问多个字段,而加锁复制整个结构体可能更高效(因为一次加锁就可以复制多个字段,避免对每个字段访问都加锁),这取决于具体字段数量和访问模式。另一种优化:使用读写锁(如pthread_rwlock_t)来允许多个读者同时访问。这里我们暂时不展开。根据需求,我们提供以下代码示例:在power_data.c中实现数据映射和更新:#include"fw_data.h"#include<string.h>//假设二级缓存数据,这里用静态数组模拟staticuint8_tl2_cache[400];//定义互斥锁(如果还没有初始化,需要在别处初始化,比如程序启动时)pthread_mutex_tpower_mutex=PTHREAD_MUTEX_INITIALIZER;//更新函数,当缓存数据更新时调用voidl2_cache_updated(void){update_power_system_from_cache(l2_cache);}voidupdate_power_system_from_cache(uint8_t*cache_data){pthread_mutex_lock(&power_mutex);memcpy(&global_power_system,cache_data,sizeof(global_power_system));pthread_mutex_unlock(&power_mutex);}在需要频繁访问的地方,使用局部副本:voidsome_function_that_reads_frequently(){//方法1:复制整个结构体(适用于需要访问多个字段,且字段较多)Power_System_Typelocal_power;pthread_mutex_lock(&power_mutex);local_power=global_power_system;pthread_mutex_unlock(&power_mutex);//使用local_power...}或者:voidanother_function(){//方法2:只复制需要的字段(适用于访问少量字段)uint32_tvoltage,current;pthread_mutex_lock(&power_mutex);voltage=global_power_system.voltage;current=global_power_system.current;pthread_mutex_unlock(&power_mutex);//使用voltage和current...}注意事项:-确保结构体Power_System_Type的大小为400字节,可以使用static_assert(C11)或者编译时检查。-考虑字节序问题,如果缓存数据来自不同字节序的设备,需要进行转换。-如果结构体内存布局与缓存数据布局不一致(比如对齐方式不同),则不能直接memcpy,需要逐个字段赋值。补充:如何确保结构体大小?可以在定义结构体后,添加检查:#include<assert.h>static_assert(sizeof(Power_System_Type)==400,"Power_System_Typesizemismatch!");如果编译器不支持static_assert,可以用:typedefcharstatic_assertion[sizeof(Power_System_Type)==400?1:-1];另外,如果缓存数据布局与结构体布局不一致,我们可能需要手动解析缓存数据并填充结构体字段。假设布局一致,完整示例:fw_data.h:#ifndefFW_DATA_H#defineFW_DATA_H#include<stdint.h>#include<pthread.h>typedefstruct{uint32_tvoltage;uint32_tcurrent;//...其他字段,确保总大小为400字节}Power_System_Type;externPower_System_Typeglobal_power_system;externpthread_mutex_tpower_mutex;#endiffw_data.c(或者放在使用全局变量的地方):#include"fw_data.h"Power_System_Typeglobal_power_system;pthread_mutex_tpower_mutex=PTHREAD_MUTEX_INITIALIZER;power_data.c:#include"fw_data.h"#include<string.h>#include<pthread.h>staticuint8_tl2_cache[400];//二级缓存//用于检查结构体大小static_assert(sizeof(Power_System_Type)==400,"Power_System_Typesizemustbe400bytes");voidl2_cache_updated(void){//当缓存更新时,调用此函数pthread_mutex_lock(&power_mutex);memcpy(&global_power_system,l2_cache,sizeof(global_power_system));pthread_mutex_unlock(&power_mutex);}//使用示例:某个需要频繁读取的函数voidmonitor_power(){//方法1:复制整个结构体Power_System_Typelocal_power;pthread_mutex_lock(&power_mutex);local_power=global_power_system;pthread_mutex_unlock(&power_mutex);//现在可以安全地使用local_power//...//方法2:只复制需要的字段(以两个字段为例)uint32_tvol,cur;pthread_mutex_lock(&power_mutex);vol=global_power_system.voltage;cur=global_power_system.current;pthread_mutex_unlock(&power_mutex);//使用vol和cur}注意:在实际应用中,可能还需要考虑缓存数据更新频率和读取频率,以及是否允许读取到旧数据。优化建议:1.如果读取操作远多于写入操作,可以考虑使用读写锁(pthread_rwlock_t),这样多个读取者可以同时进行。2.如果结构体很大,且只需要几个字段,避免复制整个结构体。3.如果实时性要求高,可能需要避免使用局部副本,因为局部副本可能是过时的。这时只能通过加锁来保证数据最新,但会牺牲性能。4.考虑内存对齐,可以在结构体上使用属性(如__attribute__((aligned(4))))来指定对齐方式,确保与缓存数据对齐一致。根据需求,我们完成了映射和优化访问的代码。</think>
### 解决方案:使用标准库实现缓存数据映射与性能优化
#### 1. 数据映射实现
通过 `memcpy` 实现字节数据到结构体的直接映射,需确保结构体大小和内存布局匹配:
```c
// fw_data.h
#pragma once
#include <stdint.h>
// 使用 __attribute__((packed)) 确保无内存填充
typedef struct __attribute__((packed)) {
uint32_t voltage; // 0-3字节:电压值
uint32_t current; // 4-7字节:电流值
float temperature; // 8-11字节:温度
uint8_t status_flags[16]; // 12-27字节:状态标志
uint16_t power_levels[180]; // 28-387字节:功率等级
uint8_t reserved[13]; // 388-400字节:保留区
} Power_System_Type; // 总大小=4+4+4+16+360+13=401? 请确认实际大小
```
```c
// power_data.c
#include "fw_data.h"
#include <string.h>
#include <pthread.h>
// 全局共享结构体和互斥锁
Power_System_Type g_power_system;
pthread_mutex_t g_power_mutex = PTHREAD_MUTEX_INITIALIZER;
// 二级缓存数据(400字节)
extern uint8_t l2_cache[400]; // 定义在其他模块
void map_cache_to_struct() {
pthread_mutex_lock(&g_power_mutex);
memcpy(&g_power_system, l2_cache, sizeof(g_power_system));
pthread_mutex_unlock(&g_power_mutex);
}
```
#### 2. 高频字段访问优化
通过局部变量缓存减少锁操作:
```c
void process_power_data() {
// 仅加锁一次读取高频字段
uint32_t local_voltage, local_current;
float local_temperature;
pthread_mutex_lock(&g_power_mutex);
local_voltage = g_power_system.voltage;
local_current = g_power_system.current;
local_temperature = g_power_system.temperature;
pthread_mutex_unlock(&g_power_mutex);
// 无锁状态下使用局部变量
for (int i = 0; i < 1000; i++) {
float power = local_voltage * local_current;
if (local_temperature > 85.0f) {
// 过热处理
}
// 其他计算...
}
}
```
### 关键优化建议
1. **内存对齐验证**
```c
static_assert(sizeof(Power_System_Type) == 400, "结构体大小必须为400字节");
```
2. **读写锁优化**
使用读写锁(`pthread_rwlock_t`)替代互斥锁:
```c
pthread_rwlock_t g_power_rwlock = PTHREAD_RWLOCK_INITIALIZER;
// 写操作
pthread_rwlock_wrlock(&g_power_rwlock);
memcpy(...);
pthread_rwlock_unlock(&g_power_rwlock);
// 读操作
pthread_rwlock_rdlock(&g_power_rwlock);
uint32_t v = g_power_system.voltage;
pthread_rwlock_unlock(&g_power_rwlock);
```
3. **缓存时效性控制**
```c
// 添加版本号机制
typedef struct {
Power_System_Type data;
uint32_t version;
} Power_Data_Wrapper;
```
4. **编译器优化提示**
```c
void __attribute__((hot)) process_frequent_fields() {
// 热点函数提示编译器优化
}
```
### 注意事项
1. **字节序问题**:若数据源来自网络/外设,需添加字节序转换
2. **原子访问**:对32/64位基础类型字段可使用`stdatomic.h`
3. **内存屏障**:在多核平台使用`__sync_synchronize()`保证内存可见性
4. **错误处理**:所有锁操作必须检查返回值
```c
if (pthread_mutex_lock(&g_power_mutex) != 0) {
// 错误处理
}
```
---
阅读全文