仿真图:
芯片/模块的特点:
AT89C52简介:
AT89C52是一款经典的8位单片机,是意法半导体(STMicroelectronics)公司生产的一系列单片机之一。它基于8051内核,并具有许多与其兼容的特性。
AT89C52的主要特点如下:
内部存储器:AT89C52具有8KB的闪存(Flash)存储器,可用于存储用户程序和数据。这些存储器的内容可以通过编程器进行编程和擦除。
RAM存储器:AT89C52配备了256字节的随机存取存储器(RAM),用于暂存数据和程序的变量。
外部扩展性:AT89C52支持多种外部扩展设备的连接,包括外部存储器(如RAM、EEPROM)和外设(如ADC、LCD、UART等),通过外部硬件连接,可以扩展单片机的功能和应用。
通用I/O引脚:AT89C52拥有32个可编程的通用输入/输出引脚,可用于连接外部设备和与其他芯片进行通信。
定时器/计数器:AT89C52内置了3个16位定时器/计数器和一个可编程的串行定时器/计数器。这些计时器/计数器可用于实现定时功能、生成脉冲信号、测量时间间隔等。0
串行通信:AT89C52支持串行通信接口,包括UART(串行异步通信)和SPI(串行外设接口),便于与其他设备进行数据通信和交互。
低功耗模式:AT89C52具有多种低功耗模式,如空闲模式和电源下模式,在不需要执行任务的时候可以将CPU进入低功耗状态以节省能量。
宽电源电压范围:AT89C52的工作电压范围通常为4.0V至5.5V,可以满足大多数应用需求。
DS1302特点:
高精度时间计数:DS1302能够提供高精度的实时时钟计数,可以记录年、月、日、星期、小时、分钟和秒等时间信息。它内部集成了晶体振荡器,提供稳定的时钟信号。
低功耗设计:DS1302采用低功耗设计,可以在低功耗模式下运行,有效延长电池寿命。即使在停电情况下,它也能保持时间数据,并通过外部连接电池继续提供计时功能。
串行接口:DS1302通过串行实时时钟接口(SPI)进行通信和控制。使用少数几个引脚,可以与主控器件进行数据交换和时钟同步。
容易集成:DS1302集成了时钟计数和RAM存储器功能,并具有简单的接口和命令,容易与各种微控制器和单片机集成。它不需要复杂的控制信号,可以通过简单的读写命令进行操作。
可编程控制功能:DS1302具有可编程的控制功能,可以设置闹钟、写保护等特殊功能。它还支持多种时间格式的选择,例如24小时制或12小时制。
温度补偿:DS1302内置温度补偿功能,可以校正温度对时钟频率的影响,提高时钟计数的准确性。
高稳定性和抗震动能力:DS1302具有高稳定性和抗震动能力,适用于各种工业和消费类应用场景。
ADC0832特点:
8位分辨率:ADC0832可以将模拟输入信号转换为8位数字输出。这意味着它可以将模拟信号划分为256个不同的离散电平,提供相对较低的分辨率。
双通道输入:ADC0832具有两个模拟输入通道,使其能够同时转换两个模拟信号。这对于需要同时测量多个信号的应用非常有用。
内部参考电压源:ADC0832提供了一个内部的参考电压源,它可以用作模拟输入信号的参考电压。这样可以简化外部电路设计,并提供更稳定和准确的参考电压。
串行输出:ADC0832通过串行接口(SPI或I2C)输出转换结果。这种串行输出形式使其与微控制器或其他数字设备的通信变得更加简单和方便。
低功耗:ADC0832具有较低的功耗特性,适合在低功耗应用中使用。
可编程时钟频率:ADC0832的转换速度可以通过控制输入时钟频率进行编程。这使得可以根据应用的需求调整转换速度,并平衡转换精度和速度。
内部自校准:ADC0832具有内部自校准电路,可以降低转换误差,并提供更准确的转换结果。
ULN2003特点:
高电流驱动能力:ULN2003具有高电流驱动能力,每个输出通道可以提供500mA的峰值输出电流。这使得它可以直接驱动各种继电器、步进电机和其他高功率负载。
集成综合保护:ULN2003集成了综合保护功能,包括输出耐压保护二极管、过电流保护电路和反嵌二极管等。它可以保护芯片和外部设备免受不良电气现象的损害。
多通道输出:ULN2003具有7个独立的输出通道,可以同时控制多个负载。每个通道都具有独立的输入引脚,可以通过输入信号来控制相应的输出通道。
低功耗:ULN2003在工作时功耗较低,适用于对功耗要求较高的应用。它还具有低静态电流消耗,即使在不工作时也能保持低功耗状态。
简单易用:ULN2003非常容易使用,只需要连接输入控制信号和负载即可。它可以直接与TTL或CMOS逻辑电平兼容,并且不需要额外的外部组件。
多种封装形式:ULN2003可以提供不同的封装形式,如多引脚直插式封装(DIP)和表面贴装技术(SMT)封装。这使得ULN2003适应不同应用的安装需求。
主程序:
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char // 以后unsigned char就可以用uchar代替
#define uint unsigned int // 以后unsigned int 就可以用uint 代替
sbit ADC_CS = P1^2; // ADC0832的CS引脚
sbit ADC_CLK = P1^0; // ADC0832的CLK引脚
sbit ADC_DAT = P1^1; // ADC0832的DI/DO引脚
sbit SCK_P = P1^4; // 时钟芯片DS1302的SCK管脚
sbit SDA_P = P1^5; // 时钟芯片DS1302的SDA管脚
sbit RST_P = P1^3; // 时钟芯片DS1302的RST管脚
sbit LcdRs_P = P3^2; // 1602液晶的RS管脚
sbit LcdRw_P = P1^6; // 1602液晶的RW管脚
sbit LcdEn_P = P1^7; // 1602液晶的EN管脚
sbit KeyMode_P = P3^3; // 模式切换
sbit KeySet_P = P3^5; // 设置时间按键
sbit KeySet2_P = P3^7; // 设置时间模式的开关时间和光照控制强度
sbit KeyDown_P = P3^6; // 减按键
sbit KeyUp_P = P3^4; // 加按键
sbit Led_P = P2^0; // 指示灯
uchar gMode=1; // 1是手动模式,2是时间自动模式,3是亮度自动模式
uchar OpenHour = 18; // 开启窗帘的小时
uchar OpenMinute = 20; // 开启窗帘的分钟
uchar CloseHour = 10; // 关闭窗帘的小时
uchar CloseMinute = 30; // 关闭窗帘的分钟
uchar gLight = 40; // 窗帘开关的阈值
uchar code Clock[]={0x80,0x40,0x20,0x10}; // 步进电机顺时针旋转数组
uchar code AntiClock[]={0x10,0x20,0x40,0x80}; // 步进电机逆时针旋转数组
uchar TimeBuff[7]={17,9,1,6,18,30,40}; // 时间数组,默认2017年9月1日,星期五,18:30:40
// TimeBuff[0] 代表年份,范围00-99
// TimeBuff[1] 代表月份,范围1-12
// TimeBuff[2] 代表日期,范围1-31
// TimeBuff[3] 代表星期,范围1-7
// TimeBuff[4] 代表小时,范围00-23
// TimeBuff[5] 代表分钟,范围00-59
// TimeBuff[6] 代表秒钟,范围00-59
/*********************************************************/
// 毫秒级的延时函数,time是要延时的毫秒数
/*********************************************************/
void DelayMs(uint time)
{
uint i,j;
for(i=0;i<time;i++)
for(j=0;j<112;j++);
}
/*********************************************************/
// 1602液晶写命令函数,cmd就是要写入的命令
/*********************************************************/
void LcdWriteCmd(uchar cmd)
{
LcdRs_P = 0;
LcdRw_P = 0;
LcdEn_P = 0;
P0=cmd;
DelayMs(2);
LcdEn_P = 1;
DelayMs(2);
LcdEn_P = 0;
}
/*********************************************************/
// 1602液晶写数据函数,dat就是要写入的数据
/*********************************************************/
void LcdWriteData(uchar dat)
{
LcdRs_P = 1;
LcdRw_P = 0;
LcdEn_P = 0;
P0=dat;
DelayMs(2);
LcdEn_P = 1;
DelayMs(2);
LcdEn_P = 0;
}
/*********************************************************/
// 1602液晶初始化函数
/*********************************************************/
void LcdInit()
{
LcdWriteCmd(0x38); // 16*2显示,5*7点阵,8位数据口
LcdWriteCmd(0x0C); // 开显示,不显示光标
LcdWriteCmd(0x06); // 地址加1,当写入数据后光标右移
LcdWriteCmd(0x01); // 清屏
}
/*********************************************************/
// 液晶光标定位函数
/*********************************************************/
void LcdGotoXY(uchar line,uchar column)
{
// 第一行
if(line==0)
LcdWriteCmd(0x80+column);
// 第二行
if(line==1)
LcdWriteCmd(0x80+0x40+column);
}
/*********************************************************/
// 液晶输出字符串函数
/*********************************************************/
void LcdPrintStr(uchar *str)
{
while(*str!='\0')
LcdWriteData(*str++);
}
/*********************************************************/
// 液晶输出数字(0-99)
/*********************************************************/
void LcdPrintNum(uchar num)
{
LcdWriteData(num/10+48); // 十位
LcdWriteData(num%10+48); // 个位
}
/*********************************************************/
// 显示模式
/*********************************************************/
void LcdPrintMode(uchar num)
{
switch(num)
{
case 1: LcdPrintStr("SD"); break;
case 2: LcdPrintStr("DS"); break;
case 3: LcdPrintStr("GK"); break;
default: break;
}
}
/*********************************************************/
// 液晶显示内容的初始化
/*********************************************************/
void LcdShowInit()
{
LcdGotoXY(0,0);
LcdPrintStr("20 - - : ");
LcdGotoXY(1,0);
LcdPrintStr(" light: ");
LcdGotoXY(1,0);
LcdPrintMode(gMode);
}
/*********************************************************/
// 刷新时间显示
/*********************************************************/
void FlashTime()
{
LcdGotoXY(0,2); // 年份
LcdPrintNum(TimeBuff[0]);
LcdGotoXY(0,5); // 月份
LcdPrintNum(TimeBuff[1]);
LcdGotoXY(0,8); // 日期
LcdPrintNum(TimeBuff[2]);
LcdGotoXY(0,11); // 小时
LcdPrintNum(TimeBuff[4]);
LcdGotoXY(0,14); // 分钟
LcdPrintNum(TimeBuff[5]);
LcdGotoXY(0,13); // 秒钟
if(TimeBuff[6]%2==0) // 秒钟是偶数显示冒号
LcdWriteData(':');
else // 秒钟是奇数显示空格
LcdWriteData(' ');
}
/*********************************************************/
// 初始化DS1302
/*********************************************************/
void DS1302_Init(void)
{
RST_P=0; // RST脚置低
SCK_P=0; // SCK脚置低
SDA_P=0; // SDA脚置低
}
/*********************************************************/
// 从DS1302读出一字节数据
/*********************************************************/
uchar DS1302_Read_Byte(uchar addr)
{
uchar i;
uchar temp;
RST_P=1;
/* 写入目标地址:addr*/
for(i=0;i<8;i++)
{
if(addr&0x01)
SDA_P=1;
else
SDA_P=0;
SCK_P=1;
_nop_();
SCK_P=0;
_nop_();
addr=addr>> 1;
}
/* 读出该地址的数据 */
for(i=0;i<8;i++)
{
temp=temp>>1;
if(SDA_P)
temp|= 0x80;
else
temp&=0x7F;
SCK_P=1;
_nop_();
SCK_P=0;
_nop_();
}
RST_P=0;
return temp;
}
/*********************************************************/
// 向DS1302写入一字节数据
/*********************************************************/
void DS1302_Write_Byte(uchar addr, uchar dat)
{
uchar i;
RST_P = 1;
/* 写入目标地址:addr*/
for(i=0;i<8;i++)
{
if(addr&0x01)
SDA_P=1;
else
SDA_P=0;
SCK_P=1;
_nop_();
SCK_P=0;
_nop_();
addr=addr>>1;
}
/* 写入数据:dat*/
for(i=0;i<8;i++)
{
if(dat&0x01)
SDA_P=1;
else
SDA_P=0;
SCK_P=1;
_nop_();
SCK_P=0;
_nop_();
dat=dat>>1;
}
RST_P=0;
}
/*********************************************************/
// 向DS1302写入时间数据
/*********************************************************/
void DS1302_Write_Time()
{
uchar i;
uchar temp1;
uchar temp2;
for(i=0;i<7;i++) // 十进制转BCD码
{
temp1=(TimeBuff[i]/10)<<4;
temp2=TimeBuff[i]%10;
TimeBuff[i]=temp1+temp2;
}
DS1302_Write_Byte(0x8E,0x00); // 关闭写保护
DS1302_Write_Byte(0x80,0x80); // 暂停时钟
DS1302_Write_Byte(0x8C,TimeBuff[0]); // 年
DS1302_Write_Byte(0x88,TimeBuff[1]); // 月
DS1302_Write_Byte(0x86,TimeBuff[2]); // 日
DS1302_Write_Byte(0x8A,TimeBuff[3]); // 星期
DS1302_Write_Byte(0x84,TimeBuff[4]); // 时
DS1302_Write_Byte(0x82,TimeBuff[5]); // 分
DS1302_Write_Byte(0x80,TimeBuff[6]); // 秒
DS1302_Write_Byte(0x80,TimeBuff[6]&0x7F); // 运行时钟
DS1302_Write_Byte(0x8E,0x80); // 打开写保护
}
/*********************************************************/
// 从DS1302读出时间数据
/*********************************************************/
void DS1302_Read_Time()
{
uchar i;
TimeBuff[0]=DS1302_Read_Byte(0x8D); // 年
TimeBuff[1]=DS1302_Read_Byte(0x89); // 月
TimeBuff[2]=DS1302_Read_Byte(0x87); // 日
TimeBuff[3]=DS1302_Read_Byte(0x8B); // 星期
TimeBuff[4]=DS1302_Read_Byte(0x85); // 时
TimeBuff[5]=DS1302_Read_Byte(0x83); // 分
TimeBuff[6]=(DS1302_Read_Byte(0x81))&0x7F; // 秒
for(i=0;i<7;i++) // BCD转十进制
{
TimeBuff[i]=(TimeBuff[i]/16)*10+TimeBuff[i]%16;
}
}
/*********************************************************/
// ADC0832的时钟脉冲
/*********************************************************/
void WavePlus()
{
_nop_();
ADC_CLK = 1;
_nop_();
ADC_CLK = 0;
}
/*********************************************************/
// 获取指定通道的A/D转换结果
/*********************************************************/
uchar Get_ADC0832()
{
uchar i;
uchar dat1=0;
uchar dat2=0;
ADC_CLK = 0; // 电平初始化
ADC_DAT = 1;
_nop_();
ADC_CS = 0;
WavePlus(); // 起始信号
ADC_DAT = 1;
WavePlus(); // 通道选择的第一位
ADC_DAT = 0;
WavePlus(); // 通道选择的第二位
ADC_DAT = 1;
for(i=0;i<8;i++) // 第一次读取
{
dat1<<=1;
WavePlus();
if(ADC_DAT)
dat1=dat1|0x01;
else
dat1=dat1|0x00;
}
for(i=0;i<8;i++) // 第二次读取
{
dat2>>= 1;
if(ADC_DAT)
dat2=dat2|0x80;
else
dat2=dat2|0x00;
WavePlus();
}
_nop_(); // 结束此次传输
ADC_DAT = 1;
ADC_CLK = 1;
ADC_CS = 1;
if(dat1==dat2) // 返回采集结果
return dat1;
else
return 0;
}
/*********************************************************/
// 按键扫描(设置当前时间)
/*********************************************************/
void KeyScanf1()
{
if(KeySet_P==0)
{
LcdGotoXY(0,13); // 显示秒钟的冒号
LcdWriteData(':');
LcdWriteCmd(0x0f); // 启动光标闪烁
LcdGotoXY(0,3); // 定位光标到年份闪烁
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
/* 调整年份 */
while(1)
{
if(KeyDown_P==0) // 如果减按键被下去
{
if(TimeBuff[0]>0) // 判断年份是否大于0
TimeBuff[0]--; // 是的话就减去1
LcdGotoXY(0,2); // 光标定位到年份的位置
LcdPrintNum(TimeBuff[0]); // 刷新显示改变后的年份
LcdGotoXY(0,3); // 定位光标到年份闪烁
DelayMs(300); // 延时0.3秒左右
}
if(KeyUp_P==0) // 如果加按键被下去
{
if(TimeBuff[0]<99) // 判断年份是否小于99
TimeBuff[0]++; // 是的话就加上1
LcdGotoXY(0,2); // 光标定位到年份的位置
LcdPrintNum(TimeBuff[0]); // 刷新显示改变后的年份
LcdGotoXY(0,3); // 定位光标到年份闪烁
DelayMs(300); // 延时0.3秒左右
}
if(KeySet_P==0)
{
break;
}
}
LcdGotoXY(0,6); // 定位光标到月份闪烁
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
/* 调整月份 */
while(1)
{
if(KeyDown_P==0) // 如果减按键被下去
{
if(TimeBuff[1]>1) // 判断月份是否大于1
TimeBuff[1]--; // 是的话就减去1
LcdGotoXY(0,5); // 光标定位到月份的位置
LcdPrintNum(TimeBuff[1]); // 刷新显示改变后的月份
LcdGotoXY(0,6); // 定位光标到月份闪烁
DelayMs(300); // 延时0.3秒左右
}
if(KeyUp_P==0) // 如果加按键被下去
{
if(TimeBuff[1]<12) // 判断月份是否小于12
TimeBuff[1]++; // 是的话就加上1
LcdGotoXY(0,5); // 光标定位到月份的位置
LcdPrintNum(TimeBuff[1]); // 刷新显示改变后的月份
LcdGotoXY(0,6); // 定位光标到月份闪烁
DelayMs(300); // 延时0.3秒左右
}
if(KeySet_P==0)
{
break;
}
}
LcdGotoXY(0,9); // 定位光标到日期闪烁
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
/* 调整日期 */
while(1)
{
if(KeyDown_P==0) // 如果减按键被下去
{
if(TimeBuff[2]>1) // 判断日期是否大于1
TimeBuff[2]--; // 是的话就减去1
LcdGotoXY(0,8); // 光标定位到日期的位置
LcdPrintNum(TimeBuff[2]); // 刷新显示改变后的日期
LcdGotoXY(0,9); // 定位光标到日期闪烁
DelayMs(300); // 延时0.3秒左右
}
if(KeyUp_P==0) // 如果加按键被下去
{
if(TimeBuff[2]<31) // 判断日期是否小于31
TimeBuff[2]++; // 是的话就加上1
LcdGotoXY(0,8); // 光标定位到日期的位置
LcdPrintNum(TimeBuff[2]); // 刷新显示改变后的日期
LcdGotoXY(0,9); // 定位光标到日期闪烁
DelayMs(300); // 延时0.3秒左右
}
if(KeySet_P==0)
{
break;
}
}
LcdGotoXY(0,12); // 定位光标到小时闪烁
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
/* 调整小时 */
while(1)
{
if(KeyDown_P==0) // 如果减按键被下去
{
if(TimeBuff[4]>0) // 判断小时是否大于0
TimeBuff[4]--; // 是的话就减去1
LcdGotoXY(0,11); // 光标定位到小时的位置
LcdPrintNum(TimeBuff[4]); // 刷新显示改变后的小时
LcdGotoXY(0,12); // 定位光标到小时闪烁
DelayMs(300); // 延时0.3秒左右
}
if(KeyUp_P==0) // 如果加按键被下去
{
if(TimeBuff[4]<23) // 判断小时是否小于23
TimeBuff[4]++; // 是的话就加上1
LcdGotoXY(0,11); // 光标定位到小时的位置
LcdPrintNum(TimeBuff[4]); // 刷新显示改变后的小时
LcdGotoXY(0,12); // 定位光标到小时闪烁
DelayMs(300); // 延时0.3秒左右
}
if(KeySet_P==0)
{
break;
}
}
LcdGotoXY(0,15); // 定位光标到分钟闪烁
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
/* 调整分钟 */
while(1)
{
if(KeyDown_P==0) // 如果减按键被下去
{
if(TimeBuff[5]>0) // 判断分钟是否大于0
TimeBuff[5]--; // 是的话就减去1
LcdGotoXY(0,14); // 光标定位到分钟的位置
LcdPrintNum(TimeBuff[5]); // 刷新显示改变后的分钟
LcdGotoXY(0,15); // 定位光标到分钟闪烁
DelayMs(300); // 延时0.3秒左右
}
if(KeyUp_P==0) // 如果加按键被下去
{
if(TimeBuff[5]<59) // 判断分钟是否小于59
TimeBuff[5]++; // 是的话就加上1
LcdGotoXY(0,14); // 光标定位到分钟的位置
LcdPrintNum(TimeBuff[5]); // 刷新显示改变后的分钟
LcdGotoXY(0,15); // 定位光标到分钟闪烁
DelayMs(300); // 延时0.3秒左右
}
if(KeySet_P==0)
{
break;
}
}
/* 退出前的设置 */
LcdWriteCmd(0x0C); // 关闭光标闪烁
DS1302_Write_Time(); // 把新设置的时间值存入DS1302芯片
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
}
}
/*********************************************************/
// 按键扫描(设置窗帘的动作)
/*********************************************************/
void KeyScanf2()
{
if(KeySet2_P==0)
{
LcdGotoXY(0,0); // 光标定位
LcdPrintStr(" OpenTime : "); // 显示第1行内容
LcdGotoXY(1,0); // 光标定位
LcdPrintStr("CloseTime : "); // 显示第2行内容
LcdGotoXY(0,10); // 光标定位
LcdPrintNum(OpenHour); // 显示开启窗帘的小时
LcdGotoXY(0,13); // 光标定位
LcdPrintNum(OpenMinute); // 显示开启窗帘的分钟
LcdGotoXY(1,10); // 光标定位
LcdPrintNum(CloseHour); // 显示关闭窗帘的小时
LcdGotoXY(1,13); // 光标定位
LcdPrintNum(CloseMinute); // 显示关闭窗帘的分钟
LcdWriteCmd(0x0f); // 启动光标闪烁
LcdGotoXY(0,11); // 定位光标
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet2_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
/* 调整开启的小时 */
while(1)
{
if(KeyDown_P==0) // 如果减按键被下去
{
if(OpenHour>0) // 判断小时是否大于0
OpenHour--; // 是的话就减去1
LcdGotoXY(0,10); // 光标定位
LcdPrintNum(OpenHour); // 刷新显示改变后的小时
LcdGotoXY(0,11); // 定位光标
DelayMs(300); // 延时0.3秒左右
}
if(KeyUp_P==0) // 如果加按键被下去
{
if(OpenHour<23) // 判断小时是否小于23
OpenHour++; // 是的话就加上1
LcdGotoXY(0,10); // 光标定位
LcdPrintNum(OpenHour); // 刷新显示改变后的小时
LcdGotoXY(0,11); // 定位光标
DelayMs(300); // 延时0.3秒左右
}
if(KeySet2_P==0)
{
break;
}
}
LcdGotoXY(0,14); // 定位光标
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet2_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
/* 调整开启的分钟 */
while(1)
{
if(KeyDown_P==0) // 如果减按键被下去
{
if(OpenMinute>0) // 判断分钟是否大于0
OpenMinute--; // 是的话就减去1
LcdGotoXY(0,13); // 光标定位
LcdPrintNum(OpenMinute); // 刷新显示改变后的分钟
LcdGotoXY(0,14); // 定位光标
DelayMs(300); // 延时0.3秒左右
}
if(KeyUp_P==0) // 如果加按键被下去
{
if(OpenMinute<59) // 判断分钟是否小于59
OpenMinute++; // 是的话就加上1
LcdGotoXY(0,13); // 光标定位
LcdPrintNum(OpenMinute); // 刷新显示改变后的分钟
LcdGotoXY(0,14); // 定位光标
DelayMs(300); // 延时0.3秒左右
}
if(KeySet2_P==0)
{
break;
}
}
LcdGotoXY(1,11); // 定位光标
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet2_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
/* 调整关闭的小时 */
while(1)
{
if(KeyDown_P==0) // 如果减按键被下去
{
if(CloseHour>0) // 判断小时是否大于0
CloseHour--; // 是的话就减去1
LcdGotoXY(1,10); // 光标定位
LcdPrintNum(CloseHour); // 刷新显示改变后的小时
LcdGotoXY(1,11); // 定位光标
DelayMs(300); // 延时0.3秒左右
}
if(KeyUp_P==0) // 如果加按键被下去
{
if(CloseHour<23) // 判断小时是否小于23
CloseHour++; // 是的话就加上1
LcdGotoXY(1,10); // 光标定位
LcdPrintNum(CloseHour); // 刷新显示改变后的小时
LcdGotoXY(1,11); // 定位光标
DelayMs(300); // 延时0.3秒左右
}
if(KeySet2_P==0)
{
break;
}
}
LcdGotoXY(1,14); // 定位光标
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet2_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
/* 调整关闭的分钟 */
while(1)
{
if(KeyDown_P==0) // 如果减按键被下去
{
if(CloseMinute>0) // 判断分钟是否大于0
CloseMinute--; // 是的话就减去1
LcdGotoXY(1,13); // 光标定位
LcdPrintNum(CloseMinute); // 刷新显示改变后的分钟
LcdGotoXY(1,14); // 定位光标
DelayMs(300); // 延时0.3秒左右
}
if(KeyUp_P==0) // 如果加按键被下去
{
if(CloseMinute<59) // 判断分钟是否小于59
CloseMinute++; // 是的话就加上1
LcdGotoXY(1,13); // 光标定位
LcdPrintNum(CloseMinute); // 刷新显示改变后的分钟
LcdGotoXY(1,14); // 定位光标
DelayMs(300); // 延时0.3秒左右
}
if(KeySet2_P==0)
{
break;
}
}
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet2_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
/* 光照强度的设置 */
LcdWriteCmd(0x0C); // 关闭光标闪烁
LcdGotoXY(0,0); // 光标定位
LcdPrintStr(" Light Set "); // 显示第1行内容
LcdGotoXY(1,0); // 光标定位
LcdPrintStr(" "); // 显示第2行内容
LcdGotoXY(1,7); // 光标定位
LcdPrintNum(gLight); // 显示窗帘的光线控制强度阈值
while(1)
{
if(KeyDown_P==0) // 如果减按键被下去
{
if(gLight>0) // 判断光线阈值是否大于0
gLight--; // 是的话就减去1
LcdGotoXY(1,7); // 光标定位
LcdPrintNum(gLight); // 刷新显示改变后的光线阈值
DelayMs(300); // 延时0.3秒左右
}
if(KeyUp_P==0) // 如果加按键被下去
{
if(gLight<99) // 判断光线阈值是否小于59
gLight++; // 是的话就加上1
LcdGotoXY(1,7); // 光标定位
LcdPrintNum(gLight); // 刷新显示改变后的光线阈值
DelayMs(300); // 延时0.3秒左右
}
if(KeySet2_P==0)
{
break;
}
}
/* 退出前的设置 */
LcdShowInit(); // 液晶显示内容初始化
DelayMs(10); // 延时等待,消除按键按下的抖动
while(!KeySet2_P); // 等待按键释放
DelayMs(10); // 延时等待,消除按键松开的抖动
}
}
/*********************************************************/
// 按键扫描(模式切换)
/*********************************************************/
void KeyScanf3()
{
if(KeyMode_P==0)
{
gMode++; // 切换到下一模式
if(gMode==4) // 如果到尽头了
gMode=1; // 回到第一种模式
LcdGotoXY(1,0); // 光标定位
LcdPrintMode(gMode); // 显示模式
DelayMs(10); // 去除按键按下的抖动
while(!KeyMode_P); // 等待按键是否
DelayMs(10); // 去除按键松开的抖动
}
}
/*********************************************************/
// 开窗
/*********************************************************/
void Open()
{
uint i,j;
for(j=0;j<255;j++) // 控制步进电机正转
{
for(i=0;i<4;i++)
{
P2=Clock[i];
DelayMs(3);
}
}
Led_P=0;
}
/*********************************************************/
// 关窗
/*********************************************************/
void Close()
{
uint i,j;
for(j=0;j<255;j++) // 控制步进电机反转
{
for(i=0;i<4;i++)
{
P2=AntiClock[i];
DelayMs(3);
}
}
Led_P=1;
}
/*********************************************************/
// 主函数
/*********************************************************/
void main()
{
uchar light;
LcdInit(); // 执行液晶初始化
DS1302_Init(); // 时钟芯片的初始化
LcdShowInit(); // 液晶显示内容的初始化
if(DS1302_Read_Byte(0x81)>=128) // 判断时钟芯片是否正在运行
{
DS1302_Write_Time(); // 如果没有,则初始化一个时间
}
while(1)
{
DS1302_Read_Time(); // 获取当前时钟芯片的时间,存在数组time_buf中
FlashTime(); // 刷新时间显示
light=Get_ADC0832(); // 读取光照强度
light=light/2.5; // 缩小光照检测结果(在0-99)
if(light>99) // 如果大于99
light=99; // 则依然保持99
LcdGotoXY(1,14); // 光标定位
LcdPrintNum(light); // 显示光照强度
KeyScanf1(); // 按键扫描(时间的设置)
KeyScanf2(); // 按键扫描(阈值的设置)
KeyScanf3(); // 按键扫描(模式切换)
/*手动控制模式*/
if(gMode==1)
{
if(KeyDown_P==0) // 如果关窗帘键按下了
{
if(Led_P==0) // 如果窗帘当前是打开的
{
Close(); // 则光标窗帘
}
}
if(KeyUp_P==0) // 如果开窗帘键按下了
{
if(Led_P==1) // 如果窗帘当前是关闭的
{
Open(); // 则打开窗帘
}
}
}
/*时间控制模式*/
if(gMode==2)
{
if((TimeBuff[4]==CloseHour)&&(TimeBuff[5]==CloseMinute)&&(TimeBuff[6]==0)) // 如果到了关窗帘的时间
{
if(Led_P==0) // 如果窗帘当前是打开的
{
Close(); // 则光标窗帘
}
}
if((TimeBuff[4]==OpenHour)&&(TimeBuff[5]==OpenMinute)&&(TimeBuff[6]==0)) // 如果到了开窗帘的时间
{
if(Led_P==1) // 如果窗帘当前是关闭的
{
Open(); // 则打开窗帘
}
}
}
/*光线控制模式*/
if(gMode==3)
{
if(light<gLight) // 当前光线小于设置的阈值
{
if(Led_P==0) // 如果窗帘当前是打开的
{
Close(); // 则光标窗帘
}
}
else // 当前光线大于或等于设置的阈值
{
if(Led_P==1) // 如果窗帘当前是关闭的
{
Open(); // 则打开窗帘
}
}
}
DelayMs(100); // 延时0.1秒
}
}
设计文件: