📄 87c752.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 + -