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

📄 87c752.c

📁 这是《Keil Cx51 V7.0单片机高级语言编程与uVision2应用实践》教材各章中列出的全部程序例子。
💻 C
字号:
#include <reg752.h>
#include <stdio.h>

/**************************** 定义符号常数 *******************************/
#define  ZERO_K      	   2730      /* 0 摄氏度, 1/10 kelvin */
#define  ONE_TENTH_CFM	   4444444L  /* 1/10 CFM 微秒 */
#define  CORRECTION	       0x11      /* 时钟频率为12MHz时计算CFM校正值 */
#define  STD_TEMP	       2980      /* 25 摄氏度, 1/10 kelvin */
#define  STD_ATM	           147	     /* 一个大气压 1/10 PSI */
#define  LOWEST_CFM	       0x40      /* 转速表的最大周期值 0x400000 */
#define  START_ADC0	       0x28      /* 各个通道A/D转换启动命令 */
#define  START_ADC1	       0x29      
#define  START_ADC2	       0x2a
#define  START_ADC3	       0x2b
#define  START_ADC4	       0x2c
#define  ADCI		       0x10      /* A/D 转换状态标志 */
#define  ADCS		       0x08
#define  FREERUN_I	       0x10
#define  SEG_A		       0x01      /* 七段LED中的 'a' 段 */
#define  CFM		       0x01      /* CFM  LED */
#define  SEG_B		       0x02      /* 七段LED中的 'b' 段 */
#define  DEGREES	       0x02      /* DEGREES  LED */
#define  SEG_C		       0x04      /* 七段LED中的 'c' 段 */
#define  PSI		       0x04      /* PSI  LED */
#define  SEG_D		       0x08      /* 七段LED中的 'd' 段 */
#define  SETPOINT	       0x08      /* SETPOINT  LED */
#define  SEG_E		       0x10      /* 七段LED中的 'e' 段 */
#define  SEG_F		       0x20      /* 七段LED中的 'f' 段 */
#define  SEG_G		       0x40      /* 七段LED中的 'g' 段 */
#define  SEG_DP 	       0x80      /* 七段LED中的 'dp'段 */

typedef  unsigned char byte;	         /* 8位无符号字节型数据 */
typedef  unsigned int  word;	         /* 16位无符号字型数据 */
typedef  unsigned long I_word;	     /* 32位无符号长字型数据 */ 

#define  TRUE		       1
#define  FALSE		       0

/********************** 定义七段LED的显示段码表 ***************************/
code byte segments []=
 {
	     SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F	   , /* 0 */
		         SEG_B | SEG_C				               , /* 1 */
	     SEG_A | SEG_B |	         SEG_D | SEG_E	           , /* 2 */
	     SEG_A | SEG_B | SEG_C | SEG_D |		     SEG_G     , /* 3 */
		         SEG_B | SEG_C |		     SEG_F | SEG_G     , /* 4 */
	     SEG_A |	         SEG_C | SEG_D |	 SEG_F | SEG_G     , /* 5 */
	     SEG_A |	         SEG_C | SEG_D | SEG_E | SEG_F | SEG_G  , /* 6 */
	     SEG_A | SEG_B | SEG_C				                    , /* 7 */
	     SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G  , /* 8 */
	     SEG_A | SEG_B | SEG_C | SEG_D |	         SEG_F | SEG_G  , /* 9 */
	     SEG_A |		             SEG_D | SEG_E | SEG_F | SEG_G  , /* E */
 };

/******************* 定义87C752中用于I/O线的特殊功能位 *******************/
sfr   PWMP      = 0x8F;   /* 定义87C752的PWM预分频寄存器 */

sbit  RELAY   	= 0x96;   /* 为高时闭合SETPOIN 继电器 */
sbit  STROBE_0	= 0x80;   /* 为高时允许点亮各个状态LED */
sbit  STROBE_1	= 0x81;   /* 为高时允许点亮cr15 (十分之一位) */
sbit  STROBE_2	= 0x82;   /* 为高时允许点亮cr14 (个位) */
sbit  NO_FLOW	= 0x83;   /* 未检测到气流量时的标志位 */
sbit  STROBE_3	= 0x84;   /* 为高时允许点亮cr13 (十位) */
sbit  SEL_0	    = 0x93;   /* 为低时用于按键输入, 选择显示模式 */
sbit  SEL_1	    = 0x94;   
sbit  INTR	    = 0x95;
sbit  UPDATE	    = 0x97;   /* 显示更新标志 */

/***************************** 定义内存变量 ******************************/
data  word    cfm;	      /* 十分之一气流量 CFM */
data  word    setpoint;   /* 十分之一气流量 CFM 的继电器设定值 */
data  word    degree_c;   /* 十分之一摄氏度 */
data  I_word  corr;	      /* 计算值 */
data  word    psi;	      /* 十分之一 PSI */
data  byte    display0;   /* 显示更新值 */
data  byte    display1;   /* display0=status LEDs, display1=cr15,*/
data  byte    display2;  /* display2=cr14, display3=cr13,*/
data  byte    display3;   
data  byte    disp_pntr;  /* 下一个要点亮的LED指针 */
data  byte    refresh;	  /* 显示更新计数 */
data  byte    high;	      /* 24位计数器的第16 - 23位 */
data  byte    middle;	  /* 24位计数器的第 8 - 15位 */
data  byte    low;	      /* 24位计数器的第 0 - 7 位 */
data  byte    ticks;	      /* 定时器溢出加一计数  */

/**************************************************************************
*  函数原型	      : void multiplex() interrupt 3;
*  功    能	      : 利用自由运行的定时器T1对显示器进行动态更新, 更新速度
*                    约为1000Hz。 
**************************************************************************/
void multiplex() interrupt 3 {
  	switch(disp_pntr) {
	       case 0x00:
		    STROBE_3 = FALSE;  /* 关闭cr13 */
		    P3 = 0xff;	       /* 关闭七段LED */
		    P3 = display0;     /* 装入段码 */
		    STROBE_0 = TRUE;   /* 点亮状态 LEDs */
		    disp_pntr = 1;     /* 指向下一个显示器 */
		    break;
	       case 0x01:
		    STROBE_0 = FALSE;  /* 关闭状态 LEDs */
		    P3 = 0xff;	       /* 关闭七段 LED */
		    P3 = display1;     /* 装入十分之一位LED段码 */
		    STROBE_1 = TRUE;   /* 点亮cr15 */
		    disp_pntr = 2;     /* 指向下一个显示器 */
		    break;
	       case 0x02:
		    STROBE_1 = FALSE;  /* 关闭cr15 */
		    P3 = 0xff;	       /* 关闭七段 LED */
		    P3 = display2;     /* 装入个位LED段码 */
		    STROBE_2 = TRUE;   /* 点亮cr14 */
		    disp_pntr = 3;     /* 指向下一个显示器 */
		    break;
	       case 0x03:
		    STROBE_2 = FALSE;  /* 关闭cr14 */
		    P3 = 0xff;	       /* 关闭七段 LED */
		    P3 = display3;     /* 装入十位LED段码 */
		    STROBE_3 = TRUE;   /* 点亮cr13*/
		    disp_pntr = 0;     /* 指向下一个显示器 */
	    }
 }

/**************************************************************************
*  函数原型	      : void read_switch() interrupt 6;
*  功    能	      : 利用自由运行的PWM预分频器产生92Hz周期的中断。每中断
*                   32次将UPDATE标志置位, main()函数将根据该标志位的状
*                   态来采样按键并进行显示更新。 
**************************************************************************/
void read_switch() interrupt 6 {
 	if (refresh++ == 32) {
	         UPDATE = TRUE;
	         refresh = 0;
	    }
 }

/**************************************************************************
*  函数原型	      : void overflow() interrupt 1;
*  功    能	      : 每当定时器T1溢出(从0xffff到0x0000)时将变量'ticks'的
*                   值加1, 该值表示24位气流量周期微秒计数器的高8位(16~
*                   23位)。如果'ticks'的值太大则将NO_FLOW标志置位, 从而
*                   使main()函数在LED上显示00.0。 
**************************************************************************/
void overflow() interrupt 1 {
  	if (++ticks > LOWEST_CFM) {
	      cfm = 0;
	      ticks = 0;
	      NO_FLOW = TRUE;
	    }
 }

/**************************************************************************
*  函数原型	      : void cal_cfm() interrupt 0;
*  功    能	      : 由转速计脉冲产生的外部中断(INT0)将定时器T0的当前计
*                   数值送到24位微秒计数器的'low'(低8位)和'middle'(中
*                   8位), 同时复位定时器T0。将前面的'ticks'值拷贝到
*                   'high'中同时使'ticks'复位为0。清除NO_FLOW标志, 从而
*                   使main()函数能在LED上显示计算出的cfm值。 
**************************************************************************/
void cal_cfm() interrupt 0 {
 	 low = TL;
	     TL = 0;
  	 middle = TH;
	     TH = 0;
 	 high = ticks;
	     ticks = 0;
 	 NO_FLOW = FALSE;
 }

/**************************************************************************
*  函数原型	      : void main();
*  功    能	      : 在完成各个I/O引脚和变量的初始化之后进入一个连续循
*                   环并完成以下任务:
*                   -根据转速计脉冲、输入的温度值和压力值计算气流量;
*                   -将气流量与设定输入值进行比较, 并控制继电器的开、闭;
*                   -在UPDATE标志置位时采样按键状态并进行显示更新。 
**************************************************************************/
void main() {
   RELAY     = 0;	     /* 初始化输出引脚 */
   INTR      = 1;
   UPDATE    = 1;
   STROBE_0  = 0;
   STROBE_1  = 0;
   STROBE_2  = 0;
   STROBE_3  = 0;
   NO_FLOW   = 0;
   I2CFG     = FREERUN_I; /* 不使用I2C, 定时器T1自由运行 */
   RTL	     = 0;         /* 定时器T0装入初值, 定时时间为0x10000 微秒 */
   RTH	     = 0;
   PWMP      = 255;	      /* PWM 中断周期约为 93 Hz */
   TR	     = 1;	      /* 启动定时器T0 */
   IT0	     = 1;	      /* 外部中断INT0 为边沿触发 */
   ticks     = 0;	      /* 变量初始化 */
   cfm	     = 0;
   low	     = 0 ;
   middle    = 0;
   high      = 0;
   degree_c  = 250;	     
   psi	     = 147;	    
   corr      = 0;
   refresh   = 0;
   disp_pntr = 0;
   IE	     = 0xab;	      /* 开中断 */
   
   /*  进入连续循环  */
   while(1) {
    
       /* 计算气流量CFM */
       corr = high * 0x10000L;
       corr += (middle * 0x100L);
       corr = low;
       corr -= CORRECTION;
       corr = ONE_TENTH_CFM / corr;
     
       /* 读取温度测量值 */
       ADCON = START_ADC1;
       while (ADCON & ADCS);
       degree_c = ADAT;
       degree_c *= 2;
      
       /* 对CFM进行温度补偿 */
       corr *= STD_TEMP;
       corr /= (ZERO_K + degree_c);
      
       /* 读取压力测量值 */
       ADCON = START_ADC0;
       while (ADCON & ADCS);
       psi = ADAT;
      
       /* 对CFM进行压力补偿 */
       corr *= psi;
       corr /= STD_ATM;
       cfm = corr;
       
       /* 读取气流量设定值 */ 
       ADCON = START_ADC2;
       while (ADCON & ADCS);
       setpoint = ADAT;
       
       /* 测试CFM速率是否大于或等于设定值, 若是则触发控制继电器 */
       if (setpoint > cfm)
	            RELAY = 0;
       else
     	    RELAY = 1;
       
       /* 测试UPDATE标志是否置位, 若是则将其复位 */
      if (UPDATE)	{
            UPDATE = 0;
       
       /* 测试NO_FLOW标志是否置位, 若是则显示'00.0' */
	            if (NO_FLOW)    {
                display0 = ~CFM;
                display1 = ~segments[0];
                display2 = ~(segments[0] | SEG_DP);
     		    display3 = ~segments[0];
	            }
         
       /* 若NO_FLOW标志未置位, 采样按键并显示合适的数据 */
	       else if (SEL_0) {
		          if (SEL_1) {
       
       /* 无键按下时则显示气流量值。若气流量值大于或等于30cfm则显示过
          载信息'EEE', 否则以'××.×'格式显示气流量值 */
 		     	   if (cfm <= 300) {
 			           display0 = ~CFM;
	     		           display1 = ~segments[cfm % 10];
		     	           cfm /= 10;
			               display2 = ~(segments[cfm % 10]);
			               cfm /= 10;
 			           display3 = ~segments[cfm % 10];
			           }
			           else  {
     			       display0 = ~CFM;
		          	       display1 = ~segments[10];
	         		       display2 = ~segments[10];
     			       display3 = ~segments[10];
		          	   }
		   }
        
       /* 若温度键(SW1)按下则显示气体温度测量值 */
		   else	{
 			   display0 = ~DEGREES;
	     		   display1 = ~segments[degree_c % 10];
		      	   degree_c /= 10;
			       display2 = ~(segments[degree_c % 10] | SEG_DP);
 			   degree_c /= 10;
	     		   display3 = ~segments[degree_c % 10];
		   	}
	      }
	      else   {
        
       /* 若PSI键(SW2)按下则显示气体压力测量值 */
		       if (SEL_1) {
 			   display0 = ~PSI;
	     		   display1 = ~segments[psi % 10];
	     		   psi /= 10;
  			   display2 = ~(segments[psi %10] | SEG_DP);
 			   psi /= 10;
 			   display3 = ~segments[psi % 10];
	     		}
        
       /* 若设定值键(SW3)按下则显示设定值 */
		        else  {
 			   display0 = ~SETPOINT;
	     		   display1 = ~segments[setpoint % 10];
	     		   setpoint /= 10;
 			   display2 = ~(segments[setpoint % 10] | SEG_DP);
 			   setpoint /= 10;
 			   display3 = ~segments[setpoint % 10];
	      		}
	        }
	      }
    }
 }

⌨️ 快捷键说明

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