木子剑
生命不熄,学习不止!

在写这个随记之前,我还是用的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模型。

 

posted on 2019-08-22 11:34  木子剑  阅读(552)  评论(0编辑  收藏  举报