#本文档是基于AT89S52单片机.docx

上传人:b****4 文档编号:3907557 上传时间:2022-11-26 格式:DOCX 页数:37 大小:83.86KB
下载 相关 举报
#本文档是基于AT89S52单片机.docx_第1页
第1页 / 共37页
#本文档是基于AT89S52单片机.docx_第2页
第2页 / 共37页
#本文档是基于AT89S52单片机.docx_第3页
第3页 / 共37页
#本文档是基于AT89S52单片机.docx_第4页
第4页 / 共37页
#本文档是基于AT89S52单片机.docx_第5页
第5页 / 共37页
点击查看更多>>
下载资源
资源描述

#本文档是基于AT89S52单片机.docx

《#本文档是基于AT89S52单片机.docx》由会员分享,可在线阅读,更多相关《#本文档是基于AT89S52单片机.docx(37页珍藏版)》请在冰豆网上搜索。

#本文档是基于AT89S52单片机.docx

#本文档是基于AT89S52单片机

本文档是基于AT89S52单片机,通过C语言编程实现了对测温电路的控制,其中包括对加热继电器的控制,对A/D转换的控制以及数码管显示。

一.程序结构说明:

程序流程图如图5.2.1示:

图5.2.1程序流程图

1.1.1软件主要模块划分

表5.2.1表的名称

按键处理模块

消抖模块一个

按键响应分类模块一个

按键响应模块两个<对应系统两个工作状态)

曲线拟合模块包括

拟合准备模块一个

拟合参数计算模块一个

显示和定时模块

中断模块一个<刷新数码管和LED,提供若干定时溢出信号)

显示匹配模块一个<将所需显示的内容翻译为中断快可以使用的信息)

数码管匹配模块一个<将所需显示的字符翻译为数码管控制字)

系统初始化模块

系统初始化模块一个

ad采样模块

利用adc0804对水温进行读数

控制模块

对水温进行实时控制,主要通过控制继电器的关断频率实现

1.1.2重要的全局变量

表5.2.2重要全局变量表

所属模块

变量名

变量类型

功能

定时器

count0_high_H

unsignedchar

定时器0初值的高4位

count0_high_L

unsignedchar

定时器0初值的低4位

count0_low_H

unsignedchar

定时器1初值的高4位

count0_low_L

unsignedchar

定时器1初值的低4位

按键

count_key

unsignedintxdata

消抖基础频率计数器

overload_key

bit

消抖溢出标志

key_down

unsignedcharxdata

按键按下存储器

last_key_down

unsignedcharxdata

按键按下确认存储器

count_key_flash

unsignedintxdata

按键重复计数器

显示

digi_scaner

unsignedcharxdata

数码管扫描驱动指针

output_sel

unsignedcharbdata

数码管位驱动和指示灯驱动信号输出缓存

led_1

sbit

output_sel^5

led_2

sbit

output_sel^6

led_3

sbit

output_sel^7

led_4

sbit

output_sel^4

显示

Vo

unsignedintxdata

输出电压

digi[4]

unsignedcharxdata

数码管输出寄存器

digi_flash_temp

unsignedcharxdata

数码管闪烁用寄存器

doublexdata

pulse_width

当前的占空比

input_for_display

unsignedintxdata

输入显示用寄存器

count_digi_flash

unsignedintxdata

闪烁计数器

input_position

unsignedcharxdata

输入位(即数码管闪烁位>

拟合

coefficient_A

doublexdata

拟合曲线的系数

coefficient_B

doublexdata

coefficient_C

doublexdata

Vo_adjust[4]

longintxdata

输出电压数组

display_for_adjust[4]

intxdata

显示数组

Ave

unsignedcharxdata

ad读数

继电器

ctr_out_foot

unsignedcharxdata

继电器电平信号

sub_set_val

unsignedcharxdata

系统设定温度

sub_cur_val

unsignedcharxdata

当前温度

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*(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>=sub_set_val>

{

ctr_out_foot=0。

count_self_ctrl=10000。

//设延迟为1s

}

}

else//继电器断开

{

if(sub_cur_val<=sub_set_val>

{

ctr_out_foot=1。

count_self_ctrl=500。

//循环延迟50ms

}

}

1.2.5按键解释功能说明

按键是人机互最重要的部分,基本所以的操作都要通过按键来完成,在系统运行中,不断扫描按键,以判断用户是否有任何输入指示,一旦用户有按键操作,系统将做出判断,给予按键解释,执行相应的命令。

但是值得注意的是任何按键都有可能有抖动的现象,因此软件中必须含有消抖程序。

在水温控制中,key3实现自动与手动的切换,在自动情况下,系统接收本地主系统的控制,自动调整水温;当在手动情况下,可以通过key1切换继电器的开和关,这样在调试时比较方便。

对于温度的设置,采用了对位的调整方法,使得温度设定更为方便。

二.程序清单:

#include

#include

#include

/*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'0':

AA|=0x40。

break。

//0

case'1':

AA|=0x79。

break。

//1

case'2':

AA|=0x24。

break。

//2

case'3':

AA|=0x30。

break。

//3

case'4':

AA|=0x19。

break。

//4

case'5':

AA|=0x12。

break。

//5

case'6':

AA|=0x02。

break。

//6

case'7':

AA|=0x78。

break。

//7

case'8':

AA|=0x00。

break。

//8

case'9':

AA|=0x10。

break。

//9

case'A':

AA|=0x08。

break。

//A

case'B':

AA|=0x03。

break。

//B

case'C':

AA|=0x46。

break。

//C

case'D':

AA|=0x21。

break。

//D

case'E':

AA|=0x06。

break。

//E

case'F':

AA|=0x0e。

break。

//F

case'G':

AA|=0x42。

break。

//G

case'H':

AA|=0x09。

break。

//H

case'I':

AA|=0x4f。

break。

//I

case'J':

AA|=0x71。

break。

//J

case'K':

AA|=0x0f。

break。

//K

case'L':

AA|=0x47。

break。

//L

case'P':

AA|=0x0c。

break。

//P

case'-':

AA|=0x3f。

break。

//减号

case'_':

AA|=0x77。

break。

//下划线

case'':

AA|=0x7f。

break。

//消隐

case'~':

AA|=0x7e。

break。

//上划线

default:

AA=0xff。

}

return(AA>。

}

/*1.2*/

/*1.2LED刷新*/

voidLEDDisplayHard(>

{

led_scaner=(led_scaner+1>%5。

//移动扫描指针

output_sel=(output_sel&0xf0>|0x01<

//选通下一个数码管

//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]<0>//原来带小数点

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<=0>//达到返回点

{

count_key_repeat=KEY_REPEAT_TIME。

returnlast_key_down。

}else

return0。

}

timer0(>interrupt1using0

{

}

/*2.3*/

/*T0时钟中断服务程序*/

/*提供系统时基*/

timer1(>interrupt3using1

{

ET0=0。

//关中断

TH1=count1_H。

//1ms定时

TL1=count1_L。

TR1=1。

if(count_led_scan!

=0>//扫描数码管

count_led_scan--。

if(count_key_scan!

=0>//扫描按键

count_key_scan-=1。

if(count_byte_miss!

=0>//字节丢失

count_byte_miss--。

elseif(com_type==COM_TYPE_IN>

{

com_type=COM_TYPE_STOP。

//通讯停止

}

if(count_byte_delay!

=0>//字节延时

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!

=0>//显示设定值

count_set_time--。

if(count_self_ctrl!

=0>//自控

count_self_ctrl--。

ET0=1。

//开中断

}

/*2.4*/

/****串口中断服务程序*****/

/****通信用中断*****/

comHard(>interrupt4using3

{

chartemp。

ES=0。

//关中断

if(RI==1>//接收中断

{

RI=0。

//接收中断复位

temp=SBUF。

if(temp=='~'&&com_type//出现SOI

{

com_rec_pos=0。

//(重新>开始接收

com_type=COM_TYPE_IN。

//转接收

count_byte_miss=BY

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 幼儿教育 > 育儿知识

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1