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

📄 wendu.c

📁 51单片机用c语言实例 包括ad
💻 C
字号:
/**************************************************************
 * 文件名:   Wendu.c
 * 功能描述: 实现闭环温度控制,将给定值与测量值在数码管上显示
 **************************************************************/

#include <reg51.h>
#include <absacc.h>
#include <math.h>

void pid(void);
void init(void);
void Display(void);
void clear();

int  mmul(int x, int y);                 /*16位乘法,溢出赋极值*/
int  madd(int x, int y);                 /*16位加法,溢出赋极值*/
int  change32_16(int z, int t);          /*将32位数转化成16位*/
char change16_8(int wd);                 /*将16位数转化成8位*/

#define C8255_A     XBYTE[0x7F00]
#define C8255_B     XBYTE[0x7F01]
#define C8255_C     XBYTE[0x7F02]
#define C8255_CON   XBYTE[0x7F03]

#define AD0809      XBYTE[0xFEFF]

sbit P17 = P1^7;

char TS    = 0x64;
int  X     = 0x80;
char SPEC  = 0x28;		// 数字给定(40)
char IBAND = 0x60;		// 积分分离值
int  KP    = 12;		// 比例系数
char KI    = 20;		// 积分系数
char KD    = 32;		// 微分系数
int  CK;				// 控制量:PID算法产生用于控制的量
int  TC;				// 采样周期变量
char FPWM;				// PWM脉冲中间标志位
int  CK_1;				// 控制量变量:记录上次控制量值
int  AAAA;				// PWM脉冲高电平时间计算
int  VAA;				// AAAA变量
int  BBB;				// PWM脉冲低电平时间计算
int  VBB;				// BBB变量
int  TKMARK;			// 采样标志值
int  ADMARK;			// AD转换结束标志位
int  ADVALUE;			// AD采样值保存
int  YK;				// 反馈:测量温度值
int  EK;				 
int  EK_1;				
int  AEK;				
int  BEK;				

unsigned char DIS;
// BCD码显示表
unsigned char Led[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7F,0x6f};
unsigned char b[] = {0x00, 0x00, 0x00, 0x00};		// 位选

// 温度表
unsigned char code  a[0x100]={0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
		     				  0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
		     				  0x1D, 0x1E, 0x1E, 0x1F, 0x20, 0x21, 0x23, 0x24, 0x25,
		     				  0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E,
		     			   	  0x2F, 0x31, 0x32, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
		    				  0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40,
		    				  0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A,
		    				  0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x4F, 0x50, 0x51,
		    				  0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A,
		    				  0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63,
		     				  0x64, 0x64, 0x65, 0x65, 0x66, 0x66, 0x67, 0x68, 0x69,
		     				  0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6E, 0x6F, 0x6F, 0x70,
		  					  0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
		   					  0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82,
		  					  0x83, 0x84, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A,
		  					  0x8B, 0x8C, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94,
		  					  0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9B, 0x9C,
		 					  0x9C, 0x9D, 0x9D, 0x9E, 0x9E, 0x9F, 0x9F, 0xA0, 0xA1,
		 					  0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA,
		 					  0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB0, 0xB1, 0xB2,
						      0xB3, 0xB4, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA,
						      0xBB, 0xBD, 0xBE, 0xBE, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5,
							  0xC6, 0xC8, 0xCA, 0xCC, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2,
						      0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC,
		  				      0xDD, 0xDE, 0xE3, 0xE6, 0xE9, 0xEC, 0xF0, 0xF2, 0xF6,
		 				      0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
						      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
		 				      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
		 				      0xFF, 0xFF, 0xFF, 0xFF  };

void delay(unsigned int time)
{
	unsigned int i;
	for(i=0; i<time; i++);
}

void main()
{
   init();

   while (1)
   {
      while (1)
      {
	      if (TKMARK == 0x01)			//采样周期到否
	          break;
      }

      TKMARK = 0x00;

      while (1)
      {
	      if (ADMARK == 0x01)			//AD转换是否结束
	          break;
      }

      ADMARK = 0x00;

      YK = a[ADVALUE];					//查温度表
      DIS = (char)YK;

      pid();							//调PID运算函数

      if( CK <= 0x80)					//根据CK产生PWM
	      AAAA = 0x00;
      else
	      AAAA = CK - 0x80;

      BBB = 0x7f - AAAA;
   }
}

