2020-09-29

 

基于PIC16F877A单片机的多功能电子时钟

文章目录

 


前言

通过硬件设计、软件编程及仿真调试的实践,进一步掌握PIC单片机的应用方法,熟练掌握PICC C语言程序的编写与调试,是毕业设计前的一次重要实践,为今后走上工作岗位打下坚实的单片机应用基础。


提示:以下是本篇文章正文内容,下面案例可供参考

一、功能实现

实时时钟显示,时间可调;实时温度显示,并具有超限报警功能。输出显示采用LCD1602或LED七段数码显示器。

二、原理说明 

DS1307是美国DALLAS公司推出的I2C总线接口实时时钟芯片,它可独立于CPU 工作,不受CPU主晶振及其电容的影响,且计时准确,月累积误差一般小于10秒。芯片还具有主电源掉电情况下的时钟保护电路,DS1307的时钟靠后备电池维持工作,拒绝CPU对其读出和写入访问。同时还具有备用电源自动切换控制电路,因而可在主电源掉电和其它一些恶劣环境场合中保证系统时钟的定时准确性。

DS1307具有产生秒、分、时、日、月、年等功能,且具有闰年自动调整功能。同时,DS1307芯片内部还集成有一定容量、具有掉电保护特性的静态RAM,可用于保存一些关键数据。

3.2 显示模块

如用LCD1602作为显示设备,要求显示屏分两行显示,第一行显示日期(年-月-日)和星期,第二行显示时间(时:分:秒)和温度。显示秒由00一直加到59,分钟数也由00加到59,小时采用24小时制,由00加到23,如此循环显示。

3.3 按键模块

按键用来作为时间调整。要求至少设计4个按键,按键1作为设置键;按键2、按键3分别为增加、减少键,在设置键按下时,此两个按键方有效;按键4是确定键,在设置键按下时方才有效。

3.4 温度采集模块

DS18B20是美国DALLAS公司推出的单总线数字温度传感器。DS18B20内部集成了温敏元件、数据转换芯片、存储器芯片和计算机接口芯片等多功能模块。其主要技术特点有:具有独特的单线接口方式;可以通过数据线供电,具有超低功耗工作方式;测温范围为-55℃~125℃,测温精度为0.5℃;温度转换精度9~12位可编程,直接将温度转换值以二进制数码的方式串行输出。

三、使用步骤

1.头文件lian_pic.h

//__delay_us(15);

//__delay_ms(15);

//使用延时函数前,需定义时钟频率 #define _XTAL_FREQ 12000000

/

#ifndef __LIAN_PIC_H__

#define __LIAN_PIC_H__



#define __STAT_BACKWARD_COMPATIBILITY   //兼容PICC低版本 

#include <htc.h>





#define uchar unsigned char

#define uint  unsigned int

#define ulong unsigned long



#define setbit(y,x)   y|=(1<<(x))    //setb(p1,2); p12=1;

#define clrbit(y,x)   y&=~(1<<(x))   //clr(p1,2);  p12=0;

#define getbit(y,x)  (0x01&(y>>(x)))    //获取某一位值

#endif //__LIAN_PIC_H__

2.lcd12864.h

#ifndef __LCD12864_H__
#define __LCD12864_H__

/******************************lcd12864常用命令******************************                           
0x30	 //基本指令集
0x01	 //清除显示(清零DDRAM)
0x02	 //位址归位,游标回原点
0x04	 //光标左移,整体显示不移动
0x06	 //光标右移,整体显示不移动
0x05	 //光标左移,整体显示移动
0x07	 //光标右移,整体显示移动
0x08	 //显示状态全关
0x0C  //显示开
0x0E  //显示开,游标开
0x0F  //显示开,游标开,游标位置开
0x10  //游标左移
0x14	 //游标右移
0x18	 //整体显示左移,光标跟随
0x1C	 //整体显示又移,光标跟随

					  	
0x36	 //扩展指令集,绘图显示ON
0x34	 //扩展指令集,绘图显示OFF
//2010年8月29日16:11:24		  st7920  并行8bit驱动
****************************************************************************/

