STM32 pid自整定+pid控温+pwm输出 源程序

主要是利用继电器反馈法进行pid参数自动整定。若测出了系统的一阶模型,或得出了系统的临界比例增益,则可很容易地设计出PID调节器。继电型自整定的基本想法是,在控制系统中设置两种模态:测试模态和调节模态。在测试模态下,调节器自动转换成位式调节,即当测量值小于设定值时,调节器输出为满量程,反之为零,使系统产生振荡,振荡过程中调节器自动提取被控对象的特征参数;而在调节模态下由系统的特征参数首先得出PID控制器,然后,由此控制器对系统进行调节。当需要PID参数整定时,开关置于调整处,系统按继电反馈建立起稳定的极限环振荡后,就可以根据系系统响应特征确定PID参数。自整定计算完成后开关置于调节处,系统进入正常控制。内含STM32程序,包含DS18B20读取温度

STM32单片机源程序如下:

  1. #include './pid/pid.h'

  2. #include './led/bsp_led.h'

  3. #include './GeneralTim/bsp_GeneralTim.h'

  4. PID pid; //存放PID算法所需要的数据

  5. uint16_t pw;

  6. uint16_t save_buff[9000] = {0}; //保存数据缓存

  7. extern volatile        uint16_t Step_Auto;

  8. extern volatile        uint32_t PID_cool_cnt;

  9. extern volatile        uint32_t PID_heat_cnt;

  10. extern volatile        uint16_t pid_self_first_status_flag;        //标志位

  11. extern volatile        uint16_t PID_Deal,PID_auto_Deal;

  12. extern volatile        uint16_t zero_across_counter;

  13. extern volatile        uint16_t k_pid_self_counter;

  14. extern volatile        uint16_t CCR4_Val;

  15. extern volatile        uint16_t kkk;

  16. void PID_Calc()  //pid计算

  17. {

  18. float DelEk;

  19. float out;

  20. if (PID_Deal == 1)

  21. {

  22. pid.Ek=pid.Sv-pid.Pv;   //得到当前的偏差值

  23. pid.SEk+=pid.Ek;        //历史偏差总和

  24. DelEk=pid.Ek-pid.Ek_1;  //最近两次偏差之差

  25. pid.Pout=pid.Kp*pid.Ek;     //比例输出

  26. pid.Iout=pid.Ki*pid.SEk;                          //积分输出

  27. pid.Dout=pid.Kd*DelEk;                            //微分输出

  28. out= pid.Pout+ pid.Iout+ pid.Dout;

  29. kkk++;

  30. if(out>255)

  31. {

  32. kkk=0;

  33. pid.SEk=0;

  34. }

  35. if(out>255)

  36. {

  37. pid.OUT=255;

  38. }

  39. else if(out<0)

  40. {

  41. pid.OUT=0;

  42. }

  43. else

  44. {

  45. pid.OUT=out;

  46. }

  47. pid.Ek_1=pid.Ek;  //更新偏差

  48. //                printf ( '\r\n%.1f\r\n',out);

  49. PID_out();

  50. }

  51. }

  52. void PID_out()  //输出PID运算结果到负载---每1ms被调用1次

  53. {

  54. uint16_t kk;

  55. if (pid.Pv>pid.Sv)//当前温度大于用户设定温度

  56. {

  57. CCR4_Val=100;

  58. GENERAL_TIM_Init();

  59. }

  60. else

  61. {

  62. kk=100-pid.OUT*100/255;

  63. CCR4_Val=kk;

  64. GENERAL_TIM_Init();

  65. //        printf ( '\r\n%3d\r\n',kk);

  66. }

  67. }

  68. void PID_auto()//继电器反馈法自整定pid参数

  69. {

  70. uint8_t i = 0;

  71. float KC = 0;

  72. float TC = 0;

  73. float V_temp = 0,min_temp = 0,max_temp = 0;

  74. float TIME_Hight=0,TIME_LOW=0;

  75. //第一步进入比较初始温度 确定此时温度处于哪种情况

  76. if (PID_auto_Deal== 0)

  77. {

  78. /******************************************************************************************************/

  79. PID_Deal = 0;//退出pid

  80. //程序第一次进入 查看对比当前温度和设定温度

  81. if(pid.Pv < pid.Sv1)//当前温度低于设定温度

  82. {

  83. PID_heat_cnt++;                //热

  84. PID_cool_cnt = 0;

  85. if(PID_heat_cnt >= 3)//连续3次结果

  86. {

  87. CCR4_Val=0;//加热

  88. GENERAL_TIM_Init();

  89. if(Step_Auto == 0)

  90. {

  91. Step_Auto = 1;

  92. zero_across_counter++;

  93. //                                        printf ( '\r\n1');

  94. }

  95. }

  96. }

  97. else//当前温度 大于 设定温度 停止加热

  98. {

  99. PID_cool_cnt++;

  100. PID_heat_cnt = 0;

  101. if(PID_cool_cnt > 3)

  102. {

  103. CCR4_Val=100;                //不加热

  104. GENERAL_TIM_Init();

  105. if(Step_Auto == 1)                //设定温度高于当前温度

  106. {

  107. Step_Auto = 0;

  108. zero_across_counter++;

  109. }

  110. }

  111. }

  112. if(PID_heat_cnt >= 65535)//连续3次结果

  113. {

  114. PID_heat_cnt=65535;

  115. }

  116. if(PID_cool_cnt >= 65534)//连续3次结果

  117. {

  118. PID_cool_cnt=65534;

  119. }

  120. /*****************开始计算强行振荡的周期和幅值****************************/

  121. if((zero_across_counter == 3 ) || (zero_across_counter == 4 ))

  122. {

  123. save_buff[k_pid_self_counter] = pid.Pv;

  124. k_pid_self_counter++;

  125. if(k_pid_self_counter >=9000)

  126. {

  127. k_pid_self_counter = 0;

  128. }

  129. }

  130. else if(zero_across_counter == 5 )//5次过0 则说明出现了振荡 整定成功

  131. {

  132. PID_Deal = 1;

  133. PID_auto_Deal = 1;

  134. zero_across_counter = 0;

  135. max_temp=save_buff[0];

  136. min_temp=save_buff[0];

  137. for(i = 0;i < k_pid_self_counter;i++)

  138. {

  139. if(save_buff[i] >= max_temp)

  140. {

  141. max_temp = save_buff[i];

  142. TIME_LOW=i;

  143. }

  144. if(save_buff[i] <= min_temp)

  145. {

  146. min_temp = save_buff[i];

  147. TIME_Hight=i;

  148. }

  149. }

  150. V_temp =  max_temp - min_temp;                                        //最大减最小就是幅值

  151. KC = 127/V_temp;

  152. //如果记录了 最低温度 与 最高温度对应的时间 那么沿用这个公式:TC = 2 * (TIME_Hight - TIME_LOW);

  153. TC = k_pid_self_counter;        //TC =2 * (TIME_Hight - TIME_LOW);

  154. pid.Kp = 0.6*KC;

  155. pid.Ki = (0.6*KC)/(0.5*TC)/10;

  156. pid.Kd = (0.6*KC)*(0.125*TC)/60;

  157. printf ( '\r\n整定成功');

  158. }

  159. }

  160. }

