基于PIC单片机的多功能电子时钟
源起
不久前做一个单片机的课程设计,主要是在液晶显示屏上显示日期时间以及温度。百度好长时间发现绝大部分都是基于51单片机的源程序,移植之后费了好长时间更改,原因是pic和51在一些细节方面有所不同。废话少说上代码,希望可以帮助到大家。
代码
程序目录
- 原始头文件
- LCD12864头文件
- DS1302头文件
- DS18B20头文件
- DS1302功能实现C程序
- 主函数main()
- 原始头文件
/
//
//__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__
- LCD12864头文件
#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
- DS1302头文件
#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
- DS18B20头文件
//**************************DS18B20驱动库****************************
//功能:实现对DS18B20的读取
//原理:单总线协议
//注意:单总线协议对延时要求比较严格,应根据单片机时钟调整延时函数
//
//pic16f877a 4MHz PICC9.8编译器
//*******************************************************************
#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以上
}
}
- 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