2023年11月30日发(作者:)

第一章 阶段任务

第二章 基于WIFI模块的无线数据传输的原理

1.1 时钟模块

1.2 最小单片机系统的原理

1.3 温度传感器DS18B20

1.4 串口

1.5 WIFI模块

第三章 基于WIFI模块的无线数据传输的实现

2.1 WIFI模块设置

2.2 串口部分设置

2.3 调试与运行过程

第四章 程序与框图

第五章 小结

1

第一章 阶段任务:

第一阶段 1天)1、了解课程所给的WIFI模块,并详细研读其说明书

2、复习单片机知识

2天)1、了解温湿度传感器模块,并设计其硬件模块

2、了解lcd1602显示模块,并设计其硬件模块

2天)1、设计整合电路:5v3.3v电路

2、串口通讯电路

第二阶段 4天) 1、链接并完成整体电路图的设计,并检查

2、焊接电路并调试。

第三阶段 3天)1、根据设计的硬件模块设计程序

1:温湿度传感器模块

2:串口通讯模块

3WIFI传输与接收模块

4:显示电路模块

3天)2、将设计好的模块程序烧录到单片机内,调试

第四阶段:2

2天)写报告

2

第二章 基于WIFI模块的无线数据传输的原理

1.1时钟DS1302模块:

电路原理图:DS1302与单片机的连接也仅需要3条线:CE引脚、SCLK串行时钟引脚、I/O

串行数据引脚,Vcc2为备用电源,外接32.768kHz晶振,为芯片提供计时脉冲。

读写时序说明:DS1302SPI总线驱动方式。它不仅要向寄存器写入控制字,还需要读取

相应寄存器的数据。控制字总是从最低位开始输出。在控制字指令输入后的下一个SCLK

钟的上升沿时,数据被写入DS1302,数据输入从最低位(

0位)开始。同样,在紧跟8位的控制字指令后的下一个SCLK脉冲的下降沿,读出DS1302

的数据,读出的数据也是从最低位到最高位。数据读写时序如图

3

1.2单片机最小系统的原理:

说明

复位电路:由电容串联电阻构成,由图并结合"电容电压不能突变"的性质,可以知道,当系统一

上电,RST脚将会出现高电平,并且,这个高电平持续的时间由电路的RC值来决定.典型的

51单片机当RST脚的高电平持续两个机器周期以上就将复位,所以,适当组合RC的取值就

可以保证可靠的复位.

晶振电路:典型的晶振取11.0592MHz(因为可以准确地得到9600波特率和19200波特

,用于有串口通讯的场合)/12MHz(产生精确的uS级时歇,方便定时操作)

单片机:一片AT89S51/52或其他51系列兼容单片机

特别注意:对于31(EA/Vpp),当接高电平时,单片机在复位后从内部ROM0000H

始执行;当接低电平时,复位后直接从外部ROM0000H开始执行.

1.3温度传感器DS18B20的原理(连接到单片机最小系统,并将温度发送给

WIFI模块)

3.1.1 DS18B20性能特点

(1) 独特的单线接口方式,只需一个接口引脚即可通信;

5

(2) 每一个DS18B20都有一个唯一的64ROM序列码;

(3) 在使用中不需要任何外围元件;

(4) 可用数据线供电,电压范围:+3.0V-+5.5 V

(5) 测温范围:-55 -+125℃,在-10-+85℃范围内精度为+0.5℃,分辨率为0.0625℃;

(6) 通过编程可实现9-12位的数字读数方式。温度转换成12位数字信号所需时间最长为

750ms,而在9位分辩模式工作时仅需93.75ms

(7) 用户可自设定非易失性的报警上下限值;

(8) 告警搜索命令可识别和定位那些超过报警限值的DS18B20

(9) 多个DS18B20可以并联在惟一的三线上,实现多点测温;

(10)电源极性接反时,DS18B20不会因发热而烧毁,但不能正常工作;

3.1.2 DS18B20内部存储器及温度数据格式

对于DS18B20内部存储器结构(如图3.1),它包括一个暂存RAM和一个非易失性电可

擦除EERAM,后者存放报警上下限THTL。当改变THT L中的值时,数据首先被写进暂存

器的第二、三字节中,主机可再读出其中内容进行验证。如果正确,当主机发送复制暂存器

命令,暂存器的第二、三字节将被复制到THTL中,这样处理有利于确保该数据在单总线

上传输的完整性

[7]

暂存器结构 EERAM结构

温度低字节 BYTE0

温度高字节 BYTE1

上限报警温度THBYTE2

下限报警温度TLBYTE3

结构寄存器 BYTE4

保留 BYTE5

保留 BYTE6

保留 BYTE7

CRC BYTE8

3.1 DS18B20结构框图

TH

TL

结构寄存器

6

暂存存储器作用是在单线通信时确保数据的完整性,它由8字节组成,头两个字节表

示测得的温度读数12位转化为例说明温度高低字节存放形式温度的存储形式如表3.1

及计算:12位转化后得到的12位数据,存储在18B20的两个高低8位的RAM中,二进制中

的前面5位是符号位。如果测得的温度大于0,这5位为0,只要将测到的数值乘于0.0625

即可得到实际温度如果温度小于05位为1测到的数值需要取反加1再乘于0.0625

才能得到实际温度

[8]

3.1 温度的存储形式

8 S S S S S 2 2 2

8 2 2 2 2 2 2 2 2

3210-1-2-3-4

654

S=1时表示温度为负,S=0时表示温度为正,其余低位以二进制补码形式表示,最低位

1时表示0.0625 。温度/数字对应关系如表3.2所示。

3.2 DS18B20温度/数字对应关系表

温度(℃) 输出的二进制码 对应的十六进制码

+125 0000 0111 1101 0000 07D0H

+85 0000 0101 0101 0000 0550H

+25.0625 0000 0001 1001 0001 0191H

+10.125 0000 0000 1010 0010 00A2H

+0.5 0000 0000 0000 1000 0008H

0 0000 0000 0000 0000 0000H

-0.5 1111 1111 1111 1000 FFF8H

-10.125 1111 1111 0110 1110 FF5EH

-25.0625 1111 1110 0110 1111 FF6FH

-55 1111 1100 1001 0000 FC90H

DS18B20有六条控制命令,如表3.3所示:

3.3 控制命令

约定代码

温度转换 44H 启动DS18B20进行温度转换

读暂存器 BEH 读暂存器9个字节内容

写暂存器 4EH 将数据写入暂存器的THTL字节

7

复制暂存器 48H 把暂存器的THTL字节写到ERAM

重新调ERAM B8H ERAM中的THTL字节写到暂存器THTL字节

读电源供电方式 B4H 启动DS18B20发送电源供电方式的信号给主CPU

22

2

3.1.3 DS18B20操作命令及时序特性

DS18B20对读写的数据位有着严格的时序要求它是在一根I/O线上读写数据的同时,

DS18B20为了保证各位数据传输的正确性和完整性,它有着严格的通信协议。DS18B20每一

步操作都要遵循严格的工作时序和通信协议如主机控制DS18B20完成温度转换这一过程,

根据DS18B20的通讯协议,须经三个步骤:每一次读写之前都要对DS18B20进行复位,复位

成功后发送一条ROM指令,最后发送RAM指令,这样才能对DS18B20进行预定的操作 。该

协议定义了几种信号的时序:初始化时序、读时序、写时序。所有时序都是将主机作为主设

单总线器件作为从设备而每一次命令和数据的传输都是从主机主动启动写时序开始的

如果要单总线器件送回数据,在进行写命令后,主机需启动读时序完成数据的接收。另外,

数据和命令的传输都是低位在先

[9]

1DS18B20的复位时序

主机控制DS18B20完成任何操作之前必须先初始化,即主机发一复位脉冲(最短为

480µs的低电平),接着主机释放总线进入接收状态DS18B20在检测到I/0引脚上的上升沿

之后,等待15~60µs,然后发出存在脉冲(60~240)µs的低电平。如图3.2所示。

2DS18B20的读时序

DS18B20的读时序分为读0时序和读1时序两个过程。DS18B20的读时序是从主机把

单总线拉低后,在15秒之内就得释放单总线,从而让DS18B20把数据传输到单总线上。

DS18B20完成一个读时序的过程,至少需要60µs。如图3.3所示。

3.2 DS18B20的复位时序

8

3.3 DS18B20的读时序

3DS18B20的写时序

DS18B20的写时序同读时序一样,仍然分为写0时序和写1时序两个过程。

DS18B200时序和写1时序的要求不同当要写0时序时单总线要被拉低至少60µs

保证DS18B20能够在15µs45µs之间能正确地采样I/O总线上的“0”电平,当要写1时序

时,单总线被拉低之后,在15µs之内就得释放单总线。如图3.4所示。

3.4 DS18B20的写时序

DS18B20的通讯协议得知,主机控制DS18B20完成温度转换的过程必须经过三个

步骤:每一次读写之前都要对DS18B20进行复位,复位成功后发送一条ROM指令,最后

发送RAM指令从而对DS18B20进行预定的操作复位要求主CPU将数据线下拉500µs

然后释放,DS18B20收到信号后等待1660µs左右,然后发出60240µs的存在低脉冲,

CPU收到此信号表示复位成功。

9

1.4串口部分(让WIFI与电脑,单片机进行通讯)

TXD

SBUF控制门

TH1TL1

1

发送控制器

÷16

TI

去串口中断

≥1

A

T1溢出率

÷2

0

SMOD

接收控制器

移位寄存器SBUF

RI

RXD

80C51串行口的工作方式

方式1

方式110位数据的异步通信口。TXD为数据发送引脚,RXD为数据接收引脚,传

送一帧数据的格式如图所示。其中1位起始位,8位数据位,1位停止位。

D0

LSBMSB

1帧共10位

数据位8位

D7

1、方式1输出

写入SBUF

TXD

TI(中断标志)

方式1输入

起始

D0 D1 D2 D3 D4 D5 D6 D7

停止位

RXD

位采样脉冲

RI(中断标志)

起始

D0 D1 D2 D3 D4 D5 D6 D7

停止位

用软件置REN1接收器以所选择波特率的16倍速率采样RXD引脚电平检测到RXD

引脚输入电平发生负跳变时,则说明起始位有效,将其移入输入移位寄存器,并开始接收这

一帧信息的其余位。接收过程中,数据从输入移位寄存器右边移入,起始位移至输入移位寄

存器最左边时,控制电路进行最后一次移位。当RI=0,且SM2=0(或接收到的停止位为1

时,将接收到的9位数据的前8位数据装入接收SBUF,第9位(停止位)进入RB8,并置

RI=1,向CPU请求中断

11

始位1位,数据9位(含1位附加的第9位,发送时为SCON中的TB8,接收时为

RB8,停止位1位,一帧数据为11位。方式2的波特率固定为晶振频率的1/641/32

方式3的波特率由定时器T1的溢出率决定。

1.5WIFI模块:

使用接口:

1 电源接口

系统采用标准电源插座,外径5.5mm内径2.1mm的标准尺寸,内正外负,输入电压范围5~48V

电流350mA

2 指示灯

ID 名称 描述

1 Power 设备供电后亮

2 Ready 内部Linux系统启动完成后亮

3 Link 网络连接建立后亮

4 RXD 本设备的串口收到数据闪烁

5 TXD 本设备通过串口向外发送数据时闪烁

2.3 RS232接口

设备的串口为公口()RS232 电平(可以直接连电脑串口的电平),引脚顺序与计算机的

COM 口保持一致,与电脑连接时需要用交叉线(2-3 交叉,7-8 交叉,5-5 直连,7-8 可以

不接但是一定不能直连电脑否则可能导致工作不正常)一共有6 根线有定义其余悬空。

序号 名称 描述

2 RXD 设备数据接收引脚

3 TXD 设备数据发送引脚

GND 信号地

RTS 请求发送

CTS 清除发送

VCC 默认未使用,PCB 上有个焊盘跳线,需要

时可以将它与设备的电源输入正极连接,

用于给串口传感器供电或者外部通过串口

线给设备供电。

12

第三章 基于WiFi模块的无线传输的实现

2.1 WIFI模块的设置

13

14

2.2串口部分设置

2.3调试:

16

运行过程:

单片机首先运行,然后对DS18B20DS1302LCD1602进行初始化,接着对DS18B20

DS1302进行写设置,读取温度和时间,单片机处理数据,将其在LCD1602上显示,单片机

进行串口初始化并通过串口程序将温度和时间准备好,等到串口接收到相应的信号,在发送

数据。在程序内检测温度,若温度超过设定的值(值可通过终端修改),将发出报警信号。

蜂鸣器报警,待温度下降后(可通过终端打开降温系统),蜂鸣器关闭。

第五章 程序与框图

程序:

#include

#include

#include

#define uchar unsigned char

#define uint unsigned int

sbit DQ=P2^0;

sbit lcden=P3^4;

sbit lcdrs=P3^5;

sbit dula=P2^6;

sbit wela=P2^7;

//sbit led=P1^0;

sbit sclk=P1^4; //时钟信号线

sbit io=P1^5; //信号线

sbit ce=P1^6; //片选,也是RST

17

sbit buzz=P2^3;

sbit ledle=P2^5;

unsigned int temp,temp1,temp2,temper,xs,flag,a,s,cc;

unsigned char j;

uchar code day[]="1234567";

uchar shi,fen,miao,nian,yue,ri;

uchar cdflag;

uchar code number[]="";

sbit ACC0 = ACC^0; //定义寄存器ACC的零位

sbit ACC7 = ACC^7;

void delay1(unsigned int m)

{

unsigned int i,j;

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

for(j=110;j>0;j--);

}

void delay(unsigned int m)

{

while(m--);

}

/************************DS18B20

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

void Init_DS18B20()

{

unsigned char x=0;

DQ=1;

delay(8);

DQ=0;

delay(80);

DQ=1;

delay(4);

x=DQ;

delay(20);

}

uchar ReadOneChar()

unsigned char dat=0;

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

{

DQ=0;

dat>>=1;

DQ=1;

if(DQ)

dat|=0x80;

delay(4);

}

return(dat);

}

void WriteOneChar(unsigned char dat)

{

unsigned char i=0;

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

{

DQ=0;

DQ=dat&0x01;

delay(5);

DQ=1;

dat>>=1;

}

}

void duwendu()

{

unsigned char a=0;

unsigned char b=0;

Init_DS18B20();

WriteOneChar(0xcc);

WriteOneChar(0x44);

delay(5);

Init_DS18B20();

WriteOneChar(0xcc);

WriteOneChar(0xbe);

delay(5);

a=ReadOneChar();

b=ReadOneChar();

temp1=(b<<4)&0x7f; //去除高四位,即正负位

temp1+=(a&0xf0)>>4; //个位

temp2=a&0x0f; //小数

temp=((b*256+a)>>4); //整数

19

xs=temp2*0.0625*10;

temper=temp+xs;

}

/****************************************lcd

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

void write_com(uchar com)

{

lcdrs=0;

P0=com;

delay(5);

lcden=1;

delay(5);

lcden=0;

}

void write_data(uchar date)

{

lcdrs=1;

P0=date;

delay(5);

lcden=1;

delay(5);

lcden=0;

}

/******************************************************************** 串口

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

void ckinit()

{

TMOD=0x20;//设置定时器1为工作方式2

TH1=0xfa;

TL1=0xfa;

TR1=1;

REN=1; //允许串行接收

SM0=0;

SM1=1; //工作方式1

// SCON=0x50;

PCON=0x80; //波特率加倍

EA=1;

ES=1;

20

}

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

************************

LCD1602

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

void lcdinit()

{

dula=0;

wela=0;

ledle=0;

lcden=0;

write_com(0x38);

write_com(0x0e);

write_com(0x06);

write_com(0x01);

write_com(0x80+0x10);

}

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

************* 温度显示

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

void display()

{

write_com(0x80+0x40);

//write_data(number[temper/100]);

write_data(number[temp/10]);

write_data(number[temp%10]);

write_data('.');

write_data(number[xs%10]);

write_data('C');

}

void fas(unsigned char dat)

{

ES=0; //串口中断允许位

SBUF=dat;

while(!TI);

TI=0;

ES=1;

}

21

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

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

void fss(unsigned char *str)

{

uchar b,i;

b=strlen(str);

for(i=0;i

{

fas(*str);

str++;

}

}

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

DS1302写字节程序 *********************************/

void write_ds1302_byte(uchar add) //DS1302写一个字节数据

{

uchar i;

ACC = add;

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

{

io = ACC0; //就是把最低位的数据传输给IO

sclk = 1; //时钟拉高读走数据

sclk = 0; //时钟拉低允许数据变化

ACC = ACC >> 1; //ACC右移一位,然后又把最低的一位传送过去

}

}

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

DS1302读字节 *********************************/

uchar read_ds1302_byte() //DS1302一个字节

{

uchar i;

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

{

ACC = ACC >>1; //特别说明,读回来的数据是从最低位到最高位。

ACC7 = io; //把读回来的数据存到ACC寄存器的最高位,然后在移到最低位

sclk = 1;

sclk = 0;

}

22

return ACC;

}

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

DS1302写地址数据 *********************************/

void write_ds1302(uchar add, uchar dat)//写任意地址,任意数据

{

ce=0; //根据时序图编写

sclk=0;

ce=1; //片选打开

write_ds1302_byte(add);

write_ds1302_byte(dat);

io=0; //释放总线

sclk=0; //时钟释放

ce=0; //片选关闭

}

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

DS1302

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

uchar read_ds1302(uchar add) //读任意地址数据

{

uchar temp;

ce=0;

sclk=0;

ce=1; //片选打开

write_ds1302_byte(add);

temp=read_ds1302_byte();

sclk=0; //时钟释放

io=0; //释放总线

ce=0; //片选关闭

return temp;

}

23

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

************************

*************

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

void dis_sj()

{

uchar th,tl;

nian=read_ds1302(0x8d); //年寄存器

yue=read_ds1302(0x89); //月寄存器

ri=read_ds1302(0x87); //日寄存器

write_com(0x80+0x08); //设置时位置

th=nian>>4;

write_data(number[th]); //刷新年高位

tl=nian&0x0f;

write_data(number[tl]); //刷新年低位

write_data('-');

th=yue>>4;

write_data(number[th]);

tl=yue&0x0f;

write_data(number[tl]);

write_data('-');

th=ri>>4;

write_data(number[th]);

tl=ri&0x0f;

write_data(number[tl]);

shi=read_ds1302(0x85); //时寄存器

fen=read_ds1302(0x83); //分寄存器

miao=read_ds1302(0x81); //秒寄存器

write_com(0x80+0x48);

th=shi>>4;

write_data(number[th]); //刷新时高位

tl=shi&0x0f;

write_data(number[tl]); //刷新时低位

24

write_data(':');

th=fen>>4;

write_data(number[th]);

tl=fen&0x0f;

write_data(number[tl]);

write_data(':');

th=miao>>4;

write_data(number[th]);

tl=miao&0x0f;

write_data(number[tl]);

}

void fssj()

{

uchar th,tl;

th=nian>>4;

fas(number[th]);

tl=nian&0x0f;

fas(number[tl]);

fas('-');

th=yue>>4;

fas(number[th]);

tl=yue&0x0f;

fas(number[tl]);

fas('-');

th=ri>>4;

fas(number[th]);

tl=ri&0x0f;

fas(number[tl]);

fas(number[th]);

tl=miao&0x0f;

fas(number[tl]);

fss(" ");

fss("Temp: ");

}

void main()

{

ckinit();

lcdinit();

cc=30;

duwendu();

delay1(1000);

while(1)

{

duwendu();

dis_sj();

duwendu();

display();

if(flag==1)

{

if(a=='1')

{

fssj();

fas(number[temp/10]);

{

fas(number[cc/10]);

fas(number[cc%10]);

fas(' ');

fas('C');

}

if(a=='3')

{

cc++;

}

if(a=='4')

{

cc--;

}

if(a=='5')

{

P1=0xff;

ledle=1;

P1=0xfe;

delay1(5);

ledle=0;

}

if(a=='6')

{

P1=0xff;

ledle=1;

delay1(5);

ledle=0;

fas('C');

fas(' ');

fss("warnning");

delay1(2000);

if(a=='3')

{

cc++;

}

if(a=='4')

{

cc--;

}

}

else

{

buzz=1;

}

}

}

void ser() interrupt 4

{

RI=0; //接收标志位

flag=1;

a=SBUF; //接收的数据

开始

初始化LCD1602

DS18B20初始化

初始化串口

读取温度

LCD1602显示

等待命令

串口发送温度

发送成功

显示

完成

第四章 小结

在这次课程设计中,有些部分的功能能够顺利的实现,但也有部分代码无法实现其功能。

首先出现的问题是温度报警功能。因为DS18B20初始化结束后默认温度为85度,单片机读

取此温度后将直接进入报警程序,这点是不合理的。为了避免初始温度的影响,我在初始化

程序后,WHILE大循环前加一段代码,首先是读温度,此时温度为85度,然后延时一段时

间,在进入大循环,紧接着读温度,此时的温度就为正常温度,单片机正常工作。然后还有

一个问题,就是在通过串口发送一些报警字符时需要一个一个发送,这会使程序繁琐,减弱

程序的可读性,这时就需要一函数来发送字符串。然而这段函数需要用到指针和字符串中的

一些函数库,介于这方面我很少使用,所以对此没有太好的方法。经过半天的学习,我重温

C语言基础,运用STRLEN()函数完成了这函数的设计。

30