本帖最后由 agy518 于 2016-3-19 23:09 编辑
大家好,我刚刚学习
单片机不久,想做个51单片机定时开关1602液晶显示AT24C02存储,我是在网上找的程序,照程序画的图,大家看看我画的图有问题吗?还有为什么没有DS1302时钟模块,哪来的时间
程序
#include <reg52.h>
#include <string.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define LCM_Data P0
#define Busy 0x80 //用于检测LCM状态字中的Busy标识
sbit LCM_RS = P3^3;
sbit LCM_RW = P3^4;//定义引脚
sbit LCM_E = P3^5;
sbit key1 = P1^4; //-
sbit key2 = P1^3; //+
sbit key3 = P1^2; //set
sbit key4 = P1^5; //run
sbit key5 = P1^6; //off
sbit key6 = P1^7; //on
sbit scl = P1^0;
sbit sda = P1^1;
sbit jdq = P3^6;
uchar id,
timecount,fl=0;
int r_hour,r_min,r_sec,r_hour2,r_min2,r_sec2;
int hour,min,sec,hour2,min2,sec2,mode=1,aa;
bit flag,sflag; //flag是时钟冒号闪烁标志,sflag是温度负号显示标志
void Disp_line1(void); //显示屏幕第一行
void Disp_line2(void); //显示屏幕第二行
void id_case1_key();
void WriteDataLCM(uchar WDLCM);
void WriteCommandLCM(uchar WCLCM,BuysC);
uchar ReadStatusLCM(void);
void LCMInit(void);
void DisplayOneChar(uchar X, uchar Y, uchar DData);
void DisplayListChar(uchar X, uchar Y, uchar code *DData);
void Delay5Ms(void);
void Delay400Ms(void);
void runtime();
void ScanKey();
void LedDisplay();
void delay() //延时5us
{ ; ; }
void init() //总线初始化
{
sda=1;
scl=1;
}
void start() //开始信号
{
sda=1;
delay();
scl=1;
delay();
sda=0;
delay();
}
void stop() //停止信号
{
sda=0;
delay();
scl=1;
delay();
sda=1;
delay();
}
void respons() //应答信号
{
uchar i=0;
scl=1;
delay();
while((sda==1)&&(i<250)) i++; //若sda为0,退出,若sda在250us内sda一直为1,则表示未收到应答,也退出。
scl=0;
delay();
}
void write_byte(uchar date)//向sda数据线上写一字节数据
{
uchar i,temp;
temp=date;
scl=0;
delay();
for(i=0;i<8;i++)
{
temp=temp<<1;
sda=CY;
delay();
scl=1; //和数码管类似,都是先送数据再打开开关
delay();
scl=0;
delay();
}
sda=1;//释放总线,为读取应答的低电平信号
delay();
}
uchar read_byte() //从sda数据线上读一字节数据
{
uchar i,j,k;
scl=0;
delay();
sda=1;
delay();
for(i=0;i<8;i++)
{
scl=1;
delay();
j=sda;
k=(k<<1)|j;
scl=0;
delay();
}
return k;
}
void write_add(uchar add,uchar date)//向24C02指定存储地址写入指定1字节数据
{
start(); //s
write_byte(0xa0); //器件地址+0:0xa0=1010 0000 B,板子硬件设计地址为1010 000
respons(); //A
write_byte(add); //写入首地址
respons(); //A
write_byte(date); //写入数据
respons(); //A
stop(); //p
}
uchar read_add(uchar add)//从24C02指定存储地址中读取1字节数据
{
uchar date;
start(); //s
write_byte(0xa0); //器件地址+0,表示主机要传送
respons(); //A
write_byte(add); //要读出数据的首地址
respons(); //A
start(); //s
write_byte(0xa1); //器件地址+1,表示主机要接受
respons(); //A
date=read_byte(); //读出数据
stop(); //p
return date;
}
void ScanKey(void) //按键判断程序
{
if(key3==0) //判断是否按下键盘
{
Delay5Ms();
if(key3==0) //确认按键按下
{
mode++; //按键计数加1
if(mode>=5) //计4次重新计数
{
mode=1;
} //将mode清零
}
while(key3==0);//按键锁定,每按一次mode只加1
}
if(key4==0) //判断是否按下键盘
{
Delay5Ms();
if(key4==0) //确认按键按下
{
WriteCommandLCM(0x01,1); //显示清屏
write_add(3,hour);
Delay5Ms();
write_add(4,min);
Delay5Ms();
write_add(5,sec);
Delay5Ms();
write_add(6,hour2);
Delay5Ms();
write_add(7,min2);
Delay5Ms();
write_add(8,sec2);
r_min=min;
r_sec=sec;
r_hour=hour;
r_min2=min2;
r_sec2=sec2;
r_hour2=hour2;
fl=0;
runtime();
}
}
}
void setonhour()
{
TR0=0;
sec=0;
jdq=1;
DisplayListChar(0,0,"Set ON Time ");
DisplayListChar(10,1,"hour");
DisplayOneChar(8,1,hour/10+0x30);
DisplayOneChar(9,1,hour%10+0x30);
if (key2==0) // 设置和选择项目键
{
Delay5Ms();
if(key2==0)
{
hour=hour+1;
if(hour>10)
hour=0;
}
while(key2==0);
}
if (key1==0) // 设置和选择项目键
{
Delay5Ms();
if(key1==0)
{
hour=hour-1;
if(hour<0)
hour=10;
}
while(key1==0);
}
}
void setonmin()
{
TR0=0;
jdq=1;
sec=0;
DisplayListChar(0,0,"Set ON Time ");
DisplayListChar(10,1,"min ");
DisplayOneChar(8,1,min/10+0x30);
DisplayOneChar(9,1,min%10+0x30);
if (key2==0) // 设置和选择项目键
{
Delay5Ms();
if(key2==0)
{
min=min+1;
if(min>60)
min=0;
}
while(key2==0);
}
if (key1==0) // 设置和选择项目键
{
Delay5Ms();
if(key1==0)
{
min=min-1;
if(min<0)
min=60;
}
while(key1==0);
}
}
void setoffhour()
{
TR0=0;
jdq=1;
sec=0;
DisplayListChar(0,0,"Set OFF Time");
DisplayListChar(10,1,"hour");
DisplayOneChar(8,1,hour2/10+0x30);
DisplayOneChar(9,1,hour2%10+0x30);
if (key2==0) // 设置和选择项目键
{
Delay5Ms();
if(key2==0)
{
hour2=hour2+1;
if(hour2>10)
hour2=0;
}
while(key2==0);
}
if (key1==0) // 设置和选择项目键
{
Delay5Ms();
if(key1==0)
{
hour2=hour2-1;
if(hour2<0)
hour2=10;
}
while(key1==0);
}
}
void setoffmin()
{
TR0=0;
jdq=1;
sec=0;
DisplayListChar(0,0,"Set OFF Time");
DisplayListChar(10,1,"min ");
DisplayOneChar(8,1,min2/10+0x30);
DisplayOneChar(9,1,min2%10+0x30);
if (key2==0) // 设置和选择项目键
{
Delay5Ms();
if(key2==0)
{
min2=min2+1;
if(min2>60)
min2=0;
}
while(key2==0);
}
if (key1==0) // 设置和选择项目键
{
Delay5Ms();
if(key1==0)
{
min2=min2-1;
if(min2<0)
min2=60;
}
while(key1==0);
}
}
void runontime()
{
DisplayListChar(0,0,"Run ON Time ");
DisplayOneChar(1,1,r_hour/10+0x30); //显示固定字符
DisplayOneChar(2,1,r_hour%10+0x30);
DisplayListChar(3,1,":");
DisplayOneChar(4,1,r_min/10+0x30); //显示固定字符
DisplayOneChar(5,1,r_min%10+0x30);
DisplayListChar(6,1,":");
DisplayOneChar(7,1,r_sec/10+0x30); //显示固定字符
DisplayOneChar(8,1,r_sec%10+0x30);
TR0=1;
jdq=0;
}
void runofftime()
{
DisplayListChar(0,0,"Run OFF Time");
DisplayOneChar(1,1,r_hour2/10+0x30); //显示固定字符
DisplayOneChar(2,1,r_hour2%10+0x30);
DisplayListChar(3,1,":");
DisplayOneChar(4,1,r_min2/10+0x30); //显示固定字符
DisplayOneChar(5,1,r_min2%10+0x30);
DisplayListChar(6,1,":");
DisplayOneChar(7,1,r_sec2/10+0x30); //显示固定字符
DisplayOneChar(8,1,r_sec2%10+0x30);
TR0=1;
jdq=1;
}
void set()
{
WriteCommandLCM(0x01,1); //显示清屏
while(1)
{
ScanKey();
LedDisplay();
}
}
void allon()
{
WriteCommandLCM(0x01,1); //显示清屏
TR0=0;
while(1)
{
DisplayListChar(0,0,"Always ON ");
jdq=0;
if(key5==0) //判断是否按下键盘
{
Delay5Ms();
if(key5==0) //确认按键按下
{
TR0=1;
fl=1;
r_min=min;
r_sec=sec;
r_hour=hour;
r_min2=min2;
r_sec2=sec2;
r_hour2=hour2;
}
while(key5==0);//按键锁定,每按一次mode只加1
runtime();
}
}
}
void alloff()
{
WriteCommandLCM(0x01,1); //显示清屏
TR0=0;
while(1)
{
DisplayListChar(0,0,"Always OFF");
jdq=1;
if(key6==0) //判断是否按下键盘
{
Delay5Ms();
if(key6==0) //确认按键按下
{
TR0=1;
fl=0;
r_min=min;
r_sec=sec;
r_hour=hour;
r_min2=min2;
r_sec2=sec2;
r_hour2=hour2;
}
while(key6==0);//按键锁定,每按一次mode只加1
runtime();
}
}
}
void runtime()
{
while(1)
{
if(fl==0)
runontime();
if(fl==1)
runofftime();
if(key3==0) //判断是否按下键盘
{
Delay5Ms();
if(key3==0) //确认按键按下
{
mode=1;
set(); //将mode清零
}
while(key3==0);//按键锁定,每按一次mode只加1
}
if(key5==0) //判断是否按下键盘
{
Delay5Ms();
if(key5==0) //确认按键按下
{
}
while(key5==0);//按键锁定,每按一次mode只加1
allon(); //将mode清零
}
if(key6==0) //判断是否按下键盘
{
Delay5Ms();
if(key6==0) //确认按键按下
{
}
while(key6==0);//按键锁定,每按一次mode只加1
alloff(); //将mode清零
}
}
}
void LedDisplay(void)
{
if(mode==1)
{
setonhour();
}
else if(mode==2)
{
setonmin();
}
else if(mode==3)
{
setoffhour();
}
else if(mode==4)
{
setoffmin();
}
}
void main(void)
{
jdq=1;
Delay400Ms(); //启动等待,等LCM讲入工作状态
LCMInit(); //LCM初始化
Delay5Ms(); //延时片刻(可不要)
TMOD=0x01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
EA=1;
ET0=1;
init();
Delay5Ms();
hour=read_add(3);
Delay5Ms();
min=read_add(4);
Delay5Ms();
sec=read_add(5);
Delay5Ms();
hour2=read_add(6);
Delay5Ms();
min2=read_add(7);
Delay5Ms();
sec2=read_add(8);
r_min=min;
r_sec=sec;
r_hour=hour;
r_min2=min2;
r_sec2=sec2;
r_hour2=hour2;
while(1)
{
runtime();
}
}
void WriteDataLCM(uchar WDLCM)
{
ReadStatusLCM(); //检测忙
LCM_Data = WDLCM;
LCM_RS = 1;
LCM_RW = 0;
LCM_E = 0; //若晶振速度太高可以在这后加小的延时
LCM_E = 0; //延时
LCM_E = 1;
}
void WriteCommandLCM(uchar WCLCM,BuysC) //BuysC为0时忽略忙检测
{
if(BuysC) ReadStatusLCM(); //根据需要检测忙
LCM_Data = WCLCM;
LCM_RS = 0;
LCM_RW = 0;
LCM_E = 0;
LCM_E = 0;
LCM_E = 1;
}
uchar ReadStatusLCM(void)
{
LCM_Data = 0xFF;
LCM_RS = 0;
LCM_RW = 1;
LCM_E = 0;
LCM_E = 0;
LCM_E = 1;
while (LCM_Data & Busy); //检测忙信号
return(LCM_Data);
}
void LCMInit(void)
{
LCM_Data = 0;
WriteCommandLCM(0x38,0); //三次显示模式设置,不检测忙信号
Delay5Ms();
WriteCommandLCM(0x38,0);
Delay5Ms();
WriteCommandLCM(0x38,0);
Delay5Ms();
WriteCommandLCM(0x38,1); //显示模式设置,开始要求每次检测忙信号
WriteCommandLCM(0x08,1); //关闭显示
WriteCommandLCM(0x01,1); //显示清屏
WriteCommandLCM(0x06,1); // 显示光标移动设置
WriteCommandLCM(0x0C,1); // 显示开及光标设置
}
void DisplayOneChar(uchar X, uchar Y, uchar DData)
{
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
if (Y) X |= 0x40; //当要显示第二行时地址码+0x40;
X |= 0x80; //算出指令码
WriteCommandLCM(X, 0); //这里不检测忙信号,发送地址码
WriteDataLCM(DData);
}
void DisplayListChar(uchar X, uchar Y, uchar code *DData)
{
uchar ListLength,j;
ListLength = strlen(DData);
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
if (X <= 0xF) //X坐标应小于0xF
{
for(j=0;j<ListLength;j++)
{
DisplayOneChar(X, Y, DData[j]); //显示单个字符
X++;
}
}
}
void Delay5Ms(void)
{
uint TempCyc = 5552;
while(TempCyc--);
}
void Delay400Ms(void)
{
uchar TempCycA = 5;
uint TempCycB;
while(TempCycA--)
{
TempCycB=7269;
while(TempCycB--);
};
}
void timer0() interrupt 1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
aa++;
if(fl==0)
{
if(aa==20)
{
aa=0;
r_sec--;
if(r_sec<0)
{
r_min--;
r_sec=59;
if(r_min<0)
{
r_hour--;
r_min=59;
}
if(r_hour<0)
{
r_min=0;
r_sec=0;
r_hour=0;
jdq=1;
fl=1;
r_min2=min2;
r_sec2=sec2;
r_hour2=hour2;
}
}
}
return;
}
if(fl==1)
{
if(aa==20)
{
aa=0;
r_sec2--;
if(r_sec2<0)
{
r_min2--;
r_sec2=59;
if(r_min2<0)
{
r_hour2--;
r_min2=59;
}
if(r_hour2<0)
{
r_min2=0;
r_sec2=0;
r_hour2=0;
jdq=0;
fl=0;
r_min=min;
r_sec=sec;
r_hour=hour;
}
}
}
return;
}
}
你好,看来你详细的解答,非常满意,辛苦了,再次请教个问题,是不是用51定时器的时间,那么断电后,在开启,时间是不是就从初始值开始走时间,AT24C02存储的应该使我们设置的时间吧,如果是请指定点改用DS1302时间加个纽扣电池,这样设备断电了,时间走起,也不用每次设置时间,
高手老师好,51单片机只有两个定时器,是不是就只能做两路定时开关了,怎么修改
定时就是设置变量的问题,假如定时器设置好了为1s,那么如果设置变量t为5s控制一路,也可以设置变量x为10s控制另外一路,多设几个变量就可以控制多路了
一周热门 更多>