×
单片机 > 单片机程序设计 > 详情

PIC16F877A编程PID+PWM+1602液晶显示

发布时间:2020-08-21 发布时间:
|

#include

#include

#include

#define uchar unsigned char

#define uint unsigned int

#include"cd1602.h"

uint adsc[5],adjz[5],adsr[5]; //定义3个A/D转换临时变量

uint resultjz,resultsr,resultsc; //PWM为jz2,PID为jz1

double scdy,jzdy,srdy,pidsc,tjkz,jzxs,scxs,srxs,PWMsr,jzzkb; 

__CONFIG(HS&WDTDIS);

typedef struct PID{

double SetPoint; //设定目标

double Proportion; //比例常数

double Integral; //积分常数

double Derivative; //微分常数

double LastError; //Error[-1]

double PrevError; //Error[-2]

double SumError;

}PID;

PID sPID;

/*短延时函数*/

void delay1()

{  

int i; //定义整型变量

   for(i=1000;i>0;i--); //延时

}

/*延时函数*/

void Delay_ms1(uint xms)

{

int i,j;

for(i=0;i

{

for(j=0;j<71;j++);

}

}

/*A/D转换初始化函数*/

void ad_init()

{

TRISA=0x0F;

TRISC=0x00; //设置C口全为输出

TRISD=0x00; //设置D口全为输出

ADCON1=0xC4; //转换结果右对齐,其他做普通I/O

ADCS1=0;

ADCS0=1;

}

//输出电压采样

void sccy()

{

resultsc=0;

  for(int i=5;i>0;i--)

{

  ad_init(); //调用初始化函数

  CHS2=0;

           CHS1=0;

  CHS0=0;//系统时钟f/16,选择RA0通道,允许ADC工作

  ADON=1;

  delay1(); //保证采样延时

  ADGO=1; //开启转换过程

  while(ADGO); //等待转换完成

  resultsc=resultsc+ADRESL+ADRESH*256; //累计转换结果 

}

resultsc=resultsc/5; //求5次结果的平均值

}

//PID基准电压采样

void jzcy()

{

resultjz=0;

  for(int i=5;i>0;i--)

{

  ad_init(); //调用初始化函数

  CHS2=0;

           CHS1=0;

  CHS0=1;//系统时钟f/16,选择RA1通道,允许ADC工作

  ADON=1;

  delay1(); //保证采样延时

  ADGO=1; //开启转换过程

  while(ADGO); //等待转换完成

  resultjz=resultjz+ADRESL+ADRESH*256; //累计转换结果 

}

resultjz=resultjz/5; //求5次结果的平均值 

}

//输入电压采样

void srcy()

{

resultsr=0;

  for(int i=5;i>0;i--)

{

  ad_init(); //调用初始化函数

  CHS2=0;

           CHS1=1;

  CHS0=1;//系统时钟f/16,选择RA3通道,允许ADC工作

  ADON=1;

  delay1(); //保证采样延时

  ADGO=1; //开启转换过程

  while(ADGO); //等待转换完成

  resultsr=resultsr+ADRESL+ADRESH*256; //累计转换结果 

}

resultsr=resultsr/5; //求5次结果的平均值 

}

/*数值转换函数*/

void conv()

{

scdy=(resultsc*5.0/1023); //A/D转换的结果

jzdy=(resultjz*5.0/1023);

srdy=(resultsr*5.0/1023);

scxs=scdy*4;

jzxs=jzdy*4;

srxs=srdy*4;

adsc[0]=((int)(scxs/10)); //十位

adsc[1]=((int)(scxs))%10; //个位

adsc[2]=((int)(scxs*10)-adsc[0]*100-adsc[1]*10); //小数点第一位

adsc[3]=((int)(scxs*100)-adsc[0]*1000-adsc[1]*100-adsc[2]*10); //小数点第二位

adsc[4]=((int)((scxs-adsc[0]*10)*1000)-adsc[1]*1000-adsc[2]*100-adsc[3]*10);//小数点第三位

adjz[0]=((int)(jzxs/10)); //十位

adjz[1]=((int)(jzxs))%10; //个位

adjz[2]=((int)(jzxs*10)-adjz[0]*100-adjz[1]*10); //小数点第一位

adjz[3]=((int)(jzxs*100)-adjz[0]*1000-adjz[1]*100-adjz[2]*10); //小数点第二位

adjz[4]=((int)((jzxs-adjz[0]*10)*1000)-adjz[1]*1000-adjz[2]*100-adjz[3]*10); //小数点第二位

adsr[0]=((int)(srxs/10)); //十位

adsr[1]=((int)(srxs))%10; //个位

adsr[2]=((int)(srxs*10)-adsr[0]*100-adsr[1]*10); //小数点第一位

adsr[3]=((int)(srxs*100)-adsr[0]*1000-adsr[1]*100-adsr[2]*10); //小数点第二位

adsr[4]=((int)((srxs-adsr[0]*10)*1000)-adsr[1]*1000-adsr[2]*100-adsr[3]*10);//小数点第三位

}

//lcd显示函数

void lcdxianshi()

{

uchar i;

lcdcom(0x80);

for(i=0;i<10;i++)

{

  if(i==0)

  lcddat(0x6A);

  else if(i==1)

  lcddat(0x7A);

  else if(i==2)

  lcddat(0x3A);

  else if(i==3)

  lcddat(adjz[i-3]+0x30);

  else if(i==4)

  lcddat(adjz[i-3]+0x30);

  else if(i==5)

  lcddat(0x2E);

  else if(i==9)

  lcddat(0x56);

  else 

  lcddat(adjz[i-4]+0x30);  

}

lcdcom(0x8B);

for(i=0;i<5;i++)

{

  if(i==0)

  lcddat(0x73);

  else if(i==1)

  lcddat(0x72);

  else if(i==2)

  lcddat(0x3A);

  else if(i==3)

  lcddat(adsr[i-3]+0x30);

  else if(i==4)

  lcddat(adsr[i-3]+0x30);  

}

lcdcom(0xC0);

for(i=0;i<10;i++)

{

  if(i==0)

  lcddat(0x73);

  else if(i==1)

  lcddat(0x63);

  else if(i==2)

  lcddat(0x3A);

  else if(i==3)

  lcddat(adsc[i-3]+0x30);

  else if(i==4)

  lcddat(adsc[i-3]+0x30);

  else if(i==5)

  lcddat(0x2E);

  else if(i==9)

  lcddat(0x56);

  else 

  lcddat(adsc[i-4]+0x30); 

}

lcdcom(0xCB);

for(i=0;i<5;i++)

{

  if(i==0)

  lcddat(0x2E);

  else if(i==4)

  lcddat(0x56);

  else 

  lcddat(adsr[i+1]+0x30);

}

}

//PID计算部分

double PIDCalc(PID *pp,double NextPoint)

{

double dError,Error;

Error=pp->SetPoint-NextPoint;

pp->SumError+=Error;

dError=pp->LastError-pp->PrevError;

pp->PrevError=pp->LastError;

pp->LastError=Error;

return(pp->Proportion * Error+pp->Integral * pp->SumError+

        pp->Derivative * dError);

}

//PID初始化

void PIDInit(PID *pp)

{

memset(pp,0,sizeof(PID)); //memset(void *s, int ch, size_t n);

                                    //函数解释:将s中当前位置后面的n个字节用ch替换并返回s 。

}

//PID输入函数

double sensor(void) //传感器

{

return scdy;

}

//PID输出函数

void PIDsc(void)

{

double rOut;

double rIn;

sPID.Proportion=0.1;

sPID.Integral=0.0;

sPID.Derivative=0.0;

sPID.SetPoint=jzdy;

rIn=sensor(); 

rOut=PIDCalc(&sPID,rIn);

pidsc=rOut;

}

//CCP1初始函数

void initCCP1()

{

int CCP1;

PR2=6; //频率17.86kHz根据公式计算

CCP1CON=0b00001100; //PWM模式

PWMsr=jzdy-pidsc;

if(srdy<=0)

srdy=0.005;

if(PWMsr<=0)

{

  PWMsr=0.2;

}

jzzkb=(1-srdy/jzdy)*5;

tjkz=jzdy*jzzkb/PWMsr;

if(tjkz>=2.25)

{

  tjkz=2.25;

}

CCP1=(int)((PR2+1)*4*tjkz/5);

CCP1Y=CCP1%2;

CCP1X=((CCP1-CCP1Y)/2)%2;

CCPR1L=(CCP1-CCP1X*2-CCP1Y)/4; 

T2CON=0b00000110; //TMR2预分频1:16,开始工作

}

/*主函数*/

void main()

{

PIDInit(&sPID);

while(1)

{

sccy();

jzcy();

srcy();

conv(); //调用转换函数

delay1();

lcdrw=0; //lcd控制

lcdinit(); //lcd初始化

lcdxianshi();

PIDsc();

initCCP1(); //初始化CCP1 

}

}


关键字:PIC16F877A  编程PID  PWM  1602液晶显示 


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多