前言
本文是在完成苏州大学电子信息学院微机实验——基于DS1302的电子日历的设计过程中所萌生的一个想法,相比于各路大佬,可能会有很多地方存在不足,还请见谅。用到的主要芯片和设备有STC15系列单片机,DS1302,LCD1602液晶显示器。
系统功能设计要求
1. 显示当前时间信息,即年、月、日、星期、时、分、秒;
2. 时间暂停;
3. 时间校准功能。
LCD1602介绍
【常用传感器】LCD1602液晶工作原理详解及例程代码-CSDN博客
DS1302介绍
单片机常用芯片总结(二)——DS1302时钟芯片-CSDN博客
功能实现
时间显示:
开发板上电默认时间为2023年12月13日10:00:00,可在程序内部更改。LCD显示屏第一行显示DATE:23-12-13WEN,第二行显示TIME:10:00:00。

时间调整功能:
年份调整模式,按下矩阵键盘S7,LCD显示屏第一行显示YearSet,第二行显示当前显示器的年份,同时LED灯L1亮起;

月份调整模式,按下矩阵键盘S11,LCD显示屏第一行显示MonthSet,第二行显示当前显示器的月份,同时LED灯L2亮起;

日期调整模式按下矩阵键盘S15,,LCD显示屏第一行显示DateSet,第二行显示当前显示器的日期,同时LED灯L3亮起;

小时调整模式,按下矩阵键盘S6,LCD显示屏第一行显示HourSet,第二行显示当前显示器的小时,同时LED灯L4亮起;

分钟调整模式,按下矩阵键盘S10,LCD显示屏第一行显示MinuteSet,第二行显示当前显示器的分钟,同时LED灯L5亮起;

秒钟调整模式,按下矩阵键盘S114,LCD显示屏第一行显示SecondSet,第二行显示当前显示器的秒,同时LED灯L6亮起;

星期调整模式,按下矩阵键盘S15,LCD显示屏第一行显示DaySet,第二行显示当前显示器的星期,同时LED灯L7亮起。

在各调整模式中,按键S19用于加调整,按键S18用于减调整。同时对年份、月份、日期、星期、是、分、秒都做了限制,调整不会超出范围,提供闰年判定功能,2月份的日期调整范围会相应变化。
确认键与取消键:
进入时间调整模式后,时间进入虚假暂停状态,等待调整,在各调整模式中调整完毕后,按下按键S12取消调整,对时间无影响;按下按键S16后,时间才会被真的调整。
时间暂停功能:
按下矩阵键盘S4,LCD显示屏显示的时间保持不变(内部时间正常变动),在此状态下,仍可通过其他按键进入时间调整,若要退出此状态,可按下按键S12,时间从内部时间继续走,按下按键S16,时间从被暂停的时间继续走。
本实验各模块代码如下
main.c
#include <STC15F2K60S2.H>
#include <DS1302.H>
#include "LCD1602.h"
#include "Led.h"
int key_flag = 0; // ???????
unsigned char key_value = 0xff;// ?????
unsigned char mode=0;
void cls_buzz(void) //????????
{
P2 = (P2 & 0x1F | 0xA0);
P0 = 0x00;
P2 &= 0x1F;
}
void Day_Show()//显示星期
{
switch(DS1302_Time[6])
{
case 1:
LCD_Display_String(1,14,"MON");
break;
case 2:
LCD_Display_String(1,14,"TUE");
break;
case 3:
LCD_Display_String(1,14,"WEN");
break;
case 4:
LCD_Display_String(1,14,"THU");
break;
case 5:
LCD_Display_String(1,14,"FRI");
break;
case 6:
LCD_Display_String(1,14,"SAT");
break;
case 7:
LCD_Display_String(1,14,"SUN");
break;
}
}
void read_keyboard(void)//矩阵键盘读取
{
static unsigned char hang;
static unsigned char key_state=0;
switch(key_state)
{
case 0:
{
P3 = 0x0f; P42 = 0; P44 = 0;
if(P3 != 0x0f) //有按键按下
key_state=1;
}
break;
case 1:
{
P3 = 0x0f; P42 = 0; P44 = 0;
if(P3 != 0x0f) //有按键按下
{
if(P30 == 0)hang = 1;
if(P31 == 0)hang = 2;
if(P32 == 0)hang = 3;
if(P33 == 0)hang = 4;//确定行
switch(hang){
case 1:{P3 = 0xf0; P42 = 1; P44 = 1;
if(P44 == 0) {key_value=0;key_state=2;}//S7按下
else if(P42 == 0) {key_value=1;key_state=2;}//S11按下
else if(P35 == 0) {key_value=2;key_state=2;}//S15按下
else if(P34 == 0) {key_value=3;key_state=2;}//S19按下
}
break;
case 2:{P3 = 0xf0; P42 = 1; P44 = 1;
if(P44 == 0) {key_value=4;key_state=2;}//S6按下
else if(P42 == 0) {key_value=5;key_state=2;}//S10按下
else if(P35 == 0) {key_value=6;key_state=2;}//S14按下
else if(P34 == 0) {key_value=7;key_state=2;}//S18按下
}
break;
case 3:{P3 = 0xf0; P42 = 1; P44 = 1;
if(P44 == 0) {key_value=8;key_state=2;}//S5按下
else if(P42 == 0) {key_value=9;key_state=2;}//S9按下
else if(P35 == 0) {key_value=10;key_state=2;}//S13按下
else if(P34 == 0) {key_value=11;key_state=2;}//S17按下
}
break;
case 4:{P3 = 0xf0; P42 = 1; P44 = 1;
if(P44 == 0) {key_value=12;key_state=2;}//S4按下
else if(P42 == 0) {key_value=13;key_state=2;}//S8按下
else if(P35 == 0) {key_value=14;key_state=2;}//S12按下
else if(P34 == 0) {key_value=15;key_state=2;}//S16按下
}
break;
}
}
else
{
key_state=0;
}
}
break;
case 2:
{
P3 = 0x0f; P42 = 0; P44 = 0;
if(P3 == 0x0f) //按键放开
key_state=0;
}
break;
}
}
void KeyAction()
{
switch(key_value)
{
case 0:
mode=1;
LED(0xfe);
break;
case 1:
mode=2;
LED(0xfd);
break;
case 2:
mode=3;
LED(0xfb);
break;
case 4:
mode=4;
LED(0xf7);
break;
case 5:
mode=5;
LED(0xef);
break;
case 6:
mode=6;
LED(0xdf);
break;
case 8:
mode=7;
LED(0xbf);
break;
case 12:
mode=12;
LED(0x00);
break;
case 14://修改取消
LCD_Init();
mode=0;
break;
case 15:
mode=15;
LED(0xff);
break;
}
}
void Disply()
{
switch(mode)
{
case 0:
DS1302_Time_ReLoad();
LCD_Display_String(1,1,"DATE:");
LCD_Display_String(2,1,"TIME:");
LCD_Display_String(1,8,"-");
LCD_Display_String(1,11,"-");
LCD_Display_String(2,8,":");
LCD_Display_String(2,11,":");
DS1302_ReadTime();
DS1302_ShowTime();
Day_Show();
break;
case 1://修改年份
LCD_Display_String(1,1,"YearSet ");
LCD_WriteNum(2,1,2,0,Temp_DS1302_Time[0]);
if(key_value==3)//??S15????+1
{
Temp_DS1302_Time[0]++;//?+1
if(Temp_DS1302_Time[0]>99){Temp_DS1302_Time[0]=0;}//??0-99
}
if(key_value==7)//??S19????-1
{
Temp_DS1302_Time[0]--;//?-1
if(Temp_DS1302_Time[0]<0){Temp_DS1302_Time[0]=99;}//??1-99
}
break;
case 2://月修改
LCD_Display_String(1,1,"MonthSet ");
LCD_WriteNum(2,1,2,0,Temp_DS1302_Time[1]);
if(key_value==3)//??S15????+1
{
Temp_DS1302_Time[1]++;//
if(Temp_DS1302_Time[1]>12){Temp_DS1302_Time[1]=1;}//??1-12
}
if(key_value==7)//??S19????-1
{
Temp_DS1302_Time[1]--;
if(Temp_DS1302_Time[1]<1){Temp_DS1302_Time[1]=12;}//?
}
break;
case 3://日修改
LCD_Display_String(1,1,"DateSet ");
LCD_WriteNum(2,1,2,0,Temp_DS1302_Time[2]);
if(key_value==3)//??S15????+1
{
Temp_DS1302_Time[2]++;
if( Temp_DS1302_Time[1]==1 || Temp_DS1302_Time[1]==3 || Temp_DS1302_Time[1]==5 || Temp_DS1302_Time[1]==7 ||
Temp_DS1302_Time[1]==8 || Temp_DS1302_Time[1]==10 || Temp_DS1302_Time[1]==12)//??
{
if(Temp_DS1302_Time[2]>31){Temp_DS1302_Time[2]=1;}//??1-31
}
else if(Temp_DS1302_Time[1]==4 || Temp_DS1302_Time[1]==6 || Temp_DS1302_Time[1]==9 || Temp_DS1302_Time[1]==11)//??
{
if(Temp_DS1302_Time[2]>30){Temp_DS1302_Time[2]=1;}//??1-30
}
else if(Temp_DS1302_Time[1]==2)
{
if(Temp_DS1302_Time[0]%4==0)//?2?
{
if(Temp_DS1302_Time[2]>29){Temp_DS1302_Time[2]=1;}//?29
}
else
{
if(Temp_DS1302_Time[2]>28){Temp_DS1302_Time[2]=1;}//??2?28?
}
}
}
if(key_value==7)//??S19????-1
{
Temp_DS1302_Time[2]--;
if( Temp_DS1302_Time[1]==1 || Temp_DS1302_Time[1]==3 || Temp_DS1302_Time[1]==5 || Temp_DS1302_Time[1]==7 ||
Temp_DS1302_Time[1]==8 || Temp_DS1302_Time[1]==10 || Temp_DS1302_Time[1]==12)
{
if(Temp_DS1302_Time[2]<1){Temp_DS1302_Time[2]=31;}
if(Temp_DS1302_Time[2]>31){Temp_DS1302_Time[2]=1;}
}
else if(Temp_DS1302_Time[1]==4 || Temp_DS1302_Time[1]==6 || Temp_DS1302_Time[1]==9 || Temp_DS1302_Time[1]==11)
{
if(Temp_DS1302_Time[2]<1){Temp_DS1302_Time[2]=30;}
if(Temp_DS1302_Time[2]>30){Temp_DS1302_Time[2]=1;}
}
else if(Temp_DS1302_Time[1]==2)
{
if(Temp_DS1302_Time[0]%4==0)
{
if(Temp_DS1302_Time[2]<1){Temp_DS1302_Time[2]=29;}
if(Temp_DS1302_Time[2]>29){Temp_DS1302_Time[2]=1;}
}
else
{
if(Temp_DS1302_Time[2]<1){Temp_DS1302_Time[2]=28;}
if(Temp_DS1302_Time[2]>28){Temp_DS1302_Time[2]=1;}
}
}
}
break;
case 4://时修改
LCD_Display_String(1,1,"HourSet ");
LCD_WriteNum(2,1,2,0,Temp_DS1302_Time[3]);
if(key_value==3)//??S15????+1
{
Temp_DS1302_Time[3]++;
if(Temp_DS1302_Time[3]>23){Temp_DS1302_Time[3]=0;}//???24
}
if(key_value==7)//??S19????-1
{
Temp_DS1302_Time[3]--;
if(Temp_DS1302_Time[3]<0){Temp_DS1302_Time[3]=23;}
}
break;
case 5://分修改
LCD_Display_String(1,1,"MinuteSet ");
LCD_WriteNum(2,1,2,0,Temp_DS1302_Time[4]);
if(key_value==3)//??S15??s??+1
{
Temp_DS1302_Time[4]++;
if(Temp_DS1302_Time[4]>59){Temp_DS1302_Time[4]=0;}//?60
}
if(key_value==7)//??S19????-1
{
Temp_DS1302_Time[4]--;
if(Temp_DS1302_Time[4]<0){Temp_DS1302_Time[4]=59;}
}
break;
case 6://秒修改
LCD_Display_String(1,1,"SecondSet ");
LCD_WriteNum(2,1,2,0,Temp_DS1302_Time[5]);
if(key_value==3)//??S15????+1
{
Temp_DS1302_Time[5]++;
if(Temp_DS1302_Time[5]>59){Temp_DS1302_Time[5]=0;}//?60
}
if(key_value==7)//??S19????-1
{
Temp_DS1302_Time[5]--;
if(Temp_DS1302_Time[5]<0){Temp_DS1302_Time[5]=59;}
}
break;
case 7://星期修改
LCD_Display_String(1,1,"DaySet ");
LCD_WriteNum(2,1,2,0,Temp_DS1302_Time[6]);
if(key_value==3)//??S15????+1
{
Temp_DS1302_Time[6]++;//?+1
if(Temp_DS1302_Time[6]>7){Temp_DS1302_Time[0]=1;}//??0-99
}
if(key_value==7)//??S19????-1
{
Temp_DS1302_Time[6]--;//?-1
if(Temp_DS1302_Time[6]==0){Temp_DS1302_Time[0]=7;}//??1-99
}
break;
case 12://时间暂停
DS1302_Time_ReLoad();
LCD_Display_String(1,1,"DATE:");
LCD_Display_String(2,1,"TIME:");
LCD_Display_String(1,8,"-");
LCD_Display_String(1,11,"-");
LCD_Display_String(2,8,":");
LCD_Display_String(2,11,":");
LCD_WriteNum(1,6,2,0,Temp_DS1302_Time[0]);
LCD_WriteNum(1,9,2,0,Temp_DS1302_Time[1]);
LCD_WriteNum(1,12,2,0,Temp_DS1302_Time[2]);
LCD_WriteNum(2,6,2,0,Temp_DS1302_Time[3]);
LCD_WriteNum(2,9,2,0,Temp_DS1302_Time[4]);
LCD_WriteNum(2,12,2,0,Temp_DS1302_Time[5]);
Day_Show();
break;
case 15://修改确认
LCD_Init();
DS1302_Time_Load();
DS1302_Time_ReLoad();
DS1302_ReSetTime();
mode=0;
break;
}
key_value = 0xff;
}
/**********************************************************
* @name Timer0Init
* @brief Timer0??????
* @param void
* @return none
**********************************************************/
void Timer0_Isr(void) interrupt 1
{
static unsigned char icount = 0; // 定时辅助计数
if(icount==10)
{
key_flag = 1;
icount=0;
}
icount++;
}
/**********************************************************
* @name Timer0Init
* @brief Timer0定时器初始化
* @param void
* @return none
**********************************************************/
void Timer0_Init(void) //1毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x20; //设置定时初始值
TH0 = 0xD1; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //使能定时器0中断
EA=1;
}
void main(void)
{
cls_buzz();
DS1302_Init();
LCD_Init();
Timer0_Init();//??????
DS1302_SetTime();
LED(0xff);//关LED
while(1)
{
if(key_flag)
{
key_flag = 0;
read_keyboard();
if(key_value != 0xFF)
{
LCD_Init();
KeyAction();
}
}
Disply();
}
}
DS1302.h
#ifndef __ds1302_H__
#define __ds1302_H__
extern int DS1302_Time[],Temp_DS1302_Time[];
extern unsigned char KeyNum,MODE,TimeSetFlashFlag;
void DS1302_Init(void);//初始化
void DS1302_WriteByte(unsigned char Command,Data);//写入
unsigned char DS1302_ReadByte(unsigned char Command);//读取
void DS1302_Time_Load(void);//时间加载
void DS1302_Time_ReLoad(void);//反加载
void DS1302_SetTime(void);//时间设置
void DS1302_ReSetTime(void);//反设置
void DS1302_ReadTime(void);//读时间
void DS1302_ShowTime(void);//显示时间
void DS1302_ShowStopTime(void);//暂停时间并显示
#endif
DS1302.c
#include <STC15F2K60S2.h>
#include <intrins.h>
#include "LCD1602.h"
sbit DS1302_SCLK=P1^7;
sbit DS1302_IO=P2^3;
sbit DS1302_CE=P1^3;
#define DS1302_SECOND 0x80
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 0x84
#define DS1302_DATE 0x86
#define DS1302_MONTH 0x88
#define DS1302_DAY 0x8A
#define DS1302_YEAR 0x8C
#define DS1302_WP 0x8E
int Temp_DS1302_Time[]={23,12,13,10,0,0,3}; //??????????????
int DS1302_Time[]={23,12,13,10,0,0,3}; //??????????????
unsigned char TimeSetSelect;
// char *week[]={"SUN"."MON","TUE","WEN","THU","FRI","SAT"};//?
void DS1302_Init()
{
DS1302_CE=0;
DS1302_SCLK=0;
}
/**
* @brief DS1302?????
* @param Command ???/??
* @param Data ??????
* @retval ?
*/
void DS1302_WriteByte(unsigned char Command,Data)
{
unsigned char i;
DS1302_CE=1;
for(i=0;i<8;i++)
{
DS1302_IO=Command&(0x01<<i);
DS1302_SCLK=1;
DS1302_SCLK=0;
}
for(i=0;i<8;i++)
{
DS1302_IO=Data&(0x01<<i);
DS1302_SCLK=1;
DS1302_SCLK=0;
}
DS1302_CE=0;
}
/**
* @brief DS1302?????
* @param Command ???/??
* @retval ?????
*/
unsigned char DS1302_ReadByte(unsigned char Command)
{
unsigned char i,Data=0x00;
Command|=0x01; //?????????
DS1302_CE=1;
for(i=0;i<8;i++)
{
DS1302_IO=Command&(0x01<<i);
DS1302_SCLK=0;
DS1302_SCLK=1;
}
for(i=0;i<8;i++)
{
DS1302_SCLK=1;
DS1302_SCLK=0;
if(DS1302_IO){Data|=(0x01<<i);}
}
DS1302_CE=0;
DS1302_IO=0; //????IO???0,??????????
return Data;
}
void DS1302_Time_Load()
{
int i=0;
for(i=0;i<7;i++)
{
DS1302_Time[i]=Temp_DS1302_Time[i];
}
}
void DS1302_Time_ReLoad()
{
int i=0;
for(i=0;i<7;i++)
{
Temp_DS1302_Time[i]=DS1302_Time[i];
}
}
/**
* @brief DS1302????,????,DS1302_Time??????????DS1302?
* @param ?
* @retval ?
*/
void DS1302_SetTime(void)
{
DS1302_WriteByte(DS1302_WP,0x00);
DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);//????BCD????
DS1302_WriteByte(DS1302_MONTH,DS1302_Time[1]/10*16+DS1302_Time[1]%10);
DS1302_WriteByte(DS1302_DATE,DS1302_Time[2]/10*16+DS1302_Time[2]%10);
DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10);
DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10);
DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10);
DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);
DS1302_WriteByte(DS1302_WP,0x80);
}
void DS1302_ReSetTime(void)
{
DS1302_WriteByte(DS1302_WP,0x00);
DS1302_WriteByte(DS1302_YEAR,Temp_DS1302_Time[0]/10*16+Temp_DS1302_Time[0]%10);//????BCD????
DS1302_WriteByte(DS1302_MONTH,Temp_DS1302_Time[1]/10*16+Temp_DS1302_Time[1]%10);
DS1302_WriteByte(DS1302_DATE,Temp_DS1302_Time[2]/10*16+Temp_DS1302_Time[2]%10);
DS1302_WriteByte(DS1302_HOUR,Temp_DS1302_Time[3]/10*16+Temp_DS1302_Time[3]%10);
DS1302_WriteByte(DS1302_MINUTE,Temp_DS1302_Time[4]/10*16+Temp_DS1302_Time[4]%10);
DS1302_WriteByte(DS1302_SECOND,Temp_DS1302_Time[5]/10*16+Temp_DS1302_Time[5]%10);
DS1302_WriteByte(DS1302_DAY,Temp_DS1302_Time[6]/10*16+Temp_DS1302_Time[6]%10);
DS1302_WriteByte(DS1302_WP,0x80);
}
/**
* @brief DS1302????,????,DS1302?????????DS1302_Time???
* @param ?
* @retval ?
*/
void DS1302_ReadTime(void)
{
unsigned char Temp;
Temp=DS1302_ReadByte(DS1302_YEAR);
DS1302_Time[0]=Temp/16*10+Temp%16;//BCD???????
Temp=DS1302_ReadByte(DS1302_MONTH);
DS1302_Time[1]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_DATE);
DS1302_Time[2]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_HOUR);
DS1302_Time[3]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_MINUTE);
DS1302_Time[4]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_SECOND);
DS1302_Time[5]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_DAY);
DS1302_Time[6]=Temp/16*10+Temp%16;
}
void DS1302_ShowTime(void)
{
LCD_WriteNum(1,6,2,0,DS1302_Time[0]);
LCD_WriteNum(1,9,2,0,DS1302_Time[1]);
LCD_WriteNum(1,12,2,0,DS1302_Time[2]);
LCD_WriteNum(2,6,2,0,DS1302_Time[3]);
LCD_WriteNum(2,9,2,0,DS1302_Time[4]);
LCD_WriteNum(2,12,2,0,DS1302_Time[5]);
}
LCD1602.h
#ifndef __LCD1602_H__
#define __LCD1602_H__
void LcdWriteCom(unsigned char com);
void LcdWriteData(unsigned char dat);
void LCD_Init(void);
void LCD_SET_POS(unsigned char p,unsigned char q);
void LCD_Display_Char(unsigned char p,unsigned char q,unsigned char ch);
void LCD_Display_String(unsigned char p,q,unsigned char *s);
unsigned char LCD_WriteNum(unsigned char p, unsigned char q, unsigned char len, unsigned char point, long num);
//unsigned char LCD_WriteHex(unsigned char p, unsigned char q, unsigned char len, long num);
#endif
LCD1602.h
#include <LCD1602.h>
#include <STC15F2K60S2.H>
//1602的控制引脚定义
sbit RS = P2^0; //寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器
sbit RW = P2^1; //读写控制,低写,高读
// RS=0、RW=0——表示向LCM写入指令,可以写入指令或者显示地址
// RS=0、RW=1——表示读取Busy标志
// RS=1、RW=0——表示向LCM写入数据
// RS=1、RW=1——表示从LCM读取数据
sbit EN = P1^2; //使能端,当E端由高电平跳变成低电平时,液晶模块执行命令
#define LCD_DATA P0 //定义传入数据的特殊功能寄存器,或者使用 “static sfr LCD_DATA=0X80;”定义
static unsigned char MaxStrlen = 40; //定义一行最多显示字符数
/*****函数部分*****/
static void LCD_Delay();
static bit LCD_BUSY(void);
/*************************************************
* @name LCD_Delay()
* @brief LCD延时函数(12Mhz晶振延时4uS)
* @param 无
* @return 无
**************************************************/
static void LCD_Delay()
{
unsigned char data i;
i = 10;
while (--i);
}
/*************************************************
* @name LCD_BUSY()
* @brief 检测LCD1602是否处于忙状态
* @param 无
* @return 忙信号布尔值(bit)。返回1,则LCD_BUSY;返回0,则OK
**************************************************/
static bit LCD_BUSY(void)
{
LCD_DATA=0xff;
RS = 0;
RW = 1;
EN = 1;
LCD_Delay();
EN = 0;
return (bit)(LCD_DATA & 0x80); //最高位为忙信号位
}
/*************************************************
* @name LcdWriteCom()
* @brief LCD写一字节命令
* @param cmd 待写控制命令(unsigned char)
* @return 无
**************************************************/
void LcdWriteCom(unsigned char cmd)
{
while(LCD_BUSY()); //测忙
RS = 0;
RW = 0;
EN = 1;
LCD_DATA = cmd;
LCD_Delay();
EN = 0;
}
/*************************************************
* @name LcdWriteData()
* @brief LCD写一字节数据
* @param dat 待写显示数据(unsigned char)
* @return 无
**************************************************/
void LcdWriteData(unsigned char dat)
{
while(LCD_BUSY()); //测忙
RS = 1;
RW = 0;
EN = 1;
LCD_DATA = dat;
LCD_Delay();
EN = 0;
}
/*************************************************
* @name LCD_ClsLine()
* @brief LCD清除行
* @param line 设置待清除行号(unsigned char)
* @return 无
**************************************************/
void LCD_ClsLine(unsigned char line)
{
unsigned char i=0;
for(i=0;i<16;i++)
LCD_Display_Char(i,line,' ');
}
/*************************************************
* @name LCD_Clear()
* @brief LCD清屏
* @param 无
* @return 无
**************************************************/
void LCD_Clear(void)
{
LCD_ClsLine(0);
LCD_ClsLine(1);
}
/*************************************************
* @name LcdInit()
* @brief LCD液晶屏的初始化
* @param 无
* @return 无
**************************************************/
void LCD_Init(void)
{
LcdWriteCom(0x38); //功能设置,8位数据接口,两行显示,5×8点阵,即0b00111000也就是0x38
LcdWriteCom(0x0c); //显示开关控制,00001100 显示开,光标不显示,光标不闪烁
LcdWriteCom(0x06); //输入方式设置,00000110 I/D=1:写入新数据后光标右移;S=0:显示不移动。
LcdWriteCom(0x01); //清除LCD的显示内容
LCD_Clear();
}
/*************************************************
* @name LCD_Display_Char()
* @brief LCD写一个字符
* @param p 设置显示的行坐标(unsigned char)
* @param q 设置显示的列坐标(unsigned char)
* @param ch 待写字符(unsigned char)
* @return 无
**************************************************/
void LCD_Display_Char(unsigned char p,unsigned char q,unsigned char ch)
{
unsigned char addr;
p-=1;
q-=1;
while(q>=16)
{
q-=16;
p++;
}
while(p>=2) p-=2;
if (p == 0)
{
addr = 0x00 + q; //第一行的x位置显示
}
else
{
addr = 0x40 + q; //第二行x的位置显示
}
LcdWriteCom(addr + 0x80);
LcdWriteData(ch);
}
/*************************************************
* @name LCD_Display_String()
* @brief LCD写字符串
* @param p 设置显示的行坐标(unsigned char)
* @param q 设置显示的列坐标(unsigned char)
* @param str 待写字符串(unsigned char)
* @return 字符长度(unsigned char)
**************************************************/
void LCD_Display_String(unsigned char p,unsigned char q, unsigned char *str)
{
unsigned char i=0;
while(str[i]!=0)
{
LCD_Display_Char(p,q, str[i]);
q++;
i++;
}
}
/*************************************************
* @name LCD_WriteNum()
* @brief LCD写一个数字。
* 整数显示——len=数字位数,point=0,num=要显示的数字;
* 小数显示——len=num位数,point=小数位数,num=需要显示的小数*10^(point)(即,先将小数放大为整形)
* @param p 设置显示的行坐标(unsigned char)
* @param q 设置显示的列坐标(unsigned char)
* @param len 待显示的数字位数(unsigned char)
* @param point 小数点位置(unsigned char)。point=0时,显示整数
* @param num 待显示的数字(long)。小数请放大为整数,范围-2147483648~2147483648
* @return 显示出来的数字所占真实位数(unsigned char)
**************************************************/
unsigned char LCD_WriteNum(unsigned char p, unsigned char q, unsigned char len, unsigned char point, long num)
{
unsigned char real_len, flag=0;
if(point) len++;
else point--;
if(num<0)
{
LCD_Display_Char(p,q,'-');
len++;
num=-num;
flag=1;
}
real_len=len+6;
while(len-flag)
{
if(num>=0) len--;
if(point)
{
LCD_Display_Char(p, q+len, '0'+num%10);
num/=10;
}
else
{
LCD_Display_Char(p, q+len, '.');
}
point--;
}
return real_len;
}
LED..h
#ifndef __LED_H_
#define __LED_H_
void LED(unsigned char x);
#endif
LED.c
#include <STC15F2K60S2.H>
#include "Led.h"
void LED(unsigned char x)
{
P2 = ((P2 & 0x1f) | 0x80);
P0 = x;
P2 &= 0x1f;
}
总结与感悟
以上代码仅实现了实验要求的功能,如需增加额外的功能用于作业加分,恕作者无能为力。
作为一名小白,在完成这份作业的过程中,除了任课老师外,得到了多名同学的帮助,他们是WGL、CYX、XYL,在此十分感谢,特别感谢WGL同学赠送了一块LCD1602显示屏,让我可以离开仿真图,进行实际的实验的调试与修改,并最终完成作业。
2万+

被折叠的 条评论
为什么被折叠?



