⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 51

📁 51单片机应用系统典型模块开发大全
💻
字号:
#include <reg51.h>
#include <intrins.h>

#define uchar unsigned char
#define uint  unsigned int
#define DS1302_SECOND	0x80		//秒寄存器
#define DS1302_MINUTE	0x82		//分寄存器
#define DS1302_HOUR		0x84		//小时寄存器
#define DS1302_WEEK		0x8A		//星期寄存器
#define DS1302_DAY		0x86		//日寄存器
#define DS1302_MONTH	0x88		//月寄存器
#define DS1302_YEAR		0x8C		//年寄存器
#define right           1			//正确
#define error           0			//错误

typedef struct SYSTEMTIME
{
    uchar Second;
    uchar Minute;
    uchar Hour;
    uchar Week;
    uchar Day;
    uchar Month;
    uchar Year;
    uchar DateString[9];
    uchar TimeString[9];
}SYSTEMTIME;						//定义的时间类型

sbit ACC0=ACC^0;
sbit ACC7=ACC^7;
sbit DQ=P1^0;						//DS1990A数据线引脚						
sbit SDA=P1^1;						//2402数据线引脚
sbit SCL=P1^2;						//2402时钟线引脚
sbit DS1302_RST=P1^3;				//DS1302复位线引脚
sbit DS1302_CLK=P1^4;				//DS1302时钟线引脚
sbit DS1302_IO=P1^5;				//DS1302数据线引脚
sbit din=P2^0;						//MAX7221数据线引脚
sbit load=P2^1;						//MAX7221控制线引脚
sbit clk=P2^2;						//MAX7221时钟线引脚
sbit Lock=P2^3;						//电子锁控制线引脚

uchar code CrcTable[256]={
    0,94,188,226,97,63,221,131,194,156,126,32,163,253,31,65,
    157,195,33,127,252,162,64,30,95,1,227,189,62,96,130,220,
    35,125,159,193,66,28,254,160,225,191,93,3,128,222,60,98,
    190,224,2,92,223,129,99,61,124,34,192,158,29,67,161,255,
    70,24,250,164,39,121,155,197,132,218,56,102,229,187,89,7,
    219,133,103,57,186,228,6,88,25,71,165,251,120,38,196,154,
    101,59,217,135,4,90,184,230,167,249,27,69,198,152,122,36,
    248,166,68,26,153,199,37,123,58,100,134,216,91,5,231,185,
    140,210,48,110,237,179,81,15,78,16,242,172,47,113,147,205,
    17,79,173,243,112,46,204,146,211,141,111,49,178,236,14,80,
    175,241,19,77,206,144,114,44,109,51,209,143,12,82,176,238,
    50,108,142,208,83,13,239,177,240,174,76,18,145,207,45,115,
    202,148,118,40,171,245,23,73,8,86,180,234,105,55,213,139,
    87,9,235,181,54,104,138,212,149,203,41,119,244,170,72,22,
    233,183,85,11,136,214,52,106,43,117,151,201,74,20,246,168,
    116,42,200,150,21,75,169,247,182,232,10,84,215,137,107,53
};									//校验码查询表

uchar code ID[]={
    0x01,0x2c,0xc5,0xb8,
    0x00,0x00,0x00,0x8b};			//默认访问者身份ID

uchar code dispcode[]={	
	0x7e,0x30,0x6d,0x79,
	0x33,0x5b,0x5f,0x70,
	0x7f,0x7b,0x77,0x1f,
	0x4e,0x3d,0x4f,0x47};			//共阴极显示代码
	
bit flag=0;
uchar CRCbyte,num=200,da_ad=0x00;	//CRC校验码,2402存储地址
uchar SN[8],time[6];
uchar buf[]={0,0,0,0,0,0,0,0};
SYSTEMTIME time1;

/******************函数声明*******************/
void Init_DS1302(void);				//DS1302初始化
void Init_DS1990(void);				//DS1990初始化
void Init_T0(void);					//定时器T0初始化
void DS1302InputByte(uchar d);		//DS1302
void Write_1302(uchar ucAddr, uchar ucDa);//DS1302写数据
void DS1302_SetProtect(bit flag);	//DS1302写保护设定
void DS1302_SetTime(uchar Address, uchar Value);//DS1302设置时间函数
void DS1302_GetTime(SYSTEMTIME *Time);//DS1302时间转换函数
void DS1302_time(void);				//DS1302时间显示函数
void Init_MAX7221(void);			//MAX7221初始化
void Write_7221(uchar com,uchar da);//MAX7221写字节程序
void Delay(uint i);					//延时函数
void Writebyte(uchar dat);			//向DS1990A写一个字节函数
void Record(void);					//记录访问时间
void Start_bit(void);				//I2C起始函数
void Stop_bit(void);				//I2C停止函数
bit Compare(void);					//验证身份函数
bit Read1990(void);					//读身份信息函数
bit Write_8bit(uchar ch);			//I2C总线写8位数据函数
uchar DS1302OutputByte(void);		//DS1302读一个字节
uchar Read1302(uchar ucAddr);		//DS1302读数据
uchar CRC(uchar j);					//DS1990A校验位计算函数
uchar Readbyte(void);				//从DS1990A读一个字节函数
uchar Page_wr(uchar firstw_ad,uchar counter,uchar *firstr_ad);//I2C总线页面写函数
/******************主函数*******************/
void main()
{
	uchar i;
	Init_MAX7221();
	Init_DS1302();
	Init_T0();
	P2=0;
	while (1)
    {
		if(Compare()==1)			//身份验证一致
		{
			Lock=1;					//闭合继电器	
			TR0=1;					//定时器T0启动
			Record();				//记录访问时间
			for(i=1;i<9;i++)
			{
				Write_7221(i,0x01);
			}
			if(da_ad==248)
				da_ad=0;			//判断存储内容是否已经满
			else
				da_ad+=8;			//修改2402存储地址
			while(Compare());
		}
		else 
		{
			DS1302_time();			//显示当前时间			
		}
    }
}
/**************T0定时器初始化******************/
void Init_T0(void)
{
	TMOD=0x01;						//工作方式1
	TH0=(65536-50000)/256;			//定时时间为0.5ms
	TL0=(65536-50000)%256;
	EA=1;							//开总中断
	ET0=1;							//允许定时器T0中断
}
/**************T0定时器服务程序******************/
void timer0(void) interrupt 1
{
	TH0=(65536-50000)/256;			//重载初值
	TL0=(65536-50000)%256;
	num--;
	if(num==0)						//5秒定时到
	{
		TR0=0;						//关定时器T0		
		num=200;					//重载时间计数器
		Lock=0;						//断开继电器
	}
}
/**************DS1302一个写字节******************/
void DS1302InputByte(uchar d)		//实时时钟写入一字节(内部函数)
{
    uchar i;
    ACC=d;
    for (i=8;i>0;i--)
    {
        DS1302_IO=ACC0;				//相当于汇编中的 RRC
        DS1302_CLK=1;
        DS1302_CLK=0;				//发一个高跳变到低的脉冲
        ACC=ACC>>1;
    }
}
/**************DS1302读一个字节******************/
uchar DS1302OutputByte(void)		//实时时钟读取一字节(内部函数)
{
    uchar i;
    for (i=8;i>0;i--)
    {
        ACC=ACC>>1;					//相当于汇编中的 RRC
        ACC7=DS1302_IO;
        DS1302_CLK=1;
        DS1302_CLK=0;				//发一个高跳变到低的脉冲
    }
    return(ACC);
}
/****************DS1302写数据********************/
void Write_1302(uchar ucAddr, uchar ucDa)
{
    DS1302_RST=0;
    DS1302_CLK=0;
    DS1302_RST=1;
    DS1302InputByte(ucAddr);		//地址,命令
    DS1302InputByte(ucDa);			//写1Byte数据
    DS1302_CLK=1;
    DS1302_RST=0;
}
/****************DS1302读数据********************/
uchar Read1302(uchar ucAddr)		//读取DS1302某地址的数据
{
    uchar ucData;
    DS1302_RST=0;
    DS1302_CLK=0;
    DS1302_RST=1;					//enable
    DS1302InputByte(ucAddr|0x01);	//地址,命令
    ucData=DS1302OutputByte();		//读1Byte数据
    DS1302_CLK=1;
    DS1302_RST=0;
    return(ucData);
}
/**************DS1302写保护设定******************/
void DS1302_SetProtect(bit flag)	//是否写保护
{
    if (flag)
        Write_1302(0x8E,0x10); 		//WP=1,不能写入
    else
        Write_1302(0x8E,0x00);		//WP=0,可以写入
}
/**************DS1302设置时间函数****************/
void DS1302_SetTime(uchar Address, uchar Value)	
{
    DS1302_SetProtect(0);
    Write_1302(Address, ((Value/10)<<4|(Value%10)));//高4位为十位,低4位为个位
}
/*****************DS1302初始化******************/
void Init_DS1302(void)
{
    uchar Second=Read1302(DS1302_SECOND);
    if (Second&0x80)				//如果第七为1(表明没有启动), 则启动时钟
        DS1302_SetTime(DS1302_SECOND,0);
}
/**************DS1302时间转换函数***************/
void DS1302_GetTime(SYSTEMTIME *Time)
{
    uchar ReadValue;
    ReadValue=Read1302(DS1302_SECOND);
    Time->Second=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);	//转换秒
    ReadValue=Read1302(DS1302_MINUTE);
    Time->Minute=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);	//转换分
    ReadValue=Read1302(DS1302_HOUR);
    Time->Hour=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);	//转换时
    ReadValue=Read1302(DS1302_DAY);
    Time->Day=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);	//转换日
    ReadValue=Read1302(DS1302_WEEK);
    Time->Week=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);	//转换星期
    ReadValue=Read1302(DS1302_MONTH);
    Time->Month=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);	//转换月
    ReadValue=Read1302(DS1302_YEAR);
    Time->Year=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);	//转换年
}
/*****************MAX7221初始化***************/
void Init_MAX7221(void)
{
    Write_7221(0x0c,0x01);			//正常工作状态,关断模式
	Write_7221(0x09,0x00);			//译码选择,非BCD码
	Write_7221(0x0a,0x0f);			//亮度调节
	Write_7221(0x0b,0x07);			//显示位数
}
/**************MAX7221写字节程序*************/
void Write_7221(uchar com,uchar da)
{
    uchar temp,i,j;
    load=0;
    clk=0;
    for (i=0;i<8;i++)				//发送命令
    {
        temp=com;
        if ((temp&(0x80>>i))!=0)
            din=1;
        else din=0;
        clk=1;
        for (j=0;j<5;j++);
        clk=0;
    }
    for (i=0;i<8;i++)				//发送数据
    {
        temp=da;
        if ((temp&(0x80>>i))!=0)
            din=1;
        else din=0;
        clk=1;
        for (j=0;j<5;j++);
        clk=0;
    }
    load=1;
}
/**************时间显示函数*******************/
void DS1302_time(void)
{
	DS1302_GetTime(&time1);			//获取当前时间
	buf[7]=(time1.Second)%10;
	buf[6]=(time1.Second)/10;
	buf[4]=(time1.Minute)%10;
	buf[3]=(time1.Minute)/10;
	buf[1]=(time1.Hour)%10;
	buf[0]=(time1.Hour)/10;
	Write_7221(0x08,dispcode[buf[7]]);
	Write_7221(0x07,dispcode[buf[6]]);
	Write_7221(0x06,0x01);
	Write_7221(0x05,dispcode[buf[4]]);
	Write_7221(0x04,dispcode[buf[3]]);
	Write_7221(0x03,0x01);
	Write_7221(0x02,dispcode[buf[1]]);
	Write_7221(0x01,dispcode[buf[0]]);
}
/**************I2C起始函数*******************/
void Start_bit(void)
{
    SCL=1;_nop_();
    SDA=1;_nop_();
    SDA=0;_nop_();
    SCL=0;_nop_();
}
/***************I2C停止函数******************/
void Stop_bit(void)
{
    SDA=0;_nop_();
    SCL=1;_nop_();
    SDA=1;_nop_();
}
/***********I2C总线写8位数据函数*************/
bit Write_8bit(uchar ch)
{
    uchar i=8;
    bit fan_w;
    SCL=0;_nop_();
    while (i--)
    {
        SDA=(bit)(ch&0x80);_nop_();
        ch<<=1;
        SCL=1;_nop_();
        SCL=0;_nop_();
    }
    SDA=1;_nop_();
    SCL=1;_nop_();
    fan_w=SDA;
    SCL=0;_nop_();
    return(fan_w);
}
/************I2C总线页面写函数**************/
uchar Page_wr(uchar firstw_ad,uchar counter,uchar *firstr_ad)
{
    uchar *ufirstr_ad;
    ufirstr_ad=firstr_ad;
    Start_bit();						//启动I2C
    if (Write_8bit(0xA0)!=0)			//发送2402器件地址
    {
        Stop_bit();						//无应答,返回
        return(0);
    }
    if (Write_8bit(firstw_ad)!=0)		//写入数据的存储地址
    {
        Stop_bit();						//无应答,返回
        return(0);
    }
    while (counter--)					//写入数据
    {
        if (Write_8bit(*ufirstr_ad)!=0)	//无应答,返回
        {
            Stop_bit();
            return(0);
        }
        ufirstr_ad++;					//准备下一数据
    }
    Stop_bit();
    return(1);							//写数据成功
}
/*****************延时函数******************/
void Delay(uint i)
{
    while (i--);
}
/***********DS1990A校验位计算函数***********/
uchar CRC(uchar j)
{
    uchar i,crc_data=0;
    for (i=0;i<j;i++)					//查表校验
        crc_data=CrcTable[crc_data^SN[i]];
    return(crc_data);
}
/*************DS1990A初始化函数*************/
void Init_DS1990(void)
{
    uchar i,x=0;
    DQ=0;								//置低
    Delay(60);							//延时480us
    DQ=1;								//释放
    Delay(10);							//延时85us
    for (i=0;i<10;i++)
    {
        if (DQ==0)						//如果拉低
        {
            flag=1;
            break;
        }
    }
    Delay(20);
}
/***********从DS1990A读一个字节函数*********/
uchar Readbyte(void)
{
    uchar i=0;
    uchar temp=0;
    for (i=0;i<8;i++)
    {
        DQ=0;
        temp>>=1;
        DQ=1;
        _nop_();
        if (DQ)temp|=0x80;
        Delay(8);
    }
    return(temp);
}
/**********向DS1990A写一个字节函数**********/
void Writebyte(uchar dat)
{
    uchar i=0,send;
    for (i=0;i<8;i++)
    {
        DQ=0;
        send=dat&0x01;
        if (send==0x01)
        {
            DQ=1;
            Delay(15);
        }
        else
        {
            Delay(15);
            DQ=1;
        }
        dat>>=1;
    }
    Delay(8);
}
/*************读身份信息函数****************/
bit Read1990(void)
{
    uchar i;
	Init_DS1990();
    if (flag==1)
    {
        while (DQ==0);
        flag=0;
        Writebyte(0x33);
        for (i=0;i<8;i++)
			SN[i]=Readbyte();
        CRCbyte=CRC(7);
        if (CRCbyte==SN[7])
		{
			return(right);	
		}
        else
			return(error);
    }
	else
		return(error);
}
/****************验证身份函数***************/
bit Compare(void)
{
    uchar i;
	if (Read1990()==1)						//若身份验证正确返回1,错误返回0
    {
		for (i=0;i<8;i++)
        {
			if (SN[i]!=ID[i])return(error);
		}
		return(right);
	}
	else
		return(error);
}
/****************记录访问时间***************/
void Record(void)
{
	DS1302_GetTime(&time1);					//获取访问时间
	time[0]=time1.Second;					//将访问时间信息存入缓冲区
	time[1]=time1.Minute;
	time[2]=time1.Hour;
	time[3]=time1.Day;
	time[4]=time1.Month;
	time[5]=time1.Year;
	while(Page_wr(da_ad,6,time)==0);		//等待写入成功
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -