我以前倒是做过,不过程序还有点问题,调时间的时候容易过界,但正常走时候就正常了。开发环境用的IAR,单片机用f149,显示用的1602的四线模式。
你自己看着改程序吧,其实我也是51上移植过去的。
悲剧了,帖不下了我帖在我博客里了啊,自己去找吧
主程序
__________________________分隔线____________________________________
#include <msp430x14xh>
#include "ds1302h"
#include "LCD1602x4_mpsh"
#define DS1302_SECOND 0x81 //时钟芯片的寄存器位置,存放时间
#define DS1302_MINUTE 0x83
#define DS1302_HOUR 0x85
#define DS1302_WEEK 0x8b
#define DS1302_DAY 0x87
#define DS1302_MONTH 0x89
#define DS1302_YEAR 0x8d
unsigned char DateString[11],TimeString[9],week_value[2],TempBuffer[7]; //
char hide_sec,hide_min,hide_hour,hide_day,hide_week,hide_month,hide_year;
char done,count,temp,flag,up_flag,down_flag;
//unsigned int temp_value=0,temp_max=0;temp_min=0; //温度值
void DateToStr(void) //将时间年,月,日,星期数据转换成液晶显示字符串,放到数组里DateString[]
{ unsigned char Year,Month,Day,Week;
Year=rtc_getyear();
Month=rtc_getmon();
Day=rtc_getdate();
Week=rtc_getday();
if(hide_year<2) //这里的if,else语句都是判断位闪烁,<2显示数据,>2就不显示,输出字符串为 2007/07/22
{
DateString[0] = '2';
DateString[1] = '0';
DateString[2] = Year/10 + '0';
DateString[3] = Year%10 + '0';
}
else
{
DateString[0] = ' ';
DateString[1] = ' ';
DateString[2] = ' ';
DateString[3] = ' ';
}
DateString[4] = '/';
if(hide_month<2)
{
DateString[5] = Month/10 + '0';
DateString[6] = Month%10 + '0';
}
else
{
DateString[5] = ' ';
DateString[6] = ' ';
}
DateString[7] = '/';
if(hide_day<2)
{
DateString[8] = Day/10 + '0';
DateString[9] = Day%10 + '0';
}
else
{
DateString[8] = ' ';
DateString[9] = ' ';
}
if(hide_week<2)
{
week_value[0] = Week%10 + '0'; //星期的数据另外放到 week_value[]数组里,跟年,月,日的分开存放,因为等一下要在最后显示
}
else
{
week_value[0] = ' ';
}
week_value[1] = '\0';
DateString[10] = '\0'; //字符串末尾加 '\0' ,判断结束字符
}
void TimeToStr(void) //将时,分,秒数据转换成液晶显示字符放到数组 TimeString[];
{ unsigned char Hour,Minute,Second;
Hour=rtc_gethour();
Minute=rtc_getmin();
Second=rtc_getsec();
if(hide_hour<2)
{
TimeString[0] = Hour/10 + '0';
TimeString[1] = Hour%10 + '0';
}
else
{
TimeString[0] = ' ';
TimeString[1] = ' ';
}
TimeString[2] = ':';
if(hide_min<2)
{
TimeString[3] = Minute/10 + '0';
TimeString[4] = Minute%10 + '0';
}
else
{
TimeString[3] = ' ';
TimeString[4] = ' ';
}
TimeString[5] = ':';
if(hide_sec<2)
{
TimeString[6] = Second/10 + '0';
TimeString[7] = Second%10 + '0';
}
else
{
TimeString[6] = ' ';
TimeString[7] = ' ';
}
DateString[8] = '\0';
}
void show_time() //液晶显示程序
{
TimeToStr(); //时间数据转换液晶字符
DateToStr(); //日期数据转换液晶字符
// ReadTemp(); //开启温度采集程序
// temp_to_str(); //温度数据转换成液晶字符
LCD_PutStr(TempBuffer,25); //显示温度
LCD_PutStr(DateString,0); //显示日期
LCD_PutStr(week_value,15); //显示星期
LCD_PutStr(" Week",10); //在液晶上显示 字母 week
LCD_PutStr(TimeString,16); //显示时间
}
////////////////////////////////////////////////////////////////////////////
void outkey() //跳出调整模式,返回默认显示
{ unsigned char Second;
if (!(P1IN&BIT0))
{
count=0;
hide_sec=0,hide_min=0,hide_hour=0,hide_day=0,hide_week=0,hide_month=0,hide_year=0;
Second=dataread(DS1302_SECOND);
datawrite(0x8e,0x00); //写入允许
datawrite(0x80,Second&0x7f);
datawrite(0x8E,0x80); //禁止写入
done=0;//temp_max=0;sund=1;
while(!(P1IN&BIT0));
delay_nms(2);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Upkey()//升序按键
{
if(!(P1IN&BIT1))
{
switch(count)
{case 1:
temp=dataread(DS1302_SECOND); //读取秒数
temp=temp+1; //秒数加1
up_flag=1; //数据调整后更新标志
if((temp&0x7f)>0x59) //超过59秒,清零
temp=0;
break;
case 2:
temp=dataread(DS1302_MINUTE); //读取分数
temp=temp+1; //分数加1
up_flag=1;
if(temp>0x59) //超过59分,清零
temp=0;
break;
case 3:
temp=dataread(DS1302_HOUR); //读取小时数
temp=temp+1; //小时数加1
up_flag=1;
if(temp>0x23) //超过23小时,清零
temp=0;
break;
case 4:
temp=dataread(DS1302_WEEK); //读取星期数
temp=temp+1; //星期数加1
up_flag=1;
if(temp>0x7)
temp=1;
break;
case 5:
temp=dataread(DS1302_DAY); //读取日数
temp=temp+1; //日数加1
up_flag=1;
if(temp>0x31)
temp=1;
break;
case 6:
temp=dataread(DS1302_MONTH); //读取月数
temp=temp+1; //月数加1
up_flag=1;
if(temp>0x12)
temp=1;
break;
case 7:
temp=dataread(DS1302_YEAR); //读取年数
temp=temp+1; //年数加1
up_flag=1;
if(temp>0x99)
temp=0;
break;
default:break;
}
while(!(P1IN&BIT1));
delay_nms(2);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Downkey()//降序按键
{
if(!(P1IN&BIT2))
{
switch(count)
{case 1:
temp=dataread(DS1302_SECOND); //读取秒数
temp=temp-1; //秒数减1
down_flag=1; //数据调整后更新标志
if((temp&0x7f)>0x59) //小于0秒,返回59秒
temp=0x59;
break;
case 2:
temp=dataread(DS1302_MINUTE); //读取分数
temp=temp-1; //分数减1
down_flag=1;
if(temp>0x59)
temp=0x59; //小于0秒,返回59秒
break;
case 3:
temp=dataread(DS1302_HOUR); //读取小时数
temp=temp-1; //小时数减1
down_flag=1;
if(temp==0x00)
temp=0x23;
break;
case 4:
temp=dataread(DS1302_WEEK); //读取星期数
temp=temp-1; //星期数减1
down_flag=1;
if(temp==0x00)
temp=0x07;
break;
case 5:
temp=dataread(DS1302_DAY); //读取日数
temp=temp-1; //日数减1
down_flag=1;
if(temp==0x00)
temp=0x31;
break;
case 6:
temp=dataread(DS1302_MONTH); //读取月数
temp=temp-1; //月数减1
down_flag=1;
if(temp==0x00)
temp=0x12;
break;
case 7:
temp=dataread(DS1302_YEAR); //读取年数
temp=temp-1; //年数减1
down_flag=1;
if(temp>0x99)
temp=0x99;
break;
default:break;
}
while(!(P1IN&BIT2));
delay_nms(2);
}
}
void Setkey()//模式选择按键
{
if(!(P1IN&BIT3))
{
count=count+1; //Setkey按一次,count就加1
done=1; //进入调整模式
while(!(P1IN&BIT3));
delay_nms(2);
}
}
void keydone()//按键功能执行
{ unsigned char Second;
if(flag==0) //关闭时钟,停止计时
{ datawrite(0x8e,0x00); //写入允许
temp=dataread(DS1302_SECOND);
datawrite(0x80,temp|0x80);
datawrite(0x8e,0x80); //禁止写入
flag=1;
}
Setkey(); //扫描模式切换按键
switch(count)
{
case 1:do //count=2,调整秒
{
outkey(); //扫描跳出按钮
Upkey(); //扫描加按钮
Downkey(); //扫描减按钮
if(up_flag==1||down_flag==1) //数据更新,重新写入新的数据
{
datawrite(0x8e,0x00); //写入允许
datawrite(0x80,temp|0x80); //写入新的秒数
datawrite(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_sec++; //位闪计数
if(hide_sec>3)
hide_sec=0;
show_time(); //液晶显示数据
}while(count==2);break;
case 2:do //count=3,调整分
{
hide_sec=0;
outkey();
Upkey();
Downkey();
if(temp>0x60)
temp=0;
if(up_flag==1||down_flag==1)
{
datawrite(0x8e,0x00); //写入允许
datawrite(0x82,temp); //写入新的分数
datawrite(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_min++;
if(hide_min>3)
hide_min=0;
show_time();
}while(count==3);break;
case 3:do //count=4,调整小时
{
hide_min=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
datawrite(0x8e,0x00); //写入允许
datawrite(0x84,temp); //写入新的小时数
datawrite(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_hour++;
if(hide_hour>3)
hide_hour=0;
show_time();
}while(count==4);break;
case 4:do //count=5,调整星期
{
hide_hour=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
datawrite(0x8e,0x00); //写入允许
datawrite(0x8a,temp); //写入新的星期数
datawrite(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_week++;
if(hide_week>3)
hide_week=0;
show_time();
}while(count==5);break;
case 5:do //count=6,调整日
{
hide_week=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
datawrite(0x8e,0x00); //写入允许
datawrite(0x86,temp); //写入新的日数
datawrite(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_day++;
if(hide_day>3)
hide_day=0;
show_time();
}while(count==6);break;
case 6:do //count=7,调整月
{
hide_day=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
datawrite(0x8e,0x00); //写入允许
datawrite(0x88,temp); //写入新的月数
datawrite(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_month++;
if(hide_month>3)
hide_month=0;
show_time();
}while(count==7);break;
case 7:do //count=8,调整年
{
hide_month=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
datawrite(0x8e,0x00); //写入允许
datawrite(0x8c,temp); //写入新的年数
datawrite(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_year++;
if(hide_year>3)
hide_year=0;
show_time();
}while(count==8);break;
case 8: count=0;hide_year=0; //count8, 跳出调整模式,返回默认显示状态
Second=dataread(0x80);
datawrite(0x8e,0x00); //写入允许
datawrite(0x80,Second&0x7f);
datawrite(0x8E,0x80); //禁止写入
done=0; //temp_max=0;sund=1;
break; //count=7,开启中断,标志位置0并退出
default:break;
}
}
////////////////////////////////////////////////////////////////////////////
void rtcinit ()
{
rtc_wp(0);
rtc_stop(0);
rtc_charger(1,1);
}
void sysinit ()
{ WDTCTL = WDTPW + WDTHOLD; //关闭看门狗
P4OUT = 0xff;
P4DIR = 0xff;
P5OUT = 0x0f;
P5DIR = 0xf0;
P6OUT = 0xfc;
P6DIR = 0xfc;
}
void main ()
{ unsigned char temp;
sysinit ();
rtcinit ();
LCD_init(); //液晶初始化
_EINT();
while (1)
{
while(done==1)
keydone(); //进入调整模式
while(done==0)
{
temp=rtc_getsec();
delay_nms(10);
if(temp!=rtc_getsec())
show_time(); //液晶显示数据
flag=0;
Setkey(); //扫描各功能键
}
}
}
#include<reg52h> //包含单片机寄存器的头文件
#include<intrinsh> //包含_nop_()函数定义的头文件
unsigned char code digit[10]={"0123456789"}; //定义字符数组显示数字
sbit SCLK=P1^0; //位定义1302芯片的接口,时钟输出端口定义在P10引脚
sbit DATA=P1^1; //位定义1302芯片的接口,数据输出端定义在P11引脚
sbit RST=P1^2; //位定义1302芯片的接口,复位端口定义在P12引脚
/
函数功能:延时若干微秒
入口参数:n
/
void delaynus(unsigned char n)
{
unsigned char i;
for(i=0;i<n;i++);
}
/
函数功能:向1302写一个字节数据
入口参数:x
/
void Write1302(unsigned char dat)
{
unsigned char i;
SCLK=0; //拉低SCLK,为脉冲上升沿写入数据做好准备
delaynus(2); //稍微等待,使硬件做好准备
for(i=0;i<8;i++) //连续写8个二进制位数据
{
DATA=dat&0x01; //取出dat的第0位数据写入1302 低位在前
,高位在后
delaynus(2); //稍微等待,使硬件做好准备
SCLK=1; //上升沿写入数据
delaynus(2); //稍微等待,使硬件做好准备
SCLK=0; //重新拉低SCLK,形成脉冲
dat>>=1; //将dat的各数据位右移1位,准备写入
下一个数据位
}
}
/
函数功能:根据命令字,向1302写一个字节数据
入口参数:Cmd,储存命令字;dat,储存待写的数据
/
void WriteSet1302(unsigned char Cmd,unsigned char dat)
{
RST=0; //禁止数据传递
SCLK=0; //确保写数居前SCLK被拉低
RST=1; //启动数据传输
delaynus(2); //稍微等待,使硬件做好准备
Write1302(Cmd); //写入命令字
Write1302(dat); //写数据
SCLK=1; //将时钟电平置于高电平状态
RST=0; //禁止数据传递
}
/
函数功能:从1302读一个字节数据
入口参数:x
/
unsigned char Read1302(void)
{
unsigned char i,dat;
delaynus(2); //稍微等待,使硬件做好准备
for(i=0;i<8;i++) //连续读8个二进制位数据
{ dat>>=1;
if(DATA==1) //如果读出的数据是1
dat|=0x80; //将1取出,写在dat的最高位
SCLK=1; //将SCLK置于高电平,为下降沿读出
delaynus(2); //稍微等待
SCLK=0; //拉低SCLK,形成脉冲下降沿
delaynus(2); //稍微等待
}
return dat; //将读出的数据返回
}
/
函数功能:根据命令字,从1302读取一个字节数据
入口参数:Cmd
/
unsigned char ReadSet1302(unsigned char Cmd)
{
unsigned char dat;
RST=0; //拉低RST
SCLK=0; //确保写数居前SCLK被拉低
RST=1; //启动数据传输
Write1302(Cmd); //写入命令字
dat=Read1302(); //读出数据
SCLK=1; //将时钟电平置于已知状态
RST=0; //禁止数据传递
return dat; //将读出的数据返回
}
/
函数功能: 1302进行初始化设置
/
void Init_DS1302(void)
{
unsigned char flag;
flag= ReadSet1302(0x81);
if(flag&0x80) { //判断时钟芯片是否关闭
WriteSet1302(0x8E,0x00); //根据写状态寄存器命令
字,写入不保护指令
WriteSet1302(0x80,((55/10)<<4|(55%10))); //根据写秒寄存器命
令字,写入秒的初始值
WriteSet1302(0x82,((59/10)<<4|(59%10))); //根据写分寄存器命
令字,写入分的初始值
WriteSet1302(0x84,((23/10)<<4|(23%10))); //根据写小时寄存器命
令字,写入小时的初始值
WriteSet1302(0x86,((18/10)<<4|(18%10))); //根据写日寄存器命令
字,写入日的初始值
WriteSet1302(0x88,((6/10)<<4|(6%10))); //根据写月寄存器命令字
,写入月的初始值
WriteSet1302(0x8c,((9/10)<<4|(9%10))); //根据写年寄存器命令
字,写入年的初始值
WriteSet1302(0x90,0xa5); //打开充电功能 选择2K
电阻充电方式
WriteSet1302(0x8E,0x80); //根据写状
态寄存器命令字,写入保护指令
}
}
//如果不想每次都初始化时间,也就是掉电后还想让时钟继续走时的话 就用
上面的语句
/--------------------这是每次都初始化的语句-----------------/
/
WriteSet1302(0x8E,0x00); //根据写状态寄存器命令字
,写入不保护指令
WriteSet1302(0x80,((55/10)<<4|(55%10))); //根据写秒寄存器命令字
,写入秒的初始值
WriteSet1302(0x82,((59/10)<<4|(59%10))); //根据写分寄存器命
令字,写入分的初始值
WriteSet1302(0x84,((23/10)<<4|(23%10))); //根据写小时寄存器命
令字,写入小时的初始值
WriteSet1302(0x86,((18/10)<<4|(18%10))); //根据写日寄存器命令
字,写入日的初始值
WriteSet1302(0x88,((6/10)<<4|(6%10))); //根据写月寄存器命令字
,写入月的初始值
WriteSet1302(0x8c,((9/10)<<4|(9%10))); //根据写年寄存器命令
字,写入年的初始值
WriteSet1302(0x90,0xa5); //打开充电功能 选择2K
电阻充电方式
WriteSet1302(0x8E,0x80); //根据写状态寄存器命令
字,写入保护指令
/
/
以下是对液晶模块的 *** 作程序
/
sbit RS=P2^0; //寄存器选择位,将RS位定义为P20引脚
sbit RW=P2^1; //读写选择位,将RW位定义为P21引脚
sbit E=P2^2; //使能信号位,将E位定义为P22引脚
sbit BF=P0^7; //忙碌标志位,,将BF位定义为P07引脚
/
函数功能:延时1ms
(3j+2)i=(3×33+2)×10=1010(微秒),可以认为是1毫秒
/
void delay1ms()
{
unsigned char i,j;
for(i=0;i<10;i++)
for(j=0;j<33;j++)
;
}
/
函数功能:延时若干毫秒
入口参数:n
/
void delaynms(unsigned char n)
{
unsigned char i;
for(i=0;i<n;i++)
delay1ms();
}
/
函数功能:判断液晶模块的忙碌状态
返回值:result。result=1,忙碌;result=0,不忙
/
bit BusyTest(void)
{
bit result;
RS=0; //根据规定,RS为低电平,RW为高电平时,可以读
状态
RW=1;
E=1; //E=1,才允许读写
_nop_(); //空 *** 作
_nop_();
_nop_();
_nop_(); //空 *** 作四个机器周期,给硬件反应时间
result=BF; //将忙碌标志电平赋给result
E=0; //将E恢复低电平
return result;
}
/
函数功能:将模式设置指令或显示地址写入液晶模块
入口参数:dictate
/
void WriteInstruction (unsigned char dictate)
{
while(BusyTest()==1); //如果忙就等待
RS=0; //根据规定,RS和R/W同时为低电平时,可
以写入指令
RW=0;
E=0; //E置低电平(根据表8-6,写指令时,E为
高脉冲,
// 就是让E从0到1发生正跳变,所以应先置"0"
_nop_();
_nop_(); //空 *** 作两个机器周期,给硬件反应时间
P0=dictate; //将数据送入P0口,即写入指令或地址
_nop_();
_nop_();
_nop_();
_nop_(); //空 *** 作四个机器周期,给硬件反应时间
E=1; //E置高电平
_nop_();
_nop_();
_nop_();
_nop_(); //空 *** 作四个机器周期,给硬件反应时间
E=0; //当E由高电平跳变成低电平时,液晶模块
开始执行命令
}
/
函数功能:指定字符显示的实际地址
入口参数:x
/
void WriteAddress(unsigned char x)
{
WriteInstruction(x|0x80); //显示位置的确定方法规定为"80H+地址码
x"
}
/
函数功能:将数据(字符的标准ASCII码)写入液晶模块
入口参数:y(为字符常量)
/
void WriteData(unsigned char y)
{
while(BusyTest()==1);
RS=1; //RS为高电平,RW为低电平时,可以写入数据
RW=0;
E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲
,
// 就是让E从0到1发生正跳变,所以应先置"0"
P0=y; //将数据送入P0口,即将数据写入液晶模块
_nop_();
_nop_();
_nop_();
_nop_(); //空 *** 作四个机器周期,给硬件反应时间
E=1; //E置高电平
_nop_();
_nop_();
_nop_();
_nop_(); //空 *** 作四个机器周期,给硬件反应时间
E=0; //当E由高电平跳变成低电平时,液晶模块开始执
行命令
}
/
函数功能:对LCD的显示模式进行初始化设置
/
void LcdInitiate(void)
{
delaynms(15); //延时15ms,首次写指令时应给LCD一段较
长的反应时间
WriteInstruction(0x38); //显示模式设置:16×2显示,5×7点阵,
8位数据接口
delaynms(5); //延时5ms ,给硬件一点反应时间
WriteInstruction(0x38);
delaynms(5); //延时5ms ,给硬件一点反应时间
WriteInstruction(0x38); //连续三次,确保初始化成功
delaynms(5); //延时5ms ,给硬件一点反应时间
WriteInstruction(0x0c); //显示模式设置:显示开,无光标,
光标不闪烁
delaynms(5); //延时5ms ,给硬件一点反应时间
WriteInstruction(0x06); //显示模式设置:光标右移,字符不
移
delaynms(5); //延时5ms ,给硬件一点反应时间
WriteInstruction(0x01); //清屏幕指令,将以前的显示内容清
除
delaynms(5); //延时5ms ,给硬件一点反应时间
}
/
以下是1302数据的显示程序
/
/
函数功能:显示秒
入口参数:x
/
void DisplaySecond(unsigned char x)
{
unsigned char i,j; //j,k分别储存十位和个位
i=x/10;//取十位
j=x%10;//取个位
WriteAddress(0x49); //写显示地址,将在第2行第7列开始显示
WriteData(digit[i]); //将百位数字的字符常量写入LCD
WriteData(digit[j]); //将十位数字的字符常量写入LCD
delaynms(50); //延时1ms给硬件一点反应时间
}
/
函数功能:显示分钟
入口参数:x
/
void DisplayMinute(unsigned char x)
{
unsigned char i,j; //j,k十位和个位
i=x/10;//取十位
j=x%10;//取个位
WriteAddress(0x46); //写显示地址,将在第2行第7列开始显示
WriteData(digit[i]); //将百位数字的字符常量写入LCD
WriteData(digit[j]); //将十位数字的字符常量写入LCD
delaynms(50); //延时1ms给硬件一点反应时间
}
/
函数功能:显示小时
入口参数:x
/
void DisplayHour(unsigned char x)
{
unsigned char i,j; //j,k十位和个位
i=x/10;//取十位
j=x%10;//取个位
WriteAddress(0x43); //写显示地址,将在第2行第7列开始显示
WriteData(digit[i]); //将百位数字的字符常量写入LCD
WriteData(digit[j]); //将十位数字的字符常量写入LCD
delaynms(50); //延时1ms给硬件一点反应时间
}
/
函数功能:显示日
入口参数:x
/
void DisplayDay(unsigned char x)
{
unsigned char i,j; //j,k十位和个位
i=x/10;//取十位
j=x%10;//取个位
WriteAddress(0x0c); //写显示地址,将在第2行第7列开始显示
WriteData(digit[i]); //将十位数字的字符常量写入LCD
WriteData(digit[j]); //将个位数字的字符常量写入LCD
delaynms(50); //延时1ms给硬件一点反应时间
}
/
函数功能:显示月
入口参数:x
/
void DisplayMonth(unsigned char x)
{
unsigned char i,j; //j,k分别储存十位和个位
i=x/10;//取十位
j=x%10;//取个位
WriteAddress(0x09); //写显示地址,将在第2行第7列开始显示
WriteData(digit[i]); //将十位位数字的字符常量写入LCD
WriteData(digit[j]); //将个位数字的字符常量写入LCD
delaynms(50); //延时1ms给硬件一点反应时间
}
/
函数功能:显示年
入口参数:x
/
void DisplayYear(unsigned char x)
{
unsigned char i,j; //j,k分别储存十位和个位
i=x/10;//取十位
j=x%10;//取个位
WriteAddress(0x06); //写显示地址,将在第2行第7列开始显示
WriteData(digit[i]); //将十位位数字的字符常量写入LCD
WriteData(digit[j]); //将个位数字的字符常量写入LCD
delaynms(50); //延时1ms给硬件一点反应时间
}
/
函数功能:主函数
/
void main(void)
{
unsigned char second,minute,hour,day,month,year; //分别储存苗
、分、小时,日,月,年
unsigned char ReadValue; //储存从1302读取的数据
LcdInitiate(); //将液晶初始化
WriteAddress(0x01); //写Date的显示地址,将在第1行第2列开始显示
WriteData('D'); //将字符常量写入LCD
WriteData('a'); //将字符常量写入LCD
WriteData('t'); //将字符常量写入LCD
WriteData('e'); //将字符常量写入LCD
WriteData(':'); //将字符常量写入LCD
WriteAddress(0x08); //写年月分隔符的显示地址, 显示在第1行第9列
WriteData('-'); //将字符常量写入LCD
WriteAddress(0x0b); //写月日分隔符的显示地址, 显示在第1行第12列
WriteData('-'); //将字符常量写入LCD
WriteAddress(0x45); //写小时与分钟分隔符的显示地址, 显示在第2行第
6列
WriteData(':'); //将字符常量写入LCD
WriteAddress(0x48); //写分钟与秒分隔符的显示地址, 显示在第2行第9
列
WriteData(':'); //将字符常量写入LCD
Init_DS1302(); //将1302初始化
while(1)
{
ReadValue = ReadSet1302(0x81); //从秒寄存器读数据
second=((ReadValue&0x70)>>4)10 + (ReadValue&0x0F);//将读出数据
转化
DisplaySecond(second); //显示秒
ReadValue = ReadSet1302(0x83); //从分寄存器读
minute=((ReadValue&0x70)>>4)10 + (ReadValue&0x0F); //将读出数据
转化
DisplayMinute(minute); //显示分
ReadValue = ReadSet1302(0x85); //从分寄存器读
hour=((ReadValue&0x70)>>4)10 + (ReadValue&0x0F); //将读出数据转
化
DisplayHour(hour); //显示小时
ReadValue = ReadSet1302(0x87); //从分寄存器读
day=((ReadValue&0x70)>>4)10 + (ReadValue&0x0F); //将读出数据转
化
DisplayDay(day); //显示日
ReadValue = ReadSet1302(0x89); //从分寄存器读
month=((ReadValue&0x70)>>4)10 + (ReadValue&0x0F); //将读出数据
转化
DisplayMonth(month); //显示月
ReadValue = ReadSet1302(0x8d); //从分寄存器读
year=((ReadValue&0xf0)>>4)10 + (ReadValue&0x0F); //将读出数据转
化
DisplayYear(year); //显示年
}
}
#include <reg51h>
#define uchar unsigned char //定义unsigned int为uint
#define uint unsigned int //定义unsigned uchar为uchar
sbit LCD_RS = P2^0 ;
sbit LCD_RW = P2^1 ;
sbit LCD_EN = P2^2 ;
sbit D_SDA = P2^6; //定义74HC164数据线为P26端口
sbit D_SCL = P2^7; //定义74HC164数据线为P27端口
sbit CLK = P1^3; /实时时钟时钟线引脚 /
sbit IO = P1^4; /实时时钟数据线引脚 /
sbit RST = P1^5; /实时时钟复位线引脚 /
sbit ACC0 = ACC^0;
sbit ACC7 = ACC^7;
uchar time[8] = {0x50,0x30,0x19,0x30,0x12,0x06,0x06};
//========= 延时函数 ============
//延时时间以1ms为单位
//s决定延时时间长短
void delay_ms(uint s)
{
uint x;
for(s;s>0;s--)
{
x = 200;
while(x--);
}
}
//========= 送出一个字节给74HC164(实现串并转换) ==========
void send_out(unsigned char out)//传送一个字节8位
{
uchar i;
D_SCL = 0;
for (i=8;i>=1;i--)
{
D_SDA = out&0x80; //送数据到数据口
D_SCL = 1; //时钟线置1
D_SCL = 0; //送一时钟
out<<=1; //左移
}
}
//========= 写命令函数 ==========
void lcd_wcmd(uchar cmd)
{
LCD_RS = 0;
LCD_RW = 0;
LCD_EN = 0;
send_out(cmd);
LCD_EN = 1;
LCD_EN = 0 ;
}
//========= 写数据函数 ==========
void lcd_wdat(uchar dat)
{
LCD_RS = 1;
LCD_RW = 0;
LCD_EN = 0;
send_out(dat);
LCD_EN = 1;
LCD_EN = 0;
}
//========= LCD初始化函数 ==========
void lcd_init()
{
lcd_wcmd(0x38);
delay_ms(1);
lcd_wcmd(0x0c); //显示开,关光标
delay_ms(1);
lcd_wcmd(0x06); //向右移动光标
delay_ms(1);
lcd_wcmd(0x01); //清除LCD显示屏
delay_ms(1);
}
//========== 往DS1302写入1Byte数据 (内部函数) =============
void w_byte(uchar dat)
{
uchar i;
for(i=8; i>0; i--)
{
IO = dat & 0x01;
CLK = 1;
CLK = 0;
dat = dat >> 1;
}
}
//======== 从DS1302读取1Byte数据 (内部函数) ===================
uchar r_byte(void)
{
uchar i;
for(i=8; i>0; i--)
{
ACC = ACC >> 1;
ACC7 = IO;
CLK = 1;
CLK = 0;
}
return(ACC);
}
//========== 指定地址往DS1302写入1Byte数据 (内部函数) =============
void write_byte(uchar addr, uchar dat)
{
RST = 0;
CLK = 0;
RST = 1;
w_byte(addr);
w_byte(dat);
CLK = 1;
RST = 0;
}
//========== 指定地址往DS1302读1Byte数据 (内部函数) =============
uchar read_byte(uchar addr)
{
uchar ucData;
RST = 0;
CLK = 0;
RST = 1;
w_byte(addr);
ucData = r_byte();
CLK = 1;
RST = 0;
return(ucData);
}
//============ 设置ds1302日期和时间 =============
void write_ds1302(uchar p)
{
uchar i;
uchar addr = 0x80;
write_byte(0x8e,0x00); // 控制命令,WP=0,写 *** 作
for(i =7; i>0; i--)
{
write_byte(addr,p); // 秒 分 时 日 月 星期 年
p++;
addr +=2;
}
write_byte(0x8e,0x80); // 控制命令,WP=1,写保护
}
//============ 读ds1302当前日期和时间 =============
void read_ds1302(uchar p)
{
uchar i;
uchar addr = 0x81;
for (i=0; i<7; i++)
{
p = read_byte(addr); //格式为: 秒 分 时 日 月 星期 年
addr += 2;
p++;
}
}
//============ 显示函数 ===================
void lcd_disp()
{
uchar addr = 4;
lcd_wcmd(0x80 + addr);
lcd_wdat(((time[2]>>4)&0x0f)+0x30); //显示小时
addr++;
lcd_wcmd(0x80 + addr);
lcd_wdat((time[2]&0x0f)+0x30);
addr++;
lcd_wcmd(0x80 + addr);
lcd_wdat(':'); //显示":"
addr++;
lcd_wcmd(0x80 + addr);
lcd_wdat(((time[1]>>4)&0x0f)+0x30); //显示分
addr++;
lcd_wcmd(0x80 + addr);
lcd_wdat((time[1]&0x0f)+0x30);
addr++;
lcd_wcmd(0x80 + addr);
lcd_wdat(':'); //显示":"
addr++;
lcd_wcmd(0x80 + addr);
lcd_wdat(((time[0]>>4)&0x0f)+0x30); //显示秒
addr++;
lcd_wcmd(0x80 + addr);
lcd_wdat((time[0]&0x0f)+0x30);
addr = 2;
lcd_wcmd(0xc0 + addr); //在第二行显示年月日和星期
lcd_wdat('2'); //显示2
addr++;
lcd_wcmd(0xc0 + addr);
lcd_wdat('0'); //显示0
addr++;
lcd_wdat(((time[6]>>4)&0x0f)+0x30); //年
addr++;
lcd_wcmd(0xc0 + addr);
lcd_wdat((time[6]&0x0f)+0x30);
addr++;
lcd_wcmd(0xc0 + addr);
lcd_wdat(' ');
addr++;
lcd_wcmd(0xc0 + addr);
lcd_wdat(((time[4]>>4)&0x0f)+0x30); //显示月
addr++;
lcd_wcmd(0xc0 + addr);
lcd_wdat((time[4]&0x0f)+0x30);
addr++;
lcd_wcmd(0xc0 + addr);
lcd_wdat(' ');
addr++;
lcd_wcmd(0xc0 + addr);
lcd_wdat(((time[3]>>4)&0x0f)+0x30); //显示日
addr++;
lcd_wcmd(0xc0 + addr);
lcd_wdat((time[3]&0x0f)+0x30);
addr++;
lcd_wcmd(0xc0 + addr);
lcd_wdat(' ');
addr++;
lcd_wcmd(0xc0 + addr);
lcd_wdat((time[5]&0x0f)+0x30); //显示星期
}
//=========== 主函数 ===============
void main()
{
lcd_init(); // 初始化LCD
write_ds1302(time);
while(1)
{
read_ds1302(time); //读DS1302数据
lcd_disp(); //LCD显示
delay_ms(500); //延时05秒
}
}
这是一个电子时钟,在LCD1602上显示,时钟芯片是DS1302
微控制器是单芯片微计算机,将微计算机的主要部件集成在一个芯片上。该微控制器诞生于1970年代中期。经过20年的发展,其成本越来越低,性能越来越强大,这使其在各个领域和各个领域都得到应用。例如,电机控制,条形码阅读器/扫描仪,消费电子产品,游戏设备,电话,HVAC,楼宇安全和访问控制,工业控制和自动化以及白色家用电器(洗衣机,微波炉)。本文主要介绍微控制器的应用和工作原理,包括微控制器的类型;微控制器和微处理器之间的区别;或世界顶级微控制器制造商等。
根据Wiki,微控制器(或微控制器单元的MCU)是位于单个集成电路上的小型计算机。用现代术语来说,它类似于片上系统或SoC,但不如后者复杂。SoC可能包括微控制器作为其组件之一。微控制器包含一个或多个CPU(处理器内核)以及存储器和可编程输入/输出外设。铁电RAM,NOR闪存或OTPROM形式的程序存储器通常也包含在芯片上,以及少量RAM。与个人计算机或其他由各种分立芯片组成的通用应用中使用的微处理器相比,微控制器是为嵌入式应用而设计的。单片机用于自动控制的产品和设备,例如汽车发动机控制系统,植入式医疗设备,遥控器,办公机器,设备,电动工具,玩具和其他嵌入式系统。与使用单独的微处理器,存储器和输入/输出设备的设计相比,通过减小尺寸和成本,微控制器使数字控制更多的设备和过程变得经济。混合信号微控制器很常见,集成了控制非数字电子系统所需的模拟组件。
微控制器功能
微控制器具有以下几个主要功能:
解析微控制器的工作原理、类型及应用
(1)可靠性好。由于微控制器的各种功能部件都集成在芯片上,特别是存储器集成在芯片上,布线短,数据大部分在芯片内部传输,不易受到外界干扰,增强了抗干扰能力强,使系统运行更加可靠。因此,可靠性显然优于一般的通用CPU系统。
(2)强大的控制功能。为了满足工业控制的要求,通用微控制器的指令系统具有丰富的条件分支转移指令,I/O端口的逻辑运算和位处理功能。通常,微控制器的逻辑控制功能和运行速度高于相同级别的CPU。
(3)易于扩展。有许多三个总线和用于扩展的并行,串行输入/输出引脚,很容易形成各种尺寸的计算机应用系统。
(4)通用微控制器中没有监控程序或系统管理软件,开发需要相应的仿真系统。
单片机类型
微控制器可分为两大类:普通单片机和数字信号处理单片机(DSP)。
根据字长,目前常见的单片机是4到32。功能强弱,适合不同场合。世界上大多数最大的半导体公司都有自己的微控制器。
单片机8051
它是一个40引脚微控制器,其Vcc为5V,连接到引脚40,而Vss的引脚20保持为0V。并且有P10-P17的输入和输出端口,并且具有开漏功能。Port3具有其他功能。引脚36处于开漏状态,引脚17内部在微控制器内部上拉晶体管。当在端口1上应用逻辑1时,则在端口21上获得逻辑1,反之亦然。微控制器的编程非常复杂。基本上,我们用C语言编写一个程序,然后将其转换为微控制器可以理解的机器语言。RESET引脚连接到与电容器相连的引脚9。当开关接通时,电容器开始充电并且RST为高。向复位引脚施加高电平将使微控制器复位。如果我们对该引脚施加逻辑零,程序将从头开始执行。
8051的存储器架构
8051的存储器分为两部分:程序存储器和数据存储器。程序存储器存储正在执行的程序,而数据存储器临时存储数据和结果。8051已在多种设备中使用,主要是因为它易于集成到设备中。微控制器主要用于能源管理,触摸屏,汽车和医疗设备。
8051的数据存储器
8051微控制器的引脚说明
引脚40:Vcc是+5VDC的主要电源。
针20:Vss_表示接地(0V)连接。
引脚32-39:称为端口0(P00至P07)用作I/O端口。
Pin-31:地址锁存使能(ALE)用于解复用端口0的地址数据信号。
针30:(EA)外部访问输入用于启用或禁用外部存储器接口。如果没有外部存储器要求,则此引脚始终保持高电平。
引脚29:程序存储使能(PSEN)用于从外部程序存储器读取信号。
引脚21-28:称为端口2(P20至P27)_除了用作I/O端口外,高阶地址总线信号还与该准双向端口复用。
引脚18和19:用于连接外部晶振以提供系统时钟。
引脚10_17:此端口还具有其他功能,例如中断,定时器输入,用于外部存储器与读写接口的控制信号。这是具有内部上拉功能的准双向端口。
针脚9:这是一个RESET针脚,用于在单片机正在工作或开始应用程序启动时将8051单片机设置为其初始值。必须在两个机器周期内将RESET引脚设置为高电平。
引脚1_8:此端口不具有任何其他功能。端口1是准双向I/O端口。
微控制器嵌入设备内部,以控制产品的动作和功能。因此,它们也可以称为嵌入式控制器。它们运行一个特定的程序,专门用于一项任务。它们是具有专用输入设备和小型LED或LCD显示输出的低功率设备。微控制器可以从他们控制的设备中获取输入,并通过将设备信号发送到设备的不同部分来保持控制。电视的微控制器就是一个很好的例子。它从遥控器获取输入,并在电视屏幕上输出其输出。
像传统计算机一样,微控制器依靠不同的功能来完成其工作。这些功能包括:
内存
RAM用于存储数据以及微控制器工作时创建的其他结果。但是,一旦切断微控制器的电源,它就不会永久存储数据,并且其内存也会丢失。RAM包含一个特殊功能寄存器(SFR)。这是微控制器制造商提供的预先配置的内存。它控制串行通信和模数转换器等特定电路的行为。
只读存储器
微控制器作为程序执行的特殊任务存储在ROM(只读存储器)中,永远不变。ROM使微控制器知道某些动作应触发特定的响应。例如,ROM使电视的微控制器知道按下频道按钮会改变屏幕上的显示。ROM中存储的程序大小取决于ROM的大小。一些微控制器以外部芯片的形式接受ROM的添加,而另一些则带有内置ROM。
程序计数器
程序计数器允许小型计算机基于一系列不同的编程指令来执行程序。每当执行一行指令时,程序计数器就会增加1。这有助于在代码行中跟踪柜台的位置。
输入和输出
与通过鼠标或键盘控制的计算机不同,微控制器具有通过输入和输出与人进行交互的独特方式。微控制器上的典型输入和输出设备包括LED显示屏,开关和确定湿度,温度和光照水平的传感器。大多数嵌入式系统不具有用于直接人机交互的屏幕或键盘。取而代之的是,微控制器具有多种输入和输出引脚或GPIO,它们被配置用于不同的输入和输出设备。
例如,您可以将一个引脚配置为通过感测温度工作的微控制器上的输入,而将另一个引脚配置为输出并连接至自动调温器,该自动调温器根据预先设置触发空调或加热器的开和关。设定温度范围。输入和输出动力学完全是机器对机器的,不需要直接的人工交互即可做出决定。
#include "stdioh"
#include "stringh"
void main(void){
char a[200]="abcdefghijklmnoqrstuvwxyz&",p=a;
while(p=='') p++;
printf("%s\n",strcpy(a,p));
}
以上就是关于改c语言程序,要显示今天的年月日时分秒,,在线等啊 ,急,,全部分了都用上了全部的内容,包括:改c语言程序,要显示今天的年月日时分秒,,在线等啊 ,急,,全部分了都用上了、求大神们帮忙!!单片机ATmega8515读取RTC(DS1302)的时间信息的C语言程序,只要读秒,分,时,这三个信息、求c51单片机电子钟程序(c语言)等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)