单片机万年历

单片机万年历,第1张

今天碰到了N个白痴问题。万年历是能够显示年月日、二十四节气、农历之类的东西,单片机是一块芯片。万年历可以用单片机来做,但是我真不知道“万年历单片机”怎么做。我想你应该想问的是怎么用单片机来做万年历,我提供思路。 1、单片机最小系统一块。可以用STC89C52芯片+外围电路。可以烧入用户编写的程序,实现万年历所需的逻辑。 2、实时时钟电路一块,可以用DS1302芯片。提供年月日、时分秒数据给单片机。 3、显示器电路一块。用来显示这些数据。 4、一些必要的按键,用来调整数据。

顶层文件 万年历.C

#include<reg51.h>

#include "LCD1602.h"

#include "DS1302.h"

#define uchar unsigned char

#define uint unsigned int

sbit speaker=P2^4

bit key_flag1=0,key_flag2=0

SYSTEMTIME adjusted

uchar sec_add=0,min_add=0,hou_add=0,day_add=0,mon_add=0,yea_add=0

uchar data_alarm[7]={0}

/************键盘控制******************************/

int key_scan() //扫描是否有键按下

{ int i=0

uint temp

P1=0xf0

temp=P1

if(temp!=0xf0)

i=1

else

i=0

return i

}

uchar key_value() //确定按键的值

{

uint m=0,n=0,temp

uchar value

uchar v[4][3]={'2','1','0','5','4','3','8','7','6','b','a','9'}

P1=0xfe temp=P1if(temp!=0xfe)m=0

P1=0xfdtemp=P1 if(temp!=0xfd)m=1

P1=0xfbtemp=P1 if(temp!=0xfb)m=2

P1=0xf7temp=P1 if(temp!=0xf7)m=3

P1=0xeftemp=P1 if(temp!=0xef)n=0

P1=0xdftemp=P1 if(temp!=0xdf)n=1

P1=0xbftemp=P1 if(temp!=0xbf)n=2

value=v[m][n]

return value

}

/***************************设置闹铃函数*******************************/

void naoling(void)

{

uchar i=0,l=0,j

init1602()

while(key_flag2&&i<12)

if(key_scan()){j=key_value()write_data(j)if(i%2==0)data_alarm[l]=(j-'0')*10else {data_alarm[l]+=(j-'0')l++}i++delay(600)}

write_com(0x01)

}

uchar according(void)

{ uchar k

if(data_alarm[0]==adjusted.Year&&data_alarm[1]==adjusted.Month&&data_alarm[2]==adjusted.Day&&data_alarm[3]==adjusted.Hour&&data_alarm[4]==adjusted.Minute&&data_alarm[5]==adjusted.Second)

k=1

else k=0

return k

}

void speak(void)

{uint i=50

while(i)

{speaker=0

delay(1)

speaker=1

delay(1)

i--

}

}

void alarm(void)

{uint i=10

while(i)

{

speak()

delay(10)

i--

}

}

/**************************修改时间 *** 作********************************/

void reset(void)

{

sec_add=0

min_add=0

hou_add=0

day_add=0

mon_add=0

yea_add=0

}

void adjust(void)

{

if(key_scan()&&key_flag1)

switch(key_value())

{case '0':sec_add++break

case '1':min_add++break

case '2':hou_add++break

case '3':day_add++break

case '4':mon_add++break

case '5':yea_add++break

case 'b':reset()break

default: break

}

adjusted.Second+=sec_add

adjusted.Minute+=min_add

adjusted.Hour+=hou_add

adjusted.Day+=day_add

adjusted.Month+=mon_add

adjusted.Year+=yea_add

if(adjusted.Second>59) adjusted.Second=adjusted.Second%60

if(adjusted.Minute>59) adjusted.Minute=adjusted.Minute%60

if(adjusted.Hour>23) adjusted.Hour=adjusted.Hour%24

if(adjusted.Day>31) adjusted.Day=adjusted.Day%31

if(adjusted.Month>12) adjusted.Month=adjusted.Month%12

if(adjusted.Year>100) adjusted.Year=adjusted.Year%100

}

/**************************中断处理函数*********************************/

void changing(void) interrupt 0 using 0 //需要修改时间和日期,或者停止修改

{

if(key_flag1)key_flag1=0

else key_flag1=1

}

void alarming(void) interrupt 3 using 0 //需要设置闹铃或者停止设置

{

if(key_flag2)key_flag2=0

else key_flag2=1

}

/********************************主函数***********************************/

main()

