用单片机定时器本人是一名电子爱好者,用业余时间自学的单片机,原来只是想玩玩而已,不过现在才发现自己不知不觉已深陷其中,不能自拔,大家是否有同感?
在网上买的几块钱的3.8寸12864液晶屏,不带字库
用3D打印的外壳,元件不多,没用PCB直接焊接,单片机被我搞成这样
完成后的成品前面
背面
运行效果
https://v.youku.com/v_show/id_XNDQ3ODM1MTA0NA==.html?spm=a2h0k.11417342.soresults.dposter
程序自己加了些注释,水平有限,应该有不少错误,希望大家能够多多指教。
代码:
主程序:
/******************************************************************************
Copyright 2007
All rights reserved.
文件名 :12864.c
模块名称:
功能概要:C51写的公历转农历,并驱动12864(KS0108)汉字液晶显示。
取代版本:0.0.1
修改人 :pulan
完成日期:2007.07.08
升级说明:create
CPU: stc89c58 主频:11.0592M
液晶型号: 生产厂家: 驱动芯片:KS0108
硬件连接:
---------------------------------------------------------------
|DB0-----P0.0 | DB4-----P0.4 | RW-------P2.2 |
|DB1-----P0.1 | DB5-----P0.5 | RS-------P2.1 |
|DB2-----P0.2 | DB6-----P0.6 | E -------P2.5 |
|DB3-----P0.3 | DB7-----P0.7 | Vo接1k电阻到地
---------------------------------------------------------------
******************************************************************************/
#include <reg52.h>
#include <intrins.h>
#include <stdio.h>
#include "shijian.c"
void main(void)
{
initial();
while(1)
{
read_temp();
ds1820disp();
verify_time(); //确认时间正确性
key();
if(setflag==0)
disp_time(); //这里调用显示时间程序
}
}
显示驱动
/******************************************************************************
Copyright 2007
All rights reserved.
文件名 :12864.c
模块名称:
功能概要:C51写的公历转农历,并驱动12864(KS0108)汉字液晶显示。
取代版本:0.0.1
修改人 :pulan
完成日期:2007.07.08
升级说明:create
CPU: stc89c58 主频:11.0592M
液晶型号: 生产厂家: 驱动芯片:KS0108
硬件连接:
---------------------------------------------------------------
|DB0-----P0.0 | DB4-----P0.4 | RW-------P2.2 |
|DB1-----P0.1 | DB5-----P0.5 | RS-------P2.1 |
|DB2-----P0.2 | DB6-----P0.6 | E -------P2.5 |
|DB3-----P0.3 | DB7-----P0.7 | Vo接1k电阻到地
---------------------------------------------------------------
******************************************************************************/
#define uchar unsigned char
sbit LCD_csa=P2^7; //定义左屏开关
sbit LCD_csb=P2^6; //定义右屏开关
sbit LCD_rs =P2^5; //定义数据或指令,1=数据,0=指令
sbit LCD_rw =P2^4; //定义读或写? 1=读, 0=写
sbit LCD_e =P2^3; //定义使能操作, 1=能, 0=否
//sbit LCD_rst = P2^0; //定义复位
sfr LCD_db=0x80; //定义数据端口
/******************************************************************************************
* 函数名称 :lcd_busy
* 功能描述 :判别LCD12864忙否?不忙才跳出此程序
* 参数 : 参数名称: 输入/输出? 类型 描述
*
* 返回值 :
* 作者 :
* 创建日期 :2006-12-19
* 全局变量 :
* 全局静态变量:
* 局部静态变量:
*----------------------------------------修改历史------------------------------------------
* 当前版本 : 修改人: 修改日期:
* 修改说明 :
******************************************************************************************/
void lcd_busy(void)
{
LCD_rs=0;
LCD_rw=1;
LCD_db=0xff;
while (1)
{
LCD_e=1;
if (LCD_db<0x80) //如果要进行简单的软件调试,可在这句前面加"//"跳过
break;
LCD_e=0;
}
LCD_e=0;
}
/******************************************************************************************
* 函数名称 :set_xy
* 功能描述 :设置显示位置! X,Y分别代表横纵坐标!
* 参数 : 参数名称: 输入/输出? 类型 描述
******************************************************************************************/
void set_xy(unsigned char x,unsigned char y)
{
if (x>=64) {LCD_csa=0;LCD_csb=1;}
else {LCD_csa=1;LCD_csb=0;} //判别是左半屏,还是右半屏
lcd_busy();
LCD_rs=LCD_rw=0;
LCD_db=0x40|x; //列地址赋值,x取值0----64
LCD_e=1;LCD_e=0;
lcd_busy();
LCD_rs=LCD_rw=0;
LCD_db=0xb8|y; //页面地址赋值,y取值0----8
LCD_e=1;LCD_e=0;
LCD_db=0xff;
}
/******************************************************************************************
* 函数名称 :lw
* 功能描述 :在指定的位置显示数据
* 参数 : 参数名称: 输入/输出? 类型 描述
******************************************************************************************/
void lw(uchar x,uchar y,uchar dd)
{
set_xy(x,y);
lcd_busy();
LCD_rs=1;
LCD_rw=0;
LCD_db=dd; //数据送显
LCD_e=1;
LCD_e=0;
LCD_db=0xff;
}
/******************************************************************************************
* 函数名称 :lcd_init
* 功能描述 :显示初始化
* 参数 : 参数名称: 输入/输出? 类型 描述
******************************************************************************************/
#pragma disable
void lcd_init(void)
{
unsigned char x,y;
/*开显示*/
// LCD_rst=0;
// Delay12864(100);
// LCD_rst=1;
// Delay12864(100);
LCD_e=LCD_rs=LCD_rw=0;
LCD_csa=LCD_csb=0;
LCD_csa=1; //选择左半屏显示
LCD_db=0x3f; //打开左半屏显示
LCD_e=1;LCD_e=0;LCD_csa=0;
LCD_csb=1; //选择右半屏显示
LCD_db=0x3f; //打开右半屏显示
LCD_e=1;LCD_e=0;LCD_csb=0;
/*0行开始显示*/
LCD_csa=1;lcd_busy();
LCD_rs=LCD_rw=0;LCD_db=0xc0; //设置左半屏起始行,是第一行
LCD_e=1;LCD_e=0;LCD_csa=0;
LCD_csb=1;lcd_busy();
LCD_rs=LCD_rw=0;LCD_db=0xc0; //设置右半屏起始行,是第一行
LCD_e=1;LCD_e=0;LCD_csb=0;
for (y=0;y<8;y++)
{
for (x=0;x<128;x++) lw(x,y,0); //全屏清零显示
}
}
按键程序:
#include<reg52.h>
#include<delayms.h>
#include"xs.c"
sbit set =P3^7; //设置
sbit key1=P3^6; //加
sbit key2=P3^5; //减
sbit key3=P3^4; //蜂鸣开关
sbit key4=P3^3; //背光开关
uchar setflag=0; //按键计数
sbit bl=P2^0; //背光控制端
sbit bz=P2^1; //蜂鸣控制端
void key() //按键程序
{
if(set==0) //如果设置键按下
{
delayms(5); //延时消抖
if(set==0) //再次确认设置键按下
{
setflag++; //按键计数加1
while(!set); //等待按键松开
switch(setflag)
{
case 1:// TR0=0; //定时器0关闭
dashuzi(4,2,10,0); //显示时与分中间的冒号
dashuzi(10,2,10,0); //显示分与秒中间的冒号
dispmiao(sec,1); //秒反显
break;
case 2: dispmiao(sec,0); //秒正显
dispfen(min,1); //分反显
break;
case 3: dispfen(min,0); //分正显
dispshi(hour,1);// //时反显
break;
case 4: dispshi(hour,0); //时正显
dispri(day,1); //日反显
break;
case 5: dispri(day,0); //日正显
dispyue(month,1); //月反显
break;
case 6: dispyue(month,0); //月正显
dispnian(year,1); //年反显
break;
case 7: setflag=0; //按键计数变为0
dispnian(year,0); //年正显
// TR0=1; //定时器0启动
break;
default:;
}
}
}
if(setflag!=0) //如果按键计数不为0
{
if(key1==0) //如果加键按下
{
delayms(5); //延时消抖
if(key1==0) //再次确认加键按下
{
while(!key1); //等待加键松开
switch(setflag)
{
case 1:// sec++; //秒加1
// if(sec==60)
sec=0; //如果秒加到60,秒归0
dispmiao(sec,1); //调用秒反显
break;
case 2: min++; //分加1
if(min==60) min=0; //如果分加到60,分归0
dispfen(min,1); //调用分反显
break;
case 3: hour++; //小时加1
if(hour==24) hour=0; //如果小时加到24,小时归0
dispshi(hour,1); //调用小时反显
break;
case 4: day++; //日加1
if(day==32) day=1; //如果日加到32,日变为1
dispri(day,1); //调用日反显
break;
case 5: month++; //月加1
if(month==13) month=1;//如果月加到13
dispyue(month,1); //调用月反显
break;
case 6: year++; //年加1
if(year==100) year=0; //如果年加到100,年归0
dispnian(year,1); //调用年反显
break;
default:;
}
}
}
if(key2==0) //如果减键按下
{
delayms(5); //延时消抖
if(key2==0) //再次确认减键按下
{
while(!key2) ; //等待减键松开
switch(setflag)
{
case 1:// sec--; //秒减1
// if(sec<0)
sec=0;//59; //如果秒小于0,秒变为59
dispmiao(sec,1); //调用秒反显
break;
case 2: min--; //分减1
if(min<0) min=59; //如果分小于0,分变为59
dispfen(min,1); //调用分反显
break;
case 3: hour--; //小时减1
if(hour<0) hour=23; //如果小时小于0,小时变为23
dispshi(hour,1); //调用小时反显
break;
case 4: day--; //日减1
if(day==0) day=31; //如果日减到0,日变为31
dispri(day,1); //调用日反显
break;
case 5: month--; //月减1
if(month==0) month=12;//如果月减到0,月变为12
dispyue(month,1); //调用月反显
break;
case 6: year--; //年减1
if(year<0) year=99; //如果年小于0,年变为99
dispnian(year,1); //
break;
default:;
}
}
}
}
if(setflag==0&&key3==0) //走时状态且蜂鸣开关按下时
{
delayms(5); //延时消抖
if(setflag==0&&key3==0) //再次确认走时状态且蜂鸣开关按下时
{
while(!key3); //等待蜂鸣开关松开
bz=~bz; //蜂鸣输出取反
}
}
if(setflag==0&&key4==0) //走时状态且背光开关按下时
{
delayms(5); //延时消抖
if(setflag==0&&key4==0) //再次确认走时状态且背光开关按下时
{
while(!key4); //等待背光开关松开
bl=~bl; //背光输出取反
}
}
}
下面是完整程序和仿真:
★★3-带农历万年历.zip
(118.95 KB, 下载次数: 248)
随后再加上闹钟和整点报时。
|