NORTH CHINA UNIVERSITY OF SCIENCE AND TECHNOLOGY
单片机课程设计报告
学生姓名: 学 号: 学 院: 信息工程学院 专业班级: 12电信4班 指导教师:
2015年6月21日
一、课程设计目的
PIC单片机课程设计报告
本课程设计是在《PIC单片机原理及应用》及《单片机C语言编程》课程的基础上,通过硬件设计、软件编程及仿真调试的实践,进一步掌握PIC单片机的应用方法,熟练掌握PICC C语言程序的编写与调试,是毕业设计前的一次重要实践,为今后走上工作岗位打下坚实的单片机应用基础。
二、设计题目及要求
2.1 设计题目:
基于PIC16F877单片机的多功能电子时钟 2.2 功能实现:
实时时钟显示,时间可调;实时温度显示,并具有超限报警功能。输出显示采用LCD1602或LED七段数码显示器。 2.3 设计要求:
自己设计硬件和程序编程,画出完整的电路原理图,用Multisim或Proteus仿真,最终可实现脱机运行。
三、设计原理说明
3.1 时钟模块
DS1307是美国DALLAS公司推出的I2C总线接口实时时钟芯片,它可独立于CPU 工作,不受CPU主晶振及其电容的影响,且计时准确,月累积误差一般小于10秒。芯片还具有主电源掉电情况下的时钟保护电路,DS1307的时钟靠后备电池维持工作,拒绝CPU对其读出和写入访问。同时还具有备用电源自动切换控制电路,因而可在主电源掉电和其它一些恶劣环境场合中保证系统时钟的定时准确性。
DS1307具有产生秒、分、时、日、月、年等功能,且具有闰年自动调整功能。同时,DS1307芯片内部还集成有一定容量、具有掉电保护特性的静态RAM,可用于保存一些关键数据。 3.2 显示模块
如用LCD1602作为显示设备,要求显示屏分两行显示,第一行显示日期(年-月-日)和星期,第二行显示时间(时:分:秒)和温度。显示秒由00一直加到59,分钟数也由00加到59,小时采用24小时制,由00加到23,如此循环显示。
按键用来作为时间调整。要求至少设计4个按键,按键1作为设置键;按键2、按键3分别为增加、减少键,在设置键按下时,此两个按键方有效;按键4是确定键,在设置键按下时方才有效。 3.4 温度采集模块
DS18B20是美国DALLAS公司推出的单总线数字温度传感器。DS18B20内部集成了温敏元件、数据转换芯片、存储器芯片和计算机接口芯片等多功能模块。其主要技术特点有:具有独特的单线接口方式;可以通过数据线供电,具有超低功耗工作方式;测温范围为-55℃~125℃,测温精度为0.5℃;温度转换精度9~12位可编程,直接将温度转换值以二进制数码的方式串行输出。
四、硬件原理图
4.1电子时钟原理图
4.3显示模块
4.5温度采集模块
4.6电路仿真图 4.6.1开机动画
4.6.2实时时钟显示,实时温度显示
4.6.3时间可调,报警温度可调
4.6.4闹钟功能
4.6.5超限报警
五、软件设计
PIC单片机课程设计报告
5.1流程图
5.2源程序 5.2.1程序清单
5.2.2主程序代码 5.2.2.1主函数.c文件
PIC单片机课程设计报告
#include #include"main.h"
uchar line1_data[]={"Electronic Clock"}; uchar line2_data[]={" Powered By Me "};
void main(void) {
ADCON1=0x06; //基本配置PORTA,PORTE设定为数字端口 TRISD=0; //PORTD设置为输出 TRISB0=0; //PORTB0设置为输出
RB0=0; //初始化蜂鸣器RB0(不响) TRISE0=0; TRISE1=0; TRISE2=0;
__delay_ms(10);
LCD_init();
Init_ds1302(); //初始化ds1302 Key_init();//按键端口初始化
LCD_write_str(0,0,line1_data);//在第0行显示字符串 LCD_write_str(0,1,line2_data);//在第一行显示字符串 __delay_ms(3000); LCD_clr(); while(1) {
Display_Time();//显示时间 Display_wendu();//显示温度 KeyScan();//按键扫描函数 if(temp1>warning_temp) {
RB0=1;
__delay_ms(400); RB0=0;
__delay_ms(400); } else {RB0=0;}
if((hour==alarm_hour)&&(min==alarm_min)) {
} } RB0=1; __delay_ms(200); RB0=0; __delay_ms(200); } else {RB0=0;} PIC单片机课程设计报告
5.2.2.2主函数.h文件
#ifndef __MAIN_H__
#define __MAIN_H__
#define __STAT_BACKWARD_COMPATIBILITY //兼容PICC低版本
#include
#include"all.h"
#include"lcd1602.h"
#include"ds1302.h"
#include"ds18b20.h"
#include"key.h"
__CONFIG(HS&WDTDIS&LVPDIS&PWRTEN);
#endif
5.2.3液晶显示屏LCD1602代码
5.2.3.1液晶显示屏LCD1602.C文件
#include"lcd1602.h"
/*******lcd清屏函数******/
void LCD_clr()
{
LCD1602_write_com(0x01);
__delay_ms(5);
}
/*********光标定位函数。x为显示列,y为显示行********/
void LocateXY(uchar x,uchar y)
{
if(y==0)
{
LCD1602_write_com(0x80+x);
}
else
{
LCD1602_write_com(0xC0+x);
}
}
//***************特定位置写字符*********************
void LCD_write_str(uchar x,uchar y,uchar *s)
{
LocateXY(x,y);
while(*s)
{
LCD1602_write_dat(*s);
s++;
}
}
//****************特定位置显示数值********************
void LCD_write_data(uchar x,uchar y,uchar data)
{
LocateXY(x,y);
LCD1602_write_dat(data/10 +48); //将数值转换成其对应的ASIC码值,相当于以字符形式输出
LCD1602_write_dat(data%10+ 48); //因为0的ASIC码值为48
}
//****************LCD1602初始化函数********************
void LCD_init(void)
{
rs=0;
rw=0;
en=0;
LCD1602_write_com(0x01); //清零
LCD1602_write_com(0x38); //设置为16位两行字符,8位数据总线
LCD1602_write_com(0x0c); //显示开关,关闭光标,没有闪烁
LCD1602_write_com(0x06); //设置增量方式,显示移位方式
}
//******************读1602读忙状态**********************
void LCD1602_check_busy(void)
{
uint i=20000;
dport_in; //端口设为输入
rs=0;
rw=1;
en=1;
while((0x80&dport)&&(i>0))
{
i--;
}
en=0;
dport_out;
}
//******************向1602写数据**********************
void LCD1602_write_dat(uchar lcd_dat)
{
LCD1602_check_busy();
rs=1;
rw=0;
en=1;
dport=lcd_dat;
en=0;
}
//****************向1602写string数据******************
void LCD1602_write_string(const uchar *cy)
{
while(*cy)
{
LCD1602_check_busy();
rs=1;
rw=0;
en=1;
dport=*cy;
en=0;
cy++;
}
}
//******************向1602写指令**********************
void LCD1602_write_com(uchar lcd_com)
{
LCD1602_check_busy();
rs=0;
rw=0;
en=1;//下降沿把数据写进出
dport=lcd_com;
en=0;
}
5.2.3.1液晶显示屏LCD1602.H文件 PIC单片机课程设计报告
#ifndef _LCD1602_H_
#define _LCD1602_H_
#include
#include"all.h"
#define dport PORTD //定义数据口
#define dport_in TRISD=0xff //PD端口设为输入
#define dport_out TRISD=0x00 //PD端口设为输出
#define rs RE0 //并行数据/控制字选择 H:数据 L:控制字 串行片选信号
#define rw RE1 //并行读/写选择 H:读 L:写 串行数据信号
#define en RE2 //并行读写使能 H有效,下降沿锁定数据 串行时钟信号
//*************** 函数定义 ******************
void LCD1602_check_busy(void); //读1602读忙状态
void LCD1602_write_dat(uchar lcd_dat);//向1602写数据********
void LCD1602_write_string(const uchar *cy);//向1602写string数据
void LCD1602_write_com(uchar lcd_com);//向1602写指令
void LocateXY(uchar x,uchar y);//光标定位函数。x为显示列,y为显示行
void LCD_init(void); //LCD1602初始化函数***********
void LCD_write_data(uchar x,uchar y,uchar data);//特定位置显示数值****** void LCD_write_str(uchar x,uchar y,uchar *s);//特定位置写字符********
void LCD_clr(); //lcd清屏函数*************
#endif
5.2.4时钟芯片DS1302代码
5.2.4.1时钟芯片DS1302.C文件
#include"ds1302.h"
//***********延时函数*************
void delay1()
{
int i;
for(i=100;i--;);
}
/******** 从ds1302读一个字节数据******/
uchar read_byte(void)
{
uchar i,dat=0;
IO_CLR;
for(i=0;i
{
SCK_CLR;
if(io)
{dat=dat|0x80;}
else
{dat=dat&0x7f;}
SCK_SET;
dat=dat>>1;
}
IO_OUT;
SCK_CLR;
return dat;
}
/***** 向ds1302写一个数据******/
void write_byte(uchar dat)
{
uchar i;
for(i=0;i
{
IO_CLR;
SCK_CLR;
if(dat&0x01)
{
IO_SET;
}
else
{
IO_CLR;
}
SCK_SET;
dat>>=1;
}
SCK_CLR;
}
/***** 从ds1302的指定地址读一个字节数据******/
uchar read_ds1302(uchar addr)
{
char data,data1,data2;
RST_CLR;
SCK_CLR;
delay1();
delay1();
write_byte(addr);
data=read_byte();
SCK_CLR;
RST_CLR;
data1=data/16;
data2=data%16;
data=data2+data1*10;
return data;
}
/***** 往ds1302的指定地址写一个字节数据******/
void write_ds1302(uchar addr,uchar data)
{
RST_CLR;
SCK_CLR;
delay1();
RST_SET;
delay1();
write_byte(addr);
SCK_CLR;
write_byte(data);
SCK_CLR;
RST_CLR;
}
/***** 初始化ds1302函数******/
void Init_ds1302()
{
RST_CLR;
SCK_CLR;
RST_OUT;
SCK_OUT;
}
/***** 写ds1302时间函数******/
void Set_Time(char year,char month,char day,char hour,char min,char sec,char week) {
write_ds1302(0x8E,0x00); //根据写状态寄存器命令字,写入不保护指令
write_ds1302(0x80,sec/10*16+sec%10); //根据写秒寄存器命令字,写入秒的值 write_ds1302(0x82,min/10*16+min%10); //根据写分寄存器命令字,写入分的值 write_ds1302(0x84,hour/10*16+hour%10); //根据写小时寄存器命令字,写入小时的值
write_ds1302(0x86,day/10*16+day%10); //根据写日寄存器命令字,写入日的值 write_ds1302(0x88,month/10*16+month%10); //根据写月寄存器命令字,写入月的
值
write_ds1302(0x8c,year/10*16+year%10); //根据写年寄存器命令字,写入年的值 write_ds1302(0x8a,week/10*16+week%10); //根据写星期寄存器命令字,写入星期的值
write_ds1302(0x8e,0x80); //根据写状态寄存器命令字,写入写保护指令 }
/***** 读ds1302时间函数******/
void Get_Time()
{
write_ds1302(0x8e,0x00);//控制命令。wp=0,允许写操作
write_ds1302(0x90,0xab);//涓流充电控制
sec=read_ds1302(0x81); //读取秒
min=read_ds1302(0x83); //读取分
hour=read_ds1302(0x85);//读取时
day = read_ds1302(0x87);//读取日
month = read_ds1302(0x89);//读取月
year = read_ds1302(0x8D);//读取年
week = read_ds1302(0x8B); //读取星期
}
/***** 显示时间函数******/
void Display_Time()
{
Get_Time();
LCD_write_data(1,0,year); //显示年
LCD1602_write_dat('-');
LCD_write_data(4,0,month); //显示月
LCD1602_write_dat('-');
LCD_write_data(7,0,day); //显示日
Write_Week(10,0,week); //显示星期
LCD_write_data(1,1,hour); //显示时
LCD1602_write_dat(':');
LCD_write_data(4,1,min); //显示分
LCD1602_write_dat(':');
LCD_write_data(7,1,sec); //显示秒
}
//**********星期显示函数***********
void Write_Week(int i,int j,uchar x)
{
LCD_write_str(i,j,xinqi[x]);
}
5.2.4.1时钟芯片DS1302.H文件
#ifndef _DS1302_H_
#define _DS1302_H_
#include
#include"all.h"
#include"lcd1602.h"
#define sclk RA1
#define io RA0
#define reset RA2
#define reset_IO TRISA2
#define sclk_IO TRISA1
#define io_IO TRISA0
/***** 复位脚******/
#define RST_CLR reset=0
#define RST_SET reset=1
#define RST_IN reset_IO=1
#define RST_OUT reset_IO=0
/***** 双向数据******/
#define IO_CLR io=0
#define IO_SET io=1
#define IO_IN io_IO=1
#define IO_OUT io_IO=0
/***** 时钟信号******/
#define SCK_CLR sclk=0
#define SCK_SET sclk=1
#define SCK_IN sclk_IO=1
#define SCK_OUT sclk_IO=0
int year,month,day,hour,min,sec,week;
int alarm_hour=13,alarm_min=30;//定义闹铃时间和闹铃分钟
uchar xinqi[8][4]={" ","SUN","MON","TUS","WED","THU","FRI","SAT"};
void delay1();//延时函数
void write_byte(uchar inbyte); //向ds1302写一个数据
uchar read_byte(void); //从ds1302读一个字节数据
void write_ds1302(uchar addr,uchar data);//往ds1302的指定地址写一个字节数据 uchar read_ds1302(uchar addr);//从ds1302的指定地址读一个字节数据
void Write_Week(int i,int j,uchar x);//星期显示函数
void Init_ds1302(void); //初始化ds1302函数**********
void Get_Time();//读ds1302时间函数******
void Set_Time(char year,char month,char day,char hour,char min,char sec,char week);//写ds1302时间函数******
void Display_Time();//显示时间函数******
#endif
5.2.5温度传感器DS18B20代码
5.2.5.1温度传感器DS18B20.C文件 PIC单片机课程设计报告
#include"ds18b20.h"
//---------------------------------------
//名称:复位DS18B20函数
//---------------------------------------
unsigned char Reset(void)
{
unsigned char k;
DQ_DIR=0; //设置RA4位输出口
DQ=0; //拉低DQ总线开始复位
__delay_us(870); //保持DQ低大约870uS,符合不低于480US的要求
DQ_DIR=1; //设置RA4为输入口,以释放总线等电阻拉高总线 __delay_us(78); //大约78uS后,判断是否复位成功
if(DQ==0) //读出数据并保存
k=0;
else
k=1;
__delay_us(400); //维持约400US,符合总读时隙不低于480US的要求
return k; //k=0为复位成功,k=1为复位失败
}
//---------------------------------------
//名称:写字节函数
//---------------------------------------
void WriteByte(unsigned char dat)
{
unsigned char j;
for(j=0;j
{
if(dat&0x01) //如果写1
{
DQ_DIR=0; //设置RA4位输出口
DQ=0; //拉低
NOP(); //维持6US,符合大于1US小于15US的规范
NOP(); //维持6US,符合大于1US小于15US的规范 NOP(); //维持6US,符合大于1US小于15US的规范
NOP(); //维持6US,符合大于1US小于15US的规范 NOP(); //维持6US,符合大于1US小于15US的规范
NOP(); //维持6US,符合大于1US小于15US的规范
DQ_DIR=1; //设置RA4为输入口,以释放总线等电阻拉高总线 __delay_us(63); //维持约63US,符合不低于60US的要求
PIC单片机课程设计报告 }
else //如果写0
{
DQ_DIR=0; //设置RA4位输出口
DQ=0; //拉低
__delay_us(63); //维持约63US,符合不低于60US的要求 DQ_DIR=1; //设置RA4为输入口,以释放总线等电阻拉高总线
NOP(); //维持2US,符合大于1US的规范
NOP(); //维持2US,符合大于1US的规范 }
dat=dat>>1; //写入字节右移1位
}
}
//---------------------------------------
//名称:读字节函数
//---------------------------------------
unsigned char ReadByte(void)
{
unsigned char j,buf=0;
for(j=1;j
{
buf=buf>>1; //接收前,先将接收缓冲区右移
DQ_DIR=0; //设置RA4位输出口
DQ=0; //拉低
NOP(); //维持2US,符合大于1US小于15US的规范 NOP(); //维持2US,符合大于1US小于15US的规范
DQ_DIR=1; //设置RA4为输入口,以释放总线等电阻拉高总线 准备读
NOP(); //维持6US,符合大于1US小于15US的规范 NOP(); //维持6US,符合大于1US小于15US的规范 NOP(); //维持6US,符合大于1US小于15US的规范 NOP(); //维持6US,符合大于1US小于15US的规范 NOP(); //维持6US,符合大于1US小于15US的规范
NOP(); //维持6US,符合大于1US小于15US的规范 if(DQ==1) buf|=0x80; //读出1位数据保存于buf中最高位
__delay_us(52); //维持约52US,符合总读时隙不低于60US的要求 }
return buf; //退出的同时将接收缓冲区参数返回 }
//---------------------------------------
//名称:温度转换函数
//---------------------------------------
unsigned char Convert(void)
{
if(Reset()==0) //如果复位成功
{
__delay_us(1000); //延时约1000US
WriteByte(0xcc); // 跳过多器件识别
WriteByte(0x44); // 启动温度转换
return 1;
}
else
{
return 0;
}
}
//*************读温度函数*************
void ReadFlash(void)
{
unsigned char Lsb,Msb;
if(Reset()==0)
{
__delay_us(1000); //延时约1000US
WriteByte(0xcc); // 跳过多器件识别
WriteByte(0xbe); // 读暂存器
Lsb=ReadByte(); // 低字节
Msb=ReadByte(); // 高字节
temp2=Lsb&0x0f; //LSB的低4位为小数部分
temp1=(Lsb>>4)|(Msb
}
else
{
temp1=0;
temp2=0;
}
}
//***********显示当前温度**************
void Display_wendu(void)
{
unsigned char buf;
if(Convert()==1) //启动转换
{
ReadFlash(); //读取温度
if(temp1>99) temp1=99;
if(temp2>15) temp2=0;
buf=temp1;
LCD_write_data(10,1,buf); //温度整数部分
LCD1602_write_dat('.'); //.
buf=table[temp2&0x0f];
buf+=0x30;
LCD1602_write_dat(buf); //温度小数部分
LCD1602_write_dat(0xdf); //.
LCD1602_write_dat(0x43); //C
}
}
//***********显示buf温度**************
void Display_temp(uchar buf)
{
LCD_write_data(10,1,buf); //温度报警温度整数部分
LCD1602_write_dat('.'); //.
LCD1602_write_dat(0x30); //温度小数部分0
LCD1602_write_dat(0xdf); //.
LCD1602_write_dat(0x43); //C
}
5.2.5.1温度传感器DS18B20.H文件
#ifndef _DS18B20_H_
#define _DS18B20_H_
#include
#include"all.h"
#include"lcd1602.h"
#define DQ_DIR TRISC0 //控制DS18B20的DQ端
#define DQ RC0 //控制DS18B20的DQ端
unsigned char temp1=0,temp2=0;//当前温度缓存
unsigned char warning_temp=50;//设置报警温度
const unsigned char table[16]={0,0,1,2,2,3,4,4,5,6,6,7,8,8,9,9};
void Display_wendu(void); //显示当前温度函数*********
void Display_temp(uchar buf); //显示buf温度函数*********
void ReadFlash(void) ; //读温度函数
unsigned char Convert(void) ; //温度转换函数
unsigned char ReadByte(void); //读字节函数
void WriteByte(unsigned char dat); //写字节函数
unsigned char Reset(void); //复位DS18B20函数
#endif
5.2.6独立按键代码
5.2.6.1独立按键.C文件 #include"key.h"
//**********按键端口初始化***********
void Key_init()
{
TRISB=0B00011110; //初始化RB4-RB1为输入方向
PORTB=0B11111110; //初始化RA5-RA0数值
}
//**********按键扫描函数*************
void KeyScan()
{
uchar i=0;
int warning_temp_buf=0; //报警温度缓存
int alarm_hour_buf=0,alarm_min_buf=0; //闹钟时间缓存
int year_buf,month_buf,day_buf,hour_buf,min_buf,sec_buf,week_buf;//设置时间缓存
if(SET==0)
{
while(!SET);//松手检测
warning_temp_buf=warning_temp; //读回报警温度设置值
Display_temp(warning_temp_buf); //显示当前报警设置
year_buf=year; //读回当前时间
month_buf=month; //***********
day_buf=day; //***********
hour_buf=hour; //***********
min_buf=min; //***********
sec_buf=sec; //***********
week_buf=week; //***********
alarm_hour_buf=alarm_hour; //读回闹钟小时设置
alarm_min_buf=alarm_min; //读回闹钟分钟设置
LCD1602_write_com(0x0f);//显示光标并闪烁
LCD1602_write_com(0x80+2);//光标移动到年位置
i=0; //清零标志位
while(1)
{
if(SET==0)
{
while(!SET);//松手检测
i++; //标志加一
{ LCD1602_write_com(0x0c); //光标不显示 LCD_clr(); break; } switch(i) //检测标志位并移动光标 { case 0: LCD1602_write_com(0x80+2);//光标移动到年位置 break; case 1: LCD1602_write_com(0x80+5);//光标移动到月位置 break; case 2: LCD1602_write_com(0x80+8);//光标移动到日位置 break; case 3: LCD1602_write_com(0x80+13);//光标移动到星期位置 break; case 4: LCD1602_write_com(0xc0+2);//光标移动到小时位置 break; case 5: LCD1602_write_com(0xc0+5);//光标移动到分钟位置 break; case 6: LCD1602_write_com(0xc0+8);//光标移动到秒位置 break; case 7: LCD1602_write_com(0xc0+11);//光标移动到温度位置 break; case 8: LCD_clr(); //清屏 LocateXY(0,0); LCD1602_write_string(" Alarm Clock "); LCD_write_data(5,1,alarm_hour_buf); //显示时 LCD1602_write_dat(':'); LCD_write_data(8,1,alarm_min_buf); //显示分 LCD1602_write_com(0xc0+6);//光标移动到小时位置 break; case 9: LCD1602_write_com(0xc0+9);//光标移动到分钟位置
default: LCD1602_write_com(0x80+2);//光标移动到年位置(出错复位) break; } } if(UP==0) { while(!UP);//松手检测 switch(i) //检测标志位并增加对应的值 { case 0: year_buf++; if(year_buf>99)year_buf=0; LCD_write_data(1,0,year_buf); //显示年 LCD1602_write_com(0x80+2);//光标移动到年位置 break; case 1: month_buf++; if(month_buf>12)month_buf=1; LCD_write_data(4,0,month_buf); //显示月 LCD1602_write_com(0x80+5);//光标移动到月位置 break; case 2: day_buf++; if(day_buf>31)day_buf=1; LCD_write_data(7,0,day_buf); //显示日 LCD1602_write_com(0x80+8);//光标移动到日位置 break; case 3: week_buf++; if(week_buf>7)week_buf=1; Write_Week(10,0,week_buf); //显示星期 LCD1602_write_com(0x80+13);//光标移动到星期位置 break; case 4: hour_buf++; if(hour_buf>23)hour_buf=0; LCD_write_data(1,1,hour_buf); //显示时 LCD1602_write_com(0xc0+2);//光标移动到小时位置 break; case 5: min_buf++; if(min_buf>59)min_buf=0;
LCD1602_write_com(0xc0+5);//光标移动到分钟位置 break; case 6: sec_buf++; if(sec_buf>59)sec_buf=0; LCD_write_data(7,1,sec_buf); //显示秒 LCD1602_write_com(0xc0+8);//光标移动到秒位置 break; case 7: warning_temp_buf++; if(warning_temp_buf>99)warning_temp_buf=0; Display_temp(warning_temp_buf); //显示报警温度 LCD1602_write_com(0xc0+11);//光标移动到温度位置 break; case 8: alarm_hour_buf++; if(alarm_hour_buf>23)alarm_hour_buf=0; LCD_write_data(5,1,alarm_hour_buf); //显示时 LCD1602_write_com(0xc0+6);//光标移动到小时位置 break; case 9: alarm_min_buf++; if(alarm_min_buf>59)alarm_min_buf=0; LCD_write_data(8,1,alarm_min_buf); //显示分 LCD1602_write_com(0xc0+9);//光标移动到分钟位置 break; default: break; } } if(DOWN==0) { while(!DOWN);//松手检测 switch(i) //检测标志位并增加对应的值 { case 0: year_buf--; if(year_buf
LCD_write_data(4,0,month_buf); //显示月 LCD1602_write_com(0x80+5);//光标移动到月位置 break; case 2: day_buf--; if(day_buf
PIC单片机课程设计报告 LCD1602_write_com(0xc0+6);//光标移动到小时位置 break;
case 9:
alarm_min_buf--;
if(alarm_min_buf
LCD_write_data(8,1,alarm_min_buf); //显示分 LCD1602_write_com(0xc0+9);//光标移动到分钟位置 break;
default:
break;
}
}
if(OK==0)
{
while(!OK);//松手检测
//********************长条件句*******************
//判断条件“时间被修改”或(“闹钟没被修改”且“温度也没改”)则更改时间。
//用以解决只更改闹钟不设置时间时,时间也被修改的问题。 //以及设置时间与当前时间相同的问题。
if(
(year_buf!=year)||(month_buf!=month)||(day_buf!=day)||(hour_buf!=hour)||(min_buf!=min)||(sec_buf!=sec)||(week_buf!=week)
||
((alarm_hour_buf==alarm_hour)&&(alarm_min_buf==alarm_min)&&(warning_temp_buf==warning_temp))
) //长条件句
{
Set_Time(year_buf,month_buf,day_buf,hour_buf,min_buf,sec_buf,week_buf);//写ds1302时间
}
//**************************************************************** warning_temp=warning_temp_buf; //存储报警温度
alarm_hour=alarm_hour_buf; //存储闹钟小时设置 alarm_min=alarm_min_buf; //存储闹钟分钟设置
LCD1602_write_com(0x0c); //光标不显示
LCD_clr();
break;
}
}
}
} PIC单片机课程设计报告
5.2.6.2独立按键.H代码
#ifndef _KEY_H_
#define _KEY_H_
#include
#include"all.h"
#include"lcd1602.h"
#include"ds1302.h"
#include"ds18b20.h"
#define SET RB1
#define UP RB2
#define DOWN RB3
#define OK RB4
void KeyScan();//按键扫描函数
void Key_init();//按键端口初始化
#endif
5.2.7全局变量及定义头文件
#ifndef __ALL_H__
#define __ALL_H__
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
#ifndef ulong
#define ulong unsigned long
#endif
#ifndef _XTAL_FREQ
#define _XTAL_FREQ 4000000
#endif
extern int year,month,day,hour,min,sec,week;
extern int alarm_hour,alarm_min;
extern unsigned char temp1,temp2,warning_temp;
#endif
六、设计总结 PIC单片机课程设计报告
通过此次PIC课程设计,使我进一步掌握PIC单片机的应用方法,并通过硬件设计、软件编程及仿真调试的实践,熟练掌握PICC C语言程序的编写与调试,使书本上的理论知识与实践相结合。丰富了知识体系,锻炼了动手能力,使我的实践能力得到了很大提高。这次课程设计是毕业设计前的一次重要实践,为今后走上工作岗位打下坚实的单片机应用基础。
设计成绩:
教师签名: 年 月 日
NORTH CHINA UNIVERSITY OF SCIENCE AND TECHNOLOGY
单片机课程设计报告
学生姓名: 学 号: 学 院: 信息工程学院 专业班级: 12电信4班 指导教师:
2015年6月21日
一、课程设计目的
PIC单片机课程设计报告
本课程设计是在《PIC单片机原理及应用》及《单片机C语言编程》课程的基础上,通过硬件设计、软件编程及仿真调试的实践,进一步掌握PIC单片机的应用方法,熟练掌握PICC C语言程序的编写与调试,是毕业设计前的一次重要实践,为今后走上工作岗位打下坚实的单片机应用基础。
二、设计题目及要求
2.1 设计题目:
基于PIC16F877单片机的多功能电子时钟 2.2 功能实现:
实时时钟显示,时间可调;实时温度显示,并具有超限报警功能。输出显示采用LCD1602或LED七段数码显示器。 2.3 设计要求:
自己设计硬件和程序编程,画出完整的电路原理图,用Multisim或Proteus仿真,最终可实现脱机运行。
三、设计原理说明
3.1 时钟模块
DS1307是美国DALLAS公司推出的I2C总线接口实时时钟芯片,它可独立于CPU 工作,不受CPU主晶振及其电容的影响,且计时准确,月累积误差一般小于10秒。芯片还具有主电源掉电情况下的时钟保护电路,DS1307的时钟靠后备电池维持工作,拒绝CPU对其读出和写入访问。同时还具有备用电源自动切换控制电路,因而可在主电源掉电和其它一些恶劣环境场合中保证系统时钟的定时准确性。
DS1307具有产生秒、分、时、日、月、年等功能,且具有闰年自动调整功能。同时,DS1307芯片内部还集成有一定容量、具有掉电保护特性的静态RAM,可用于保存一些关键数据。 3.2 显示模块
如用LCD1602作为显示设备,要求显示屏分两行显示,第一行显示日期(年-月-日)和星期,第二行显示时间(时:分:秒)和温度。显示秒由00一直加到59,分钟数也由00加到59,小时采用24小时制,由00加到23,如此循环显示。
按键用来作为时间调整。要求至少设计4个按键,按键1作为设置键;按键2、按键3分别为增加、减少键,在设置键按下时,此两个按键方有效;按键4是确定键,在设置键按下时方才有效。 3.4 温度采集模块
DS18B20是美国DALLAS公司推出的单总线数字温度传感器。DS18B20内部集成了温敏元件、数据转换芯片、存储器芯片和计算机接口芯片等多功能模块。其主要技术特点有:具有独特的单线接口方式;可以通过数据线供电,具有超低功耗工作方式;测温范围为-55℃~125℃,测温精度为0.5℃;温度转换精度9~12位可编程,直接将温度转换值以二进制数码的方式串行输出。
四、硬件原理图
4.1电子时钟原理图
4.3显示模块
4.5温度采集模块
4.6电路仿真图 4.6.1开机动画
4.6.2实时时钟显示,实时温度显示
4.6.3时间可调,报警温度可调
4.6.4闹钟功能
4.6.5超限报警
五、软件设计
PIC单片机课程设计报告
5.1流程图
5.2源程序 5.2.1程序清单
5.2.2主程序代码 5.2.2.1主函数.c文件
PIC单片机课程设计报告
#include #include"main.h"
uchar line1_data[]={"Electronic Clock"}; uchar line2_data[]={" Powered By Me "};
void main(void) {
ADCON1=0x06; //基本配置PORTA,PORTE设定为数字端口 TRISD=0; //PORTD设置为输出 TRISB0=0; //PORTB0设置为输出
RB0=0; //初始化蜂鸣器RB0(不响) TRISE0=0; TRISE1=0; TRISE2=0;
__delay_ms(10);
LCD_init();
Init_ds1302(); //初始化ds1302 Key_init();//按键端口初始化
LCD_write_str(0,0,line1_data);//在第0行显示字符串 LCD_write_str(0,1,line2_data);//在第一行显示字符串 __delay_ms(3000); LCD_clr(); while(1) {
Display_Time();//显示时间 Display_wendu();//显示温度 KeyScan();//按键扫描函数 if(temp1>warning_temp) {
RB0=1;
__delay_ms(400); RB0=0;
__delay_ms(400); } else {RB0=0;}
if((hour==alarm_hour)&&(min==alarm_min)) {
} } RB0=1; __delay_ms(200); RB0=0; __delay_ms(200); } else {RB0=0;} PIC单片机课程设计报告
5.2.2.2主函数.h文件
#ifndef __MAIN_H__
#define __MAIN_H__
#define __STAT_BACKWARD_COMPATIBILITY //兼容PICC低版本
#include
#include"all.h"
#include"lcd1602.h"
#include"ds1302.h"
#include"ds18b20.h"
#include"key.h"
__CONFIG(HS&WDTDIS&LVPDIS&PWRTEN);
#endif
5.2.3液晶显示屏LCD1602代码
5.2.3.1液晶显示屏LCD1602.C文件
#include"lcd1602.h"
/*******lcd清屏函数******/
void LCD_clr()
{
LCD1602_write_com(0x01);
__delay_ms(5);
}
/*********光标定位函数。x为显示列,y为显示行********/
void LocateXY(uchar x,uchar y)
{
if(y==0)
{
LCD1602_write_com(0x80+x);
}
else
{
LCD1602_write_com(0xC0+x);
}
}
//***************特定位置写字符*********************
void LCD_write_str(uchar x,uchar y,uchar *s)
{
LocateXY(x,y);
while(*s)
{
LCD1602_write_dat(*s);
s++;
}
}
//****************特定位置显示数值********************
void LCD_write_data(uchar x,uchar y,uchar data)
{
LocateXY(x,y);
LCD1602_write_dat(data/10 +48); //将数值转换成其对应的ASIC码值,相当于以字符形式输出
LCD1602_write_dat(data%10+ 48); //因为0的ASIC码值为48
}
//****************LCD1602初始化函数********************
void LCD_init(void)
{
rs=0;
rw=0;
en=0;
LCD1602_write_com(0x01); //清零
LCD1602_write_com(0x38); //设置为16位两行字符,8位数据总线
LCD1602_write_com(0x0c); //显示开关,关闭光标,没有闪烁
LCD1602_write_com(0x06); //设置增量方式,显示移位方式
}
//******************读1602读忙状态**********************
void LCD1602_check_busy(void)
{
uint i=20000;
dport_in; //端口设为输入
rs=0;
rw=1;
en=1;
while((0x80&dport)&&(i>0))
{
i--;
}
en=0;
dport_out;
}
//******************向1602写数据**********************
void LCD1602_write_dat(uchar lcd_dat)
{
LCD1602_check_busy();
rs=1;
rw=0;
en=1;
dport=lcd_dat;
en=0;
}
//****************向1602写string数据******************
void LCD1602_write_string(const uchar *cy)
{
while(*cy)
{
LCD1602_check_busy();
rs=1;
rw=0;
en=1;
dport=*cy;
en=0;
cy++;
}
}
//******************向1602写指令**********************
void LCD1602_write_com(uchar lcd_com)
{
LCD1602_check_busy();
rs=0;
rw=0;
en=1;//下降沿把数据写进出
dport=lcd_com;
en=0;
}
5.2.3.1液晶显示屏LCD1602.H文件 PIC单片机课程设计报告
#ifndef _LCD1602_H_
#define _LCD1602_H_
#include
#include"all.h"
#define dport PORTD //定义数据口
#define dport_in TRISD=0xff //PD端口设为输入
#define dport_out TRISD=0x00 //PD端口设为输出
#define rs RE0 //并行数据/控制字选择 H:数据 L:控制字 串行片选信号
#define rw RE1 //并行读/写选择 H:读 L:写 串行数据信号
#define en RE2 //并行读写使能 H有效,下降沿锁定数据 串行时钟信号
//*************** 函数定义 ******************
void LCD1602_check_busy(void); //读1602读忙状态
void LCD1602_write_dat(uchar lcd_dat);//向1602写数据********
void LCD1602_write_string(const uchar *cy);//向1602写string数据
void LCD1602_write_com(uchar lcd_com);//向1602写指令
void LocateXY(uchar x,uchar y);//光标定位函数。x为显示列,y为显示行
void LCD_init(void); //LCD1602初始化函数***********
void LCD_write_data(uchar x,uchar y,uchar data);//特定位置显示数值****** void LCD_write_str(uchar x,uchar y,uchar *s);//特定位置写字符********
void LCD_clr(); //lcd清屏函数*************
#endif
5.2.4时钟芯片DS1302代码
5.2.4.1时钟芯片DS1302.C文件
#include"ds1302.h"
//***********延时函数*************
void delay1()
{
int i;
for(i=100;i--;);
}
/******** 从ds1302读一个字节数据******/
uchar read_byte(void)
{
uchar i,dat=0;
IO_CLR;
for(i=0;i
{
SCK_CLR;
if(io)
{dat=dat|0x80;}
else
{dat=dat&0x7f;}
SCK_SET;
dat=dat>>1;
}
IO_OUT;
SCK_CLR;
return dat;
}
/***** 向ds1302写一个数据******/
void write_byte(uchar dat)
{
uchar i;
for(i=0;i
{
IO_CLR;
SCK_CLR;
if(dat&0x01)
{
IO_SET;
}
else
{
IO_CLR;
}
SCK_SET;
dat>>=1;
}
SCK_CLR;
}
/***** 从ds1302的指定地址读一个字节数据******/
uchar read_ds1302(uchar addr)
{
char data,data1,data2;
RST_CLR;
SCK_CLR;
delay1();
delay1();
write_byte(addr);
data=read_byte();
SCK_CLR;
RST_CLR;
data1=data/16;
data2=data%16;
data=data2+data1*10;
return data;
}
/***** 往ds1302的指定地址写一个字节数据******/
void write_ds1302(uchar addr,uchar data)
{
RST_CLR;
SCK_CLR;
delay1();
RST_SET;
delay1();
write_byte(addr);
SCK_CLR;
write_byte(data);
SCK_CLR;
RST_CLR;
}
/***** 初始化ds1302函数******/
void Init_ds1302()
{
RST_CLR;
SCK_CLR;
RST_OUT;
SCK_OUT;
}
/***** 写ds1302时间函数******/
void Set_Time(char year,char month,char day,char hour,char min,char sec,char week) {
write_ds1302(0x8E,0x00); //根据写状态寄存器命令字,写入不保护指令
write_ds1302(0x80,sec/10*16+sec%10); //根据写秒寄存器命令字,写入秒的值 write_ds1302(0x82,min/10*16+min%10); //根据写分寄存器命令字,写入分的值 write_ds1302(0x84,hour/10*16+hour%10); //根据写小时寄存器命令字,写入小时的值
write_ds1302(0x86,day/10*16+day%10); //根据写日寄存器命令字,写入日的值 write_ds1302(0x88,month/10*16+month%10); //根据写月寄存器命令字,写入月的
值
write_ds1302(0x8c,year/10*16+year%10); //根据写年寄存器命令字,写入年的值 write_ds1302(0x8a,week/10*16+week%10); //根据写星期寄存器命令字,写入星期的值
write_ds1302(0x8e,0x80); //根据写状态寄存器命令字,写入写保护指令 }
/***** 读ds1302时间函数******/
void Get_Time()
{
write_ds1302(0x8e,0x00);//控制命令。wp=0,允许写操作
write_ds1302(0x90,0xab);//涓流充电控制
sec=read_ds1302(0x81); //读取秒
min=read_ds1302(0x83); //读取分
hour=read_ds1302(0x85);//读取时
day = read_ds1302(0x87);//读取日
month = read_ds1302(0x89);//读取月
year = read_ds1302(0x8D);//读取年
week = read_ds1302(0x8B); //读取星期
}
/***** 显示时间函数******/
void Display_Time()
{
Get_Time();
LCD_write_data(1,0,year); //显示年
LCD1602_write_dat('-');
LCD_write_data(4,0,month); //显示月
LCD1602_write_dat('-');
LCD_write_data(7,0,day); //显示日
Write_Week(10,0,week); //显示星期
LCD_write_data(1,1,hour); //显示时
LCD1602_write_dat(':');
LCD_write_data(4,1,min); //显示分
LCD1602_write_dat(':');
LCD_write_data(7,1,sec); //显示秒
}
//**********星期显示函数***********
void Write_Week(int i,int j,uchar x)
{
LCD_write_str(i,j,xinqi[x]);
}
5.2.4.1时钟芯片DS1302.H文件
#ifndef _DS1302_H_
#define _DS1302_H_
#include
#include"all.h"
#include"lcd1602.h"
#define sclk RA1
#define io RA0
#define reset RA2
#define reset_IO TRISA2
#define sclk_IO TRISA1
#define io_IO TRISA0
/***** 复位脚******/
#define RST_CLR reset=0
#define RST_SET reset=1
#define RST_IN reset_IO=1
#define RST_OUT reset_IO=0
/***** 双向数据******/
#define IO_CLR io=0
#define IO_SET io=1
#define IO_IN io_IO=1
#define IO_OUT io_IO=0
/***** 时钟信号******/
#define SCK_CLR sclk=0
#define SCK_SET sclk=1
#define SCK_IN sclk_IO=1
#define SCK_OUT sclk_IO=0
int year,month,day,hour,min,sec,week;
int alarm_hour=13,alarm_min=30;//定义闹铃时间和闹铃分钟
uchar xinqi[8][4]={" ","SUN","MON","TUS","WED","THU","FRI","SAT"};
void delay1();//延时函数
void write_byte(uchar inbyte); //向ds1302写一个数据
uchar read_byte(void); //从ds1302读一个字节数据
void write_ds1302(uchar addr,uchar data);//往ds1302的指定地址写一个字节数据 uchar read_ds1302(uchar addr);//从ds1302的指定地址读一个字节数据
void Write_Week(int i,int j,uchar x);//星期显示函数
void Init_ds1302(void); //初始化ds1302函数**********
void Get_Time();//读ds1302时间函数******
void Set_Time(char year,char month,char day,char hour,char min,char sec,char week);//写ds1302时间函数******
void Display_Time();//显示时间函数******
#endif
5.2.5温度传感器DS18B20代码
5.2.5.1温度传感器DS18B20.C文件 PIC单片机课程设计报告
#include"ds18b20.h"
//---------------------------------------
//名称:复位DS18B20函数
//---------------------------------------
unsigned char Reset(void)
{
unsigned char k;
DQ_DIR=0; //设置RA4位输出口
DQ=0; //拉低DQ总线开始复位
__delay_us(870); //保持DQ低大约870uS,符合不低于480US的要求
DQ_DIR=1; //设置RA4为输入口,以释放总线等电阻拉高总线 __delay_us(78); //大约78uS后,判断是否复位成功
if(DQ==0) //读出数据并保存
k=0;
else
k=1;
__delay_us(400); //维持约400US,符合总读时隙不低于480US的要求
return k; //k=0为复位成功,k=1为复位失败
}
//---------------------------------------
//名称:写字节函数
//---------------------------------------
void WriteByte(unsigned char dat)
{
unsigned char j;
for(j=0;j
{
if(dat&0x01) //如果写1
{
DQ_DIR=0; //设置RA4位输出口
DQ=0; //拉低
NOP(); //维持6US,符合大于1US小于15US的规范
NOP(); //维持6US,符合大于1US小于15US的规范 NOP(); //维持6US,符合大于1US小于15US的规范
NOP(); //维持6US,符合大于1US小于15US的规范 NOP(); //维持6US,符合大于1US小于15US的规范
NOP(); //维持6US,符合大于1US小于15US的规范
DQ_DIR=1; //设置RA4为输入口,以释放总线等电阻拉高总线 __delay_us(63); //维持约63US,符合不低于60US的要求
PIC单片机课程设计报告 }
else //如果写0
{
DQ_DIR=0; //设置RA4位输出口
DQ=0; //拉低
__delay_us(63); //维持约63US,符合不低于60US的要求 DQ_DIR=1; //设置RA4为输入口,以释放总线等电阻拉高总线
NOP(); //维持2US,符合大于1US的规范
NOP(); //维持2US,符合大于1US的规范 }
dat=dat>>1; //写入字节右移1位
}
}
//---------------------------------------
//名称:读字节函数
//---------------------------------------
unsigned char ReadByte(void)
{
unsigned char j,buf=0;
for(j=1;j
{
buf=buf>>1; //接收前,先将接收缓冲区右移
DQ_DIR=0; //设置RA4位输出口
DQ=0; //拉低
NOP(); //维持2US,符合大于1US小于15US的规范 NOP(); //维持2US,符合大于1US小于15US的规范
DQ_DIR=1; //设置RA4为输入口,以释放总线等电阻拉高总线 准备读
NOP(); //维持6US,符合大于1US小于15US的规范 NOP(); //维持6US,符合大于1US小于15US的规范 NOP(); //维持6US,符合大于1US小于15US的规范 NOP(); //维持6US,符合大于1US小于15US的规范 NOP(); //维持6US,符合大于1US小于15US的规范
NOP(); //维持6US,符合大于1US小于15US的规范 if(DQ==1) buf|=0x80; //读出1位数据保存于buf中最高位
__delay_us(52); //维持约52US,符合总读时隙不低于60US的要求 }
return buf; //退出的同时将接收缓冲区参数返回 }
//---------------------------------------
//名称:温度转换函数
//---------------------------------------
unsigned char Convert(void)
{
if(Reset()==0) //如果复位成功
{
__delay_us(1000); //延时约1000US
WriteByte(0xcc); // 跳过多器件识别
WriteByte(0x44); // 启动温度转换
return 1;
}
else
{
return 0;
}
}
//*************读温度函数*************
void ReadFlash(void)
{
unsigned char Lsb,Msb;
if(Reset()==0)
{
__delay_us(1000); //延时约1000US
WriteByte(0xcc); // 跳过多器件识别
WriteByte(0xbe); // 读暂存器
Lsb=ReadByte(); // 低字节
Msb=ReadByte(); // 高字节
temp2=Lsb&0x0f; //LSB的低4位为小数部分
temp1=(Lsb>>4)|(Msb
}
else
{
temp1=0;
temp2=0;
}
}
//***********显示当前温度**************
void Display_wendu(void)
{
unsigned char buf;
if(Convert()==1) //启动转换
{
ReadFlash(); //读取温度
if(temp1>99) temp1=99;
if(temp2>15) temp2=0;
buf=temp1;
LCD_write_data(10,1,buf); //温度整数部分
LCD1602_write_dat('.'); //.
buf=table[temp2&0x0f];
buf+=0x30;
LCD1602_write_dat(buf); //温度小数部分
LCD1602_write_dat(0xdf); //.
LCD1602_write_dat(0x43); //C
}
}
//***********显示buf温度**************
void Display_temp(uchar buf)
{
LCD_write_data(10,1,buf); //温度报警温度整数部分
LCD1602_write_dat('.'); //.
LCD1602_write_dat(0x30); //温度小数部分0
LCD1602_write_dat(0xdf); //.
LCD1602_write_dat(0x43); //C
}
5.2.5.1温度传感器DS18B20.H文件
#ifndef _DS18B20_H_
#define _DS18B20_H_
#include
#include"all.h"
#include"lcd1602.h"
#define DQ_DIR TRISC0 //控制DS18B20的DQ端
#define DQ RC0 //控制DS18B20的DQ端
unsigned char temp1=0,temp2=0;//当前温度缓存
unsigned char warning_temp=50;//设置报警温度
const unsigned char table[16]={0,0,1,2,2,3,4,4,5,6,6,7,8,8,9,9};
void Display_wendu(void); //显示当前温度函数*********
void Display_temp(uchar buf); //显示buf温度函数*********
void ReadFlash(void) ; //读温度函数
unsigned char Convert(void) ; //温度转换函数
unsigned char ReadByte(void); //读字节函数
void WriteByte(unsigned char dat); //写字节函数
unsigned char Reset(void); //复位DS18B20函数
#endif
5.2.6独立按键代码
5.2.6.1独立按键.C文件 #include"key.h"
//**********按键端口初始化***********
void Key_init()
{
TRISB=0B00011110; //初始化RB4-RB1为输入方向
PORTB=0B11111110; //初始化RA5-RA0数值
}
//**********按键扫描函数*************
void KeyScan()
{
uchar i=0;
int warning_temp_buf=0; //报警温度缓存
int alarm_hour_buf=0,alarm_min_buf=0; //闹钟时间缓存
int year_buf,month_buf,day_buf,hour_buf,min_buf,sec_buf,week_buf;//设置时间缓存
if(SET==0)
{
while(!SET);//松手检测
warning_temp_buf=warning_temp; //读回报警温度设置值
Display_temp(warning_temp_buf); //显示当前报警设置
year_buf=year; //读回当前时间
month_buf=month; //***********
day_buf=day; //***********
hour_buf=hour; //***********
min_buf=min; //***********
sec_buf=sec; //***********
week_buf=week; //***********
alarm_hour_buf=alarm_hour; //读回闹钟小时设置
alarm_min_buf=alarm_min; //读回闹钟分钟设置
LCD1602_write_com(0x0f);//显示光标并闪烁
LCD1602_write_com(0x80+2);//光标移动到年位置
i=0; //清零标志位
while(1)
{
if(SET==0)
{
while(!SET);//松手检测
i++; //标志加一
{ LCD1602_write_com(0x0c); //光标不显示 LCD_clr(); break; } switch(i) //检测标志位并移动光标 { case 0: LCD1602_write_com(0x80+2);//光标移动到年位置 break; case 1: LCD1602_write_com(0x80+5);//光标移动到月位置 break; case 2: LCD1602_write_com(0x80+8);//光标移动到日位置 break; case 3: LCD1602_write_com(0x80+13);//光标移动到星期位置 break; case 4: LCD1602_write_com(0xc0+2);//光标移动到小时位置 break; case 5: LCD1602_write_com(0xc0+5);//光标移动到分钟位置 break; case 6: LCD1602_write_com(0xc0+8);//光标移动到秒位置 break; case 7: LCD1602_write_com(0xc0+11);//光标移动到温度位置 break; case 8: LCD_clr(); //清屏 LocateXY(0,0); LCD1602_write_string(" Alarm Clock "); LCD_write_data(5,1,alarm_hour_buf); //显示时 LCD1602_write_dat(':'); LCD_write_data(8,1,alarm_min_buf); //显示分 LCD1602_write_com(0xc0+6);//光标移动到小时位置 break; case 9: LCD1602_write_com(0xc0+9);//光标移动到分钟位置
default: LCD1602_write_com(0x80+2);//光标移动到年位置(出错复位) break; } } if(UP==0) { while(!UP);//松手检测 switch(i) //检测标志位并增加对应的值 { case 0: year_buf++; if(year_buf>99)year_buf=0; LCD_write_data(1,0,year_buf); //显示年 LCD1602_write_com(0x80+2);//光标移动到年位置 break; case 1: month_buf++; if(month_buf>12)month_buf=1; LCD_write_data(4,0,month_buf); //显示月 LCD1602_write_com(0x80+5);//光标移动到月位置 break; case 2: day_buf++; if(day_buf>31)day_buf=1; LCD_write_data(7,0,day_buf); //显示日 LCD1602_write_com(0x80+8);//光标移动到日位置 break; case 3: week_buf++; if(week_buf>7)week_buf=1; Write_Week(10,0,week_buf); //显示星期 LCD1602_write_com(0x80+13);//光标移动到星期位置 break; case 4: hour_buf++; if(hour_buf>23)hour_buf=0; LCD_write_data(1,1,hour_buf); //显示时 LCD1602_write_com(0xc0+2);//光标移动到小时位置 break; case 5: min_buf++; if(min_buf>59)min_buf=0;
LCD1602_write_com(0xc0+5);//光标移动到分钟位置 break; case 6: sec_buf++; if(sec_buf>59)sec_buf=0; LCD_write_data(7,1,sec_buf); //显示秒 LCD1602_write_com(0xc0+8);//光标移动到秒位置 break; case 7: warning_temp_buf++; if(warning_temp_buf>99)warning_temp_buf=0; Display_temp(warning_temp_buf); //显示报警温度 LCD1602_write_com(0xc0+11);//光标移动到温度位置 break; case 8: alarm_hour_buf++; if(alarm_hour_buf>23)alarm_hour_buf=0; LCD_write_data(5,1,alarm_hour_buf); //显示时 LCD1602_write_com(0xc0+6);//光标移动到小时位置 break; case 9: alarm_min_buf++; if(alarm_min_buf>59)alarm_min_buf=0; LCD_write_data(8,1,alarm_min_buf); //显示分 LCD1602_write_com(0xc0+9);//光标移动到分钟位置 break; default: break; } } if(DOWN==0) { while(!DOWN);//松手检测 switch(i) //检测标志位并增加对应的值 { case 0: year_buf--; if(year_buf
LCD_write_data(4,0,month_buf); //显示月 LCD1602_write_com(0x80+5);//光标移动到月位置 break; case 2: day_buf--; if(day_buf
PIC单片机课程设计报告 LCD1602_write_com(0xc0+6);//光标移动到小时位置 break;
case 9:
alarm_min_buf--;
if(alarm_min_buf
LCD_write_data(8,1,alarm_min_buf); //显示分 LCD1602_write_com(0xc0+9);//光标移动到分钟位置 break;
default:
break;
}
}
if(OK==0)
{
while(!OK);//松手检测
//********************长条件句*******************
//判断条件“时间被修改”或(“闹钟没被修改”且“温度也没改”)则更改时间。
//用以解决只更改闹钟不设置时间时,时间也被修改的问题。 //以及设置时间与当前时间相同的问题。
if(
(year_buf!=year)||(month_buf!=month)||(day_buf!=day)||(hour_buf!=hour)||(min_buf!=min)||(sec_buf!=sec)||(week_buf!=week)
||
((alarm_hour_buf==alarm_hour)&&(alarm_min_buf==alarm_min)&&(warning_temp_buf==warning_temp))
) //长条件句
{
Set_Time(year_buf,month_buf,day_buf,hour_buf,min_buf,sec_buf,week_buf);//写ds1302时间
}
//**************************************************************** warning_temp=warning_temp_buf; //存储报警温度
alarm_hour=alarm_hour_buf; //存储闹钟小时设置 alarm_min=alarm_min_buf; //存储闹钟分钟设置
LCD1602_write_com(0x0c); //光标不显示
LCD_clr();
break;
}
}
}
} PIC单片机课程设计报告
5.2.6.2独立按键.H代码
#ifndef _KEY_H_
#define _KEY_H_
#include
#include"all.h"
#include"lcd1602.h"
#include"ds1302.h"
#include"ds18b20.h"
#define SET RB1
#define UP RB2
#define DOWN RB3
#define OK RB4
void KeyScan();//按键扫描函数
void Key_init();//按键端口初始化
#endif
5.2.7全局变量及定义头文件
#ifndef __ALL_H__
#define __ALL_H__
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
#ifndef ulong
#define ulong unsigned long
#endif
#ifndef _XTAL_FREQ
#define _XTAL_FREQ 4000000
#endif
extern int year,month,day,hour,min,sec,week;
extern int alarm_hour,alarm_min;
extern unsigned char temp1,temp2,warning_temp;
#endif
六、设计总结 PIC单片机课程设计报告
通过此次PIC课程设计,使我进一步掌握PIC单片机的应用方法,并通过硬件设计、软件编程及仿真调试的实践,熟练掌握PICC C语言程序的编写与调试,使书本上的理论知识与实践相结合。丰富了知识体系,锻炼了动手能力,使我的实践能力得到了很大提高。这次课程设计是毕业设计前的一次重要实践,为今后走上工作岗位打下坚实的单片机应用基础。
设计成绩:
教师签名: 年 月 日