❶ 跪求 51单片机+12864液晶+1302时钟制成的万年历c程序
顶层文件 万年历.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=P1; if(temp!=0xfe)m=0;
P1=0xfd;temp=P1 ;if(temp!=0xfd)m=1;
P1=0xfb;temp=P1 ;if(temp!=0xfb)m=2;
P1=0xf7;temp=P1 ;if(temp!=0xf7)m=3;
P1=0xef;temp=P1 ;if(temp!=0xef)n=0;
P1=0xdf;temp=P1 ;if(temp!=0xdf)n=1;
P1=0xbf;temp=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')*10;else {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=0;i<9;i++)
{
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=z;x>0;x--)
for(y=110;y>0;y--);
}
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=0;i<n;i++)
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=8; i>0; i--)
{
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=8; i>0; i--)
{
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
❷ 鍗旷墖链虹殑涓囧勾铡呜繍琛屾椂鍊栾烦鍙樼壒鍒蹇銆
鍗旷墖链虹殑涓囧勾铡呜繍琛屾椂鍊栾烦鍙樼壒鍒蹇铡熷洜濡备笅銆
1銆佺敱浜74HC164镄勮緭鍏ュ唴阒婚梾棰树笉锷犱笂𨰾夌数阒2k-10k锛屼细鍑虹幇鏁版嵁涓嶆e父銆
2銆佹櫠鎸鎴栬呮櫠鎸鍖归厤镄勭数瀹瑰嚭鐜颁简闂棰桡纴镟存崲涓涓鏂扮殑鏅舵尟鎴栬呮櫠鎸鍝佺墝鐢靛瑰嵆鍙銆
3銆佹櫠鎸钥佸寲锛岄戠巼涓岖ǔ瀹氢简锛屽艰嚧璧版椂鍑虹幇锅忓樊銆
❸ 用51单片机做万年历计时怎么不准,差很多
用51单片机做万年历计时,一般都是为了试验,所以多没有专门的实时时钟芯片。晶振频率会有偏差和温度系数,虽然日常使用不会有什么不良影响,但作为实时时钟,连续累积的偏差就很大了,所以时钟会不准,差很多。
❹ C51单片机的万年历程序设计
我这有个数码管显示的程序
以前做的,。。
你可以在我这个程序上修改修改
包括键盘扫描,还有动态显示
。
。
【。。。】
#include
//常量参数
#define TMODW 0x01;
#define SCONW 0x00;
#define xplay 0x04;//显示分频系数
//显示位选
unsigned char data stb;
//键值缓存,0xFF无键命令
unsigned char data keynum;
//显示字型变量
unsigned char data play[8];
//工作参数
unsigned char data l,m;
//字型码
unsigned char code BCDPC[10]=
{0x3F,0x06,0x5B,0x4F,0x66,
0x6D,0x7D,0x07,0x7F,0x6F};
//字位码
unsigned char code STBCODE[8]=
{0x01,0x02,0x04,0x08,
0x10,0x20,0x40,0x80 };
//400Hz xplay分频计数
unsigned char data cttime;
//时钟参数
unsigned char data hr,min,sec,sec100;
//调整时钟参数(时钟“走”)
void ct1()
{sec100++;
if (sec100==100)
{sec100=0;sec++;
if (sec==60)
{sec=0;min++;
if (min==60)
{min=0;hr++;
if (hr==24) hr=0;
}
}
}
}
//时钟参数→LED 显示缓存7段参数转换函数;
void xcplay()
{play[0]=BCDPC[hr/10];
play[1]=BCDPC[hr%10];
play[2]=BCDPC[min/10];
play[3]=BCDPC[min%10];
play[4]=BCDPC[sec/10];
play[5]=BCDPC[sec%10];
play[6]=BCDPC[sec100/10];
play[7]=BCDPC[sec100%10];
}
//显示扫描
void cplay()
{T0=1;//T0-高电平消隐
T1=0;//T1-低电平准备发脉冲前沿
TI=0;//?
P1=0;//?
SBUF=STBCODE[stb];
while (TI==0)
{
};
TI=0;
SBUF=play[stb];
while (TI==0)
{
};
T1=1;
T0=0;
stb=++stb&0x07;
}
extern void cthl0();
//定时器0中断处理程序
void ct0(void) interrupt 1 using 1
{cthl0();
cttime--;
if (cttime==0)
{cttime=xplay;
ct1();//调用时钟“走”函数
xcplay();//调用时钟参数→Led显示缓存转换函数
};
cplay();
}
void w20ms()
{for (l=0;l<41;l++)
{for (m=0;m<81;m++)
{
}
}
}
void tkey()
{P1=0xF0;
keynum=0xFF;
if (P1!=0xF0)
{w20ms();
P1=0xF0;
if (P1!=0xF0)
{P1=0xFE;
switch (P1)
{case 0xEE:keynum=0;break;
case 0xDE:keynum=1;break;
case 0xBE:keynum=2;break;
case 0x7E:keynum=3;break;
}
P1=0xFD;
switch (P1)
{case 0xED:keynum=4;break;
case 0xDD:keynum=5;break;
case 0xBD:keynum=6;break;
case 0x7B:keynum=7;break;
}
P1=0xFB;
switch (P1)
{
case 0xEB:keynum=8;break;
}
};
};
P1=0x00;
}
void command()
{switch (keynum)
{
case 0:{hr=hr+1;
if (hr==24)
hr=0;
}
break;
case 1:{min=min+1;
if (min==60)
min=0;
}
break;
case 2:{sec=sec+1;
if (sec==60)
sec=0;
}
break;
case 3:{sec100=0;
}
break;
case 4:{
while(!(P1=0xED))
{
hr=0;
min=0;
sec=0;
}
}
break;
case 5:{hr=hr-1;
if (hr==00)
hr=24;
}
break;
case 6:{min=min-1;
if (min==00)
min=59;
}
break;
case 7:{sec=sec-1;
if (sec==00)
sec=0;
}
break;
case 0xFF:break;
}
keynum=0xFF;
}
main ()
{ hr=8;
min=5;
sec=8;
sec100=0;
TMOD=TMODW;
SCON=SCONW;
ET0=1;
TR0=1;
EA=1;
cttime=xplay;
while (1)
{w20ms();
tkey();
command();
};
}
❺ 单片机做万年历用数码管的优缺点
优点,定时精准,缺点,电路复杂成本高。
数码管万年历的设计原理是利用AT89C5单片机内部定时/计数器TO的模式2(8位自动重装初值)产生一个时间为250us的信号,再计数4000次产生1S的时间后发出中断,再由单片机进行数据处理后,送人数码管(共阴极数码管)显示(动态显示)。
❻ 基于51单片机制作万年历,用数码管,定时器,不用时钟芯片,不用液晶,怎么做求大神解,原理图和C程序
基于51单片机制作万年历,用两个8位一体的共阴数码管,显示日期和时间。数码管位选用两片74HC138,便于动态扫描显示,又节省引脚。用3个按键调时,K1为选择调时状态,K2为加1键,K3为减1键。
仿真图如下: