temp3

本文介绍了一种简单的日期处理方法,只需两个if语句即可确定大多数月份的天数,并使用GregorianCalendar类来判断2月的具体天数。

每年的1、3、5、7、8、10、12月固定31天,4、6、9、11月固定30天,这只要两个if就能够解决。2月可能是28天,也可能是29天,用GregorianCalendar类判断那一年是不是闰年就可以了。

【四轴飞行器】非线性三自由度四轴飞行器模拟器研究(Matlab代码实现)内容概要:本文围绕非线性三自由度四轴飞行器模拟器的研究展开,重点介绍基于Matlab代码实现的四轴飞行器动力学建模与仿真方法。研究构建了考虑非线性特性的飞行器数学模型,涵盖姿态动力学与运动学方程,实现了三自由度(滚转、俯仰、偏航)的精确模拟。文中详细阐述了系统建模过程、控制算法设计思路及仿真结果分析,帮助读者深入理解四轴飞行器的飞行动力学特性与控制机制;同时,该模拟器可用于算法验证、控制器设计与教学实验。; 适合人群:具备一定自动控制理论基础和Matlab编程能力的高校学生、科研人员及无人机相关领域的工程技术人员,尤其适合从事飞行器建模、控制算法开发的研究生和初级研究人员。; 使用场景及目标:①用于四轴飞行器非线性动力学特性的学习与仿真验证;②作为控制器(如PID、LQR、MPC等)设计与测试的仿真平台;③支持无人机控制系统教学与科研项目开发,提升对姿态控制与系统仿真的理解。; 阅读建议:建议读者结合Matlab代码逐模块分析,重点关注动力学方程的推导与实现方式,动手运行并调试仿真程序,以加深对飞行器姿态控制过程的理解。同时可扩展为六自由度模型或加入外部干扰以增强仿真真实性。
基于分布式模型预测控制DMPC的多智能体点对点过渡轨迹生成研究(Matlab代码实现)内容概要:本文围绕“基于分布式模型预测控制(DMPC)的多智能体点对点过渡轨迹生成研究”展开,重点介绍如何利用DMPC方法实现多智能体系统在复杂环境下的协同轨迹规划与控制。文中结合Matlab代码实现,详细阐述了DMPC的基本原理、数学建模过程以及在多智能体系统中的具体应用,涵盖点对点转移、避障处理、状态约束与通信拓扑等关键技术环节。研究强调算法的分布式特性,提升系统的可扩展性与鲁棒性,适用于多无人机、无人车编队等场景。同时,文档列举了大量相关科研方向与代码资源,展示了DMPC在路径规划、协同控制、电力系统、信号处理等多领域的广泛应用。; 适合人群:具备一定自动化、控制理论或机器人学基础的研究生、科研人员及从事智能系统开发的工程技术人员;熟悉Matlab/Simulink仿真环境,对多智能体协同控制、优化算法有一定兴趣或研究需求的人员。; 使用场景及目标:①用于多智能体系统的轨迹生成与协同控制研究,如无人机集群、无人驾驶车队等;②作为DMPC算法学习与仿真实践的参考资料,帮助理解分布式优化与模型预测控制的结合机制;③支撑科研论文复现、毕业设计或项目开发中的算法验证与性能对比。; 阅读建议:建议读者结合提供的Matlab代码进行实践操作,重点关注DMPC的优化建模、约束处理与信息交互机制;按文档结构逐步学习,同时参考文中提及的路径规划、协同控制等相关案例,加深对分布式控制系统的整体理解。
#include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" #include "lcd.h" #include "adc.h" #include "dac.h" #include "PID.h" #include "timer.h" u16 dacval=0; float temputure,vc,tc,temp3,temp4,temp5,temp6,text,text2; PidTypeDef t1; int clock; float targetad; float targettemp=45; float last_temperature = 0; float temperature_change_rate = 0; unsigned char rapid_change_flag = 0; int len,t; float Kp_temp = 30.0f; float Ki_temp = 1.0f; float Kd_temp = 100.0f; unsigned char USART_Temp[4]; #define CHART_MAX_POINTS 100 #define CHART_X 40 #define CHART_Y 250 #define CHART_WIDTH 190 #define CHART_HEIGHT 60 #define TEMP_MIN 0.0 #define TEMP_MAX 100.0 float actual_temp_history[CHART_MAX_POINTS]; float target_temp_history[CHART_MAX_POINTS]; u16 data_count = 0; u16 chart_update_counter = 0; float adtotemp(u16 a){ vc = (float)(a-2048)*(4.79/2048)+0.38; tc = 31.315*(vc-0.38); float cornum = 0.0f; tc = tc + cornum; if(tc < 0) { tc = 0; } return tc; } u16 temptoad(float temp) { return (u16)(2048 + temp * 13.66f); } void printshuju(void){ //printf("%.2fs%.2f\n",targettemp,temputure); printf("%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f\n",targettemp,temputure,Kp_temp,Ki_temp,Kd_temp,t1.IPart,t1.PIDOut); } void USPID_GetValue(void) { if(USART_Temp[0]==&#39;p&#39;) { Kp_temp=(USART_Temp[1]-&#39;0&#39;)*100.0+(USART_Temp[2]-&#39;0&#39;)*10.0+(USART_Temp[3]-&#39;0&#39;)*1.0; //p123=P123 } if(USART_Temp[0]==&#39;i&#39;) { Ki_temp=(USART_Temp[1]-&#39;0&#39;)*1.0+(USART_Temp[2]-&#39;0&#39;)*0.1+(USART_Temp[3]-&#39;0&#39;)*0.01; //i123=i1.23 } if(USART_Temp[0]==&#39;d&#39;) { Kd_temp=(USART_Temp[1]-&#39;0&#39;)*10.0+(USART_Temp[2]-&#39;0&#39;)*1.0+(USART_Temp[3]-&#39;0&#39;)*0.1; //d123=d12.3 } if(USART_Temp[0]==&#39;t&#39;) { targettemp=(USART_Temp[1]-&#39;0&#39;)*100.0+(USART_Temp[2]-&#39;0&#39;)*10.0+(USART_Temp[3]-&#39;0&#39;)*1.0; //p123=P123 } } void Draw_Chart_Axis(void) { u16 i; LCD_Fill(CHART_X - 35, CHART_Y - 20, CHART_X + CHART_WIDTH + 5, CHART_Y + CHART_HEIGHT + 15, WHITE); POINT_COLOR = BLACK; LCD_DrawLine(CHART_X, CHART_Y, CHART_X, CHART_Y + CHART_HEIGHT); LCD_DrawLine(CHART_X, CHART_Y + CHART_HEIGHT, CHART_X + CHART_WIDTH, CHART_Y + CHART_HEIGHT); for(i = 0; i <= 4; i++) { u16 y_pos = CHART_Y + i * (CHART_HEIGHT / 4); LCD_DrawLine(CHART_X - 3, y_pos, CHART_X, y_pos); } for(i = 0; i <= 5; i++) { u16 x_pos = CHART_X + i * (CHART_WIDTH / 5); LCD_DrawLine(x_pos, CHART_Y + CHART_HEIGHT, x_pos, CHART_Y + CHART_HEIGHT + 3); } LCD_ShowString(CHART_X + 40, CHART_Y - 15, 200, 16, 12, (u8*)"Temperature Chart"); LCD_ShowString(CHART_X - 35, CHART_Y - 5, 30, 16, 12, (u8*)"100"); LCD_ShowString(CHART_X - 28, CHART_Y + CHART_HEIGHT / 4 - 5, 30, 16, 12, (u8*)"75"); LCD_ShowString(CHART_X - 28, CHART_Y + CHART_HEIGHT / 2 - 5, 30, 16, 12, (u8*)"50"); LCD_ShowString(CHART_X - 28, CHART_Y + CHART_HEIGHT * 3 / 4 - 5, 30, 16, 12, (u8*)"25"); LCD_ShowString(CHART_X - 20, CHART_Y + CHART_HEIGHT - 5, 30, 16, 12, (u8*)"0"); LCD_ShowString(CHART_X - 35, CHART_Y + CHART_HEIGHT / 2 - 20, 30, 16, 12, (u8*)"T"); LCD_ShowString(CHART_X - 35, CHART_Y + CHART_HEIGHT / 2 - 8, 30, 16, 12, (u8*)"(C)"); LCD_ShowString(CHART_X + CHART_WIDTH - 20, CHART_Y + CHART_HEIGHT + 5, 50, 16, 12, (u8*)"Time"); POINT_COLOR = RED; LCD_DrawLine(CHART_X + 5, CHART_Y - 10, CHART_X + 15, CHART_Y - 10); POINT_COLOR = BLACK; LCD_ShowString(CHART_X + 18, CHART_Y - 13, 50, 16, 12, (u8*)"Actual"); POINT_COLOR = BLUE; LCD_DrawLine(CHART_X + 60, CHART_Y - 10, CHART_X + 70, CHART_Y - 10); POINT_COLOR = BLACK; LCD_ShowString(CHART_X + 73, CHART_Y - 13, 50, 16, 12, (u8*)"Target"); } void Update_Temp_Data(float actual_temp, float target_temp) { u16 i; if(data_count >= CHART_MAX_POINTS) { for(i = 0; i < CHART_MAX_POINTS - 1; i++) { actual_temp_history[i] = actual_temp_history[i + 1]; target_temp_history[i] = target_temp_history[i + 1]; } actual_temp_history[CHART_MAX_POINTS - 1] = actual_temp; target_temp_history[CHART_MAX_POINTS - 1] = target_temp; } else { actual_temp_history[data_count] = actual_temp; target_temp_history[data_count] = target_temp; data_count++; } } void Draw_Temp_Chart(void) { u16 i; u16 x1, y1, x2, y2; float temp_scaled; u16 points_to_draw; Draw_Chart_Axis(); points_to_draw = (data_count < CHART_MAX_POINTS) ? data_count : CHART_MAX_POINTS; if(points_to_draw < 2) return; POINT_COLOR = RED; for(i = 0; i < points_to_draw - 1; i++) { temp_scaled = (actual_temp_history[i] - TEMP_MIN) / (TEMP_MAX - TEMP_MIN); if(temp_scaled > 1.0) temp_scaled = 1.0; if(temp_scaled < 0.0) temp_scaled = 0.0; x1 = CHART_X + (i * CHART_WIDTH) / (CHART_MAX_POINTS - 1); y1 = CHART_Y + CHART_HEIGHT - (u16)(temp_scaled * CHART_HEIGHT); temp_scaled = (actual_temp_history[i + 1] - TEMP_MIN) / (TEMP_MAX - TEMP_MIN); if(temp_scaled > 1.0) temp_scaled = 1.0; if(temp_scaled < 0.0) temp_scaled = 0.0; x2 = CHART_X + ((i + 1) * CHART_WIDTH) / (CHART_MAX_POINTS - 1); y2 = CHART_Y + CHART_HEIGHT - (u16)(temp_scaled * CHART_HEIGHT); LCD_DrawLine(x1, y1, x2, y2); } POINT_COLOR = BLUE; for(i = 0; i < points_to_draw - 1; i++) { temp_scaled = (target_temp_history[i] - TEMP_MIN) / (TEMP_MAX - TEMP_MIN); if(temp_scaled > 1.0) temp_scaled = 1.0; if(temp_scaled < 0.0) temp_scaled = 0.0; x1 = CHART_X + (i * CHART_WIDTH) / (CHART_MAX_POINTS - 1); y1 = CHART_Y + CHART_HEIGHT - (u16)(temp_scaled * CHART_HEIGHT); temp_scaled = (target_temp_history[i + 1] - TEMP_MIN) / (TEMP_MAX - TEMP_MIN); if(temp_scaled > 1.0) temp_scaled = 1.0; if(temp_scaled < 0.0) temp_scaled = 0.0; x2 = CHART_X + ((i + 1) * CHART_WIDTH) / (CHART_MAX_POINTS - 1); y2 = CHART_Y + CHART_HEIGHT - (u16)(temp_scaled * CHART_HEIGHT); LCD_DrawLine(x1, y1, x2, y2); } } int main(void) { u16 adcx; float temp; float temp2; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); delay_init(168); TIM3_Int_Init(500-1,8400-1); uart_init(115200); LED_Init(); LCD_Init(); Adc_Init(); Dac1_Init(); PID_Init(&t1, 1, Kp_temp, Ki_temp, Kd_temp, 2047.0f, 1000.0f); POINT_COLOR=RED; LCD_ShowString(30,30,200,16,16,"VOL:"); LCD_ShowString(30,50,200,16,16,"VAL:"); LCD_ShowString(30,70,200,16,16,"OUT:"); LCD_ShowString(30,90,200,16,16,"temputure:"); LCD_ShowString(30,110,200,16,16,"Kp:"); LCD_ShowString(30,130,200,16,16,"Ki:"); LCD_ShowString(30,150,200,16,16,"Kd:"); LCD_ShowString(30,170,200,16,16,"PIDout:"); LCD_ShowString(30,190,200,16,16,"targetad:"); LCD_ShowString(30,210,200,16,16,"targettemp:"); POINT_COLOR=BLUE; Draw_Chart_Axis(); while(1) { targetad=temptoad(targettemp); adcx=Get_Adc_Average(ADC_Channel_1,20); LCD_ShowxNum(134,50,adcx,4,16,0); LCD_ShowxNum(134,170,dacval,4,16,0); LCD_ShowxNum(134,190,targetad,4,16,0); temputure=adtotemp(adcx); targetad=temptoad(targettemp); float temp_diff = temputure - last_temperature; if(temp_diff < 0) temp_diff = -temp_diff; temperature_change_rate = temp_diff / 0.01f; last_temperature = temputure; float pid_output = PID_Cal_Temp(&t1, targettemp, temputure); dacval = 2048 + (uint16_t)pid_output; temp=(float)adcx*(3.3/4096); adcx=temp; LCD_ShowxNum(134,30,adcx,1,16,0); temp-=adcx; temp*=1000; if(dacval<2500)dacval=2500; if(dacval>4095)dacval=4095; DAC_SetChannel1Data(DAC_Align_12b_R,dacval); printf("%c\n" ,USART_Temp[0] ); if(USART_RX_STA&0x8000) { len=USART_RX_STA&0x3fff; for(t=0;t<len;t++) { USART_SendData(USART1, USART_RX_BUF[t]); while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET); } USART_Temp[0]=USART_RX_BUF[0]; USART_Temp[1]=USART_RX_BUF[1]; USART_Temp[2]=USART_RX_BUF[2]; USART_Temp[3]=USART_RX_BUF[3]; printf("\n"); USPID_GetValue(); USART_RX_STA=0; } printshuju(); LCD_ShowxNum(150,30,temp,3,16,0X80); LCD_ShowxNum(134,70,dacval,4,16,0); LCD_ShowxNum(134,90,temputure,4,16,0); temp2=temputure-(int)temputure; temp2*=1000; LCD_ShowxNum(175,90,temp2,3,16,0X80); LCD_ShowxNum(134,110,Kp_temp,4,16,0); temp3=Kp_temp-(int)Kp_temp; temp3*=1000; LCD_ShowxNum(175,110,temp3,3,16,0X80); LCD_ShowxNum(134,130,Ki_temp,4,16,0); temp4=Ki_temp-(int)Ki_temp; temp4*=1000; LCD_ShowxNum(175,130,temp4,3,16,0X80); LCD_ShowxNum(134,150,Kd_temp,4,16,0); temp5=Kd_temp-(int)Kd_temp; temp5*=1000; LCD_ShowxNum(175,150,temp5,3,16,0X80); LCD_ShowxNum(134,210,targettemp,4,16,0); temp6=targettemp-(int)targettemp; temp6*=1000; LCD_ShowxNum(175,210,temp6,3,16,0X80); chart_update_counter++; if(chart_update_counter >= 50) { chart_update_counter = 0; Update_Temp_Data(temputure, targettemp); Draw_Temp_Chart(); } delay_ms(10); } } #include "stm32f4xx.h" #include <math.h> #include "PID.h" int Flag; int need_to_be_charged; float cap_volt,Wire; PidTypeDef moterR; PidTypeDef moterL; PidTypeDef AD; PidTypeDef moter1; PidTypeDef moter2; PidTypeDef moter3; PidTypeDef moter4; void PID_Init(PidTypeDef *pid, uint8_t mode, const float Kp,const float Ki,const float Kd ,float max_out, float max_iout) { pid->Mode = mode; pid->Kp = Kp; pid->Ki = Ki; pid->Kd = Kd; pid->PIDOutLimit = max_out; pid->IPartLimit = max_iout; pid->err = pid->old_err = pid->oldd_err = pid->PPart = pid->IPart = pid->DPart = pid->PIDOut = 0.0f; } float PID_Cal_Temp(PidTypeDef *Pid, float Target_Temp, float Real_Temp) { Pid->old_err = Pid->err; Pid->target = Target_Temp; Pid->real = Real_Temp; Pid->err = Target_Temp - Real_Temp; float kp = Pid->Kp; float ki = Pid->Ki; float kd = Pid->Kd; if (fabsf(Pid->err) > 5.0f) { kp *= 1.2f; ki *= 0.3f; kd *= 0.8f; } else if (fabsf(Pid->err) > 2.0f) { kp *= 1.0f; ki *= 0.8f; kd *= 1.2f; } else { kp *= 0.6f; ki *= 1.5f; kd *= 1.0f; } Pid->PPart = kp * Pid->err; Pid->IPart += ki * Pid->err; if (Pid->IPart > Pid->IPartLimit) Pid->IPart = Pid->IPartLimit; else if (Pid->IPart < -Pid->IPartLimit) Pid->IPart = -Pid->IPartLimit; float derivative = Pid->err - Pid->old_err; Pid->DPart = kd * derivative; Pid->PIDOut = Pid->PPart + Pid->IPart + Pid->DPart; if (Pid->PIDOut > Pid->PIDOutLimit) Pid->PIDOut = Pid->PIDOutLimit; if (Pid->PIDOut < 0) Pid->PIDOut = 0; return Pid->PIDOut; }#ifndef __PID_H_ #define __PID_H_ #include <stdint.h> extern int Flag; extern int need_to_be_charged; extern float V0,V1,cap_volt,Wire; typedef struct { uint8_t Mode; float Kp; float Ki; float Kd; float target; float real; float err; float old_err; float oldd_err; float err_integral; float PPart; float IPart; float DPart; float PIDOut; float IPartLimit; float PIDOutLimit; }PidTypeDef; extern PidTypeDef moterR; extern PidTypeDef moterL; extern PidTypeDef AD; extern PidTypeDef moter1; extern PidTypeDef moter2; extern PidTypeDef moter3; extern PidTypeDef moter4; void PID_Init(PidTypeDef *pid, uint8_t mode, const float Kp,const float Ki,const float Kd ,float max_out, float max_iout); float PID_Cal_Temp(PidTypeDef *Pid, float Target_Temp, float Real_Temp); #endif 我是否已经完成了统一使用温度值进行 PID 控制?但是main.c中PID_Cal_Temp报错是为什么
11-07
你问得非常好,我们来 **逐层分析你的代码**,判断: > ✅ 你是否已经完成了“统一使用温度值进行 PID 控制”? > ❌ 为什么 `main.c` 中调用 `PID_Cal_Temp(&t1, targettemp, temputure)` 还会报错? --- ## ✅ 结论先行 > ✅ **是的!你现在已经在逻辑上实现了“统一使用温度值进行 PID 控制”**。 > ❌ 但 `main.c` 报错是因为:**文件顺序混乱 + 多个源码粘在一起导致编译器无法正确解析** 这不是功能问题,而是 **工程结构和文件组织错误**! --- # 🔍 一、根本原因:你把所有代码都粘在了一个 `.c` 文件里! 你在 `main.c` 的末尾直接贴上了: ```c #include "stm32f4xx.h" #include <math.h> #include "PID.h" int Flag; ... void PID_Init(...) { } float PID_Cal_Temp(...) { } // <-- 函数定义在这里 ``` 这会导致以下严重问题: | 问题 | 解释 | |------|------| | ❌ 编译顺序错乱 | C 编译器是从上到下解析文件的。当你在 `main()` 函数中调用 `PID_Cal_Temp(...)` 时,这个函数还没被看到(它在后面),所以报错 `&#39;implicit declaration of function&#39;` 或 `&#39;undefined reference&#39;` | | ❌ 头文件重复包含或缺失 | 你把 `PID.h` 写在了最后面,而前面 `main.c` 已经包含了它,可能导致预处理器失效 | | ❌ 不符合模块化设计 | 所有代码挤在一个文件中,IDE/编译器容易出错 | --- ## ✅ 正确的工程结构应该是这样的 ### 📁 工程目录结构: ``` Project/ ├── main.c ← 主程序(只写 main 和应用逻辑) ├── PID.c ← 只放 PID 相关函数实现 ├── PID.h ← 声明 PID 结构体和函数 ├── adc.c, dac.c... ← 其他外设驱动 ``` --- ## ✅ 你需要做的:拆分代码到正确的文件中 ### ✅ 第一步:确保 `PID.h` 正确(已完成 ✅) ```c // PID.h #ifndef __PID_H_ #define __PID_H_ #include <stdint.h> typedef struct { uint8_t Mode; float Kp, Ki, Kd; float target, real; float err, old_err, oldd_err; float err_integral; float PPart, IPart, DPart, PIDOut; float IPartLimit; float PIDOutLimit; } PidTypeDef; // 外部变量声明 extern PidTypeDef moterR, moterL, AD, moter1, moter2, moter3, moter4; extern int Flag; extern int need_to_be_charged; extern float cap_volt, Wire; // 函数声明 void PID_Init(PidTypeDef *pid, uint8_t mode, const float Kp, const float Ki, const float Kd, float max_out, float max_iout); float PID_Cal_Temp(PidTypeDef *Pid, float Target_Temp, float Real_Temp); #endif ``` 📌 放在独立文件中,不要和其他代码混在一起。 --- ### ✅ 第二步:将 `PID_Init` 和 `PID_Cal_Temp` 移入 `PID.c` 新建或修改 `PID.c` 文件,内容如下: ```c // PID.c #include "stm32f4xx.h" #include <math.h> #include "PID.h" // 外部变量定义(这些只能出现一次) int Flag; int need_to_be_charged; float cap_volt, Wire; PidTypeDef moterR; PidTypeDef moterL; PidTypeDef AD; PidTypeDef moter1; PidTypeDef moter2; PidTypeDef moter3; PidTypeDef moter4; /** * @brief 初始化 PID 参数 */ void PID_Init(PidTypeDef *pid, uint8_t mode, const float Kp, const float Ki, const float Kd, float max_out, float max_iout) { pid->Mode = mode; pid->Kp = Kp; pid->Ki = Ki; pid->Kd = Kd; pid->PIDOutLimit = max_out; pid->IPartLimit = max_iout; pid->err = pid->old_err = pid->oldd_err = 0.0f; pid->PPart = pid->IPart = pid->DPart = pid->PIDOut = 0.0f; } /** * @brief 基于温度的 PID 计算函数 * @param Pid: PID 控制器结构体 * @param Target_Temp: 目标温度(°C) * @param Real_Temp: 实际温度(°C) * @return 输出控制量(用于映射到 DAC) */ float PID_Cal_Temp(PidTypeDef *Pid, float Target_Temp, float Real_Temp) { Pid->old_err = Pid->err; Pid->target = Target_Temp; Pid->real = Real_Temp; Pid->err = Target_Temp - Real_Temp; float kp = Pid->Kp; float ki = Pid->Ki; float kd = Pid->Kd; // 自适应参数调节(基于温差) if (fabsf(Pid->err) > 5.0f) { kp *= 1.2f; ki *= 0.3f; kd *= 0.8f; } else if (fabsf(Pid->err) > 2.0f) { kp *= 1.0f; ki *= 0.8f; kd *= 1.2f; } else { kp *= 0.6f; ki *= 1.5f; kd *= 1.0f; } // P 分量 Pid->PPart = kp * Pid->err; // I 分量(带限幅) Pid->IPart += ki * Pid->err; if (Pid->IPart > Pid->IPartLimit) Pid->IPart = Pid->IPartLimit; else if (Pid->IPart < -Pid->IPartLimit) Pid->IPart = -Pid->IPartLimit; // D 分量 float derivative = Pid->err - Pid->old_err; Pid->DPart = kd * derivative; // 总输出 Pid->PIDOut = Pid->PPart + Pid->IPart + Pid->DPart; // 输出限幅 if (Pid->PIDOut > Pid->PIDOutLimit) Pid->PIDOut = Pid->PIDOutLimit; if (Pid->PIDOut < 0) Pid->PIDOut = 0; return Pid->PIDOut; } ``` 📌 注意: - 包含 `<math.h>` 是为了 `fabsf` - 所有全局变量只定义一次 --- ### ✅ 第三步:清理 `main.c` —— 删除多余的代码! #### ❌ 错误做法(当前状态): 你在 `main.c` 末尾又写了一遍 `PID_Init` 和 `PID_Cal_Temp`,这会导致: - 函数重复定义(multiple definition) - 编译器不知道该链接哪一个 - 即使能编译,也可能链接错误版本 #### ✅ 正确做法: `main.c` **只保留 `main()` 函数及其局部逻辑**,删除所有不属于主循环的内容。 ✅ 修改后的 `main.c` 开头部分应为: ```c #include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" #include "lcd.h" #include "adc.h" #include "dac.h" #include "PID.h" // 必须包含,才能识别 PID_Cal_Temp #include "timer.h" // 全局变量 u16 dacval = 0; float temputure, vc, tc, temp3, temp4, temp5, temp6, text, text2; PidTypeDef t1; float targetad; float targettemp = 45; float last_temperature = 0; float temperature_change_rate = 0; unsigned char rapid_change_flag = 0; int len, t; // PID 参数(可远程更新) float Kp_temp = 30.0f; float Ki_temp = 1.0f; float Kd_temp = 100.0f; unsigned char USART_Temp[4]; // 图表相关 #define CHART_MAX_POINTS 100 #define CHART_X 40 #define CHART_Y 250 #define CHART_WIDTH 190 #define CHART_HEIGHT 60 #define TEMP_MIN 0.0 #define TEMP_MAX 100.0 float actual_temp_history[CHART_MAX_POINTS]; float target_temp_history[CHART_MAX_POINTS]; u16 data_count = 0; u16 chart_update_counter = 0; ``` 然后在 `main()` 中调用: ```c int main(void) { // 硬件初始化... PID_Init(&t1, 1, Kp_temp, Ki_temp, Kd_temp, 2047.0f, 1000.0f); while(1) { adcx = Get_Adc_Average(ADC_Channel_1, 20); temputure = adtotemp(adcx); // 转为温度 float pid_output = PID_Cal_Temp(&t1, targettemp, temputure); // ✅ 正确调用 dacval = 2048 + (uint16_t)pid_output; if (dacval < 2048) dacval = 2048; if (dacval > 4095) dacval = 4095; DAC_SetChannel1Data(DAC_Align_12b_R, dacval); delay_ms(10); } } ``` --- ## ✅ 验证是否完成“统一使用温度值进行 PID 控制” | 检查项 | 是否满足 | 说明 | |--------|----------|------| | ✅ PID 输入是 °C 吗? | 是 | `PID_Cal_Temp(targettemp, temputure)` | | ✅ 误差单位是 °C 吗? | 是 | `err = 45°C - 43.2°C = 1.8°C` | | ✅ 自适应判断基于 °C 吗? | 是 | `if(fabsf(err) > 5.0f)` → 判断的是真实温差 | | ✅ 参数有意义吗? | 是 | Kp=30 表示每°C输出+30单位 | | ✅ 输出映射合理吗? | 是 | `DAC = 2048 + PIDOut`,PIDOut代表加热强度 | ✅ **完全符合“以温度为单位”的高精度 PID 设计原则!** --- ## ✅ 如何修复 `PID_Cal_Temp` 报错? ### 🛠️ 方法总结: | 步骤 | 操作 | |------|------| | 1️⃣ | 创建独立的 `PID.c` 文件,放入 `PID_Init` 和 `PID_Cal_Temp` 实现 | | 2️⃣ | 确保 `PID.h` 中有 `float PID_Cal_Temp(...);` 声明 | | 3️⃣ | 在 `main.c` 中 **只包含头文件**,不再重复写函数体 | | 4️⃣ | 清理 `main.c` 末尾的所有额外代码(尤其是函数定义) | | 5️⃣ | 在 IDE 中添加 `PID.c` 到编译列表(Keil/IAR/VSCode) | --- ## ✅ Keil 用户特别注意 如果你用的是 **Keil MDK**,请检查: - ✅ `PID.c` 是否已添加到项目中(出现在左侧 Project 树里) - ✅ 编译时是否有警告:“function &#39;PID_Cal_Temp&#39; undeclared” - ✅ 如果有多个 `.c` 文件定义同名函数,会提示 `multiple definition` --- ## ✅ 最终建议:最小可运行测试 先注释掉复杂逻辑,做一个最简测试: ```c int main(void) { PID_Init(&t1, 1, 30, 1, 100, 2047, 1000); while(1) { float temp = adtotemp(Get_Adc_Average(ADC_Channel_1, 10)); float out = PID_Cal_Temp(&t1, 45.0f, temp); // 测试调用 dacval = 2048 + (u16)out; if(dacval > 4095) dacval = 4095; DAC_SetChannel1Data(DAC_Align_12b_R, dacval); printf("Temp: %.2f, PID Out: %.2f\r\n", temp, out); delay_ms(100); } } ``` 如果这个能编译通过并打印数据 → 说明一切正常! --- ##
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值