复制代码

  1. #include 'stm32f10x.h'

  2. #include 'core_cm3.h'

  3. #include './systick/bsp_SysTick.h'

  4. #include './led/bsp_led.h'

  5. #include './usart/bsp_usart.h'

  6. #include './ds18b20/bsp_ds18b20.h'

  7. #include './pid/pid.h'

  8. #include './timer/timer.h'

  9. #include './AdvanceTim/bsp_AdvanceTim.h'

  10. #include './GeneralTim/bsp_GeneralTim.h'

  11. volatile uint32_t time = 0; // ms 计时变量

  12. volatile uint32_t time2 = 0; // ms 计时变量

  13. float TM1,TM2;

  14. volatile uint8_t ucDs18b20Id[8];

  15. volatile        uint16_t Step_Auto;

  16. volatile        uint32_t PID_cool_cnt;

  17. volatile        uint32_t PID_heat_cnt;

  18. volatile        uint16_t pid_self_first_status_flag;        //标志位

  19. volatile        uint16_t PID_Deal,PID_auto_Deal;

  20. volatile        uint16_t zero_across_counter;

  21. volatile        uint16_t k_pid_self_counter;

  22. volatile        uint16_t CCR4_Val;

  23. volatile        uint16_t kkk;

  24. //volatile         uint16_t save_buff[9000] = {0};

  25. void delay();

  26. void PID_Init()

  27. {

  28. pid.Sv=30;                //用户设定温度

  29. pid.OUT0=1;

  30. zero_across_counter=0;

  31. PID_cool_cnt=0;

  32. PID_heat_cnt=0;

  33. PID_Deal=0;

  34. PID_auto_Deal=0;

  35. pid_self_first_status_flag = 0;

  36. k_pid_self_counter=0;

  37. if( pid.Pv <= pid.Sv)        //设定温度高于当前温度

  38. {

  39. pid.Sv1=(pid.Sv-pid.Pv)/2+pid.Pv;

  40. pid.Sv1=(pid.Sv-pid.Pv)/2+pid.Pv;

  41. pid.Sv1=(pid.Sv-pid.Pv)/2+pid.Pv;

  42. pid.Sv1=(pid.Sv-pid.Pv)/2+pid.Pv;

  43. pid.Sv1=(pid.Sv-pid.Pv)/2+pid.Pv;

  44. }

  45. //                CCR4_Val=100;

  46. //                PID_auto_Deal=1;

  47. //                PID_Deal=1;

  48. //                pid.Sv=30;

  49. //                pid.Kp=38.0999985;

  50. //                pid.Ki=0.21666673;

  51. //                pid.Kd=2.8575;

  52. }

  53. /**

  54. * @brief  主函数

  55. * @param  无

  56. * @retval 无

  57. */

  58. int main(void)

  59. {

  60. delay();

  61. CCR4_Val=50;

  62. ADVANCE_TIM_Init();

  63. GENERAL_TIM_Init();

  64. /* 配置SysTick 为1us中断一次 */

  65. SysTick_Init();

  66. //        /* 端口初始化 */

  67. //        LED_GPIO_Config();//初始化了PB1口

  68. USART_Config();        //初始化串口1

  69. printf('\r\n this is a ds18b20 test demo \r\n');

  70. while( DS18B20_Init() )

  71. printf('\r\n no ds18b20 exit \r\n');//初始化DS18B20,不初始化就等待这里?

  72. printf('\r\n ds18b20 exit \r\n');

  73. DS18B20_ReadId(ucDs18b20Id);

  74. TM1=DS18B20_GetTemp_MatchRom ( ucDs18b20Id );

  75. pid.Pv=TM1;

  76. PID_Init();  //参数初始化

  77. pid.Sv1=28;

  78. while(1)

  79. {

  80. printf ( '\r\n%.1f',TM1);                // 打印通过 DS18B20 序列号获取的温度值

  81. Delay_ms(10);

  82. TM1=DS18B20_GetTemp_MatchRom ( ucDs18b20Id );

  83. pid.Pv=TM1;//当前温度

  84. pid.Pv=TM1;//当前温度

  85. PID_auto();

  86. PID_Calc(); //pid计算

  87. //                printf ( '\r\n%.1f',TM1);                // 打印通过 DS18B20 序列号获取的温度值

  88. //                Delay_ms(1000);

  89. //                if ( time >= 10 ) /* 10 * 1 ms = 10ms 时间到 */

  90. //    {

  91. //      time = 0;

  92. //                        TM1=DS18B20_GetTemp_MatchRom ( ucDs18b20Id );

  93. //                        pid.Pv=TM1;//当前温度

  94. //    }

  95. //                if ( time2 >= 1000 ) /* 1000 * 1 ms = 1s 时间到 */

  96. //    {

  97. //      time2 = 0;

  98. //                        pid.Pv=TM1;//当前温度

  99. //                        PID_auto();

  100. //                        PID_Calc(); //pid计算

  101. //                }

  102. }

  103. }

  104. void delay(void)

  105. {

  106. int i;

  107. for(i=0; i<10000000; i++)

  108. ;

  109. }

