具体如下:
1、如果加入D抖动的特别厉害,试试只用PI控制。
2、还有PID参数都是一步一步调出来的,我建议你做个上位机,就是个简单的VB串口程序,用来设置PID参数
3、然后在单片机这边弄个串口接收程序,这里就是个简单的串口程序,人人都会,把接收到的PID存储在缓冲区里。
4、然后单片机程序直接调用。单片机带EEPROM的话,当接收到改变的PID参数时,存储这些参数。去STC官网下你的单片机资料,上面有EEPROM测试程序,直接套用。
include "stc12.h"#include <intrins.h>
#include"pid.h"
typedef unsigned charuint8
typedef unsigned int uint16
typedef unsigned long intuint32
/*********************************函数声明******************
结构体设定
***********************************************************/
typedef struct PIDValue
{
uint32 Ek_Uint32[3] //差值保存,给定和反馈的差值
uint8 EkFlag_Uint8[3]//差值标志位符号,1则对应的为负数,0为对应的为正数
uint8 KP_Uint8 //比例系数
uint8 KI_Uint8 //积分系数
uint8 KD_Uint8 //微分显示
uint16 Uk_Uint16 //上一时刻的控制电压
uint16 RK_Uint16 //设定值
uint16 CK_Uint16 //实际值
uint8 Vaule_Flag //输出的值正负标志位,0为正,1为负
}PIDValueStr
PIDValueStr PID //定义一个结P构体
uint16out // 加热输出(PID运算后的输出值)
/***********************************************************************************
增量型PID算式:PID :Uk=KP*[E(k)-E(k-1)]+KI*E(k)+KD*[E(k)-2E(k-1)+E(k-2)]
函数入口: RK(设定值),CK(实际值),KP,KI,KD PID比例参数
函数出口: U(K)
PID运算函数
**************************************************************************************/
uint16 PID_Calc(uint16 PIDinput)
{
uint32 Temp[3] //中间临时变量
uint32 PostSum //正数和
uint32 NegSum //负数和
Temp[0] = 0 //给储存中间临时变量赋初值
Temp[1] = 0
Temp[2] = 0
PostSum = 0 //给存储所有的正数变量赋初值
NegSum = 0 //给存储所有的负值变量赋初值
PID.RK_Uint16=180 //设定值为180
PID.CK_Uint16=PIDinput //输入值
if( PID.RK_Uint16 >PID.CK_Uint16 ) //如果设定值大于实际值,就是当前的值比设定值小
{
if( PID.RK_Uint16 - PID.CK_Uint16 >10 )//计算偏差是否大于 piancha=10 ( 这里的10由 piancha 来设定大小,根据实际情况设定)
//if( PID.RK_Uint16 - PID.CK_Uint16 >piancha )
{ //如果偏差大于 piancha=10 不在设定的PID调控范围之内就全速加热
out = 100 //偏差大于piancha=10为上限幅值输出(全速加热)
// PID.Uk_Uint16 = full_speed //全速时的加热值,更具实际情况可自由设定 这里full_speed=100;
}
else //如果偏差小于 piancha=10 再调节的范围内就计算储存起来
{ //下面就是PID算法
Temp[0] = PID.RK_Uint16 - PID.CK_Uint16 // 计算出当前偏差值E(k)
PID.EkFlag_Uint8[1]=0 //E(k)为正数 的标志位 0为正,1为负
//数值移位
PID.Ek_Uint32[2] = PID.Ek_Uint32[1] //存储E(k-2)
PID.Ek_Uint32[1] = PID.Ek_Uint32[0] //储存E(k-1)
PID.Ek_Uint32[0] = Temp[0] //存储E(k)
/****************************************************************************************/
if( PID.Ek_Uint32[0] >PID.Ek_Uint32[1] )//E(k)>E(k-1) 为正数
{
Temp[0]=PID.Ek_Uint32[0] - PID.Ek_Uint32[1] //E(k)-E(k-1) 保存
PID.EkFlag_Uint8[0]=0 // 设定标志位 0为正,1为负
}
else //E(k)<E(k-1)
{
Temp[0]=PID.Ek_Uint32[1] - PID.Ek_Uint32[0] //E(k)-E(k-1)为负数
PID.EkFlag_Uint8[0]=1
}
/*****************************************************************************************/
Temp[2]=PID.Ek_Uint32[1]*2 // 2E(k-1)
if( (PID.Ek_Uint32[0]+ PID.Ek_Uint32[2])>Temp[2] ) //E(k-2)+E(k)>2E(k-1)
{
Temp[2]=(PID.Ek_Uint32[0]+ PID.Ek_Uint32[2])-Temp[2] //E(k-2)+E(k)-2E(k-1)为正数
PID.EkFlag_Uint8[2]=0
}
else //E(k-2)+E(k)-2E(k-1)为负数
{
Temp[2]=Temp[2]-(PID.Ek_Uint32[0]+ PID.Ek_Uint32[2]) //2E(k-1)-(E(k-2)+E(k))
PID.EkFlag_Uint8[2]=1
}
/**********************************************************************************************/
Temp[0] = (uint32)PID.KP_Uint8 * Temp[0] // KP*[E(k)-E(k-1)]
Temp[1] = (uint32)PID.KI_Uint8 * PID.Ek_Uint32[0] // KI*E(k)
Temp[2] = (uint32)PID.KD_Uint8 * Temp[2] // KD*[E(k-2)+E(k)-2E(k-1)]
/************************以下部分代码是讲所有的正数项叠加,负数项叠加**************************/
/**************************************KP*[E(k)-E(k-1)]********************************************/
if(PID.EkFlag_Uint8[0]==0)
PostSum += Temp[0] //正数和
else
NegSum += Temp[0]//负数和
/*************************************** KI*E(k)*************************************************/
if(PID.EkFlag_Uint8[1]==0)
PostSum += Temp[1]//正数和
else
//空 *** 作,E(K)>0
/************************************KD*[E(k-2)+E(k)-2E(k-1)]*************************************/
if(PID.EkFlag_Uint8[2]==0)
PostSum += Temp[2]//正数和
else
NegSum += Temp[2] //负数和
/**********************************************U(K)*************************************************/
//PostSum += (uint32)PID.Uk_Uint16
if(PostSum >NegSum ) // 是否控制量为正数
{
out= PostSum - NegSum
PID.Vaule_Flag=0 //PID调节值是正值
}
else //控制量输出为负数
{
out=NegSum-PostSum
PID.Vaule_Flag=1 //PID调节值是负值
}
}
//return out
}
else //如果设定值小于实际值,就是当前的值大于设定值,就不进行PID计算直接输出 0
{
out = 0
}
return out
}
你可以按照以下步骤编写STC8G1K08芯片的LED点亮和灭的时间控制程序:
设置芯片的时钟和计数器,以便实现时间控制。例如,可以使用定时器或延时函数来控制时间。
在主函数中编写程序,实现LED点亮和灭的时间控制。可以使用if语句或while语句来判断时间是否达到要求,然后控制LED灯的点亮和灭。
在main函数中添加延时函数,以实现上电后30秒后LED灯开始点亮的要求。
下面是一个简单的示例程序,仅供参考:
#include<reg52.h>
sbit LED=P1^0
void delay(unsigned int i)
{
while(i--)
}
void main()
{
unsigned int count=0 //计数器,用于实现30秒的延时
while(count<30000) //上电后30秒开始执行程序
{
delay(1000) //每次延时1秒
count+=1000
}
LED=1 //点亮LED
delay(3000) //LED持续3秒
LED=0 //灭掉LED
while(1) //芯片不工作
}
在上述程序中,使用了一个计数器来实现上电后30秒的延时,然后LED点亮并持续3秒后灭掉,最后芯片不工作。需要注意的是,示例程序仅供参考,具体实现方式需要根据实际情况进行调整和优化。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)