电路CAD课程设计报告

 电路CAD课程设计报告

设计题目:    温湿度控制仪的设计   

专业班级:             

学    号:          

学生姓名:               

同组学生:       

温湿度控制仪的设计 

摘  要

本次设计是采用MSC-51系列单片机中的AT89S51和DHT11的低成本的温湿度的检测系统。本设计主要包括硬件电路的设计和系统软件的设计。硬件电路主要包括单片机、温湿度传感器、显示模块、报警器以及键盘等5部分,由DHT11温湿度传感器及1602字符型液晶模块构成系统显示模块,该系统电路简单、工作稳定、集成度高,调试方便,测试精度高,具有一定的实用价值。其中测温湿度控制电路由温湿度传感器和预设温度值比较报警电路组成,用户根据需要预先输入预设值,当实际测量的温湿度大于预设的温湿度数值时,发出报警信号(蜂鸣器蜂鸣)。软件部分包括了主程序、显示子程序、测温湿度子程序。    

本次设计采用的DHT11温湿度传感器是一款含有已校准数字输出的温湿度复合传感器,传感器包括一个电阻式感湿原件和一个NTC测温元件,并与一个高性能的8位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。单片机AT89S51是一款低消耗、高性能的CMOS8位单片机,由于它强大的功能和低价位,因此在很多领域都是用它。

关键词:温度测量、湿度测量、AT89C51、STH11

Abstract

This design is the use of MSC-51 Series MCU AT89S51 and DHT11 in the low-cost temperature and humidity detection system. This design includes the design of hardware and system software design. Hardware circuit includes a microcontroller, temperature and humidity sensors, display module, the alarm and the keyboard 5, the DHT11 temperature and humidity sensor and 1602 constitute a system of character LCD module display module, the system circuit is simple, stable, high integration, commissioning Convenient, high precision, has some practical value. Temperature and humidity control circuit in which the temperature and humidity sensors and compare the value of the preset temperature alarm circuit, the user input required pre-default value, when the actual temperature and humidity measurements of temperature and humidity is greater than the preset value, an alarm signal (bee Buzzer beep). Software part includes the main program, display routines, subroutines side temperature and humidity

The design uses the DHT11 temperature and humidity sensors is a digital output with a calibrated temperature and humidity combined sensor, the sensor includes a resistance and a sense of the original wet NTC temperature measurement devices, and with a high-performance 8-bit microcontroller connected. Therefore, the product has excellent quality, fast response, anti-interference ability, high cost and other advantages. AT89S51 is a low consumption of item-level, high-performance CMOS8 bit microcontroller, because of its powerful features and low price, so use it in many fields.

KEY WORDS: temperature measurement, humidity measurements, AT89C51, STH11

                       目  录

一、设计任务与要求...................................... 6

§1.1 设计任务及要求................................... 6

二、方案设计与认证...................................... 6

§2.1  设计总体方案及方案论证........................... 6

§2.2  温湿度传感器的选择............................... 7

§2.3  输出显示设备的选择................................................................ 7

三、单元电路设计与参数计算.............................. 7

§3.1  复位电路部分..................................... 7

§3.2  时钟电路部分..................................... 8

§3.3  超限电路部分..................................... 8

§3.4  实时时钟电路模块................................. 9

§3.5  温湿度传感器电路................................................................... 9

§3.6  输出显示电路......................................................................... 10

四、总原理图与元器件清单............................................................... 11

§4.1  总原理图................................................................................. 11

§4.2  原理说明................................................................................. 12

§4.3  元器件清单............................................................................. 12

§4.4  PCB图.................................................................................... 12

五、结论与心得......................................... 13

六、参考文献.......................................... 13

七、附  录............................................ 15

一、设计任务与要求

设计一个以单片机为核心的温湿度控制系统,需要实现的功能为:

(1)能够准确的显示当前的温度以及湿度。温度检测的范围20℃-60℃,测温精度:±2℃;湿度检测范围30%-80%RH,  测湿精度:±5%RH。

(2)能够自主调节当前需要温度以及湿度的预设温湿度值,在系统上面有调节按钮,可随时根据需要增加或者减少预设值。

(3)一旦发现超过了预设值,蜂鸣器蜂鸣报警。

(4)报警方式为三极管驱动的蜂鸣音报警。

(5)系统的显示方式均为四位显示,采用LCD显示。

二、方案设计与论证

  1. 设计的总体方案及论证

    按照系统设计功能的要求,确定系统由6个模块组成:主控制器,数字温湿度传感器,报警电路,时钟电路,超限电路,复位电路及显示电路等。

    本方案以AT89C51单片机系统为核心来对温度、湿度进行实时控制和监测。各检测单元能独立完成各自功能,并根据主控机的指令对温湿度进行实时采集。主控机负责控制指令的发送,并控制各个检测单元进行温度采集,收集测量数据,同时对测量结果进行整理和显示。其中包括单片机、复位电路、温度检测、湿度检测、键盘及显示、报警电路、系统软件等部分的设计。

系统原理框图:

图一:温湿度控制器原理框图

系统工作原理:主控制器的功能由单片机来完成,主要负责处理由数字温湿度传感器送来数据,并把处理好的数据送向显示模块。数字温湿传感器主要用来采集周围环境参数,并把所采集来的参数送向主控制器。温湿度传感器上的按键可以用来完成单片机的复位操作和温湿度初始值的设定。超限电路就是用五个发光二极管和一个扬声器来实现的,用来判断周围环境的温度或者湿度是否超出设定值了,任何一个超出设定值发光二极管就会被点亮。显示电路主要用来显示系统实时的的时间、日历以及温度和湿度。

各单元电路的功能如下:

(1)复位电路:复位电路有上电式自动复位电路与手动复位电路,本设计中我们采用手动复位电路,这样便于我们对整个电路进行更有效的控制。

(2)时钟电路:为系统提供基本的时钟信号。通常一个系统共用一个晶振,便于各部分保持同步。有些通讯系统的基频和射频使用不同的晶振,而通过电子调整频率的方法保持同步。

(3)超限电路:当系统的温度或湿度超过或者低于设定的要求时,超限电路模块的报警电路就会发出报警信号,同时会提示是干燥,加湿,升温,降温等。

(4)实时时钟电路模块:此模块产生实时的系统时间和日历,能对某个确定环境的实时温湿度控制起到一定的作用。

(5)温湿度传感器:此模块是整个电路设计的信号采集及初步处理的模块,采集室内的温度及湿度。

(6)显示电路:此电路用来显示系统的时间和日历,温度以及湿度等。

2. 温湿度传感器的选择

    方案一:采用单总线的DS1820的温度传感器和HS110X相对湿度传感器组成的控制仪。

    方案二:采用集温湿度传感器于一体的SHT11芯片为主要芯片的控制仪。

    由于传统的模拟式湿度传感器(方案一)一般不仅要设计信号调理电路,还要经过复杂的校准和标定过程,其测量精度难以保证。而SHT11是瑞士Sensiri-on公司生产的具有二线串行接口的单片全校准数字式新型相对湿度和温度传感器,可用来测量相对湿度、温度和露点等参数,具有数字式输出、免调试、免标定、免外围电路及全互换的特点。该传感器将CMOS芯片技术与传感器技术融合,为开发高集成度、高精度、高可靠性的温湿度测控系统提供了解决方案。所以本设计采用的是方案二。

3. 输出显示设备的选择

电子设计中常用的输出显示设备有两种:数码管和LCD。

方案一:数码管是现在电子设计中使用相当普遍的一种显示设备,每个数码管由7个发光二极管按照一定的排列结构组成,根据七个发光二极管的正负极连接不同,又分为共阴极数码管和共阳极数码管两种,选择的数码管不同,程序设计上也有一定的差别。数码管显示的数据内容比较直观,通常显示从0到F中的任意一个数字,一个数码管可以显示一位,多个数码管就可以显示多位,在显示位数比较少的电路中,程序编写,外围电路设计都十分简单,但是当要显示的位数相对多的时候,数码管操作起来十分烦琐,显示的速度受到限制。并且当硬件电路设计好之后,系统显示能力基本也被确定,系统显示能力的扩展受到了限制。

方案二:而液晶显示屏具有体积小、功耗低、显示内容丰富等特点,用户可以根据自己的需求,显示自己所需要的、甚至是自己动手设计的图案。当需要显示的数据比较复杂的时候,它的优点就突现出来了,并且当硬件设计完成时,可以通过软件的修改来不断扩展系统显示能力。外围驱动电路设计比较简单,显示能力的扩展将不会涉及到硬件电路的修改,可扩展性很强。字符型液晶显示屏已经成为了单片机应用设计中最常用的信息显示器件之一。不足之处在于其价格比较昂贵,驱动程序编写比较复杂。

本设计需要显示温度值和湿度值,还可显示系统实时的时间与日期等,显示数字较多,因此选用方案二液晶频做输出设备。

三、单元电路设计与参数计算

1. 复位电路部分

    这种复位电路的工作原理是:单片机的复位电路在刚接通电时,电容是没有电的,电容内的电阻很低,通电后,5V 的电源通过电阻给电容进行充电, 电容两端的电压会0V慢慢的升到 4V 左右(此时间很短一般小于 0.3 秒),RC 构成的微分电路在上电瞬间产生一个微分脉冲,其宽度大于两个机器周期,AT89C51将复位。正因为这样,复位脚的电由低电位升到高电位,引起了内部电路的复位工作,RST 端电压慢慢下降,降到一定电压值以后,即为低电平,单片机开始正常工作(这是单片机的上电复位,也叫初始化复位);当按下复位键时,电容两端放电,电容又回到0V了,于是又进行了一次复位动作。

2. 时钟电路部分

单片机系统都有晶振,在单片机系统中晶振的作用非常大,全称叫做晶体振荡器,它结合单片机内部电路产生所需时钟频率,单片机晶振提供的时钟频率越高,那么单片机的运行速度就会越快,单片机的一切指令执行都是建立在单片机晶振所提供的时钟频率。在通常的工作条件下,普通的晶振频率的绝对精度可以达到百万分之五十,高级晶振精度更高,有些晶振还可以由外加的电压在一定范围内调整频率,称为压榨振荡器,在共振的状态下晶振用一种能把电能和机械能相互转化的晶体工作,以提供稳定,精确的单频振荡。

单片机晶振的作用是为系统提供及本周的时钟信号,通常一个系统共用一个晶振,以便于各部分保持同步,有些通讯系统的基频和射频使用不同的晶振,而是通过电子调整频率的方法保持同步。晶振通常与锁相环电路配合使用,以提供系统所需的时钟频率,可以用于同一个晶振项链的不同锁相环来提供的。

3. 超限电路部分

此部分电路是由 5 个发光二极管和一个蜂鸣报警器构成,分别是 D1、D2、D3、D4 和 D5,蜂鸣器接单片机的 P1.0 口,发光二极管与单片机的连接部分如图所示。D1、D2、D3、D4、D5 分别代表着发光、降温、加热、干燥和加湿,一旦传感器测定的温湿度超过或者低于设定的限额,就会产生不同的发光反应,起警示作用, 同时蜂鸣报警器连续发出“滴”的报警声音。

超限处理警示电路

蜂鸣器电路

4. 实时时钟电路模块

     此模块是为系统时间的实时显示而设计的,主要由芯片 DS1302 构成,其中引脚 RST、CLK、I/O 分别接单片机 P3.0、P3.1、P3.2 口,属于控制引脚。此模块是产生实时的系统时间和日历,能对某个确定环境的实时温湿度控制起到一定的作用。芯片连接电路简单,时间日期准确。

实时时钟电路

5. 温湿度传感器电路

此模块是整个电路设计的信号采集及初步处理的模块,由温湿度传感器芯片SHT11 构成。

SHT11 是瑞士Scnsirion 公司推出的一款数字温湿度传感器芯片。温湿度传感器SHT11集温度传感器和湿度传感器于一体,因此采用SHT11进行温湿度实时监测的系统具有精度高、成本低、体积小、接口简单等优点;另外SHT11芯片内部集成14位A/D 转换器,且采用数字信号输出,因此抗干扰能力也比同类芯片高。该芯片在温湿度监测、自动控制等领域均已得到广泛应用。该芯片广泛应用于暖通空调、汽车、消费电子、自动控制等领域。

6. 输出显示电路

此模块分为两个显示部分,一个部分是由 LCD1604 芯片组成的日期时间和实时温、湿度显示的电路部分,另一部分是由 LCD128×64 液晶显示模块组成的电路部分。LCD1604是一个四行每行16字的液晶显示屏,D0-D7 接 P0 口,RS、RW、E接 P3.5、P3.6、P3.7 起控制作用。LCD128×64组成部分是用来显示“温度和湿度的控制与测量”的,它的作用是让人们了解实验的目的,作用不是十分的明显,因此不作详细的介绍。

    LCD128×64 显示及其连接电路

LCD1604 显示及其连接电路

7.小结

此部分主要介绍系统各部分单元电路的设计,其中包含了各个模块电路的基本原理,基本结构以及基本功能等。

四、总原理图及元器件清单

1.总原理图

Proteus绘制的温湿度控制器电路原理图

Protel99se绘制的温湿度控制器电路原理图

2. 原理说明

首先温、湿度传感器STH11从设备环境的不同位置采集温度及湿度的数据,然后将采集的温、湿度数据送给单片机 AT89S51 ,经单片机处理后得到当前环境中一个比较稳定的温度和湿度值,再根据当前设定的温、湿度的上下限值,通过加热和降温,加湿和干燥对当前温度及湿度进行调整。当采集的温度或者湿度经处理后超过设定温度的上限时,或者低于相应的下限时,超限电路模块开始工作,相应的二极管发光 ,同时报警电路发出声响。如:当温度超过设定的上限时,超限电路模块的降温的二极管就会发光,同时报警。

3.元器件清单

表1 温湿度控制原理图中的元件清单

4. PCB图

五、结论与心得

通过本次温湿度控制器的设计,使我对电路CAD、protel99se、proteus软件有了更进一步的掌握。同时,让我对AT89C51单片机以及数字温湿度传感器STH11的使用更加熟练。通过对温湿度控制器的设计,让我从中受益匪浅,提高了分析解决问题的能力。

在设计过程中遇到很多问题,首先在使用keil51进行C语言程序的编译时遇到了一些问题,一开始对这个软件的使用不是很熟练,所以进度有点慢。同时,在网上下载的程序也存在一定的问题,有的函数没有定义就使用了,因此在编译的过程中存在错误。通过重新修改程序,添加需要的函数,经过多次的编译,使得最终的程序编译成功生成.HEX文件。经过本次设计,我对C语言程序的编写有了更深的理解和认识。虽然程序中还存在一点缺陷,使得最终的仿真结果不是十分的精确,但由于这不是本次设计的主要意图,所以没有对程序进行进一步的修改。

总之,在本次设计中我学到了很多,受益匪浅。

这次课程设计是一次理论联系实际的过程,在这次课程设计中遇到了许多实际问题,在理论上正确的结果可能会在试验中出现各种意料之外的结果,这就要我们在设计过程中从实际出发,尽可能多地考虑各种因素对实验的影响。另外,在遇到问题时要学会用理论联系实际的方法分析问题,解决问题。

回想这次课程设计,到现在还有许多的感慨,从最初的设计到最终的仿真成功使我懂得了理论联系实际的重要性,只有理论是远远不够的,只有把所学的理论与实践相结合起来,从理论中的出结论,在实践中检验理论,才能真正掌握知识,从而提高自己的实际动手能力和独立思考能力。

六、参考文献

  [1] 中国计量出版社组编. 新编电子电路大全(第1卷, 共6卷)——家用与民用电路. 北京: 中国计量出版社, 2001.

[2] 夏路易. 电路原理图与电路板设计教程. 兵器工业出版社. 2002. 

[3] 萧宝瑾. 电路CAD讲义. 太原理工大学 信息工程学院.2010.  

[4] 岑红蕾, 吴延祥, 谢江, 任玲. 顺序控制流程图在交通灯自动控制系统中的应用. 石河子大学学报(自然科学版), 2006, 24(6): 765-767.  

[5] 阉石.数字电子技术基础[M].高等教育出版社.  

[6] 周立功.单片机实验与实践[M].北京航空航天大学出版社.

七、附录

1. 主函数解析:

#include<reg51.h>

#include<absacc.h>

#include<intrins.h>

#include<math.h>

#include<12864.h>

#include<LCD1604.h>

#include<DS1302.h>

#include<SHT11.h>

#include<set_key.h>

void Delay1ms(unsigned int count)         //延时函数

{

unsigned int i,j; for(i=0;i<count;i++) for(j=0;j<120;j++);

}

main()

{

SYSTEMTIME CurrentTime;      //定义时间日期结构体

SHT_dat aa;  //定义温湿度测量处理结构体

Init_12864(); //12864 的显示*/ Initial_DS1302();                //DS1302 初始化*/

LCD_Initial();         //LCD 初始化

{GotoXY(0,0);        //LCD 显示函数

Print("Date:"); GotoXY(16,0); Print("Temper:"); GotoXY(0,1); Print("Time:"); GotoXY(16,1); Print("Humidi:");

while(1)

{

convert_SHT(&aa,TEMP); //温度转换

convert_SHT(&aa,HUMI);  //湿度转换

caculation_SHT(&aa);        //温度和湿度的补偿

float_convert(&aa);  //将浮点数转换成整型,各个位的数分别保存

doing_temp(&aa);    //检测温度是否超限

doing_humi(&aa);   //检测湿度是否超限

DS1302_GetTime(&CurrentTime); DateToStr(&CurrentTime); TimeToStr(&CurrentTime);

GotoXY(5,0);         //第一行显示日期

Print(CurrentTime.DateString);

GotoXY(23,0);        //第三行显示温度

Print(aa.num_temp); GotoXY(28,0); Print("      ");

GotoXY(5,1);         //第二行显示时间

Print(CurrentTime.TimeString);

GotoXY(23,1);        //第四行显示湿度

Print(aa.num_humi); GotoXY(28,1); Print("      ");

Delay1ms(300);       //延时

}

}

}

2. 源程序

SET_KEY.H

#ifndef _setkey_h_

#define _setkey_h_

#include<SHT11.h>

float setwen_h,setwen_l,setshi_h,setshi_l;

sbit hot =P1^4;

// 加热

sbit cold =P1^3;

// 降温

sbit speek =P1^2;

// 发光

sbit ganzao =P1^5;

//干燥

sbit jiashi =P1^6;

//加湿

sbit speaker =P1^0;

//       报警

void Delay_xMs(unsigned int x)

{

unsigned int i,j;

for( i =0;i < x;i++ )

{

for( j =0;j<50;j++ );

}

}

void Speaker(void)   //报警程序

{

unsigned int i;

for(i=0;i<80;i++ )

{

speaker=~speaker; Delay_xMs(2);

}

}

void doing_temp(SHT_dat *s)

{float xianshi_temp; setwen_h=80.00; setwen_l=20.00; xianshi_temp=s->temperature;

if((xianshi_temp<setwen_h)&(xianshi_temp>setwen_l))

{ cold=0;hot=0;speek=0;speaker=0;ganzao=0;jiashi=0;}

if(xianshi_temp>setwen_h)

{ cold=1;hot=0;speek=1;Speaker();Delay_xMs(200);speaker=0;}

if(xianshi_temp<setwen_l)

{ cold=0;hot=1;speek=1;Speaker();Delay_xMs(200);speaker=0;}

}

void doing_humi(SHT_dat *s)

{float xianshi_humi; setshi_h=90.00; setshi_l=30.00; xianshi_humi=s->humidity;

if((xianshi_humi<setshi_h)&(xianshi_humi>setshi_l))

{ cold=0;hot=0;speek=0;speaker=0;ganzao=0;jiashi=0;}

if(xianshi_humi>setshi_h)

{ ganzao=1;jiashi=0;speek=1;Speaker();Delay_xMs(200);speaker=0;}

if(xianshi_humi<setshi_l)

{ ganzao=0;jiashi=1;speek=1;Speaker();Delay_xMs(200);speaker=0;}

}

#endif

LCD1604.H

#ifndef LCD_CHAR_1604

#define LCD_CHAR_1604

#include <intrins.h>

//Port Definitions****************************************************

sbit    LcdRs =       P3^5;

sbit LcdRw =P3^6;

sbit LcdEn = P3^7;

sfr DBPort    =0x80;

//P0=0x80,P1=0x90,P2=0xA0,P3=0xB0.数据端口

//内部等待函数**************************************************

unsigned char LCD_Wait(void)

{

LcdRs=0;

LcdRw=1;    _nop_(); LcdEn=1;  _nop_();

//while(DBPort&0x80);// LcdEn=0;

return DBPort;

}

//向 LCD 写入命令或数据***************************************

#define LCD_COMMAND 0        // Command

#define LCD_DATA 1        // Data

#define LCD_CLEAR_SCREEN  0x01   // 清屏

#define LCD_HOMING     0x02   // 光标返回原点

void LCD_Write(bit style, unsigned char input)

{

LcdEn=0; LcdRs=style;

LcdRw=0;    _nop_();

DBPort=input;        _nop_();//注意顺序

LcdEn=1;     _nop_();//注意顺序 LcdEn=0;     _nop_(); LCD_Wait();

}

//设置显示模式************************************************

#define         LCD_SHOW 0x04   //显示开

#define         LCD_HIDE   0x00   //显示关

#define LCD_CURSOR     0x02   //显示光标

#define LCD_NO_CURSOR        0x00   //无光标

#define         LCD_FLASH         0x01   //光标闪动

#define         LCD_NO_FLASH            0x00   //光标不闪动

void LCD_SetDisplay(unsigned char DisplayMode)

{

LCD_Write(LCD_COMMAND, 0x08|DisplayMode);

}

//设置输入模式*********************************************

#define LCD_AC_UP        0x02

#define LCD_AC_DOWN  0x00   // default

#define LCD_MOVE         0x01   // 画面可平移

#define LCD_NO_MOVE  0x00   //default

void LCD_SetInput(unsigned char InputMode)

{

LCD_Write(LCD_COMMAND, 0x04|InputMode);

}

//移动光标或屏幕********************************************

/*

#define LCD_CURSOR     0x02

#define LCD_SCREEN     0x08

#define LCD_LEFT 0x00

#define LCD_RIGHT        0x04

void LCD_Move(unsigned char object, unsigned char direction)

{

if(object==LCD_CURSOR) LCD_Write(LCD_COMMAND,0x10|direction);

if(object==LCD_SCREEN) LCD_Write(LCD_COMMAND,0x18|direction);

}

*/

//初始化****************************************************

void LCD_Initial()

{

LcdEn=0;

LCD_Write(LCD_COMMAND,0x38);    //8 位数据端口,2 行显示,5*7 点阵

LCD_Write(LCD_COMMAND,0x38); LCD_SetDisplay(LCD_SHOW|LCD_NO_CURSOR);    //开启显示, 无光标 LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN);    //清屏 LCD_SetInput(LCD_AC_UP|LCD_NO_MOVE);     //AC 递增, 画面不动

}

//******************************************************************/

void GotoXY(unsigned char x, unsigned char y) //x 列,y 行

{

if(y==0) LCD_Write(LCD_COMMAND,0x80|x);

if(y==1)

LCD_Write(LCD_COMMAND,0x80|(x-0x40));

}

void Print(unsigned char *str)

{

while(*str!='\0')

{

LCD_Write(LCD_DATA,*str);

str++;

}

}

/*

void LCD_LoadChar(unsigned char user[8], unsigned char place)

{

unsigned char i; LCD_Write(LCD_COMMAND,0x40|(place*8)); for(i=0; i<8; i++)

LCD_Write(LCD_DATA,user[i]);

}

*/

//******************************************************************/

#endif

DS1302.H

#ifndef _REAL_TIMER_DS1302

#define _REAL_TIMER_DS1302

sbit DS1302_CLK = P3^1;           

//实时时钟时钟线引脚

sbit DS1302_IO = P3^2;           

//实时时钟数据线引脚

sbit DS1302_RST = P3^0;           

//实时时钟复位线引脚

sbit ACC0 = ACC^0;

sbit ACC7 = ACC^7;

//__SYSTEMTIME__

typedef struct

{

unsigned char Second; unsigned char Minute; unsigned char Hour; unsigned char Day; unsigned char Month; unsigned char   Year;

unsigned char DateString[9];

unsigned char TimeString[9];

}SYSTEMTIME;    //定义的时间类型

#define AM(X)        X

#define PM(X)        (X+12)         // 转成 24 小时制

#define DS1302_SECOND 0x80

#define DS1302_MINUTE 0x82

#define DS1302_HOUR     0x84

#define DS1302_DAY       0x86

#define DS1302_MONTH  0x88

#define DS1302_YEAR     0x8C

#define DS1302_RAM(X)  (0xC0+(X)*2)         //用于计算 DS1302_RAM 地址的宏

void DS1302InputByte(unsigned char d)  //实时时钟写入一字节(内部函数)

{

unsigned char i; ACC = d;

for(i=8; i>0; i--)

{

DS1302_IO = ACC0;        //相当于汇编中的 RRC DS1302_CLK = 1;

DS1302_CLK = 0;

ACC = ACC >> 1;

}

}

unsigned char DS1302OutputByte(void)  //实时时钟读取一字节(内部函数)

{

unsigned char i;

for(i=8; i>0; i--)

{

ACC = ACC >>1;   //相当于汇编中的 RRC ACC7 = DS1302_IO;

DS1302_CLK = 1; DS1302_CLK = 0;

}

return(ACC);

}

void Write1302(unsigned char ucAddr, unsigned char ucDa)    //ucAddr: DS1302 地址, ucData: 要写的数据

{

DS1302_RST = 0; DS1302_CLK = 0; DS1302_RST = 1;

DS1302InputByte(ucAddr); // 地址,命令 DS1302InputByte(ucDa);         // 写 1Byte 数据 DS1302_CLK = 1;

DS1302_RST = 0;

}

unsigned char Read1302(unsigned char ucAddr)  //读取 DS1302 某地址的数据

{

unsigned char ucData; DS1302_RST = 0; DS1302_CLK = 0; DS1302_RST = 1;

DS1302InputByte(ucAddr|0x01);  // 地址,命令 ucData = DS1302OutputByte(); // 读 1Byte 数据 DS1302_CLK = 1;

DS1302_RST = 0;

return(ucData);

}

void DS1302_SetProtect(bit flag)  //是否写保护

{

if(flag)

         Write1302(0x8E,0x10);

else

         Write1302(0x8E,0x00);

}

void DS1302_SetTime(unsigned char Address, unsigned char Value)  // 设置时间函数

{

DS1302_SetProtect(0);

Write1302(Address, ((Value/10)<<4 | (Value%10)));

}

void DateToStr(SYSTEMTIME *Time)

{

Time->DateString[0] = Time->Year/10 + '0'; Time->DateString[1] = Time->Year%10 + '0'; Time->DateString[2] = '-';

Time->DateString[3] = Time->Month/10 + '0'; Time->DateString[4] = Time->Month%10 + '0'; Time->DateString[5] = '-';

Time->DateString[6] = Time->Day/10 + '0'; Time->DateString[7] = Time->Day%10 + '0'; Time->DateString[8] = '\0';

}

void TimeToStr(SYSTEMTIME *Time)

{

Time->TimeString[0] = Time->Hour/10 + '0'; Time->TimeString[1] = Time->Hour%10 + '0'; Time->TimeString[2] = ':';

Time->TimeString[3] = Time->Minute/10 + '0'; Time->TimeString[4] = Time->Minute%10 + '0';

Time->TimeString[5] = ':';

Time->TimeString[6] = Time->Second/10 + '0'; Time->TimeString[7] = Time->Second%10 + '0'; Time->DateString[8] = '\0';

}

void DS1302_GetTime(SYSTEMTIME *Time)

{

unsigned char ReadValue;

ReadValue = Read1302(DS1302_SECOND);

Time->Second = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); ReadValue = Read1302(DS1302_MINUTE);

Time->Minute = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); ReadValue = Read1302(DS1302_HOUR);

Time->Hour = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); ReadValue = Read1302(DS1302_DAY);

Time->Day = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); ReadValue = Read1302(DS1302_MONTH);

Time->Month = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);

ReadValue = Read1302(DS1302_YEAR);

Time->Year = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);

}

void Initial_DS1302(void)

{

unsigned char Second=Read1302(DS1302_SECOND);

if(Second&0x80) DS1302_SetTime(DS1302_SECOND,0);

}

/******************************************************************************

**

void BurstWrite1302(unsigned char *pWClock) //往 DS1302 写入时钟数据(多字节方式)

{

unsigned char i;

Write1302(0x8e,0x00);      // 控制命令,WP=0,写操作? DS1302_RST = 0;

DS1302_CLK = 0; DS1302_RST = 1;

DS1302InputByte(0xbe);    // 0xbe:时钟多字节写命令

for (i = 8; i>0; i--)   //8Byte = 7Byte 时钟数据 + 1Byte 控制

{

DS1302InputByte(*pWClock);     // 写 1Byte 数据

pWClock++;

}

DS1302_CLK = 1; DS1302_RST = 0;

}

void BurstRead1302(unsigned char *pRClock)   //读取 DS1302 时钟数据(时钟多字节方

式)

{

unsigned char i; DS1302_RST = 0; DS1302_CLK = 0; DS1302_RST = 1;

DS1302InputByte(0xbf);    // 0xbf:时钟多字节读命令

for (i=8; i>0; i--)

{

*pRClock = DS1302OutputByte();         // 读 1Byte 数据

pRClock++;

}

DS1302_CLK = 1; DS1302_RST = 0;

}

void DS1302_TimeStop(bit flag)  // 是否将时钟停止

{

unsigned char Data; Data=Read1302(DS1302_SECOND); DS1302_SetProtect(0);

if(flag)

Write1302(DS1302_SECOND, Data|0x80);

else

}

Write1302(DS1302_SECOND, Data&0x7F);

/******************************************************************************

**/

#endif

STH11.H

#ifndef _SHT11_h_

#define _SHT11_h_

#define uchar unsigned char

#define uint   unsigned int

#define NOP() _nop_()

#define TEMP 0

#define HUMI 1

sbit    DQ=P2^7;    //端口定义

sbit    SCK=P2^6;

typedef struct

{

float temperature; float humidity; float crc_temp; float crc_humi; uchar num_temp[5]; uchar num_humi[5];

}SHT_dat;

/*=========================================

启动函数

=========================================*/

void init_SHT()

{

DQ=1; SCK=0; NOP(); SCK=1; NOP();

DQ=0; NOP(); SCK=0; NOP(); NOP(); NOP(); SCK=1; NOP();

DQ=1;

NOP(); SCK=0;

}

/*=========================================

字节传送函数

=========================================*/

uchar write_byte(uchar value)

{

uchar i,error=0;

for(i=0x80;i>0;i/=2) //高位先传送

{

if(i & value)DQ=1;  //循环相与,结果即为要发送的位

else DQ=0;

SCK=1; NOP(); NOP(); NOP(); SCK=0;

}

DQ=1;         //释放总线

SCK=1;

if(DQ==1) error=1;  //检查应答,确认通讯正常

SCK=0;

return error;   //error=1,通讯有误

}

/*=========================================

读数据函数

=========================================*/

uchar read_byte(uchar dat)

{

uchar i,val=0;

DQ=1;

for(i=0x80;i>0;i/=2)

{

SCK=1;

if(DQ) val=(val | i); SCK=0;

}

DQ=dat;

SCK=1; NOP(); NOP(); NOP(); SCK=0; DQ=1;

return val;

}

/*=========================================

复位函数

=========================================*/

void reset_SHT()

{

uchar i;

DQ=1; SCK=0;

for(i=0;i<9;i++)      //DATA 保持高电平,SCK 时钟出发 9 次复位

{

SCK=1; NOP(); SCK=0;

}

init_SHT();

}

/*=========================================

发送指令到 SHT11 执行温度和湿度的测量转换

=========================================*/

convert_SHT(SHT_dat *s,uchar mode)

{

uchar i,ack=0;

uchar valueM,valueL,checksum;

float com;

do{reset_SHT();

switch(mode){

case TEMP: ack=write_byte(0x03);break; case HUMI: ack=write_byte(0x05);break; default:  break;}

}while(ack==1);

for(i=0;i<65535;i++)         //等待测量结束

{

if(DQ==0)break;

}        //若长时间数据线 DQ 没拉低,则说明测量有错误

valueM=read_byte(0);        //数据的高字节

valueL=read_byte(0);         //数据的低字节

checksum=read_byte(1);     //CRC 校验码

com=(float)valueM*256+(float)valueL;

if(mode==TEMP)

{

s->temperature=com;

s->crc_temp=(float)checksum;

}

if(mode==HUMI)

{

s->humidity=com;

s->crc_humi=(float)checksum;

}

}

/*=========================================

温度和湿度补偿及输出温度值和相对湿度值

=========================================*/

void caculation_SHT(SHT_dat *s)

{

const float c1=-4.0;

const float c2=+0.0405;

const float c3=-0.0000028; //以上为 12 位湿度修正公示取值

const float t1=+0.01;

const float t2=+0.00008;    //以上为 14 位温度修正公示取值

float t=s->temperature;

float rh=s->humidity;

float rh_lin; float rh_ture; float t_c;

t_c=t * 0.01 - 40;    //温度的补偿

rh_lin=c3*rh*rh      + c2*rh + c1; //相对湿度非线性补偿

rh_ture=( t_c - 25 ) * ( t1 + t2*rh ) + rh_lin; //相对湿度对于温度依赖性补偿

if( rh_ture > 100 ) rh_ture=100;    //相对湿度最大值修正

if( rh_ture < 0.1 ) rh_ture=0.1;     //相对湿度最小值修正

if(t_c<0)t_c=0;

s->temperature=t_c; //保存温度补偿后的结果

s->humidity=rh_ture;        //保存相对湿度补偿后的结果

}

/*=========================================

计算绝对湿度值

=========================================

float calc_dewpoint(float h,float t)

{

float logEx,dew_point;

logEx=0.66077+7.5*t/(237.3+t)+(log10(h)-2);

dew_point = (logEx - 0.66077)*237.3/(0.66077+7.5-logEx);

return dew_point;

}

/*=========================================

浮点数数据处理

=========================================*/

void float_convert(SHT_dat *s)

{

float com;

uint dat;

com=s->temperature; com*=100; dat=(uint)com;

s->num_temp[0]=dat/1000+0x30;          //十位 s->num_temp[1]=dat%1000/100+0x30;      //个位 s->num_temp[2]=0x2e;

s->num_temp[3]=dat%100/10+0x30;      //小数点第一位

s->num_temp[4]=dat%10+0x30;   //小数点第二位

com=s->humidity; com*=100; dat=(uint)com;

s->num_humi[0]=dat/1000+0x30; //十位

s->num_humi[1]=dat%1000/100+0x30;  //个位

s->num_humi[2]=0x2e;

s->num_humi[3]=dat%100/10+0x30;      //小数点第一位

s->num_humi[4]=dat%10+0x30;  //小数点第二位

}

#endif

相关推荐