#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有效,下降沿锁定数据  串行时钟信号
#define psb       RC3       //串口,并口选择       H:并口  L:串口


//*************** 函数定义 ******************
void lcd12864_io_init(void);
void lcd12864_check_busy(void);
void lcd12864_write_dat(uchar lcd_dat);
void lcd12864_write_com(uchar lcd_com);

//*********************初始化12864操作io口************************
void lcd12864_io_init(void)
{ 
  rs=1;
  rw=1;
  en=1;
  psb=1;    //选择8bit并口
}

//******************读12864读忙状态**********************
void lcd12864_check_busy(void)
{
  uint i=20000;	    
  dport_in;       //端口设为输入
  rs=0;
  rw=1;
  en=1;
  while((0x80&dport)&&(i>0))
  {
    i--;
  }
  en=0; 	
}

//******************向12864写数据**********************
void lcd12864_write_dat(uchar lcd_dat)
{
  lcd12864_check_busy();
  dport_out;
  rs=1;
  rw=0;
  en=1;
  dport=lcd_dat;
  en=0;
}

//******************向12864写指令**********************
void lcd12864_write_com(uchar lcd_com)
{
  lcd12864_check_busy();
  dport_out;
  rs=0;
  rw=0;
  en=1;
  dport=lcd_com;
  en=0;
}

#endif

3.ds18b20.h

DS18B20头文件
//**************************DS18B20驱动库****************************
//功能:实现对DS18B20的读取
//原理:单总线协议
//注意:单总线协议对延时要求比较严格,应根据单片机时钟调整延时函数
//       
//pic16f877a   4MHz   PICC9.8编译器
//2010年12月28日14:56:57
//*******************************************************************


#define	DQ_DIR  TRISB5     //控制DS18B20的DQ端
#define	DQ      RB5        //控制DS18B20的DQ端


//ds18b20 ROM操作指令码
#define ds18b20_skip_rom     0xCC    //跳过ROM指令码
#define ds18b20_search_rom   0xF0    //搜索ROM指令码
#define ds18b20_read_rom     0x33    //读ROM指令码
#define ds18b20_match_rom    0x55    //匹配ROM指令码
#define ds18b20_alarm_rom    0xEC    //报警搜索ROM指令码
//ds18b20 RAM操作指令码
#define ds18b20_convert_ram   0x44   //启动温度转换指令码
#define ds18b20_read_ram      0xBE   //读RAM指令码    
#define ds18b20_write_ram     0x4E   //写RAM指令码     
#define ds18b20_copy_ram      0x48   //把RAM的TH,TL,CFG中的内容复制到EEPROM指令码
#define ds18b20_recall_eeprom 0xB8   //把EEPROM的TH,TL,CFG中的内容恢复到RAM指令码


//*************** 函数定义 ******************
uchar ds18b20_init(void);                 //初始化函数
uchar ds18b20_read(void);                 //读一个字节 
void  ds18b20_write(uchar ds18b20_dat);            //写一个字节


//*************************初始化函数************************
uchar ds18b20_init(void)     
{
  uchar b=0;
  DQ=0;
  DQ_DIR=0;           //单片机将DQ拉低
  __delay_us(495);    //精确延时495us  大于480us
  DQ_DIR=1;           //拉高总线
  __delay_us(80);     //延时80us       大于60us
  b=DQ;               //读端口如果x=0则初始化成功 x=1则初始化失败
  __delay_us(495);    //精确延时495us  大于480us
  return b;
}


//***************************读一个字节**********************
uchar ds18b20_read(void)
{
  uchar c;
  uchar ds18b20_dat=0;   //ds18b20_dat用于存储读到的数据,先清零
  for(c=8;c>0;c--)
  {
    DQ=0;
    DQ_DIR=0;          //拉低总线         
    __delay_us(2);     //延时1us以上   
    DQ_DIR=1;          //拉高总线
    __delay_us(2);     //延时1us以上
                       //在15us以内读数据
    ds18b20_dat>>=1;           //数据右移,读顺序(先低后高)
    if(DQ)
    {
      ds18b20_dat|=0x80;
    }
    __delay_us(65);    //保持60us以上
  }
  return(ds18b20_dat);
}


//***************************写一个字节********************
void ds18b20_write(uchar ds18b20_dat)
{
  uchar d;
  for(d=8;d>0;d--)        //写8次,一次写1位,先写低字节
  {
    DQ=0;              
    DQ_DIR=0;             //拉低数据线
    __delay_us(2);        //延时1us以上
    DQ=ds18b20_dat&0x01;          //写数据
    __delay_us(65);       //保持60us以上
    ds18b20_dat>>=1;              //数据右移1位,先写低位
    DQ_DIR=1;             //拉高数据线
    __delay_us(2);        //延时1us以上
                          //两次写之间保持1us以上   
  }
}

4.ds1302.h

#ifndef __DS1302_H__
#define __DS1302_H__

#define SCLK	RC0			//DS1302串行时钟输入引脚
#define DSIO	RC1			//数据输入/输出引脚,具有三态功能
#define RST		RC2			//复位引脚,低电平有效,操作时高电平


//*************** 函数定义 ******************
void ds1302_write(uchar addr,uchar dat);		// 向DS1302命令(地址+数据)
uchar ds1302_read(uchar addr);					// 读取ds1302内容
void ds1302_init();								//ds1302初始化
void ds1302_read_time();						//读取时间函数

uchar TIME[7];									//定义全局变量
#endif

5.ds1302.c

#include "lian_pic.h"
#include "DS1302.H"

//---DS1302写入和读取时分秒的地址命令---//
//---秒分时日月周年 最低位读写位;-------//
uchar READ_RTC_ADDR[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d}; 
uchar WRITE_RTC_ADDR[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};

//---DS1302时钟初始化2019年12月20日星期五18点58分00秒。---//
//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
uchar TIME[7]={0x00,0x58,0x18,0x20,0x12,0x05,0x19};

//*********************DS1302WRITE************************
void ds1302_write(uchar addr,uchar dat)
{
	TRISC=0X00;
	uchar f;
	RST=0;
	NOP();
	
	SCLK=0;			//先将SCLK置低电平
	NOP();
	RST=1;			//然后将RST(CE)置高电平
	NOP();
	
	for(f=0;f<8;f++)		//开始传送八位地址命令
	{
		DSIO=addr&0x01;		//数据从低位开始传送
		addr>>=1;
		SCLK=1;				//数据在上升沿时,DS1302读取数据
		NOP();
		SCLK=0;
		NOP();
	}
	for(f=0;f<8;f++)		//开始写入八位数据
	{
		DSIO=dat&0x01;		//数据从低位开始传送
		dat>>=1;
		SCLK=1;				//数据在上升沿时,DS1302读取数据
		NOP();
		SCLK=0;
		NOP();
	}
	
	RST=0;					//传送数据结束
	NOP();
	
}

//******************DS1302READ**********************
uchar ds1302_read(uchar addr)
{
	uchar j,dat,dat1;
	RST=0;
	NOP();
	
	SCLK=0;		//先将SCLK置低电平
	NOP();
	RST=1;		//然后将RST(CE)置高电平
	NOP();
	
	for(j=0;j<8;j++)		//开始传送八位地址命令
	{
		TRISC1=0;
		NOP();
		DSIO=addr&0x01;		//数据从低位开始传送
		addr>>=1;
		SCLK=1;				//DS1302上升沿时,读取数据
		NOP();
		SCLK=0;				//DS1302下降沿时,放置数据
		NOP();
		
	}
	NOP();
	for(j=0;j<8;j++)		//读取8位数据
	{	
		TRISC1=1;
		NOP();
		dat1=DSIO;			//从最低位开始接收
		dat=(dat>>1)|(dat1<<7);
		SCLK=1;
		NOP();
		SCLK=0;				//DS1302下降沿时,放置数据
		NOP();	
	}	
	RST=0;
	NOP();					//以下为DS1302复位的稳定时间,必须的。
	SCLK=1;
	NOP();
	DSIO=0;
	NOP();
	DSIO=1;
	NOP();
	return dat;
	
}

//******************DS1302INIT**********************
void ds1302_init()
{
	uchar k;
	ds1302_write(0x8e,0x00);			//禁止写保护,就是关闭写保护功能
	for(k=0;k<7;k++)
	{
		ds1302_write(WRITE_RTC_ADDR[k],TIME[k]);
	}
	ds1302_write(0x80,0x00);
	ds1302_write(0x8e,0x80);			//打开写保护功能
}
//****************DS1302READTIME******************
void ds1302_read_time()
{
	uchar l;
	for(l=0;l<7;l++)
	{
		TIME[l]=ds1302_read(READ_RTC_ADDR[l]);
	}
}

6.main.c

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

程序功能:LCD602液晶显示时间(DS1307)温度(DS18B20)实验

开发环境:PICC9.8编译器

硬件环境:CEPARK多功能开发学习板/实验箱(2013版),PIC16F877A核心板,芯片PIC16F877A,晶振4MHZ
																							   
接线说明:LCD16302核心板RD口接底板JP33,具体为:RD0-D0,RD1-D1,RD2-D2,RD3-D3,RD4-D4,RD5-D5,RD6-D6,RD7-D7
          核心板RE0~RE2接底板JP31,具体为:RE0-RS,RE1-RW,RE2-EN
		  
		  DS18B20核心板RB5接底板JP35

		  DS1302 RC0-SCK,RC1-IO,RC2-RST

		  按键设置时间  RA0-K1(K1键进入时钟设置) RA1-K2(选择更改年月日时分秒) RA2-K3(选择设置加一) RA3-K4(确定时钟设置完成设置) 

跳线说明:无

实验现象:LCD112864第一行显示日期 XX年XX月XX日

          第二行显示时间 XX-XX-XX
		  
	      第三行显示温度 
									 



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

#define _XTAL_FREQ 4000000


//********************按键定义*********************
#define K1 RA0
#define K2 RA1
#define K3 RA2
#define K4 RA3
#define bee RB7


#include "lian_pic.H"
//#include "LCD1602.H"
#include "DS18B20.H"
#include "DS1302.H"
#include "LCD12864.H"
__CONFIG(HS&WDTDIS&LVPDIS&PWRTEN);	
//HS振荡,禁止看门狗,低压编程关闭,启动延时定时器


//********************按键定义*********************
uchar SetPlace;			//数组TIME[SetPlace]

const uchar ucpic[]=
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xE0,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x01,0x80,0x30,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x19,0x80,0x30,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x60,0x60,0x0C,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x60,0x60,0x0C,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x01,0xE0,0x7F,0x0C,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x01,0xE1,0x80,0xCC,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x01,0xE7,0xE3,0xFC,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x01,0x9F,0xEF,0xFC,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x01,0x9F,0xFF,0xFC,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x07,0x9F,0xEF,0xCC,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x06,0x07,0x8F,0x03,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x18,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x18,0x00,0x03,0x00,0xC0,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x18,0x00,0x03,0x00,0xC0,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x33,0x00,0x18,0x00,0x0C,0x03,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x03,0x0F,0x86,0x01,0x90,0x0F,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0x00,0x70,0x0C,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x07,0x80,0x03,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xFE,0x1F,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x01,0xF8,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x03,0xC0,0x00,0x00,0x03,0xC0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x3C,0x00,0x00,0x00,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,
0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,
0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,
0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x00,
0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};           //图像数据

//********************函数定义按键*********************
void keyset_init();

//********************变量定义DS18B20*********************  
//DS18B20测量的温度放到固定的数组中
uchar ds18b20_buf[7];		//存放温度
uint t;						//温度的量化值
void warn();				//温度超越阈值报警
//********************变量定义DS1302*********************  
uchar displaydate[10];		//存放时分秒
uchar displaydate1[10];		//存放年月日
uchar displaydate2;		//存放星期

//********************函数定义LCD12864*********************
void lcd12864_init();
void lcd12864_dis_oneline(uchar line,uchar *p);
void lcd12864_dis_image(uchar *p);

//********************函数定义DS18B20*********************   
void ds18b20_startconvert();		//ds18b20模块开始测量温度
uint ds18b20_getconvert();			//提取ds18b20模块测量的温度
void T_convert_buf(uint cnt);		//将温度转换为数组形式

//********************函数定义DS1302*********************
void ds1302_datapros();				//将读取出来的TIME[7]转换为十进制

//********************综合函数定义RUN*********************
void run();

//*************** 主程序 ********************
void main(void)
{
	  keyset_init();		//按键初始化
	  lcd12864_init();
	  //ds1302_init();
	  lcd12864_write_com(0x01);    //清除显示(清零DDRAM)
	  lcd12864_dis_image(ucpic);
	  __delay_ms(3000);
	 while(1)
	  {
			warn();
			
			if(K1==1)
			{
					ds1302_write(0x8e,0x00); //设置为可写
//***************ds18b20处理程序********************	 
					ds18b20_startconvert();	//启动温度转换
				    t=ds18b20_getconvert();	//读取温度值 
				  	T_convert_buf(t);
					run();
			}
			else if(K1==0)
			{
				int i=0;
				while(K4==1)
				{
							if(K2==0)		//检测按键K2是否按下
								{
									__delay_ms(10);	//消除抖动
									if(K2==0)
									{
										SetPlace++;
										if(SetPlace>=7)
										SetPlace=0;					
									}
									/*while((i<50)&&(K2==0))	 //检测按键是否松开
									{
										__delay_ms(10);
										i++;
									}
									i=0;*/
								}
							switch(SetPlace)
								{
									case 0:
											lcd12864_write_com(0x97);
											lcd12864_write_dat(0x24);
											lcd12864_write_dat(0x24);
											__delay_ms(500);
											lcd12864_write_com(0x97);
											lcd12864_write_dat(displaydate[8]);
											lcd12864_write_dat(displaydate[9]);
											__delay_ms(500);
											break;
									case 1:
											lcd12864_write_com(0x95);
											lcd12864_write_dat(0x24);
											lcd12864_write_dat(0x24);
											__delay_ms(500);
											lcd12864_write_com(0x95);
											lcd12864_write_dat(displaydate[4]);
											lcd12864_write_dat(displaydate[5]);
											__delay_ms(500);
											break;
									case 2:
											lcd12864_write_com(0x93);
											lcd12864_write_dat(0x24);
											lcd12864_write_dat(0x24);
											__delay_ms(500);
											lcd12864_write_com(0x93);
											lcd12864_write_dat(displaydate[0]);
											lcd12864_write_dat(displaydate[1]);
											__delay_ms(500);
											break;
									case 3:
											lcd12864_write_com(0x87);
											lcd12864_write_dat(0x24);
											lcd12864_write_dat(0x24);
											__delay_ms(500);
											lcd12864_write_com(0x87);
											lcd12864_write_dat(displaydate1[8]);
											lcd12864_write_dat(displaydate1[9]);
											__delay_ms(500);
											break;
									case 4:
											lcd12864_write_com(0x85);
											lcd12864_write_dat(0x24);
											lcd12864_write_dat(0x24);
											__delay_ms(500);
											lcd12864_write_com(0x85);
											lcd12864_write_dat(displaydate1[4]);
											lcd12864_write_dat(displaydate1[5]);
											__delay_ms(500);
											break;
									case 5:
											lcd12864_write_com(0x9b);
											lcd12864_write_dat(0x24);
											lcd12864_write_dat(0x24);
											__delay_ms(500);
											lcd12864_write_com(0x9b);
											lcd12864_write_dat(displaydate2);
											__delay_ms(500);
											break;
									case 6:
											lcd12864_write_com(0x83);
											lcd12864_write_dat(0x24);
											lcd12864_write_dat(0x24);
											__delay_ms(500);
											lcd12864_write_com(0x83);
											lcd12864_write_dat(displaydate1[0]);
											lcd12864_write_dat(displaydate1[1]);
											__delay_ms(500);
											break;
			
								}
							if(K3==0)		//检测按键K3是否按下
								{
									__delay_ms(10);	//消除抖动
									if(K3==0)
									{
										TIME[SetPlace]++;
										if((TIME[SetPlace]&0x0f)>9)					 //换成BCD码。
										{
											TIME[SetPlace]=TIME[SetPlace]+6;
										}
										if((TIME[SetPlace]>=0x60)&&(SetPlace<2))		//分秒只能到59
										{
											TIME[SetPlace]=0;
										}
										if((TIME[SetPlace]>=0x24)&&(SetPlace==2))		//小时只能到23
										{
											TIME[SetPlace]=0;
										}
										if((TIME[SetPlace]>=0x32)&&(SetPlace==3))		//日只能到31
										{
											TIME[SetPlace]=0;	
										}
										if((TIME[SetPlace]>=0x13)&&(SetPlace==4))		//月只能到12
										{
											TIME[SetPlace]=0;
										}	
										if((TIME[SetPlace]>=0x7)&&(SetPlace==5))		//周只能到7
										{
											TIME[SetPlace]=1;
										}			
									}
									/*while((i<50)&&(K3==0))	 //检测按键是否松开
									{
										__delay_ms(10);
										i++;
									}*/
									i=0;	
							}
						ds1302_init();
						run();
									
				}
			} 
	}
}

//********************按键扫描初始化扫描函数*********************
void keyset_init()
{
	TRISA=0XFF;
}

//********************函数定义LCD12864*********************
void lcd12864_init()
{
		  ADCON1=0x06;       //PORTA,PORTE设定为数字端口
		  TRISD=0;           //PORTD设置为输出
		  TRISE0=0;
		  TRISE1=0;
		  TRISE2=0;
		  TRISC3=0;  
		  
		  __delay_ms(10);  
		  
		  lcd12864_io_init();
		  lcd12864_write_com(0x30);  //基本指令集
		  lcd12864_write_com(0x0c);  //显示开
		  lcd12864_write_com(0x06);  //光标右移,整体显示不移动
		  lcd12864_write_com(0x01);  //清除显示(清零DDRAM) 	
}
//***************函数定义ds18b20********************
void ds18b20_startconvert()			//ds18b20启动转换 将温度转换为数字量
{
		ds18b20_init();				//ds18b20初始化
		ds18b20_write(ds18b20_skip_rom);			//跳过都序列号的操作
		ds18b20_write(ds18b20_convert_ram);			//启动温度转换
}

unsigned int ds18b20_getconvert()	//ds18b20将温度提取出来
{
		uchar Temperature_L=0;		//温度寄存器低八位
		uchar Temperature_H=0;		//温度寄存器高八位
		
		ds18b20_init();
		ds18b20_write(ds18b20_skip_rom);		//跳过读序列号的操作
		ds18b20_write(ds18b20_read_ram);		//读取温度寄存器(共可读9个寄存器)前两个就是温度
		Temperature_L=ds18b20_read();			//读取低八位
		Temperature_H=ds18b20_read();			//读取高八位
		t=(Temperature_H<<8)|Temperature_L;
		t=(uint)(t*0.0625*100);    //将测量值转换为实际温度并扩大100倍
		if(t>9900) 
		{
		    t=0;
		}
		return t;

}

void T_convert_buf(uint cnt)		//将温度转换为ASCII码便于lcd1602显示
{
		  ds18b20_buf[0]=(cnt/1000)%10+0x30;	//取出十位
		  cnt=cnt%1000;							
		  ds18b20_buf[1]=(cnt/100)%10+0x30;     //取出个位
		  cnt=cnt%100;
		  ds18b20_buf[2]=0x2e;					//小数点
		  ds18b20_buf[3]=cnt/10+0x30;          //取出十分位
		  ds18b20_buf[4]=cnt%10+0x30;          //取出百分位
		  ds18b20_buf[5]=0x27;
		  ds18b20_buf[6]=0x63;
}

void warn()			//温度报警器
{
		TRISC7=0;
		uchar W=50;
		if((t/100)>W)
			{
				bee=~bee;
			}

}
//***************函数定义ds1302********************
void ds1302_datapros() 	 			//将读取的时间BCD码转化成0x,转换为ASCII
{
   	ds1302_read_time();
	displaydate[0]=TIME[2]/16+0X30;				//时
	displaydate[1]=(TIME[2]&0x0f)+0X30;				 
	displaydate[2]=0xca;
	displaydate[3]=0xb1;
	displaydate[4]=TIME[1]/16+0X30;				//分
	displaydate[5]=(TIME[1]&0x0f)+0X30;	
	displaydate[6]=0xb7;
	displaydate[7]=0xd6;
	displaydate[8]=TIME[0]/16+0X30;				//秒
	displaydate[9]=(TIME[0]&0x0f)+0X30;

   
	displaydate1[0]=TIME[6]/16+0X30;				//年
	displaydate1[1]=(TIME[6]&0x0f)+0X30;				 
	displaydate1[2]=0xc4;
	displaydate1[3]=0xea;
	displaydate1[4]=TIME[4]/16+0X30;				//月
	displaydate1[5]=(TIME[4]&0x0f)+0X30;	
	displaydate1[6]=0xd4;
	displaydate1[7]=0xc2;
	displaydate1[8]=TIME[3]/16+0X30;				//日
	displaydate1[9]=(TIME[3]&0x0f)+0X30;
	
	displaydate2=(TIME[5]&0x0f)+0x30;
}


//***************************函数定义lcd12864*********************
void lcd12864_dis_oneline(uchar line,uchar *p)			//显示一行字符
{
  uchar c;
  switch(line%4)
  {
    case 0:   
            lcd12864_write_com(0x80);
            for(c=0;c<6;c++)
            {
              lcd12864_write_dat(*p);
              p++;
              if(*p==0)
              {
                break;
              }
            }    
            break;
    case 1:
            lcd12864_write_com(0x90);
            for(c=0;c<5;c++)
            {
              lcd12864_write_dat(*p);
      			   p++;
              if(*p==0)
              {
                break;
              }
            }
			lcd12864_write_dat(0x04);    
            break;
    case 2:
            lcd12864_write_com(0x88);
            for(c=0;c<5;c++)
            {
              lcd12864_write_dat(*p);
              p++;
              if(*p==0)
              {
                break;
              }
            } 
			lcd12864_write_dat(0x04);    
            break;
    case 3:
            lcd12864_write_com(0x98);
            for(c=0;c<6;c++)
            {
              lcd12864_write_dat(*p);
              p++;
              if(*p==0)
              {
                break;
              }
            }
			lcd12864_write_dat(0x04);     
            break;
    default : break; 
  }
}

void lcd12864_dis_image(uchar *p)		//显示图像
{
  uchar x,y;
  lcd12864_write_com(0x34);	      //扩展指令集动作,绘图显示OFF
  for(y=0;y<32;y++)                //送上半屏显示数据
  {
    lcd12864_write_com(0x80|y);    //送显示Y坐标0x80-0x9f
    lcd12864_write_com(0x80);      //送显示X坐标0x80
    for(x=0;x<16;x++)
    {
      lcd12864_write_dat(*p);
      p++;
    }
  }
							  
  for(y=0;y<32;y++)				       //送下半屏显示数据
  {
    lcd12864_write_com(0x80|y);   //送显示Y坐标0x80-0x9f
    lcd12864_write_com(0x88);     //送显示X坐标0x88
    for(x=0;x<16;x++)			  
    {
      lcd12864_write_dat(*p);
      p++;
    }
  }
  lcd12864_write_com(0x36);       //扩展指令集动作,绘图显示ON
}

//********************综合函数定义RUN*********************
void run()
{
					ds1302_read_time();
					ds1302_datapros();
				    lcd12864_write_com(0x30);     //基本指令集
				    lcd12864_write_com(0x01);     //清除显示(清零DDRAM)
				    int n,q,p;
					
					lcd12864_dis_oneline(0,"日期20");    
					for(n=0;n<10;n++)
					{
						lcd12864_write_dat(displaydate1[n]);
					}
				     
					lcd12864_dis_oneline(1,"时间:");
				    for(q=0;q<10;q++)
					{
						lcd12864_write_dat(displaydate[q]);
					}
					
					lcd12864_dis_oneline(2,"温度:");  
				   	for(p=0;p<7;p++)
					{
						lcd12864_write_dat(ds18b20_buf[p]);
					}
					//__delay_ms(500);
					lcd12864_dis_oneline(3,"星期:");
					lcd12864_write_dat(displaydate2);

 


总结

宝剑锋从磨砺出,梅花香自苦寒来~加油!

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是代码实现: ```python import datetime def format_time_diff(start_time, end_time): time_diff = end_time - start_time if time_diff.days > 365: return end_time.strftime("%Y年%m月") elif time_diff.days > 30: return end_time.strftime("%Y年%m月%d日") elif time_diff.days > 0: return f"{time_diff.days}天前" elif time_diff.seconds > 3600: return f"{int(time_diff.seconds/3600)}小时前" elif time_diff.seconds > 60: return f"{int(time_diff.seconds/60)}分钟前" elif time_diff.seconds > 0: return f"{time_diff.seconds}秒前" else: return "未来时间" start_time = datetime.datetime(2018, 3, 1, 9, 0, 0) end_time = datetime.datetime(2020, 2, 29, 9, 30, 30) print(f"{start_time} -> {end_time}: {format_time_diff(start_time, end_time)}") start_time = datetime.datetime(2020, 1, 1, 9, 0, 0) end_time = datetime.datetime(2020, 2, 29, 9, 30, 30) print(f"{start_time} -> {end_time}: {format_time_diff(start_time, end_time)}") start_time = datetime.datetime(2020, 2, 1, 9, 0, 0) end_time = datetime.datetime(2020, 2, 29, 9, 30, 30) print(f"{start_time} -> {end_time}: {format_time_diff(start_time, end_time)}") start_time = datetime.datetime(2020, 2, 29, 8, 0, 0) end_time = datetime.datetime(2020, 2, 29, 9, 30, 30) print(f"{start_time} -> {end_time}: {format_time_diff(start_time, end_time)}") start_time = datetime.datetime(2020, 2, 29, 9, 29, 20) end_time = datetime.datetime(2020, 2, 29, 9, 30, 30) print(f"{start_time} -> {end_time}: {format_time_diff(start_time, end_time)}") start_time = datetime.datetime(2020, 2, 29, 9, 29, 50) end_time = datetime.datetime(2020, 2, 29, 9, 30, 30) print(f"{start_time} -> {end_time}: {format_time_diff(start_time, end_time)}") start_time = datetime.datetime(2020, 2, 29, 9, 30, 40) end_time = datetime.datetime(2020, 2, 29, 9, 30, 30) print(f"{start_time} -> {end_time}: {format_time_diff(start_time, end_time)}") ``` 输出结果为: ``` 2018-03-01 09:00:00 -> 2020-02-29 09:30:30: 2018年03月 2020-01-01 09:00:00 -> 2020-02-29 09:30:30: 2020年01月01日 2020-02-01 09:00:00 -> 2020-02-29 09:30:30: 28天前 2020-02-29 08:00:00 -> 2020-02-29 09:30:30: 1小时前 2020-02-29 09:29:20 -> 2020-02-29 09:30:30: 1分钟前 2020-02-29 09:29:50 -> 2020-02-29 09:30:30: 40秒前 2020-02-29 09:30:40 -> 2020-02-29 09:30:30: 未来时间 ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值