|
前两天做了一个ds18b20+lcm1602温度显示报警系统,将报告及源代码分享给大家学习,有什么问题还请指正
一、单片机简介
二、项目任务和要求
三、项目设计方案的总体设计框图
3.1硬件电路框图
3.2硬件电路概述
3.3主控电路
3.4显示电路
3.5报警温度调节电路
1、蜂鸣器
2、跑马灯
3.6温度传感器及DS18B20测温基本原理
3.7单片机硬件连接实物图
四、系统软件算法设计
五、总结与体会
附录
参考文献
单片机简介
1.实验系统简介
本次课设单片机实验系统采用nKDE-51 单片机实验系统,nKDE-51 单片机实验教学系统采用模块化设计,以方便学生自由组合功能,设计实验。整个实验系统包括六个功能模块,分别为CPU板、基本IO板、模拟总线接口IO口、扩展总线接口IO板,字符点阵LCD/大容量 flash/GPRS 模块板和uart/以太网及电话接口拓展板。本次课设需要CPU板,lcm1602模块,温度传感器模块,流水灯模块、蜂鸣器模块以及数码管模块,所以该实验板完全满足课设的需要,具体用的各部分图如下:
CPU板部分如图:
IO口板部分和模拟总线部分板如下图
2.系统资源及功能简介
(1) 单片机端口的引出
MCS-51 系列单片机共有 4 个独立的 8 位并行 I/O 端口分别为 P0、P1、P2 和 P3在 CPU板上各通过两个8 芯单排插针引出,可通过杜邦插座连接到其它模块或器件。
(2) CPU 工作频率的选择
nKDE-51 系统提供了四种常用的晶振频率分别是 11.0592MHz、12MHz、18.432MHz 和
22.1184MHz。用户可通过跳线JP1 和 JP2来选择系统晶振的频率。如果用户还需要其它的晶振频率,本系统预留了一个焊接晶振的位置X5可供使用。
(3) CPU 工作模式的选择
MCS-51 单片机的工作方式可分为端口工作方式不扩展总线和扩展总线模式。在扩展总线模式单片机的P0口通过ALE信号控制外部地址锁存器复用为地址总线低8位地址和数据 总线,P2口提供高8位地址,同时P3.6和P3.7作为W R和R D信号。而当单片机工作在端口方式下时P0~P3的每一位都可以作为独立的端口引脚使用。 在 nKDE-51 系统中当实验中不使用扩展总线时,单片机的端口可通过表 1-1 所列出的插座引出。如果单片机实验需要使用扩展总线用户可使用系统提供的 40 芯连接电缆将J9和JX1连接起来。此时 P0、P2 和 P3.6、P3.7 等引脚已作为系统总线使用,不要再将它们用作普通的 I/O。JX2 和 JX3 的各引脚和 JX1 的对应引脚相连可以通过它们将总线连接到其它模块上。
单片机的ISP及串行口
电路连接nKDE-51系统使用 STC 公司的STC 12C5A60S2 作为 CPU。该 CPU 兼容标准51内核自带 64K字节的 Flash 程序存储器支持通过串行口进行在系统编程ISP以及程序调试单片机的串行口通过双向自锁开关 SW2 选择连接到 9 芯孔型插座 COM1 RS232 接口用于和 计算机通信进行 ISP 或程序调试或者连接到 J4、J8 及 J9用于进行 I/O 端口及 RS485 通信等实验.计算机必须通过实验系统提供的9 芯串口延长电缆和 COM1 相连。 当SW2 弹起时单片机的串行口连接到 COM1 , 当 SW2 按下时单片机串行口连接到 J4、J8 及J9。
项目任务及要求
1. 单片机P0.0和DS18B20的数据端相连;(实验八)
2. 编写单片机通过IO端口模拟单总线时序控制DS18B20的程序,读出温度;(实验八)
3. 在1602字符点阵液晶显示模块上显示实测温度(实验七)
4.蜂鸣器报警功能;(+5)
5.串口显示功能;(+5)
6.发光二极管流水灯报警功能,随着温度超过警戒值范围改变,流水灯的速率进行改变。(+5)
7.计数器功能记录超过警戒值的次数,单个或者八位数码管显示 计数。(+5)
1-3为基本功能部分,4-6为增加功能部分
创新部分: 比如:音乐播放实现声音报警等。
三、项目设计方案的总体设计框图
3.1硬件电路框图
3.2硬件电路概述
单片机P0.0和DS18B20的数据端相连,在1602字符点阵液晶显示模块上显示实测温度,P0.7和蜂鸣器相连,P0其余口接LED1-6。
3.3主控电路
主控电路主要使用 STC 公司的STC 12C5A60S2作为 CPU,控制整个系统的工作。
3.4显示电路
LCD显示器是一种用液晶材料制成的液晶显示器,它具有体积小、功耗低、字迹清晰、无电磁辐射、寿命长等优点,1602 字符点阵式LCM共有两个显示行,每行可显示16个字符,为最常用的一种字符式LCM,显示控制器为HD44780,通过HD44100进行规模的扩展。
3.5报警温度调节电路
1、蜂鸣器
当温度超过30度时,蜂鸣器会发出间隔的报警声响。
2、跑马灯
在30度以上时,跑马灯会常亮,28-30度时会随着温度的升高而加快。
3.6温度传感器及DS18B20测温基本原理
DS18B20 数字温度传感器提供9位(二进制)温度读数指示器件的温度数据经单线接口和CPU交互,因此CPU和DS18B20之间只需一条信号线和地址线即可进行通信。
原理图如下:
3.7单片机硬件连接实物图
四、系统软件算法设计
主程序 main.c
#include <reg51.h>
#include <intrins.h>
#include <stdio.h>
#include "lcm16x2p.h"
#include "DS18B20.h"
#define OSC 11059200 //晶振频率
#define BAUDRATE 9600 //波特率
#define LCM_DB P2
sbit BUZ_CON = P0^7;
sbit LED =P0;
sbit LCM_BLC=P1^3;
void main(void)
{
unsigned char ucTH,ucTL,Ticks; //中断程序
unsigned int i;
unsigned char tmph,tmpl;
Temp t;
unsigned char strTemp[8]; //显示到屏幕的温度数据
LCM_BLC = 0; //开背光
TMOD = 0x21; //选择方式2作为波特率发生
SCON = 0x50; //串口方式1,允许中断
PCON |= 0x80; //SMOD=1
TL1 = 256 -(OSC/12/16/BAUDRATE);
TH1 = 256 -(OSC/12/16/BAUDRATE);
TR1 = 1; //启动定时器
TI = 1; //TI有效
//检测DS18B20温度传感器是否存在并复位传感器
if(DSReset())
printf("\r\Temp sensor ResetOK!");
else printf("\r\Temp Sensor Notready!");
while(1){
DSReset(); //复位传感器
Delay(12);
DSWriteByte(SkipROM); //跳读 省时
DSWriteByte(StartConvert); //温度转换
for(i=0;i<40000;i++);
DSReset();
Delay(12);
DSWriteByte(SkipROM);
DSWriteByte(ReadMemory); //读RAM程序
tmpl = DSReadByte();
tmph = DSReadByte();
printf("\r\nTemperature code HI=%02bX,LO=%02bX ",tmph,tmpl);
DSReadTemp(&t);
//准备输出到显示屏的数据
strTemp[0]=t.z/10+0x30; //十位
strTemp[1]=t.z%10+0x30; //个位
strTemp[2]='.'; //小数点
strTemp[3]=t.x/1000+0x30; //十分位
strTemp[4]=(t.x/100)%10+0x30; //百分位
strTemp[5]=(t.x/10)%10+0x30;//千分位
strTemp[6]=t.x%10+0x30; //万分位
strTemp[7]='C';
if(t.z>=30)
printf("\nWarning!!!Temperature= %d.%04d ",t.z,t.x) ; //大于30度温度警告
else
printf("\r\nTemperature = %d.%04d",t.z,t.x);
//小于26度LED灯全亮
if(t.z<26)
{
P0=0x00;
}
else
{
P0=0xff; //灯灭
}
//大于28度流水灯循环(慢)
if(t.z>=28)
{
BUZ_CON=1;
P0=0xfd;
LCMDelay(60);
P0=0xfb;
LCMDelay(60);
P0=0xf7;
LCMDelay(60);
P0=0xdf;
LCMDelay(60);
//大于29度流水灯循环(快)
if(t.z>=29)
{
P0=0xfd;
LCMDelay(10);
P0=0xfb;
LCMDelay(10);
P0=0xf7;
LCMDelay(10);
P0=0xdf;
LCMDelay(10);
P0=0xbf;
LCMDelay(10);
}
//大于30度灯全亮。蜂鸣器响
if(t.z>=30)
{
BUZ_CON=0;
LCMDelay(100);
P0=0x00;
}
}
else{
BUZ_CON=1;
}
//初始化
EA = 0; // 停止所有中断
Ticks = 0;
ucTH =(65536-OSC/12/20)/256; // 计算 50ms 定时的时间常数
ucTL =(65536-OSC/12/20)%256;
TMOD = 0x21; // T0:模式 1,16 位定时器
TH0 = ucTH;
TL0 = ucTL;
ET0 = 1; // T0 允许中断
TR0 = 1; // 启动定时器
EA = 1; // 打开总中断允许
//输出数据到显示屏
LCMInit(); //初始化LCM显示器
LCMClear(); //清屏
if(t.z>=30){
LCMDisplayString(0,0,"TempWarning!!!"); //大于29度警告
LCMDisplayString(1,0,"Temp:");
LCMDisplayString(1,6,strTemp);
}
else{
LCMDisplayString(0,0,"Temperature:");
LCMDisplayString(1,0,strTemp);
}
//闪烁(刷新)
for(i = 0; i < 16;i++)
LCMBlink(0,i,BLINK);
for(i = 0; i < 16;i++)
LCMBlink(1,i,BLINK);
}
}
子程序ds18b20.h文件
#ifndef __DS18B20H__
#define __DS18B20H__
#define ReadROM 0x33
#define MatchROM 0x55
#define ReadMemory 0xBE
#define SkipROM 0xCC
#define SearchROM 0xF0
#define StartConvert 0x44 //变换指令
typedef struct{
int z; //整数部分
int x; //小数部分
}Temp;
extern unsigned char ucTH,ucTL,Ticks; //外部引用
void Delay(unsigned int);
bit DSReset(void);
void DSWriteByte(char);
unsigned char DSReadByte(void);
void DSReadTemp(Temp *t);
#endif
ds18b20.c文件
#include "DS18B20.h"
#include <reg51.h>
#include <intrins.h>
sbit DQ = P0^0;
/*
Delay
通过循环计时
参数:int,表示要延时的 毫秒 数
*/
void Delay(unsigned int i)
{ i=i*12;
while(i--);
}
/*
DSReset
复位DS18B20并返回是否存在
*/
bit DSReset(void)
{
bit x;
DQ = 1;
Delay(8);
DQ = 0; // 主机拉低总线
Delay(80); // 延时约 500 个机器周期
DQ = 1; // 主机释放总线
Delay(8); // 延时 60 个机器周期
x = DQ;
Delay(20);
if(x == 0)
return 1;
else return 0;
}
/*
DSWriteByte
向 DS18820 写入一个字节
*/
void DSWriteByte(unsigned char c)
{
unsigned char ic;
for( ic = 0; ic < 8;ic++ )
{
DQ = 0; //主机拉低总线,开始写位
DQ = c&0x01;
Delay(5); //延时60个机器周期
DQ = 1; //释放总线
c >>= 1;
}
}
/*
DSReadByte
从温度传感器读出一个字节
返回:读出的字节
*/
unsigned char DSReadByte(void)
{
unsigned char c,ic;
c = 0;
for(ic = 0; ic < 8;ic++)
{
DQ = 0;
c >>= 1; //右移
DQ = 1;
if(DQ )
c |= 0x80;
Delay(4);
}
return c;
}
/*
DSReadTemp
读出温度
参数:温度(由整数和小数部分构成)
*/
void DSReadTemp(Temp *t)
{
unsigned char tmpl,tmph;
DSReset();
Delay(12);
DSWriteByte(SkipROM);
DSWriteByte(StartConvert);
DSReset();
Delay(12);
DSWriteByte(SkipROM);
DSWriteByte(ReadMemory);
tmpl = DSReadByte();
tmph = DSReadByte();
t->z =(int)((tmph&0x07)<<4 | (tmpl&0xf0)>>4);
t->x =(int)((tmpl&0x0f)*625);
}
/*
T0ISR
50ms中断服务程序
*/
void T0ISR(void) interrupt 1
{
unsigned char ucTH,ucTL,Ticks;
TH0 = ucTH;
TL0 = ucTL;
TR0 = 1;
Ticks ++;
if(Ticks == 20)
{
Ticks = 0;
}
}
lcm16x2p.h文件
#ifndef LCM16X2_H
#define LCM16X2_H
#define BUSYFLAG 0x80
#define BLINK 0X01
#define NOBLINE 0X00
unsigned char LCMReadState(void);
void LCMDelay(int);
void LCMWriteData(unsigned char);
void LCMWriteCmd(unsigned char);
void LCMClear(void);
void LCMInit(void);
void LCMGotoXY(unsigned char,unsigned char);
void LCMDisplay(unsigned char,unsigned char,unsigned char);
void LCMDisplayString(unsigned char,unsigned char,unsigned char*);
void LCMBlink(unsigned char,unsigned char,unsigned char);
#endif
llcm16x2p.c文件
#include <reg51.h>
#include <intrins.h>
#include "LCM16X2P.H"
#define LCM_DB P2
sbit LCM_RS = P1^0;
sbit LCM_RW = P1^1;
sbit LCM_E = P1^2;
sbit LCM_BLC = P1^3;
unsigned int data DelayConst = 140;
// 延时程序
void LCMDelay (int ms)
{
unsigned int i,cnt;
cnt = DelayConst * ms*12;
for(i=0;i<cnt;i++);
}
//查询LCM忙的标志
unsigned char LCMReadState(void)
{
unsigned char state;
LCM_E = 0;
LCM_RS = 0;
LCM_RW = 1;
LCM_E = 1;
_nop_();
_nop_();
state = LCM_DB;
LCM_E = 0;
return state;
}
//clear qingpin
void LCMClear(void)
{
LCMDelay(12);
LCM_E = 0;
LCM_RS = 0;
LCM_RW = 0;
LCM_DB = 0x01;
LCM_E = 1;
_nop_();
_nop_();
LCM_E = 0;
LCMDelay(12);
}
//writecmd xierukongzhizi
void LCMWriteCmd(unsigned char cmd)
{
LCMDelay(1);
LCM_E = 0;
LCM_RS = 0;
LCM_RW = 0;
LCM_DB = cmd;
LCM_E = 1;
_nop_();
_nop_();
LCM_E = 0;
}
//write data xierushuju
void LCMWriteData(unsigned char dc)
{
while (LCMReadState()&BUSYFLAG);
LCM_RS = 1;
LCM_RW = 0;
LCM_DB = dc;
LCM_E = 1;
_nop_();
_nop_();
LCM_E = 0;
}
// init chushihua
void LCMInit(void)
{
LCMDelay(720);
LCMWriteCmd(0x38);
LCMDelay(60);
LCMWriteCmd(0x38);
LCMDelay(12);
LCMWriteCmd(0x38);
while(LCMReadState()&BUSYFLAG);
LCMWriteCmd(0x08);
while(LCMReadState()&BUSYFLAG);
LCMWriteCmd(0x01);
while(LCMReadState()&BUSYFLAG);
LCMWriteCmd(0x06);
while(LCMReadState()&BUSYFLAG);
LCMWriteCmd(0x0e);
while(LCMReadState()&BUSYFLAG);
}
//gotoxy yidongguangbiaodao x hang y lie
void LCMGotoXY(unsigned char x, unsigned char y)
{
unsigned char cmd;
if(x==0)
{
cmd = 0x80|y;
}
else
{
cmd =0x80 | 0x40 |y ;
}
LCMWriteCmd(cmd);
while(LCMReadState() & BUSYFLAG);
}
//LCMDISPLAYchar zhidingweizhixianshizifu
void LCMDisplayChar(unsigned char x, unsigned char y,unsigned char ch)
{
LCMGotoXY(x,y);
LCMWriteData(ch);
}
//xianshizifuchan
void LCMDisplayString(unsigned char x,unsigned char y,unsigned char* str)
{
unsigned char ptr;
ptr=0;
while (*(str+ptr)!=0)
{
LCMDisplayChar(x,(y+ptr),*(str+ptr));
ptr++;
}
}
//LCMBLINK zifushanshuo
void LCMBlink(unsigned char x,unsigned char y, unsigned char cmd)
{
LCMGotoXY(x,y);
if(cmd == BLINK)
{
LCMWriteCmd(0x0d);
}
else
{
LCMWriteCmd(0x0c);
}
}
五、总结与体会
经过一周的学习与努力,温度显示系统的设计终于完成了,真正的学到了东西。学习了单片机这门,感觉是有点难。也不明白整个学习过程是怎样过来得,但是时间不等人。但是在学习中,我才发现学习单片机不仅仅仅需要软件的知识,还需要硬件的知识。没有相应的硬件知识,我连单片机怎样和电脑相连都不明白,我为我当初的想法感到羞愧。单片机是一门很好的学问,需要我去钻研它。一转眼,一个学期又进尾声了,本学期的单片机综合设计也在一周内完成了。
说起设计,我认为最重要的就是做好设计的预习,认真的研究老师给的题目,其次,老师对实验的讲解要一丝不苟的去听去想,因为只有都明白了,做起设计就会事半功倍,如果没弄明白,就迷迷糊糊的去做设计,到头来一点收获也没有。最后,要重视程序的模块化,修改的方便,也要注重程序的调试,掌握其方法。在享受我们成果之时,不得不感慨单片机的重要性与高难度性,所以为期一周的单片机设计没有浪费我我们学到了很多知识,也让我对单片机有了更深一步的了解,虽然最后结果是出来了,可这与老师的精心指导是分不开的她引导我们的思路,本来一窍不通的我经过老师的点拨基本上通了,所以老师是功不可没的。总而言之,单片机设计对于我有很大的帮忙,我从中受益匪浅。
|
|