⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pid.c

📁 嵌入式C的一个课程设计:电模拟系统的单片机PID控制。程序用C语言写。最小系统板与电模拟系统的原理图都有。把PID.C编译下载到目标板。运行接到示波器即可显示控制结果。
💻 C
字号:
/*******************/
/*  键盘显示程序   */
/*                 */
/*******************/
#include <reg51.h>
#define uint unsigned int
#define uchar unsigned char
#define tim 65536-5000
#define K  10
#define Kp  para[1]
#define Ki  para[2]
#define Kd  para[3]
void PCF8591DA(uchar x);
sbit dis0 =P2^6;
sbit dis1 =P2^5;
sbit dis2 =P2^4;
sbit dis3 =P2^3;
sbit dis4 =P2^2;
sbit key1 =P2^1;
sbit key0 =P2^0;
uchar disp[5],dis,sp,m,dac;
int  r,e0,e1,e2,e3,e4,y0,u;
uchar key,keyx,ts,bigan=0;
int para[8],ptr;
uchar code numtab[5]={0x40,0x20,0x10,0x04,0x08};
uchar code distab[16]={0x28,0xee,0x32,0xa2,0xe4,0xa1,0x21,0xea,
		       0x20,0xa0,0x60,0x25,0x39,0x26,0x31,0x71};
uchar code ledtab[8]={0x08,0x10,0x20,0x40,0x88,0x90,0xa0,0xc0};

void time(uint t)
{
  uint i;
  for(i=0;i<t;i++);
}

void distran()
{ 
  switch(ptr)
  {
  case 0:
  case 4:
  case 5:
  case 6:
  case 7:
  disp[4]=distab[(para[ptr]*2)%10];
  disp[0]=distab[((para[ptr]*2)/10)%10];
  disp[1]=distab[((para[ptr]*2)/100)%10]&0xdf;
  disp[2]=distab[((para[ptr]*2)/1000)%10];
  disp[3]=~ledtab[ptr]; break;
  case 1:
  disp[4]=distab[para[ptr]%10];
  disp[0]=distab[(para[ptr]/10)%10];
  disp[1]=distab[(para[ptr]/100)%10];
  disp[2]=0x70;
  disp[3]=~ledtab[ptr];break;
  case 2:
  disp[4]=distab[para[ptr]%10];
  disp[0]=distab[(para[ptr]/10)%10];
  disp[1]=distab[(para[ptr]/100)%10];
  disp[2]=0xef;
  disp[3]=~ledtab[ptr];break;
  case 3:
  disp[4]=distab[para[ptr]%10];
  disp[0]=distab[(para[ptr]/10)%10];
  disp[1]=distab[(para[ptr]/100)%10];
  disp[2]=0x26;
  disp[3]=~ledtab[ptr];break;
  }
}

void display()
{
  dis=(dis+1)%5;
  P2=0xff;
  P0=disp[dis]; 
  P2=~numtab[dis];
  key0=1; key1=1;
  if(!key0) keyx=dis+1;
  if(!key1) keyx=dis+5; 
}

void keyproc()
{
  if(key>0)
  { 
    switch(key)
    {
      case 1: para[ptr]--;    break;
      case 5: para[ptr]++;    break;
      case 2: para[ptr]-=5;  break;
      case 6: para[ptr]+=5;  break;
      case 3: bigan=1;  break;
      case 7: para[0]=125;   break;
      case 8: ptr++; break;
      case 4: bigan=0; para[0]=0;
	          PCF8591DA(para[0]);
	          for(m=4;m<8;m++)
			  para[m]=0;break;
    }
    if(ptr>7) ptr=0;
    if(ptr<0) ptr=7;
    if(para[ptr]<0)   para[ptr]=0;
    if(para[ptr]>255) para[ptr]=255;
    distran();
  } 
  key=0;
}

void timer0() interrupt 1
{
  TH0=tim>>8; TL0=tim; display(); 
}
/****************************************************************
 
       I2C总线协议程序

****************************************************************/
#include <intrins.h>
 
sbit SCL=P1^0;           /*模拟I2C时钟控制位*/
sbit SDA=P1^1;           /*模拟I2C数据传送位*/
bit ack;	             /*应答标志位*/
   
void Start_I2c()
{
  SDA=1;  time(2);
  SCL=1;  time(2);   
  SDA=0;  time(2);        
  SCL=0;  time(2); 
}

void Stop_I2c()
{
  SDA=0;  time(2);  
  SCL=1;  time(2); 
  SDA=1;  time(2);  
}

void  Senduchar(uchar c)
{
  uchar i;
  for(i=0;i<8;i++)  /*要传送的数据长度为8位*/
  {
     if((c<<i)&0x80)SDA=1;  
	 else  SDA=0;  time(2);
     SCL=1;  time(2);          
     SCL=0;  time(2);
  }
    
  SDA=1;  time(2);     
  SCL=1;  time(2);   
  if(SDA==1)ack=0;  else ack=1;      
  SCL=0;  time(2); 
}

uchar  Rcvuchar()
{
  uchar x=0;
  uchar i;
  
  SDA=1;             /*置数据线为输入方式*/
  for(i=0;i<8;i++)
  {
    SCL=1;  time(2); 
    x=x<<1;
    if(SDA==1) x=x+1; /*读数据位,接收的数据位放入retc中 */
    SCL=0;  time(2);   
  }
  return(x);
}


void Ack_I2c(bit a)
{
  
  if(a==0) SDA=0;  
  else SDA=1;
  time(2);        
  SCL=1; time(2);   
  SCL=0; time(2);    
}

bit ISendStr(uchar sla,uchar suba,uchar *s,uchar no)
{
   uchar i;

   Start_I2c();               /*启动总线*/
   Senduchar(sla);            /*发送器件地址*/
   if(ack==0)return(0);
   Senduchar(suba);            /*发送器件子地址*/
   if(ack==0)return(0);

   for(i=0;i<no;i++)
   {   
     Senduchar(*s);               /*发送数据*/
     if(ack==0)return(0);
     s++;
   } 
  Stop_I2c();                 /*结束总线*/ 
  return(1);
}


bit IRcvStr(uchar sla,uchar suba,uchar *s,uchar no)
{
   uchar i;

   Start_I2c();               /*启动总线*/
   Senduchar(sla);             /*发送器件地址*/
   if(ack==0)return(0);
   Senduchar(suba);            /*发送器件子地址*/
   if(ack==0)return(0);

   Start_I2c();
   Senduchar(sla+1);
   if(ack==0)return(0);

   for(i=0;i<no-1;i++)
    {   
     *s=Rcvuchar();               /*发送数据*/
      Ack_I2c(0);                /*发送就答位*/  
     s++;
    } 
   *s=Rcvuchar();
   Ack_I2c(1);                 /*发送非应位*/
   Stop_I2c();                 /*结束总线*/ 
   return(1);
}

/***************************************************

   PCF8591  4路A/D转换+1路D/A转换

****************************************************/
#define PCF8591 0x90 //PCF8591的IIC地址

void PCF8591DA(uchar x)
{
	ISendStr(PCF8591,0x40,&x,1);
}

uchar PCF8591AD(uchar n)
{
    uchar res;
	IRcvStr(PCF8591,n+0x40,&res,1);
	IRcvStr(PCF8591,n+0x40,&res,1);
	return res;
}

void main()
{ unsigned int i;
  TMOD=0X11;IE=0x82;
  TH0=tim>>8;  TL0=tim; TR0=1;
  dis=0;ptr=0;
  for(i=0;i<8;i++) para[i]=i; 
  distran();  
  for(;;)
  {
    time(250);
   if(bigan==1)
   {
     i=0;
     para[4]=PCF8591AD(0);
     para[5]=PCF8591AD(1);
     para[6]=PCF8591AD(2);
     para[7]=PCF8591AD(3);

	 y0=para[ptr];r=para[0];
	 e4=e3; e3=e2;e2=e1; e1=e0; e0=r-y0;
	 u+=e0*Ki+(3*e1-3*e2+e0-e3)*Kp+(e0+2*e1-6*e2+2*e3+e4)*Kd;
	 if(u>255*K) u=255*K;
	 if(u<0) u=0;
	 dac=u/K;	

     PCF8591DA(dac);
     distran();
   }
   if(keyx>0)
   {
     key=keyx;   
     while(keyx!=0) {keyx=0; time(3000);}
     keyproc(); 
   }
   time(500);
  } 
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -