c51单片机吧 关注:1,858贴子:1,648
  • 1回复贴,共1

大佬们能给解释一下吗 看不懂呀

只看楼主收藏回复

#include <reg52.h> //调用单片机头文件
#define uchar unsigned char //无符号字符型 宏定义变量范围0~255
#define uint unsigned int //无符号整型 宏定义变量范围0~65535
#include "nongli.h"
sbit rs=P2^5; //寄存器选择信号 H:数据寄存器 L:指令寄存器
sbit rw=P2^6; //寄存器选择信号 H:数据寄存器 L:指令寄存器
sbit e =P2^7; //片选信号 下降沿触发
sbit beep = P3^7;//蜂鸣器IO口
sbit dq = P3^1; //18b20 IO口的定义
uint temperature ; //温度变量
bit flag_200ms ; //200毫秒的变量
bit flag_100ms ; //100毫秒的变量
uchar flag_clock_en;//闹钟标志位
uchar n_nian,n_yue,n_ri; //农历显示的变量
uchar menu_1; //设置不同参数的变量
sbit key1 = P3^6; //按键IO口定义
sbit key2 = P3^5;//按键IO口定义
sbit key3 = P3^4;//按键IO口定义
sbit key4 = P3^3;//按键IO口定义
/********************************************************************
* 名称 : delay_1ms()
* 功能 : 延时1ms函数
* 输入 : q
* 输出 : 无
***********************************************************************/
void delay_1ms(uint q)
{
uint i,j;
for(i=0;i<q;i++)
for(j=0;j<120;j++);
}
#include "ds1302.h"
/*********************定时器0初始化******************/
void time0_init()
{
EA = 1; //开总中断
TMOD = 0X01; //定时器0工作方式1
ET0 = 1; //开定时器0中断
TR0 = 1; //允许定时器0定时
TH0 = 0X3C;
TL0 = 0XB0; //定时50毫秒中断一次
}
/************ 延时函数 *****************/
void delay_uint(uint z)
{
while(z--);
}
/***************交换函数 高位变低位 低位变高位*****************/
uchar change_dat(uchar dat)
{
uchar i,value;
for(i=0;i<8;i++)
{
value <<= 1;
if((dat & 0x01) == 0x01)
value |= 0x01;
dat >>= 1;
}
return value;
}
/************ 写命令函数 *****************/
void write_com(uchar com)
{
rs=0; //写命令
rw=0; //对12864写操作
P0=change_dat(com); //P0口对12864写命令数据
delay_uint(25);
e=1; //e=1使能信号
delay_uint(100); //延时一下等12864完成操作
e=0;
}
/************ 写数据函数 *****************/
void write_dat(uchar dat)
{
rs=1; //写数据
rw=0; //对12864写操作
P0=change_dat(dat); //P0口对12864写数据
delay_uint(25);
e=1; //e=1使能信号
delay_uint(100); //延时一下等12864完成操作
e=0;
}
/**********************************************************
*函数名: addr_12864
*功能:写地址
*说明:写汉字时要写个地址
*输入:无
*返回:无
**********************************************************/
void addr_12864(uchar hang,uchar lie) //地址转换
{
uchar address;
switch(hang)
{
case 1: address=0x80 + lie ; //计算12864第一行的地址
break;
case 2: address=0x90 + lie ; //计算12864第二行的地址
break;
case 3: address=0x88 + lie ; //计算12864第三行的地址
break;
case 4: address=0x98 + lie ; //计算12864第四行的地址
break;
default :
break;
}
write_com(address);//写地址给12864
}
/**********************************************************
*函数名: write_shu16
*功能:在12864上显示16进制数据
*说明:
*输入:无
*返回:无
**********************************************************/
void write_shu16(uchar hang,uchar lie,uchar dat)
{
addr_12864(hang,lie); //地址转换
write_dat(0x30+dat/16);//显示十位数
write_dat(0x30+dat%16);//显示个位数
}
/**********************************************************
*函数名: write_string
*功能:在12864上显示字符数据
*说明:
*输入:无
*返回:无
**********************************************************/
void write_string(uchar hang,uchar lie,uchar *p)
{
addr_12864(hang,lie); //地址转换
while(1)
{
if(*p == '\0') break;//\0字符串的结尾标志 break结束while循环 结束写字符
write_dat(*p); //写数据
p++; //指针地址加1
}
}
/*****************控制光标函数********************/
void write_guanbiao(uchar hang,uchar lie,uchar date)
{
addr_12864(hang,lie); //地址转换
if(date == 1)
write_com(0x0f); //显示光标并且闪烁
else
write_com(0xc0); //关闭光标
}
/************12864液晶初始化函数*****************/
void init_12864()
{
write_com(0x30); //功能设置 基本指令
write_com(0x0c); //开显示 不显示光标
write_com(0x01); //清除显示
write_string(1,0," 多功能电子日历"); //初始化12864显示
write_string(2,0,"阳历2000年00月00"); //初始化12864显示
write_string(3,0,"农历00-00 星期 "); //初始化12864显示
write_string(4,0," 00:00:00 00.0℃"); //初始化12864显示
}
/************初始化设置显示*****************/
void init_12864_set1()
{
write_string(1,0,"2013年00月00日 "); //初始化12864显示
write_string(2,0," 00时00分00秒 "); //初始化12864显示
write_string(3,0,"设置 星期01 "); //初始化12864显示
write_string(4,0,"闹钟开 00时00分"); //初始化12864显示
if(open1 == 1)
write_string(4,2,"开");
else
write_string(4,2,"关");
write_guanbiao(1,1,1);
}
/***********************18b20初始化函数*****************************/
void init_18b20()
{
bit q;
dq = 1;//把总线拿高
delay_uint(8);
dq = 0;//给复位脉冲 再将数据线从高拉低,要求保持480~960us
delay_uint(80);
dq = 1;//把总线拿高 等待
delay_uint(8);
q = dq;//读取18b20初始化信号
delay_uint(4);
dq = 1;//把总线拿高 释放总线
}
/*************写18b20内的数据***************/
void write_18b20(uchar dat)
{
uchar i;
for(i=0;i<8;i++) //单总线写8位的数据需要循环8次才能写完
{ //写数据是低位开始
dq = 0; //把总线拿低写时间隙开始
dq = dat & 0x01; //向18b20总线写一位数
delay_uint(4);
dq = 1; //释放总线
dat >>= 1;//将dat中的各二进制位数据右移1位
}
delay_uint(4);//稍作延时,给硬件一点反应时间
}
/*************读取18b20内的数据***************/
uchar read_18b20()
{
uchar i,value;
for(i=0;i<8;i++)
{
dq = 0; //把总线拿低读时间隙开始
value >>= 1; //读数据是低位开始
dq = 1; //释放总线
if(dq == 1) //开始读写数据
value |= 0x80;
delay_uint(4);
}
return value; //返回数据
}
/*************读取温度的值 读出来的是小数***************/
uint read_temp()
{
uint value;
uchar low; //在读取温度的时候如果中断的太频繁了,就应该把中断给关了,否则会影响到18b20的时序
init_18b20(); //初始化18b20
write_18b20(0xcc); //跳过64位ROM
write_18b20(0x44); //启动一次温度转换命令
delay_uint(50); //转换一次温度需要时间 延时一下
init_18b20(); //初始化18b20
write_18b20(0xcc); //跳过64位ROM
write_18b20(0xbe); //发出读取暂存器命令
low = read_18b20(); //读温度低字节
value = read_18b20(); //读温度高字节
value <<= 8; //把温度的高位左移8位
value |= low; //把读出的温度低位放到value的低八位中
value *= 0.625; //转换到温度值 小数
return value; //返回读出的温度 带小数
}
/******************时间芯片显示函数**********************/
void ds1302_dis()
{
if(menu_1 == 0)
{
read_time();
Conversion(0,nian,yue,ri);//农历转换
n_nian = year_moon ;
n_yue = month_moon ;
n_ri = day_moon ;
write_shu16(2,3,nian); //显示年
write_shu16(2,5,yue); //显示月
write_shu16(2,7,ri); //显示日
write_shu16(3,7,week); //显示星期
addr_12864(3,2); //地址转换
write_dat(0x30+n_yue/16); //显示农历月
write_dat(0x30+n_yue%16); //显示农历月
write_dat('-');
write_dat(0x30+n_ri/16); //显示农历日
write_dat(0x30+n_ri%16); //显示农历日
addr_12864(4,0); //地址转换
write_dat(0x30+shi/16); //显示时
write_dat(0x30+shi%16);
write_dat(':');
write_dat(0x30+fen/16); //显示分
write_dat(0x30+fen%16);
write_dat(':');
write_dat(0x30+miao/16); //显示秒
write_dat(0x30+miao%16);
write_dat(' ');
write_dat(0x30+temperature/100%10); //显示温度
write_dat(0x30+temperature/10%10);
write_dat('.');
write_dat(0x30+temperature%10);
}
}
/********************独立按键程序*****************/
uchar key_can; //按键值
void key() //独立按键程序
{
if(key1 == 0 || key2 == 0 || key3 == 0 || key4 == 0)//有按键按下
{
delay_1ms(1); //按键延时消抖动
if(key1 == 0)//确认是按键按下
key_can = 1; //得到按键值
if(key2 == 0)//确认是按键按下
key_can = 2; //得到按键值
if(key3 == 0)//确认是按键按下
key_can = 3; //得到按键值
if(key4 == 0)//确认是按键按下
key_can = 4; //得到按键值
}
}
/**********************设置函数************************/
void key_with()
{
if(key_can == 4) //退出键
{
init_12864(); //lcd12864初始化显示
menu_1 = 0;
}
if(key_can == 1)//设置键
{
menu_1 ++;
if(menu_1 == 1)
init_12864_set1();
if(menu_1 > 10)
menu_1 = 1;
}
if(menu_1 != 0)
{
if(menu_1 == 1) //设置年
{
if(key_can == 2)//加键
{
nian+=0x01;//设置年加1
if((nian & 0x0f) >= 0x0a)
nian = (nian & 0xf0) + 0x10;
if(nian >= 0x9a)
nian = 1;
}
if(key_can == 3)//减键
{
if(nian == 0x01)
nian = 0x9a;
if((nian & 0x0f) == 0x00)
nian = (nian | 0x0a) - 0x10;
nian -- ;//设置年减1
}
}
if(menu_1 == 2) //设置月
{
if(key_can == 2)//加键
{
yue+=0x01;//设置月加1
if((yue & 0x0f) >= 0x0a)
yue = (yue & 0xf0) + 0x10;
if(yue >= 0x13)
yue = 1;
}
if(key_can == 3)//减键
{
if(yue == 0x01)
yue = 0x13;
if((yue & 0x0f) == 0x00)
yue = (yue | 0x0a) - 0x10;
yue -- ;//设置月减1
}
}
if(menu_1 == 3) //设置日
{
if(key_can == 2)//加键
{
ri+=0x01;//设置日加1
if((ri & 0x0f) >= 0x0a)
ri = (ri & 0xf0) + 0x10;
if(ri >= 0x32)
ri = 0;
}
if(key_can == 3)//减键
{
if(ri == 0x01)
ri = 0x32;
if((ri & 0x0f) == 0x00)
ri = (ri | 0x0a) - 0x10;
ri -- ;//设置日减1
}
}
if(menu_1 == 4) //设置时
{
if(key_can == 2)//加键
{
shi+=0x01; //设置时钟加1
if((shi & 0x0f) >= 0x0a)
shi = (shi & 0xf0) + 0x10;
if(shi >= 0x24)
shi = 0;
}
if(key_can == 3)//减键
{
if(shi == 0x00)
shi = 0x24;
if((shi & 0x0f) == 0x00)
shi = (shi | 0x0a) - 0x10;
shi -- ; //设置时钟减1
}
}
if(menu_1 == 5) //设置分
{
if(key_can == 2)//加键
{
fen+=0x01;//设置分钟加1
if((fen & 0x0f) >= 0x0a)
fen = (fen & 0xf0) + 0x10;
if(fen >= 0x60)
fen = 0;
}
if(key_can == 3)//减键
{
if(fen == 0x00)
fen = 0x5a;
if((fen & 0x0f) == 0x00)
fen = (fen | 0x0a) - 0x10;
fen -- ; //设置分钟减1
}
}
if(menu_1 == 6) //设置秒
{
if(key_can == 2)//加键
{
miao+=0x01;//设置秒钟加1
if((miao & 0x0f) >= 0x0a)
miao = (miao & 0xf0) + 0x10;
if(miao >= 0x60)
miao = 0;
}
if(key_can == 3)//减键
{
if(miao == 0x00)
miao = 0x5a;
if((miao & 0x0f) == 0x00)
miao = (miao | 0x0a) - 0x10;
miao -- ; //设置秒减1
}
}
if(menu_1 == 7) //设置星期
{
if(key_can == 2)//加键
{
week+=0x01;//设置星期加1
if((week & 0x0f) >= 0x0a)
week = (week & 0xf0) + 0x10;
if(week >= 0x08)
week = 1;
}
if(key_can == 3)//减键
{
if(week == 0x01)
week = 0x08;
if((week & 0x0f) == 0x00)
week = (week | 0x0a) - 0x10;
week -- ;//设置星期减1
}
}
if(menu_1 == 8) //设置闹钟时
{
if(key_can == 2)//加键
{
shi1+=0x01;//设置闹钟时加1
if((shi1 & 0x0f) >= 0x0a)
shi1 = (shi1 & 0xf0) + 0x10;
if(shi1 >= 0x24)
shi1 = 0;
}
if(key_can == 3)//减键
{
if(shi1 == 0x00)
shi1 = 0x5a;
if((shi1 & 0x0f) == 0x00)
shi1 = (shi1 | 0x0a) - 0x10;
shi1 -- ;//设置闹钟分减1
}
}
if(menu_1 == 9) //设置闹钟分
{
if(key_can == 2)//加键
{
fen1+=0x01;//设置闹钟分加1
if((fen1 & 0x0f) >= 0x0a)
fen1 = (fen1 & 0xf0) + 0x10;
if(fen1 >= 0x60)
fen1 = 0;
}
if(key_can == 3)//减键
{
if(fen1 == 0x00)
fen1 = 0x5a;
if((fen1 & 0x0f) == 0x00)
fen1 = (fen1 | 0x0a) - 0x10;
fen1 -- ; //设置闹钟分减1
}
}
if(menu_1 == 10) //设置闹钟分
{
if((key_can == 2) || (key_can == 3))//加
open1 ++;
if(open1 >= 2)
open1 = 0;
if(open1 == 1)
write_string(4,2,"开");
else
write_string(4,2,"关");
}
write_shu16(1,1,nian); //显示年
write_shu16(1,3,yue); //显示月
write_shu16(1,5,ri); //显示日
write_shu16(2,1,shi); //显示时
write_shu16(2,3,fen); //显示分
write_shu16(2,5,miao); //显示秒
write_shu16(3,5,week); //显示星期
write_shu16(4,4,shi1); //显示闹钟时
write_shu16(4,6,fen1); //显示闹钟分
switch(menu_1) // 光标显示
{
case 1: write_guanbiao(1,1,1); break; // 显示光标
case 2: write_guanbiao(1,3,1); break; // 显示光标
case 3: write_guanbiao(1,5,1); break; // 显示光标
case 4: write_guanbiao(2,1,1); break; // 显示光标
case 5: write_guanbiao(2,3,1); break; // 显示光标
case 6: write_guanbiao(2,5,1); break; // 显示光标
case 7: write_guanbiao(3,5,1); break; // 显示光标
case 8: write_guanbiao(4,4,1); break; // 显示光标
case 9: write_guanbiao(4,6,1); break; // 显示光标
case 10: write_guanbiao(4,2,1); break; // 显示光标
}
write_time(); //把时间写到1302里面
}
}
/*************闹钟报警函数***************/
void menu_dis()
{
if(menu_1 == 0)
if(open1 == 1)//如果闹钟打开
{
if((fen == fen1) && (shi == shi1) && (miao == 0))
{
flag_clock_en = 1;//有报警 打开蜂鸣器响的标志位
}
if(flag_clock_en == 1)//闹钟以被打开
{
beep = ~beep; //蜂鸣器叫3秒
}
}
}
/************主函数**************/
void main()
{
beep = 0; //开机叫一声
delay_1ms(150);
P0 = P1 = P2 = P3 = 0xff;//单片机IO口初始化为1
init_12864(); //lcd12864初始化显示
time0_init(); //初始化定时器
while(1)
{
key();
if(flag_clock_en == 0) //只有闹钟关了的时候才能进入设置
key_with();
else
{
beep = 1;
flag_clock_en = 0; //按下任意键可关闭闹钟
}
if(flag_200ms == 1)
{
flag_200ms = 0;
ds1302_dis(); //时钟显示函数
temperature = read_temp();//先读出温度的值
}
if(flag_100ms == 1)
{
menu_dis(); //闹钟报警函数
flag_100ms = 0;
}
delay_1ms(1);
}
}
/**************定时器0中断程序*****************/
void time0() interrupt 1
{
uchar value;
TH0 = 0X3C;
TL0 = 0XB0; //定时50毫秒中断一次
value ++;
if((value % 2) == 0) //100ms
flag_100ms = 1; //定时产生一个100毫秒的变量
if(value >= 4) //200ms
{
value = 0;
flag_200ms = 1;//定时产生一个200毫秒的变量
}
}


IP属地:河北1楼2023-09-08 09:32回复
    这个还有错 找不到 大佬们


    IP属地:河北2楼2023-09-08 10:19
    回复