【51单片机】【protues仿真】基于51单片机宠物投食器系统
目录
一、主要功能
二、使用步骤
三、硬件资源
四、软件设计
五、实验现象
一、主要功能
1、LCD1602液晶显示当前时间
2、按键设置时间,5个定时投喂时间
3、可以通过手动按键进行投喂食物
4、步进电机模拟投喂食物
二、使用步骤
基于51单片机的宠物自动投食器系统设计可实现定时喂食、手动喂食及状态监测等功能。
三、硬件资源
1、51单片机核心模块
2、按键模块
3、时钟模块
4、蜂鸣器模块
5、步进电机模块
6、LCD1602显示模块
四、软件设计
#include "common.h"
#include "lcd1602.h"
#include "eeprom52.h"
#include "DS1302.h"
sbit key1 = P1^0;//切换键
sbit key2 = P1^1;//加键
sbit key3 = P1^2;//减键
sbit key4 = P1^3;//开启
sbit key5 = P1^4;//关闭
sbit beep = P3^7;//蜂鸣器
#define angle 360 //电机旋转的角度
uchar code Clock[]={0x01,0x02,0x04,0x08}; // 步进电机顺时针旋转数组
uchar code AntiClock[]={0x08,0x04,0x02,0x01}; // 步进电机逆时针旋转数组
unsigned char setn = 0;//设置标志
uchar DS1302_Table[7]={0};
uchar sec, min, hour, day, month, week, year;
bit open_flag=0;
bit feeding_time = 0;
typedef struct {
unsigned char shi; //时
unsigned char fen; //分
}user;
user foodtime1={7,00}; //喂食时间1
user foodtime2={11,03}; //喂食时间2
user foodtime3={14,0}; //喂食时间3
user foodtime4={17,0}; //喂食时间4
user foodtime5={22,19}; //喂食时间5
/*********************************************************/
// 毫秒级的延时函数,time是要延时的毫秒数
/*********************************************************/
void DelayMs(uint time)
{
uint i,j;
for(i=0;i<time;i++)
for(j=0;j<112;j++);
}
/*********************************************************/
// 开
/*********************************************************/
void Ul2003_Open()
{
uint i,j;
for(j=0;j<10;j++) // 控制步进电机正转
{
for(i=0;i<4;i++)
{
P2=Clock[i]|0xf0;
DelayMs(10);
}
}
}
/*********************************************************/
// 关
/*********************************************************/
void Ul2003_Close()
{
uint i,j;
for(j=0;j<10;j++) // 控制步进电机反转
{
for(i=0;i<4;i++)
{
P2=AntiClock[i]|0xf0;
DelayMs(10);
}
}
}
void time_init(void) //定时器初始化
{
TMOD |= 0x01; //定时器0工作方式1
TL0 = 0xCD;
TH0 = 0xF8; //定时器定时2ms
TR0 = 1;
ET0 = 1; //开定时器0中断
EA = 1; //开总中断
}
void eepromWriteByte(void)
{
uint addr=0x2000;
SectorErase(addr);//扇区擦除
byte_write(addr++, foodtime1.shi);
byte_write(addr++, foodtime1.fen);
byte_write(addr++, foodtime2.shi);
byte_write(addr++, foodtime2.fen);
byte_write(addr++, foodtime3.shi);
byte_write(addr++, foodtime3.fen);
byte_write(addr++, foodtime4.shi);
byte_write(addr++, foodtime4.fen);
byte_write(addr++, foodtime5.shi);
byte_write(addr++, foodtime5.fen);
byte_write(0x2014, 0xAA);
}
void eepromInit(void)
{
uint addr=0x2000;
if(byte_read(0x2014)!=0xAA)//校验是不是新的单片机
{
eepromWriteByte();
delay_ms(100);
}
}
void displayTime(void)
{
//显示时间
lcd_write_com(0x80);
lcd_write_data(DS1302_Table[0]/10+0x30);
lcd_write_data(DS1302_Table[0]%10+0x30);
lcd_write_data('/');
lcd_write_data(DS1302_Table[1]/10+0x30);
lcd_write_data(DS1302_Table[1]%10+0x30);
lcd_write_data('/');
lcd_write_data(DS1302_Table[2]/10+0x30);
lcd_write_data(DS1302_Table[2]%10+0x30);
lcd_write_com(0x80+0x40);
lcd_write_data(DS1302_Table[4]/10+0x30);
lcd_write_data(DS1302_Table[4]%10+0x30);
lcd_write_data(':');
lcd_write_data(DS1302_Table[5]/10+0x30);
lcd_write_data(DS1302_Table[5]%10+0x30);
lcd_write_data(':');
lcd_write_data(DS1302_Table[6]/10+0x30);
lcd_write_data(DS1302_Table[6]%10+0x30);
}
void write_week(uchar week)//写星期函数
{
lcd_write_com(0x80+9);//星期字符的显示位置
switch(week)
{
case 1:
lcd_write_data('M');//星期数为1时,显示
lcd_write_data('O');
lcd_write_data('N');
break;
case 2:
lcd_write_data('T');//星期数据为2时显示
lcd_write_data('U');
lcd_write_data('E');
break;
case 3:
lcd_write_data('W');//星期数据为3时显示
lcd_write_data('E');
lcd_write_data('D');
break;
case 4:
lcd_write_data('T');//星期数据为4是显示
lcd_write_data('H');
lcd_write_data('U');
break;
case 5:
lcd_write_data('F');//星期数据为5时显示
lcd_write_data('R');
lcd_write_data('I');
break;
case 6:
lcd_write_data('S');//星期数据为6时显示
lcd_write_data('A');
lcd_write_data('T');
break;
case 0:
lcd_write_data('S');//星期数据为7时显示
lcd_write_data('U');
lcd_write_data('N');
break;
}
}
void Run_DS1302(void)//DS1302运行
{
//获取时间:年月日时分秒
v_W1302(0x8f, 0);
sec = bcdtodec(uc_R1302(0x81));
v_W1302(0x8f, 0);
min = bcdtodec(uc_R1302(0x83));
v_W1302(0x8f, 0);
hour = bcdtodec(uc_R1302(0x85));
v_W1302(0x8f, 0);
day = bcdtodec(uc_R1302(0x87));
v_W1302(0x8f, 0);
month = bcdtodec(uc_R1302(0x89));
v_W1302(0x8f, 0);
week = bcdtodec(uc_R1302(0x8b));
v_W1302(0x8f, 0);
year = bcdtodec(uc_R1302(0x8d));
DS1302_Table[0]=year;
DS1302_Table[1]=month;
DS1302_Table[2]=day;
DS1302_Table[3]=week;
DS1302_Table[4]=hour;
DS1302_Table[5]=min;
DS1302_Table[6]=sec;
displayTime();
// write_week(week);
}
void displayUserSetValue(const user * const date)//显示设置值
{
lcd_write_char(6,1,date ->shi / 10+'0');
lcd_write_char(7,1,date ->shi % 10+'0');
lcd_write_char(9,1,date ->fen / 10+'0');
lcd_write_char(10,1,date ->fen % 10+'0');
}
void keyscan()
{
if(key1 == 0)//设置键
{
delay_ms(10);
if(key1 == 0)
{
beep = 0;
delay_ms(100);
beep = 1;
while(key1 == 0);//等待按键松开
setn++;
if(setn > 16)//按下次数超过16次,退出设置
{
setn = 0;
lcd_write_com(0x0c);//关闭光标
lcd_clear();
lcd_write_str(0, 0, " / / ");
lcd_write_str(0, 1, " : : ");
eepromWriteByte(); //退出设置之后,把数据保存一遍
}
if(setn == 1)//设置年
{
displayTime();
lcd_write_com(0x80+1);
lcd_write_com(0x0f);
}
if(setn == 2)//设置月
{
lcd_write_com(0x80+4);
lcd_write_com(0x0f);
}
if(setn == 3)//日
{
lcd_write_com(0x80+7);
lcd_write_com(0x0f);
}
if(setn == 4)//时
{
lcd_write_com(0x80+0x40+1);
lcd_write_com(0x0f);
}
if(setn == 5)//分
{
lcd_write_com(0x80+0x40+4);
lcd_write_com(0x0f);
}
if(setn == 6)//秒
{
lcd_write_com(0x80+0x40+7);
lcd_write_com(0x0f);
}
if(setn == 7)
{
lcd_write_str(0, 0, "set food time 1 ");
lcd_write_str(0, 1, " 00:00 ");
displayUserSetValue(&foodtime1);
lcd_write_com(0x80+0x40+7);
lcd_write_com(0x0f);
}
if(setn == 8)
{
lcd_write_com(0x80+0x40+10);
lcd_write_com(0x0F);
}
if(setn == 9)
{
lcd_write_str(0, 0, "set food time 2 ");
lcd_write_str(0, 1, " 00:00 ");
displayUserSetValue(&foodtime2);
lcd_write_com(0x80+0x40+7);
lcd_write_com(0x0f);
}
if(setn == 10)
{
lcd_write_com(0x80+0x40+10);
lcd_write_com(0x0F);
}
if(setn == 11)
{
lcd_write_str(0, 0, "set food time 3 ");
lcd_write_str(0, 1, " 00:00 ");
displayUserSetValue(&foodtime3);
lcd_write_com(0x80+0x40+7);
lcd_write_com(0x0f);
}
if(setn == 12)
{
lcd_write_com(0x80+0x40+10);
lcd_write_com(0x0F);
}
if(setn == 13)
{
lcd_write_str(0, 0, "set food time 4 ");
lcd_write_str(0, 1, " 00:00 ");
displayUserSetValue(&foodtime4);
lcd_write_com(0x80+0x40+7);
lcd_write_com(0x0f);
}
if(setn == 14)
{
lcd_write_com(0x80+0x40+10);
lcd_write_com(0x0F);
}
if(setn == 15)
{
lcd_write_str(0, 0, "set food time 5 ");
lcd_write_str(0, 1, " 00:00 ");
displayUserSetValue(&foodtime5);
lcd_write_com(0x80+0x40+7);
lcd_write_com(0x0f);
}
if(setn == 16)
{
lcd_write_com(0x80+0x40+10);
lcd_write_com(0x0F);
}
}
}
if(key2 == 0)
{
delay_ms(10);
if(key2 == 0)
{
beep = 0;
delay_ms(100);
beep = 1;
while(key2 == 0);
if(setn == 1)//设置年
{
DS1302_Table[0]++;
if(DS1302_Table[0] == 100)//最大到100
DS1302_Table[0] = 0;
Write_DS1302Init(DS1302_Table[0],DS1302_Table[1],DS1302_Table[2],0,DS1302_Table[4],DS1302_Table[5],DS1302_Table[6]);//写入DS1302
displayTime();//显示
lcd_write_com(0x80+1);
lcd_write_com(0x0f);//光标闪烁
}
else if(setn == 2)//设置月
{
DS1302_Table[1]++;
if(DS1302_Table[1]==13)//最大12个月
DS1302_Table[1]=1;
Write_DS1302Init(DS1302_Table[0],DS1302_Table[1],DS1302_Table[2],0,DS1302_Table[4],DS1302_Table[5],DS1302_Table[6]);//写入DS1302
displayTime();//显示
lcd_write_com(0x80+4);
lcd_write_com(0x0f);//光标闪烁
}
else if(setn == 3)//设置日
{
DS1302_Table[2]++;
if(DS1302_Table[2]==32)
DS1302_Table[2]=1;
Write_DS1302Init(DS1302_Table[0],DS1302_Table[1],DS1302_Table[2],0,DS1302_Table[4],DS1302_Table[5],DS1302_Table[6]);//写入DS1302
displayTime();//显示
lcd_write_com(0x80+7);
lcd_write_com(0x0f);//光标闪烁
}
else if(setn == 4)//设置时
{
DS1302_Table[4]++;
if(DS1302_Table[4] == 24)//到0点
DS1302_Table[4] = 0;
Write_DS1302Init(DS1302_Table[0],DS1302_Table[1],DS1302_Table[2],0,DS1302_Table[4],DS1302_Table[5],DS1302_Table[6]);//写入DS1302
displayTime();//显示
lcd_write_com(0x80+0x40+1);
lcd_write_com(0x0f);//光标闪烁
}
else if(setn == 5)//设置分
{
DS1302_Table[5]++;
if(DS1302_Table[5] == 60)//60分钟
DS1302_Table[5] = 0;
Write_DS1302Init(DS1302_Table[0],DS1302_Table[1],DS1302_Table[2],0,DS1302_Table[4],DS1302_Table[5],DS1302_Table[6]);//写入DS1302
displayTime();//显示
lcd_write_com(0x80+0x40+4);
lcd_write_com(0x0f);//光标闪烁
}
else if(setn == 6)//设置分
{
DS1302_Table[6]++;
if(DS1302_Table[6] == 60)//60秒
DS1302_Table[6] = 0;
Write_DS1302Init(DS1302_Table[0],DS1302_Table[1],DS1302_Table[2],0,DS1302_Table[4],DS1302_Table[5],DS1302_Table[6]);//写入DS1302
displayTime();//显示
lcd_write_com(0x80+0x40+7);
lcd_write_com(0x0f);//光标闪烁
}
else if(setn == 7)
{
foodtime1.shi++;
if(foodtime1.shi==24)
foodtime1.shi=0;
displayUserSetValue(&foodtime1);
lcd_write_com(0x80+0x40+7);
lcd_write_com(0x0f);
}
else if(setn == 8)
{
foodtime1.fen++;
if(foodtime1.fen==60)
foodtime1.fen=0;
displayUserSetValue(&foodtime1);
lcd_write_com(0x80+0x40+10);
lcd_write_com(0x0F);
}
else if(setn == 9)
{
foodtime2.shi++;
if(foodtime2.shi==24)
foodtime2.shi=0;
displayUserSetValue(&foodtime2);
lcd_write_com(0x80+0x40+7);
lcd_write_com(0x0f);
}
else if(setn == 10)
{
foodtime2.fen++;
if(foodtime2.fen==60)
foodtime2.fen=0;
displayUserSetValue(&foodtime2);
lcd_write_com(0x80+0x40+10);
lcd_write_com(0x0F);
}
else if(setn == 11)
{
foodtime3.shi++;
if(foodtime3.shi==24)
foodtime3.shi=0;
displayUserSetValue(&foodtime3);
lcd_write_com(0x80+0x40+7);
lcd_write_com(0x0f);
}
else if(setn == 12)
{
foodtime3.fen++;
if(foodtime3.fen==60)
foodtime3.fen=0;
displayUserSetValue(&foodtime3);
lcd_write_com(0x80+0x40+10);
lcd_write_com(0x0F);
}
else if(setn == 13)
{
foodtime4.shi++;
if(foodtime4.shi==24)
foodtime4.shi=0;
displayUserSetValue(&foodtime4);
lcd_write_com(0x80+0x40+7);
lcd_write_com(0x0f);
}
else if(setn == 14)
{
foodtime4.fen++;
if(foodtime4.fen==60)
foodtime4.fen=0;
displayUserSetValue(&foodtime4);
lcd_write_com(0x80+0x40+10);
lcd_write_com(0x0F);
}
else if(setn == 15)
{
foodtime5.shi++;
if(foodtime5.shi==24)
foodtime5.shi=0;
displayUserSetValue(&foodtime5);
lcd_write_com(0x80+0x40+7);
lcd_write_com(0x0f);
}
else if(setn == 16)
{
foodtime5.fen++;
if(foodtime5.fen==60)
foodtime5.fen=0;
displayUserSetValue(&foodtime5);
lcd_write_com(0x80+0x40+10);
lcd_write_com(0x0F);
}
}
}
if(key3 == 0)
{
delay_ms(10);
if(key3 == 0 )
{
beep = 0;
delay_ms(100);
beep = 1;
while(key3 == 0);
if(setn == 1)//设置年
{
if(DS1302_Table[0] == 0)
DS1302_Table[0] = 100;
DS1302_Table[0]--;
Write_DS1302Init(DS1302_Table[0],DS1302_Table[1],DS1302_Table[2],0,DS1302_Table[4],DS1302_Table[5],DS1302_Table[6]);
displayTime();
lcd_write_com(0x80+1);
lcd_write_com(0x0f);
}
else if(setn == 2)//设置月
{
DS1302_Table[1]--;
if(DS1302_Table[1]==0)
DS1302_Table[1]=12;
Write_DS1302Init(DS1302_Table[0],DS1302_Table[1],DS1302_Table[2],0,DS1302_Table[4],DS1302_Table[5],DS1302_Table[6]);
displayTime();
lcd_write_com(0x80+4);
lcd_write_com(0x0f);
}
else if(setn == 3)//设置日
{
DS1302_Table[2]--;
if(DS1302_Table[2]==0)
DS1302_Table[2]=31;
Write_DS1302Init(DS1302_Table[0],DS1302_Table[1],DS1302_Table[2],0,DS1302_Table[4],DS1302_Table[5],DS1302_Table[6]);
displayTime();
lcd_write_com(0x80+7);
lcd_write_com(0x0f);
}
else if(setn == 4)//设置时
{
if(DS1302_Table[4] == 0)
DS1302_Table[4] = 24;
DS1302_Table[4]--;
Write_DS1302Init(DS1302_Table[0],DS1302_Table[1],DS1302_Table[2],0,DS1302_Table[4],DS1302_Table[5],DS1302_Table[6]);
displayTime();
lcd_write_com(0x80+0x40+1);
lcd_write_com(0x0f);
}
else if(setn == 5)//设置分
{
if(DS1302_Table[5] == 0)
DS1302_Table[5] = 60;
DS1302_Table[5]--;
Write_DS1302Init(DS1302_Table[0],DS1302_Table[1],DS1302_Table[2],0,DS1302_Table[4],DS1302_Table[5],DS1302_Table[6]);
displayTime();
lcd_write_com(0x80+0x40+4);
lcd_write_com(0x0f);
}
else if(setn == 6)//设置秒
{
if(DS1302_Table[6] == 0)
DS1302_Table[6] = 60;
DS1302_Table[6]--;
Write_DS1302Init(DS1302_Table[0],DS1302_Table[1],DS1302_Table[2],0,DS1302_Table[4],DS1302_Table[5],DS1302_Table[6]);
displayTime();
lcd_write_com(0x80+0x40+7);
lcd_write_com(0x0f);
}
else if(setn == 7)
{
if(foodtime1.shi==0)
foodtime1.shi=24;
foodtime1.shi--;
displayUserSetValue(&foodtime1);
lcd_write_com(0x80+0x40+7);
lcd_write_com(0x0f);
}
else if(setn == 8)
{
if(foodtime1.fen==0)
foodtime1.fen=60;
foodtime1.fen--;
displayUserSetValue(&foodtime1);
lcd_write_com(0x80+0x40+10);
lcd_write_com(0x0F);
}
else if(setn == 9)
{
if(foodtime2.shi==0)
foodtime2.shi=24;
foodtime2.shi--;
displayUserSetValue(&foodtime2);
lcd_write_com(0x80+0x40+7);
lcd_write_com(0x0f);
}
else if(setn == 10)
{
if(foodtime2.fen==0)
foodtime2.fen=60;
foodtime2.fen--;
displayUserSetValue(&foodtime2);
lcd_write_com(0x80+0x40+10);
lcd_write_com(0x0F);
}
else if(setn == 11)
{
if(foodtime3.shi==0)
foodtime3.shi=24;
foodtime3.shi--;
displayUserSetValue(&foodtime3);
lcd_write_com(0x80+0x40+7);
lcd_write_com(0x0f);
}
else if(setn == 12)
{
if(foodtime3.fen==0)
foodtime3.fen=60;
foodtime3.fen--;
displayUserSetValue(&foodtime3);
lcd_write_com(0x80+0x40+10);
lcd_write_com(0x0F);
}
else if(setn == 13)
{
if(foodtime4.shi==0)
foodtime4.shi=24;
foodtime4.shi--;
displayUserSetValue(&foodtime4);
lcd_write_com(0x80+0x40+7);
lcd_write_com(0x0f);
}
else if(setn == 14)
{
if(foodtime4.fen==0)
foodtime4.fen=60;
foodtime4.fen--;
displayUserSetValue(&foodtime4);
lcd_write_com(0x80+0x40+10);
lcd_write_com(0x0F);
}
else if(setn == 15)
{
if(foodtime5.shi==0)
foodtime5.shi=24;
foodtime5.shi--;
displayUserSetValue(&foodtime5);
lcd_write_com(0x80+0x40+7);
lcd_write_com(0x0f);
}
else if(setn == 16)
{
if(foodtime5.fen==0)
foodtime5.fen=60;
foodtime5.fen--;
displayUserSetValue(&foodtime5);
lcd_write_com(0x80+0x40+10);
lcd_write_com(0x0F);
}
}
}
if(key4 == 0) //手动开
{
delay_ms(10);
if(key4 == 0 )
{
beep = 0;
delay_ms(100);
beep = 1;
while(key4 == 0);
if(setn != 0)
{
setn = 0;
lcd_write_com(0x0c);//关闭光标
lcd_clear();
lcd_write_str(0, 0, " / / ");
lcd_write_str(0, 1, " : : ");
eepromWriteByte(); //退出设置之后,把数据保存一遍
}
else
{
Ul2003_Open();
open_flag=1;
}
}
}
if(key5 == 0) //手动关
{
delay_ms(10);
if(key5 == 0 )
{
beep = 0;
delay_ms(100);
beep = 1;
while(key5 == 0);
if(setn != 0)
{
setn = 0;
lcd_write_com(0x0c);//关闭光标
lcd_clear();
lcd_write_str(0, 0, " / / ");
lcd_write_str(0, 1, " : : ");
eepromWriteByte(); //退出设置之后,把数据保存一遍
}
else
{
Ul2003_Close();
open_flag=0;
}
}
}
}
void main()
{
lcd_init();//1602液晶初始化
eepromInit();
lcd_write_str(0, 0, "00/00/00 ");
lcd_write_str(0, 1, "00:00:00 ClOSE ");
time_init();
while(1)
{
keyscan();//按键扫描
if(setn == 0)
{
Run_DS1302(); //获取时间
if(open_flag==0)lcd_write_str(9, 1, "ClOSE");
else lcd_write_str(9, 1, "OPEN ");
/***************************************************/
/************* 喂食时间到了 ************/
/***************************************************/
if( (foodtime1.shi == hour && foodtime1.fen == min && sec == 0) ||
(foodtime2.shi == hour && foodtime2.fen == min && sec == 0) ||
(foodtime3.shi == hour && foodtime3.fen == min && sec == 0) ||
(foodtime4.shi == hour && foodtime4.fen == min && sec == 0) ||
(foodtime5.shi == hour && foodtime5.fen == min && sec == 0)
)
{
if(feeding_time==0)
{
open_flag=1; //开启喂食标志
Ul2003_Open();
}
feeding_time = 1;
}
}
delay_ms(1);
}
}
五、实验现象
演示视频: