苏州大学微机实验——基于DS1302的电子日历的设计

前言

本文是在完成苏州大学电子信息学院微机实验——基于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显示屏,让我可以离开仿真图,进行实际的实验的调试与修改,并最终完成作业。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值