跪求 51单片机+12864液晶+1302时钟制成的万年历c程序

跪求 51单片机+12864液晶+1302时钟制成的万年历c程序,第1张

顶层文件 万年历C

#include<reg51h>

#include "LCD1602h"

#include "DS1302h"

#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]==adjustedYear&&data_alarm[1]==adjustedMonth&&data_alarm[2]==adjustedDay&&data_alarm[3]==adjustedHour&&data_alarm[4]==adjustedMinute&&data_alarm[5]==adjustedSecond)

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;

}

adjustedSecond+=sec_add;

adjustedMinute+=min_add;

adjustedHour+=hou_add;

adjustedDay+=day_add;

adjustedMonth+=mon_add;

adjustedYear+=yea_add;

if(adjustedSecond>59) adjustedSecond=adjustedSecond%60;

if(adjustedMinute>59) adjustedMinute=adjustedMinute%60;

if(adjustedHour>23) adjustedHour=adjustedHour%24;

if(adjustedDay>31) adjustedDay=adjustedDay%31;

if(adjustedMonth>12) adjustedMonth=adjustedMonth%12;

if(adjustedYear>100) adjustedYear=adjustedYear%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) ;

adjustedSecond=TSecond;

adjustedMinute=TMinute;

adjustedHour=THour;

adjustedWeek=TWeek;

adjustedDay=TDay;

adjustedMonth=TMonth;

adjustedYear=TYear;

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

{

adjustedDateString[i]=TDateString[i];

adjustedTimeString[i]=TTimeString[i];

}

adjust();

if(key_flag2)naoling();

if(according())alarm();

DateToStr(&adjusted);

TimeToStr(&adjusted);

write_com(0x82);

write_string(adjustedDateString,8);

write_com(0xc2);

write_string(adjustedTimeString,8);

delay(10);

}

(二)头文件1 显示模块 LCD1602H

#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 时钟模块 DS1302H

#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

对lcd有干扰是应为你按键的判断里面一直有个while(按键是否按下)函数,按键不释放就会一直while()空等待,你只要在while函数里面加上显示函数就行了。

即:

while(按键没释放)

{

LCD显示;

}

你可以这么做,我没有使用编译器,个别单词可能打错,明白意思就行。

unsigned char Time_Buffer[8] = {"09:15:33"};// 这是定义了一个数组来作为时钟显示

unsigned char Setting_Status = 0;    // 状态标志,0:无设置 1:设置时钟 2:分钟

bit Time_500ms_IS_OK = 0; 

// 这个标志位可以用延时来改变它的状态,最好用定时器,500毫秒改变一次,0变1变0循环

// 这个是用来做闪烁标志的,当状态为小时或分钟设置时,判断这个标志位来改变Time_Buffer的赋值。如Time_500ms_IS_OK == 1,Time_Buffer[3] = Time_Buffer[4] = ' ';为0时,就让Time_Buffer[3] = Minute / 10; ime_Buffer[4] = Minute % 10;

// 需要注意的是,你需要在12864的驱动程序里写一个可以显示字符串的子函数

// 在while里面,Setting_Status 状态为0时,显示正常的不闪烁的数

Write_Strins( 0, 0, Time_Buffer,8 );// 第1行第1个位置显示这个字符串

// 当按键按下,改变Setting_Status的值,进入小时/分钟/退出设置

// 当Setting_Status==3时,清零,回到初始状态

单片机用12864显示16X32字体的方法是图像取模:

1、首先先去下载取模软件,下载完成点击打开取模软件。

2、在菜单栏点击模式然后选择图形模式。

3、现在就可以点击打开文件,要注意的是取模之前要把转换为bmp格式,选择点击打开进行添加。

4、现在点击选项,进行参数设置。

5、根据下图进行设置字模格式,设置完成点击确定。

6、点击下面的生成字模就可以获得代码了,点击将代码复制到程序,就可以了。

我也是刚学会,具体怎么做,我给你贴个例子,很详细。接收数据的也有,供你下一步的学习

1建立项目:

打开VC++60,建立一个基于对话框的MFC应用程序SCommTest;

2在项目中插入MSComm控件

选择Project菜单下Add To Project子菜单中的 Components and Controls…选项,在d出的对话框中双击Registered ActiveX Controls项(稍等一会,这个过程较慢),则所有注册过的ActiveX控件出现在列表框中。 选择Microsoft Communications Control, version 60,,单击Insert按钮将它插入到我们的Project中来,接受缺省的选项。(如果你在控件列表中看不到Microsoft Communications Control, version 60,那可能是你在安装VC6时没有把ActiveX一项选上,重新安装VC6,选上ActiveX就可以了),

这时在ClassView视窗中就可以看到CMSComm类了,(注意:此类在ClassWizard中看不到,重构clw文件也一样),并且在控件工具栏Controls中出现了电话图标,现在要做的是用鼠标将此图标拖到对话框中,程序运行后,这个图标是看不到的。

3利用ClassWizard定义CMSComm类控制对象

打开ClassWizard->Member Viariables选项卡,选择CSCommTestDlg类,为IDC_MSCOMM1添加控制变量:m_ctrlComm,这时你可以看一看,在对话框头文件中自动加入了//}AFX_INCLUDES 。

4在对话框中添加控件 向主对话框中添加两个编辑框,一个用于接收显示数据ID为IDC_EDIT_RXDATA,另一个用于输入发送数据,ID为IDC_EDIT_TXDATA,再添加一个按钮,功能是按一次就把发送编辑框中的内容发送一次,将其ID设为IDC_BUTTON_MANUALSEND。别忘记了将接收编辑框的Properties->Styles中把Miltiline和Vertical Scroll属性选上,发送编辑框若你想输入多行文字,也可选上Miltiline。

再打开ClassWizard->Member Viariables选项卡,选择CSCommTestDlg类, 为IDC_EDIT_RXDATA添加CString变量m_strRXData, 为IDC_EDIT_TXDATA添加CString变量m_strTXData。说明: m_strRXData和m_strTXData分别用来放入接收和发送的字符数据。

5添加串口事件消息处理函数OnComm()

打开ClassWizard->Message Maps,选择类CSCommTestDlg,选择IDC_MSCOMM1,双击消息OnComm,将d出的对话框中将函数名改为OnComm。

这个函数是用来处理串口消息事件的,如每当串口接收到数据,就会产生一个串口接收数据缓冲区中有字符的消息事件,我们刚才添加的函数就会执行,我们在OnComm()函数加入相应的处理代码就能实现自已想要的功能了。请你在函数中加入如下代码:

void CSCommTestDlg::OnComm()

{

// TODO: Add your control notification handler code here

VARIANT variant_inp;

COleSafeArray safearray_inp;

LONG len,k;

BYTE rxdata[2048]; //设置BYTE数组 An 8-bit integerthat is not signed

CString strtemp;

if(m_ctrlCommGetCommEvent()==2) //事件值为2表示接收缓冲区内有字符

{ ////////以下你可以根据自己的通信协议加入处理代码

variant_inp=m_ctrlCommGetInput(); //读缓冲区

safearray_inp=variant_inp; //VARIANT型变量转换为ColeSafeArray型变量

len="safearray"_inpGetOneDimSize(); //得到有效数据长度

for(k=0;k<len;k++)

safearray_inpGetElement(&k,rxdata+k);//转换为BYTE型数组

for(k=0;k<len;k++) //将数组转换为Cstring型变量

{

BYTE bt=(char)(rxdata+k); //字符型

strtempFormat("%c",bt); //将字符送入临时变量strtemp存放

m_strRXData+=strtemp; //加入接收编辑框对应字符串

}

}

UpdateData(FALSE); //更新编辑框内容

}

到目前为止还不能在接收编辑框中看到数据,因为我们还没有打开串口,但运行程序不应该有任何错误,不然,你肯定哪儿没看仔细,因为我是打开VC6对照着做一步写一行的,运行试试。没错吧?那么做下一步:

6打开串口和设置串口参数

你可以在你需要的时候打开串口,例如在程序中做一个开始按钮,在该按钮的处理函数中打开串口。现在我们在主对话框的CSCommTestDlg::OnInitDialog()打开串口,加入如下代码:

// TODO: Add extra initialization here

if(m_ctrlCommGetPortOpen())

m_ctrlCommSetPortOpen(FALSE);

m_ctrlCommSetCommPort(1); //选择com1

if( !m_ctrlCommGetPortOpen())

m_ctrlCommSetPortOpen(TRUE);//打开串口

else

AfxMessageBox("cannot open serial port");

m_ctrlCommSetSettings("9600,n,8,1"); //波特率9600,无校验,8个数据位,1个停止位

m_ctrlCommSetInputModel(1); //1:表示以二进制方式检取数据

m_ctrlCommSetRThreshold(1);

//参数1表示每当串口接收缓冲区中有多于或等于1个字符时将引发一个接收数据的OnComm事件

m_ctrlCommSetInputLen(0); //设置当前接收区数据长度为0

m_ctrlCommGetInput();//先预读缓冲区以清除残留数据

现在你可以试试程序了,将串口线接好后(不会接?去看看我写的串口接线基本方法),打开串口调试助手,并将串口设在com2,选上自动发送,也可以等会手动发送。再执行你编写的程序,接收框里应该有数据显示了。

7发送数据

先为发送按钮添加一个单击消息即BN_CLICKED处理函数,打开ClassWizard->Message Maps,选择类CSCommTestDlg,选择IDC_BUTTON_MANUALSEND,双击BN_CLICKED添加OnButtonManualsend()函数,并在函数中添加如下代码:

void CSCommTestDlg::OnButtonManualsend()

{

// TODO: Add your control notification handler code here

UpdateData(TRUE); //读取编辑框内容

m_ctrlCommSetOutput(COleVariant(m_strTXData));//发送数据

}

以上就是关于跪求 51单片机+12864液晶+1302时钟制成的万年历c程序全部的内容,包括:跪求 51单片机+12864液晶+1302时钟制成的万年历c程序、lcd12864与矩阵键盘、单片机光标显示问题 12864方面的等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

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

原文地址: http://outofmemory.cn/zz/10143525.html

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

发表评论

登录后才能评论

评论列表(0条)

保存