复制代码

代码工程文件51hei附件下载:

代码.7z(197.13 KB, 下载次数: 15)

(0)

相关推荐

  • SMT回流焊操作使用核心知识参考

    SMT回流焊操作应该选择正确的材料和正确的操作方法来进行回流焊接.回流焊品质的好坏跟回流焊机的正确操作使用有很大的关系,广晟德回流焊这里为大家分步骤分享一下SMT回流焊操作使用核心知识参考. 一.SM ...

  • 在加热设备中,温控仪该如何使用?

    在加热设备中,温控仪是常用恒温控制电器元件. XMTG-7411温度控制仪 PV为测量显示值,SV为设定显示值,SET为设定模式键,方向键为温度值.参数值调节键. 在正常状态下,按一下SET键,SV数 ...

  • 301 热力学-液体工质-热物性2

    301 热力学-液体工质-热物性2 汽化潜热 r=hsv-hsl 式中,r为汽化潜热,hsv为饱和气的焓,hsl为饱和液的焓. 计算示例 15℃时水的汽化潜热为(15℃时水的饱和液与饱和气的焓分别为4 ...

  • 【分享】增量式PID的stm32实现,整定过程 (amobbs.com 阿莫电子论坛)

    感谢大家最近的帮忙,让我顺利做完增量PID功能,虽然PID不是什么牛逼的东西,但是真心希望以后刚刚接触这块的人能尽快进入状态. 也下面我分享一下近期的这些工作吧.欢迎大家批评指点~ 首先说说增量式PI ...

  • 熟悉PID工艺流程图的工控人更吃香!

    PID图作为化工生产的技术核心,无论是设计院的工程师.化工厂的工艺员,还是中控控制室的主操,了解PID图上每一个字母.符号所表示的意义,并清楚明白这些元件的作用和控制方法,是必不可少的技能. 01 P ...

  • 最经典的PID参数整定口诀

    用经验法整定调节器参数又称为试凑法,是广大仪表工数十年整定经验的积累,是应用最为广泛的一种调节器参数整定方法.它就是根据仪表工的经验及控制过程的曲线形状,直接对控制系统反复地.逐渐地试凑,最终得到满意 ...

  • 【知识普及】PID控制器整定软件如何优化工业流程?

    本文来自于<控制工程中文版>(CONTROL ENGINEERING China )2017年3月刊,原标题为:克服控制回路优化的挑战 良好的控制回路优化可以提高产品质量.增加产量,并将与 ...

  • 一体化伺服电机PID的整定(伺服增益调整)

    来源:立迈胜 大部分伺服电机在空载情况下具备良好的功能特性,但一旦负载运行时表现出的"性能"却差强人意,这主要是因为伺服电机在受到机械传动系统反作用力扰动时无法作出合理的响应而造成 ...

  • 还在用传统烟熏火燎的艾灸?左点智能小罐灸,旋转控温还防烫!

    还在用传统烟熏火燎的艾灸?左点智能小罐灸,旋转控温还防烫!

  • 盘点4种浇多即死的植物,特别是夏天,控温也要控水

    盘点4种浇多即死的植物 水虽为水命之源,乃植物生长发育时,不可或缺的重要元素之一,但若具体的浇水量未能把握好的话,那么,结果只有一个,即大半的花花草草,因被水淹而频生黑腐烂根现象,最终走向灭亡.其中, ...

  • 冷暖双面,8H这床控温夏被我喜欢

    入手需求 人类总是有很多矛盾的地方,比如说夏天天气很热,晚上即使开着空调,但还是想盖着被子,甚至是很厚的被子.其实要是不开空调,不盖被子,不穿衣服,在夏夜里睡觉完全是可以的.但是,笔者和大家一样,就是 ...

  • 超级实用!PID算法和PID控制原理

    电工技术讲堂 17篇原创内容 公众号 PID控制原理和特点 工程实际中,应用最为广泛调节器控制规律为比例.积分.微分控制,简称PID控制,又称PID调节.PID控制器问世至今已有近70年历史,它以其结 ...