#本文档是基于AT89S52单片机Word格式.docx
《#本文档是基于AT89S52单片机Word格式.docx》由会员分享,可在线阅读,更多相关《#本文档是基于AT89S52单片机Word格式.docx(37页珍藏版)》请在冰豆网上搜索。
按键按下存储器
last_key_down
按键按下确认存储器
count_key_flash
按键重复计数器
显示
digi_scaner
数码管扫描驱动指针
output_sel
unsignedcharbdata
数码管位驱动和指示灯驱动信号输出缓存
led_1
sbit
output_sel^5
led_2
output_sel^6
led_3
output_sel^7
led_4
output_sel^4
Vo
输出电压
digi[4]
unsignedcharxdata
数码管输出寄存器
digi_flash_temp
数码管闪烁用寄存器
doublexdata
pulse_width
当前的占空比
input_for_display
输入显示用寄存器
count_digi_flash
闪烁计数器
input_position
输入位(即数码管闪烁位>
拟合
coefficient_A
拟合曲线的系数
coefficient_B
coefficient_C
Vo_adjust[4]
longintxdata
输出电压数组
display_for_adjust[4]
intxdata
显示数组
Ave
ad读数
继电器
ctr_out_foot
继电器电平信号
sub_set_val
系统设定温度
sub_cur_val
当前温度
1.2控制软件各功能模块介绍
1.2.1AD转换模块介绍
当ad_mode==1时,此模块有效,以方便开闭环的转换。
程序利用变量ad_flag作为标记,判断读adc0804的时机,在读D时采用了取平均值的方法。
在进行了一定次数后将采样值与标准值比较。
其中定义采样次数AD_SMPL_NUM=30。
对实际水温0—100分2段拟合:
(1>
.0—80曲线拟和:
temp=-0.004*(double>
ave*(double>
ave+3.856*(double>
ave+307.64。
(2>
.80—100曲线拟和:
temp=-0.0061*(double>
ave+4.011*(double>
ave+268.27。
1.2.2模块程序第一部分
图5.3.1AD转换流程图
源程序见附录
1.2.3继电器控制模块介绍
此模块根据加热时水温的上升和过冲程度决定继电器的通断,可以改变继电器的通断频率来解决温度过冲问题,并在达到设定温度后保持恒温。
1.2.4模块程序第二部分
分两段对继电器控制:
0—75度:
继电器1.05s通断一次
75—100度:
继电器0.25s通断一次
每段作如下处理
图5.3.2控制模块原理图
其效果是温度达到指定范围后继电器即处于关断交替状态
算法如下:
if(ctr_out_foot==1>
//当继电器接通时
{
if(ave>
150>
//第一段大于75度
if(sub_cur_val+40>
=sub_set_val>
ctr_out_foot=0。
count_self_ctrl=2000。
//设延迟为0.2s
}
else//第二段小于75度
if(sub_cur_val+60>
count_self_ctrl=10000。
//设延迟为1s
else//继电器断开
if(sub_cur_val<
ctr_out_foot=1。
count_self_ctrl=500。
//循环延迟50ms
1.2.5按键解释功能说明
按键是人机互最重要的部分,基本所以的操作都要通过按键来完成,在系统运行中,不断扫描按键,以判断用户是否有任何输入指示,一旦用户有按键操作,系统将做出判断,给予按键解释,执行相应的命令。
但是值得注意的是任何按键都有可能有抖动的现象,因此软件中必须含有消抖程序。
在水温控制中,key3实现自动与手动的切换,在自动情况下,系统接收本地主系统的控制,自动调整水温;
当在手动情况下,可以通过key1切换继电器的开和关,这样在调试时比较方便。
对于温度的设置,采用了对位的调整方法,使得温度设定更为方便。
二.程序清单:
#include<
absacc.h>
reg51.h>
math.h>
/*0~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~全局变量开始~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*****************定时器******************/
#definecount0_H0xfc//计数器0计数初值(1.0004ms时基>
,(crystal11.059200MHz>
#definecount0_L0x65
#definecount1_H0xff//9600波特率(307200/32>
#definecount1_L0xa3
/*************按键key*************/
#defineKEY_SCAN_TIME500//按键扫描周期
#defineKEY_REPEAT_TIME10//按键重复周期
#defineKEY_TYPE_SEC1
#defineKEY_TYPE_DIS2
#defineKEY_TYPE_CHG3
#defineKEY_TYPE_POS4
#defineKEY_TYPE_ERROR5
sbitKEY1=P1^0。
sbitKEY2=P1^1。
sbitKEY3=P1^2。
sbitKEY4=P1^3。
intcount_key_scan。
//按键扫描计数器
charxdatalast_key_down。
//上次按键
charxdatacount_key_repeat。
//按键重复计数器
charxdatakey_type。
/*************数码管显示************/
#defineADDR_8SEGXBYTE[0x2000]//数码管段驱动寄存器地址
#defineADDR_SELXBYTE[0x4000]//数码管位驱动和指示灯驱动寄存器地址
#defineLED_SCAN_TIME40//数码管扫描周期(1000/4/4=62.5Hz>
#defineLED_FLASH_MAX_TIME100
#defineLED_FLASH_GATE_TIME50
#defineSET_TIME20000。
intcount_led_scan。
//数码管扫描计数器
unsignedcharxdataled_scaner。
//数码管扫描驱动指针
unsignedcharbdataoutput_sel。
//数码管位驱动和指示灯驱动信号输出缓存,定义了一个可位寻址的变量
sbitled_1=output_sel^5。
sbitled_2=output_sel^6。
sbitled_3=output_sel^7。
sbitled_4=output_sel^4。
charxdataled[4]。
//数码管状态寄存器
charled_flash_pos。
//数码管闪烁位
intcount_led_flash。
charled_flash_temp。
intcount_set_time。
chardis_rewrite_flag。
chardis_set_flag。
/***************通信****************/
#defineCOM_FRAME_LENGTH8//6+2
#defineCOM_BUFFER_LENGTH16//8*2
#defineCOM_TYPE_STOP0//通讯停止
#defineCOM_TYPE_IN1//接收
#defineCOM_TYPE_OUT2//发送
#defineCOM_TYPE_MANAGE4//接收后处理
#defineSUB_ADDR2//作为从机的地址
#defineSUB_ADDR_0'
0'
#defineSUB_ADDR_1'
2'
#defineMASTER_ADDR0//主机地址
#defineLOCAL_VER1//本地协议版本号
#defineBYTE_MISS_TIME400//字节最大延时
#defineBYTE_DELAY_TIME170//字节发送延时
#defineSTD_FRAME_LEN12//标准最短帧长
intcount_byte_miss。
//接收字节计时
intcount_byte_delay。
//发送字节计时
charcom_tra_pin。
//发送用指针
charcom_tra_pos。
//发送数据区标志
charcom_tra_buf[COM_BUFFER_LENGTH+2]。
//发送帧缓冲区
charcom_rec_pos。
//接收数据区标志
charcom_rec_buf[COM_BUFFER_LENGTH]。
//接受帧缓冲区
charcom_type。
//通信机状态
/********************子系统相关*****************/
#defineADDR_0804XBYTE[0x6000]
#defineAD_TIME500//0.05秒采样
#defineDATA_BUF_LEN10//数据缓冲区长度
sbitctr_out_foot=P3^3。
unsignedchardata_buf[DATA_BUF_LEN]。
//数据缓冲区
intcount_self_ctrl=0。
//抽样计数器
intcount_data_manage=0。
//数据处理计数器
intxdatasub_cur_val。
//初值
intxdatasub_set_val。
//设定值
intxdatasub_max_val。
//最大值
intxdatasub_min_val。
//最小值
intxdatasub_max_val_base。
//最大数量级
intxdatasub_dis_temp。
//显示缓冲
intxdatasub_cur_val_base。
//当前输入位数量级
intxdatasub_val_base。
charxdatasub_set_posib。
//可设置标志位
charxdatamaster_lock。
//锁定标志位
/*0^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^全局变量结束^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
/*1~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~硬件接口输出层开始~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*1.1*/
/*****7段数码显示译码(D7~0=PGFEDCBA>
*****/
unsignedcharNUMTOSEG7(charDATA>
{
unsignedcharAA。
if(DATA<
0>
{
DATA=-DATA。
AA=0x00。
}else
AA=0x80。
}
switch(DATA>
case'
:
AA|=0x40。
break。
//0
1'
AA|=0x79。
//1
AA|=0x24。
//2
3'
AA|=0x30。
//3
4'
AA|=0x19。
//4
5'
AA|=0x12。
//5
6'
AA|=0x02。
//6
7'
AA|=0x78。
//7
8'
AA|=0x00。
//8
9'
AA|=0x10。
//9
A'
AA|=0x08。
//A
B'
AA|=0x03。
//B
C'
AA|=0x46。
//C
D'
AA|=0x21。
//D
E'
AA|=0x06。
//E
F'
AA|=0x0e。
//F
G'
AA|=0x42。
//G
H'
AA|=0x09。
//H
I'
AA|=0x4f。
//I
J'
AA|=0x71。
//J
K'
AA|=0x0f。
//K
L'
AA|=0x47。
//L
P'
AA|=0x0c。
//P
-'
AA|=0x3f。
//减号
_'
AA|=0x77。
//下划线
'
AA|=0x7f。
//消隐
~'
AA|=0x7e。
//上划线
default:
AA=0xff。
return(AA>
。
/*1.2*/
/*1.2LED刷新*/
voidLEDDisplayHard(>
led_scaner=(led_scaner+1>
%5。
//移动扫描指针
output_sel=(output_sel&
0xf0>
|0x01<
<
led_scaner。
//选通下一个数码管
//output_sel=0xf0。
/*初值,令数码管驱动位无效,指示灯全灭*/
/*if(KEY1==0>
led_1=0。
if(KEY2==0>
led_2=0。
if(KEY3==0>
led_3=0。
if(KEY4==0>
led_4=0。
*/
if(led_flash_pos<
=3&
&
led_flash_pos>
=0>
//数码管闪烁
count_led_flash--。
if(count_led_flash==LED_FLASH_GATE_TIME>
//点亮
{
led[led_flash_pos]=led_flash_temp。
}elseif(count_led_flash==0>
//熄灭
count_led_flash=LED_FLASH_MAX_TIME。
//循环计时
if(led[led_flash_pos]<
//原来带小数点
led[led_flash_pos]=-'
//显示小数点
else//原来不带小数点
led[led_flash_pos]='
}
if(com_type==COM_TYPE_IN||com_type==COM_TYPE_OUT>
//通信指示灯
led_4=0。
else
led_4=1。
ADDR_8SEG=NUMTOSEG7(led[led_scaner]>
//输出数码管形状
ADDR_SEL=output_sel。
//输出选通
/*1^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^硬件接口输出层结束^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
/*2~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~硬件接口功能层开始~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*2.1*/
/*2.2*/
/*按键消抖*/
charkeyDown(void>
charkey_down=0。
/*扫描按键*/
if(KEY1==0>
key_down=1。
elseif(KEY2==0>
key_down=2。
elseif(KEY3==0>
key_down=3。
elseif(KEY4==0>
key_down=4。
if(last_key_down!
=key_down>
//抖动
last_key_down=key_down。
count_key_repeat=0。
}else//有效信号
count_key_repeat--。
if(count_key_repeat<
//达到返回点
count_key_repeat=KEY_REPEAT_TIME。
returnlast_key_down。
return0。
timer0(>
interrupt1using0
/*2.3*/
/*T0时钟中断服务程序*/
/*提供系统时基*/
timer1(>
interrupt3using1
ET0=0。
//关中断
TH1=count1_H。
//1ms定时
TL1=count1_L。
TR1=1。
if(count_led_scan!
//扫描数码管
count_led_scan--。
if(count_key_scan!
//扫描按键
count_key_scan-=1。
if(count_byte_miss!
//字节丢失
count_byte_miss--。
elseif(com_type==COM_TYPE_IN>
com_type=COM_TYPE_STOP。
//通讯停止
if(count_byte_delay!
//字节延时
count_byte_delay--。
elseif(com_type==COM_TYPE_OUT>
SBUF=com_tra_buf[com_tra_pin]。
count_byte_delay=BYTE_DELAY_TIME。
//延迟5ms发送下一字节
if(count_set_time!
//显示设定值
count_set_time--。
if(count_self_ctrl!
//自控
count_self_ctrl--。
ET0=1。
//开中断
/*2.4*/
/****串口中断服务程序*****/
/****通信用中断*****/
comHard(>
interrupt4using3
chartemp。
ES=0。
if(RI==1>
//接收中断
RI=0。
//接收中断复位
temp=SBUF。
if(temp=='
&
com_type<
COM_TYPE_OUT>
//出现SOI
{
com_rec_pos=0。
//(重新>
开始接收
com_type=COM_TYPE_IN。
//转接收
count_byte_miss=BY