在写这个随记之前,我还是用的CONTIKI OS进行测试的,没办法我用CONTIKI用上瘾了,如果你是用的裸奔代码或者是KILL的,会有差异的。
这次讲的大概是IAR下的CONTIKI,STM32F103VET6,PID恒温的过程控制,调试工具用*宝的上ST-LINK。
我最终利用PID进行35度恒温控制。试验的加热箱可以一直加热到76度的,经过简单的PID控制后,在35度,误差在正负1度。达到预期目的
第一步:查找PID源码进行测试
我是在GitHub网上找了三个PID源码,发现上三个PID源都是中国人发布的,但是查看到内部源码时,也是移植其他系统里面的PID的,看来都不是源创作者!!
测试的PID源码pid.h和pid.c
pid.h在下面
/* 增量式PID,测试可以使用,2019年08月21日 */ #ifndef _PID_H #ifdef _PID_C #define PID_EXT #else #define PID_EXT extern #endif typedef struct PID { int SetPoint; unsigned char BitMove; float Proportion; float Integral; float Derivative; int iError; int iIncpid; int LastError; int PrevError; int Uk; }PID,*pPID; PID_EXT PID sPID; PID_EXT pPID sptr; void IncPIDInit(void); int IncPIDCalc(int NextPoint); #endif
pid.c在下面
#define _PID_C #include "pid.h" #include <math.h> #define MAXOUT 1000 //输出最大值 void IncPIDInit(void) //PID初始化 { sptr = &sPID; sptr->SetPoint = 1600;//用户要设定值,比如温度值ADC值,配合Process_08进程,实测为35度恒温控制 sptr->BitMove = 0; //返回结果比例 sptr->LastError = 0; //前2次误差值 sptr->PrevError = 0; //前1次误差值 sptr->Proportion = 3; //有用户要设定值:比例,要控制的比例值, sptr->Integral = 0; //积分 sptr->Derivative = 0; //微分 sptr->iError = 0; //当前误差 sptr->iIncpid = 0; //增量误差 sptr->Uk = 0; //输出返回值 } int IncPIDCalc(int NextPoint) { //当前误差 sptr->iError = sptr->SetPoint - NextPoint; //增量误差 sptr->iIncpid= sptr->Proportion * sptr->iError//int类型与float类型运算,有一个警告。。。 - sptr->Integral * sptr->LastError + sptr->Derivative * sptr->PrevError; //存储误差,用于下次计算 sptr->PrevError = sptr->LastError; sptr->LastError = sptr->iError; sptr->Uk += sptr->iIncpid; //输出值限幅 if ((sptr->Uk>>sptr->BitMove) >= MAXOUT) { sptr->Uk = MAXOUT; } else if((sptr->Uk>>sptr->BitMove) <= 0) { sptr->Uk = 0; } else sptr->Uk = sptr->Uk>>sptr->BitMove; return(sptr->Uk); } //一些模拟的数据测试, /* 100-99 1 //P比列控制,其他:1000减去值,除以10,作为时间参数,加热固定时间为1.4S,使用CONTII OS操作系统 99-97 2 97-94 3 94-90 4 90-85 5 85-79 6 6 //I 14 22 30 38 46 54 //D */
CONTIKI的Process_08.h,是我的恒温事件驱动
我不是一个职业的程序员,只是一个小小的CONTIKI爱好者,下面源码都是自己原创的,花了4天左右进行测试好编写的。
跟本不能入大神的法眼,实在是脑子转不过来了,就用了GOTO无条件跳转指令(有点野蛮了),如果恒温控制不好的话,
就微调PID的P比例,或恒温时的cont1加热时间。只要测试工作时间有半天或一天后,温度受控制在35度,正负1度就行了。
#include <includes.h>//统一的头文件加载,如OS的,ST的,标准库的,用户自建的 #include "lib/sensors.h" #include <stdio.h> /******************************************************************************* process8 1.----使用STM32F103VET6的串口2(RA2-TX),进行数据画图输出,同时RA2也是OS系统的printf 2.----SerialChart V1.0是画图工具,配置好后可使用此进程画一个铌齿波形! 3.----因为使用了printf进行画图,最好其他的进程,要先关掉进行测试为好! 4.----加入增量式PID控制,效果正在测试---测试OK!! 就当前程序参数,配合夏新加热、制冷机,经过半天的测试,一直保持在35.1度,34.9度 ----2019、8、22 如果用SerialChart画图的话,要把本进程的所有printf去掉。 *******************************************************************************/ PROCESS(hello_world_process8, "Hello world process8");//申请线程process8测试 PROCESS_THREAD(hello_world_process8, ev, data)//进程3的功能体 { static struct etimer timeout2; //声明ETMIER事件 static int sensor_in=0,sensor_out=0; //PID的 输入信号 和 输出信号 static char pid_time,cont=0,contmp,cont1=0;//用的控制量 PROCESS_BEGIN();//开始 etimer_set(&timeout2,CLOCK_SECOND/5);//从当前时间起的,为200MS的etimer事件 leds_init(); //初始LED相关,CONTIKI驱动包leds.c功能 GPIOx_LED(); //初始化,其实是PC05,IO输出控制电源开关的 IncPIDInit();//这个进程用到了PID的相关功能,要进行初始化 PIDok = 1; //完成的标示位,是用户自建的位段 sensor_out = IncPIDCalc(1000);//避开上电PID不称定时间段 sensor_out = IncPIDCalc(1200);//不处理也无所谓的 sensor_out = IncPIDCalc(1400);// while(1) { PROCESS_WAIT_EVENT();//进行等待 if(ev == PROCESS_EVENT_TIMER) {//如果时间到了就打印信息,如果事件产生?? while(cont1)//是恒温中,加热动作 { printf("恒温加热中1.4秒\r\n");//画图中。 GPIO_WriteBit(GPIOC, GPIO_Pin_5, Bit_SET);//Bit_RESET, Bit_SET开电 cont1--; //200MS执行一次 goto loop;//跳出下面所有功能,到LOOP处(有点爆力,有点野蛮了) } sensor_in = Get_Adc_Average(ADC_Channel_1,10);//ADC_Channel_1通道,10次相加后平均(RA1引脚) sensor_out = IncPIDCalc(sensor_in);//以输入信号in为参数,控制量out pid_time = (1000 - sensor_out)/10; //算出断电时间pid_time if(pid_time>0)//有断电时间信号 { __NOP(); __NOP(); if(PIDok==1)//如果上次断电时间已完成, { cont = 0; contmp = pid_time;//存当前断电时间 printf("保存的contmp:%d \r\n",contmp); PIDok = 0; } if(cont<contmp)//断电中 { GPIO_WriteBit(GPIOC, GPIO_Pin_5, Bit_RESET);//Bit_RESET关, Bit_SET PIDok=0;//没有完成 cont++; printf("关掉供电中\r\n");//断电中 printf("cont:%d contmp:%d \r\n",cont, contmp);//断电计数器和当前的断电时间 } if(cont>=contmp)//上次存的断电时间contmp,已完成 { PIDok=1;//可以进行存新的PID time了 printf("可以进行更新PIDTIME\r\n");//画图中。。 cont1=7;//恒温时加热时间为7*200MS } __NOP(); __NOP(); } else if(pid_time==0)//上电时,温度很低时,直接加热信号,加热间隔时间为pid_time==0,利用PID算出来的 { GPIO_WriteBit(GPIOC, GPIO_Pin_5, Bit_SET);//Bit_RESET, Bit_SET开电 printf("通电加热中\r\n");// __NOP(); __NOP(); } loop: __NOP();//恒温加热跳转点,直接退出执行,进行恒温。 __NOP(); } etimer_reset(&timeout2);//复位时间,周而复始 } PROCESS_END();//结束,与PROCESS_BEGIN()配对! }
很遗憾,使用一段时间的CONTIKI OS,还是不会使用它的sensors模型,上次的button-sensor也没搞定,
有大神看到的话,求指导,求例程,先谢谢!网上找的资料关键地方都没有,细节讲得不清不楚的。
不然这上温度传感器值一定会用上sensors模型。