void init(void)							//初始化函数
{
	YK      = 0x00;						//变量初始化
	EK      = 0x00;
	EK_1    = 0x00;
	AEK     = 0x00;
	BEK     = 0x00;
	CK      = 0x00;
	CK_1    = 0x00;
	BBB     = 0x00;
	VBB     = 0x00;
	ADVALUE = 0x00;
	TKMARK  = 0x00;
	ADMARK  = 0x00;
	TC      = 0x00;
	FPWM    = 0x01;
	AAAA    = 0x7F;
	VAA     = 0x7F;
	
	C8255_CON = 0x81;
	Display();
	clear();
	
	TMOD = 0x11;						// T1, T0 16位定时器
	IP = 0x02;							// pt0 定时器0中断为高优先级
	IT1 = 1;							// 外中断1为下降沿有效
	EX1 = 1;							// 允许INT1中断
	TH0 = 0xD8;
	TL0 = 0xEF;
	
	TH1 = 0xD8;
	TL1 = 0xEF;
	ET0 = ET1 = 1;						//使能定时器中断
	TR0 = TR1 = 1;						//启动定时器
	EA = 1;
	AD0809 = 1;							// 启动AD
}

void myint3(void) interrupt 3			// 定时器1,LED显示
{
	TH1 = 0xD8;
	TL1 = 0xEF;
	ET1 = 1;
	Display();
	clear();
}

void myint1(void) interrupt 2			// 外中断1,读AD转换结果
{
	ADVALUE = AD0809;
	ADMARK = 0x01;
}

void myint2(void) interrupt 1			// 定时器0,启动AD转换
{
	TH0 = 0xD8;
	TL0 = 0xEF;
	ET0 = 1;
	AD0809 = 1;
	if (TC < TS)
	    TC++;
	else
	{
	    TKMARK = 0x01;
	    TC = 0x00;
	}
	
	if (FPWM == 0x01)					//产生PWM
	{
		if (VAA != 0x00)
		{
			VAA = VAA - 1;
			P17 = 0;					// P10输出为低, 加热
		}
		else
		{
			FPWM = 0x02;
			VBB = BBB / 2;
		}
	}
	if (FPWM == 0x02)
	{
		if (VBB != 0x00)
		{
			VBB = VBB - 1;
			P17 = 1;					// P10输出为高, 停止加热
		}
		else
		{
			FPWM = 0x01;
			VAA = AAAA / 2;
		}
	}	
	return;
}

void pid(void)
{
	int K,P,I,D;
	
	K=P=I=D=0;
	EK=SPEC-YK;						//得到偏差
	BEK=EK-EK_1-AEK;				//△2EK
	AEK=EK-EK_1;					//△EK 偏差变化量
	
	if (abs(EK)>abs(IBAND))  I=0;	//判积分分离
	else    I=(EK*TS)/KI;			//计算积分项
	
	P=AEK;
	D=((KD/TS)*BEK)/10000;			//计算微分项
	
	//△UK=KP*△EK + KI*Ek + KD*(△EK-△EK_1)  UK=△UK+UK_1
	K=madd(I,P);
	K=madd(D,K);
	K=mmul(K,KP);
	K=K/10;
	CK=K+CK_1;
	
	//将UK值转化成8位数据,取K的低8位值并取符号
	CK=change16_8(CK);
	CK_1=CK;
	EK_1=EK;
	CK=CK+X;
}

int mmul( int x,int y)
{
	int t,z;
	long s;
	s=x*y;
	z=(int)(s&0x0FFFF);
	t=(int)((s>>16)&0x0FFFF);
	s=change32_16(z,t);
	return(s);
}

int change32_16(int z,int t)		//t=高字,z=低字
{
	int s;
	
	if(t==0)
	{ 
	    if((z&0x8000)==0) s=z;
	    else s=0x7fff;
	}
	else if ((t&0xffff)==0xffff)
	{ 
	    if((z&0x8000)==0) s=0x8000;
	    else s=z;
	}
	else if ((t&0x8000)==0) s=0x7fff;
	else s=0x8000;
	return(s);
}

int madd(int x,int y)
{
	int t;
	t=x+y;
	if(x>=0 && y>=0)					//同号相乘,符号位变反说明溢出
	{ if((t&0x8000)!=0) t=0x7fff; }
	else if (x<=0 && y<=0)
	{ if((t&0x8000)==0) t=0x8000; }
	return(t);
}

char change16_8(int wd)					//t=高字节,z=低字节
{
	char z,t,s;
	
	z=wd&0x0FF;
	t=(wd>>8)&0x0FF;
	
	if(t==0x00)
	{ 
	    if((z&0x80)==0) s=z;
	    else s=0x7f;
	}
	else if ((t&0xff)==0xff)
	{ 
	    if((z&0x80)==0) s=0x80;
	    else s=z;
	}
	else if((t&0x80)==0) s=0x7f;
	else s=0x80;
	
	return(s);
}


void Display()							//数码管显示函数
{
	unsigned char i, j = 0xF7;
	b[3] = SPEC/10;
	b[2] = SPEC%10;
	b[1] = DIS/10;
	b[0] = DIS%10;
	for(i=0; i<4; i++)
	{
		C8255_A = j;
		C8255_B = Led[b[i]];
		delay(0x55);
		j >>= 1;
	}
}

void clear()
{
	C8255_B = 0x00;
}

⌨️ 快捷键说明

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