{uint i

uchar *l

uchar p1[]="D:",p2[]="T:"

SYSTEMTIME T

EA=1

EX0=1

IT0=1

EA=1

EX1=1

IT1=1

init1602()

Initial_DS1302()

while(1)

{ write_com(0x80)

write_string(p1,2)

write_com(0xc0)

write_string(p2,2)

DS1302_GetTime(&T)

adjusted.Second=T.Second

adjusted.Minute=T.Minute

adjusted.Hour=T.Hour

adjusted.Week=T.Week

adjusted.Day=T.Day

adjusted.Month=T.Month

adjusted.Year=T.Year

for(i=0i<9i++)

{

adjusted.DateString[i]=T.DateString[i]

adjusted.TimeString[i]=T.TimeString[i]

}

adjust()

if(key_flag2)naoling()

if(according())alarm()

DateToStr(&adjusted)

TimeToStr(&adjusted)

write_com(0x82)

write_string(adjusted.DateString,8)

write_com(0xc2)

write_string(adjusted.TimeString,8)

delay(10)

}

(二)头文件1 显示模块 LCD1602.H

#ifndef LCD_CHAR_1602_2009_5_9

#define LCD_CHAR_1602_2009_5_9

#define uchar unsigned char

#define uint unsigned int

sbit lcdrs = P2^0

sbit lcdrw = P2^1

sbit lcden = P2^2

void delay(uint z)// 延时

{

uint x,y

for(x=zx>0x--)

for(y=110y>0y--)

}

void write_com(uchar com) // 写入指令数据到 lcd

{

lcdrw=0

lcdrs=0

P0=com

delay(5)

lcden=1

delay(5)

lcden=0

}

void write_data(uchar date) // 写入字符显示数据到 lcd

{

lcdrw=0

lcdrs=1

P0=date

delay(5)

lcden=1

delay(5)

lcden=0

}

void init1602() // 初始化设定

{

lcdrw=0

lcden=0

write_com(0x3C)

write_com(0x0c)

write_com(0x06)

write_com(0x01)

write_com(0x80)

}

void write_string(uchar *pp,uint n)

{

int i

for(i=0i<ni++)

write_data(pp[i])

}

#endif

(三)头文件2 时钟模块 DS1302.H

#ifndef _REAL_TIMER_DS1302_2009_5_20_

#define _REAL_TIMER_DS1302_2003_5_20_

sbit DS1302_CLK = P2^6 //实时时钟时钟线引脚

sbit DS1302_IO = P2^7 //实时时钟数据线引脚

sbit DS1302_RST = P2^5 //实时时钟复位线引脚

sbit ACC0 = ACC^0

sbit ACC7 = ACC^7

typedef struct SYSTEM_TIME

{

unsigned char Second

unsigned char Minute

unsigned char Hour

unsigned char Week

unsigned char Day

unsigned char Month

unsigned char Year

unsigned char DateString[9] //用这两个字符串来放置读取的时间

unsigned char TimeString[9]

}SYSTEMTIME//定义的时间类型

#define AM(X) X

#define PM(X) (X+12) // 转成24小时制

#define DS1302_SECOND 0x80

#define DS1302_MINUTE 0x82

#define DS1302_HOUR 0x84

#define DS1302_WEEK 0x8A

#define DS1302_DAY 0x86

#define DS1302_MONTH 0x88

#define DS1302_YEAR 0x8C

#define DS1302_RAM(X) (0xC0+(X)*2)//用于计算 DS1302_RAM 地址的宏

/******内部指令**********/

void DS1302InputByte(unsigned char d) //实时时钟写入一字节(内部函数)

{

unsigned char i

ACC = d

for(i=8i>0i--)

{

DS1302_IO = ACC0

DS1302_CLK = 1

DS1302_CLK = 0

ACC = ACC >>1//因为在前面已经定义了ACC0 = ACC^0以便再次利用DS1302_IO = ACC0

}

}

unsigned char DS1302OutputByte(void) //实时时钟读取一字节(内部函数)

{

unsigned char i

for(i=8i>0i--)

{

ACC = ACC >>1

ACC7 = DS1302_IO

DS1302_CLK = 1

DS1302_CLK = 0

}

return(ACC)

}

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

void Write1302(unsigned char ucAddr, unsigned char ucDa) //ucAddr: DS1302地址, ucData: 要写的数据

{

DS1302_RST = 0

DS1302_CLK = 0

DS1302_RST = 1

DS1302InputByte(ucAddr) // 地址,命令

DS1302InputByte(ucDa) // 写1Byte数据

DS1302_CLK = 1

DS1302_RST = 0

}

unsigned char Read1302(unsigned char ucAddr) //读取DS1302某地址的数据

{

unsigned char ucData

DS1302_RST = 0

DS1302_CLK = 0

DS1302_RST = 1

DS1302InputByte(ucAddr|0x01) // 地址,命令

ucData = DS1302OutputByte()// 读1Byte数据

DS1302_CLK = 1

DS1302_RST = 0

return(ucData)

}

void DS1302_SetProtect(bit flag)//是否写保护

{

if(flag)

Write1302(0x8E,0x10)

else

Write1302(0x8E,0x00)

}

void DS1302_SetTime(unsigned char Address, unsigned char Value)// 设置时间函数

{

DS1302_SetProtect(0)

Write1302(Address, ((Value/10)<<4 | (Value%10))) //将十进制数转换为BCD码

}//在DS1302中的与日历、时钟相关的寄存器存放的数据必须为BCD码形式

void DS1302_GetTime(SYSTEMTIME *Time)

{

unsigned char ReadValue

ReadValue = Read1302(DS1302_SECOND)

Time->Second = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F)//将BCD码转换为十进制数

ReadValue = Read1302(DS1302_MINUTE)

Time->Minute = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F)

ReadValue = Read1302(DS1302_HOUR)

Time->Hour = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F)

ReadValue = Read1302(DS1302_DAY)

Time->Day = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F)

ReadValue = Read1302(DS1302_WEEK)

Time->Week = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F)

ReadValue = Read1302(DS1302_MONTH)

Time->Month = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F)

ReadValue = Read1302(DS1302_YEAR)

Time->Year = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F)

}

unsigned char *DataToBCD(SYSTEMTIME *Time)

{

unsigned char D[8]

D[0]=Time->Second/10<<4+Time->Second%10

D[1]=Time->Minute/10<<4+Time->Minute%10

D[2]=Time->Hour/10<<4+Time->Hour%10

D[3]=Time->Day/10<<4+Time->Day%10

D[4]=Time->Month/10<<4+Time->Month%10

D[5]=Time->Week/10<<4+Time->Week%10

D[6]=Time->Year/10<<4+Time->Year%10

return D

}

void DateToStr(SYSTEMTIME *Time)

{

//将十进制数转换为液晶显示的ASCII值

Time->DateString[0] = Time->Year/10 + '0'

Time->DateString[1] = Time->Year%10 + '0'

Time->DateString[2] = '-'

Time->DateString[3] = Time->Month/10 + '0'

Time->DateString[4] = Time->Month%10 + '0'

Time->DateString[5] = '-'

Time->DateString[6] = Time->Day/10 + '0'

Time->DateString[7] = Time->Day%10 + '0'

Time->DateString[8] = '\0'

}

void TimeToStr(SYSTEMTIME *Time)

{

//将十进制数转换为液晶显示的ASCII值

Time->TimeString[0] = Time->Hour/10 + '0'

Time->TimeString[1] = Time->Hour%10 + '0'

Time->TimeString[2] = ':'

Time->TimeString[3] = Time->Minute/10 + '0'

Time->TimeString[4] = Time->Minute%10 + '0'

Time->TimeString[5] = ':'

Time->TimeString[6] = Time->Second/10 + '0'

Time->TimeString[7] = Time->Second%10 + '0'

Time->DateString[8] = '\0'

}

void Initial_DS1302(void)

{

unsigned char Second

Second=Read1302(DS1302_SECOND)

if(Second&0x80) //初始化时间

DS1302_SetTime(DS1302_SECOND,0)

}

void DS1302_TimeStop(bit flag) // 是否将时钟停止

{

unsigned char Data

Data=Read1302(DS1302_SECOND)

DS1302_SetProtect(0)

if(flag)

Write1302(DS1302_SECOND, Data|0x80)

else

Write1302(DS1302_SECOND, Data&0x7F)

}

#endif

DS_WriteBCDBata(0x80,second|0x80)

这个函数应该是把秒写到DS1302芯片的秒寄存器中,秒的寄存器的地址上80和81两个地址(寄存器0)。寄存器0中最高位 CH 是一个时钟停止标志位。如果时钟电路有备用电源,上电后,我们要先检测一下这一位,如果这一位是 0,那说明时钟芯片在系统掉电后,由于备用电源的供给,时钟是持续正常运行的;如果这一位是 1,那么说明时钟芯片在系统掉电后,时钟部分不工作了。如果 Vcc1 悬空或者是电池没电了,当我们下次重新上电时,读取这一位,那这一位就是 1,我们可以通过这一位判断时钟在单片机系统掉电后是否还正常运行。剩下的7 位高 3 位是秒的十位,低 4 位是秒的个位,这里再提请注意一次,DS1302 内部是 BCD 码,而秒的十位最大是 5,所以 3 个二进制位就够了。second|0x80后面的这个数据使用 | 符号就是把最高位CH变成1.


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/11080523.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-13
下一篇 2023-05-13

发表评论

登录后才能评论

评论列表(0条)

保存