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

📄 16x32点阵.c

📁 这是一个用AT89S52和8*8点阵做的时间显示电路
💻 C
字号:
#include<reg51.h>
#include<intrins.h>
#include<font.h>					   //字库
#include<ds1302.h>
#include<ds18b20.h>


#define uchar unsigned char
#define uint unsigned int
#define	light 180						//点阵亮度调节;视情况而定

void delayms(uint n);                   //(n)ms延时子程序
void delay();                           //显示扫描延时
void DS1302_Initial (void);             //初始化ds1302
void initTimer(void);                   //初始化定时器
void lie();                             //列控制
void send8bit(unsigned int n);          //发送字函数
void set_key(void);    	              	//SET键处理程序
void read_clockS(void);	            	//时钟数据读取
void Set_time(unsigned char sel);    	//设置时间函数
void check_shijian(void);		        //读取时间
void load_shijian(void);		     	//将待显示时间内容存至缓冲区
void check_wendu(void);		        	//读取温度
void load_wendu(void);		            //将待显示温度内容存至缓冲区
void display(void);			         	//显示子程序

sbit wendu=P3^4;						//温度显示键(长按显示温度)
sbit SET=P3^2;							//时间设定键
sbit ADD=P3^3;						    //时间调节键
sbit dat=P1^7;                          //595数据
sbit clock=P1^5;                        //595时钟信号
sbit so=P1^6;                           //595锁存信号
sbit gate1=P1^4;                        //154门控信号
uchar count,q=0;                       //标志位

uchar disbuf[64];						//显示缓冲区
uchar m,n,p,t;							//缓冲区中间量
uchar min,hour;							//定义时间映射全局变量
uchar dian1,dian2,dian3,dian4;			//用于时间闪烁的冒号

uchar set_st=0;							//调整选择标志0:正常走时;1:调时;2:调分
uchar set_key_st=0;						//设置标志,为1则调用一次SET键处理
uchar add_key_st=0;						//增加标志,为1则调用一次调时函数

uchar k=1;								//秒闪烁及选中闪烁标志
uchar x,y,z;							//时基

/**主函数**/
void main()
{   
    gate1=1;                            //关闭显示,防止花屏
	delayms(500);						//等待芯片复位,目的是稳定检测是否需要初始化
	while(SET==0)						//通电前按下SET键不放,接通电源时便初始化时间信息
	{
		DS1302_Initial();
	}

	initTimer();						//初始化定时器
	TR0=1;								//开启定时器0
	ET0=1;								//允许T0中断
	EA=1;								//开中断总开关

	IT0=1;								//开启外部中断0
	EX0=1;
	IT1=1;								//开启外部中断1
	EX1=1;
	y=0;								//系统时基清零
													   

	while(1)
	{ 
	  while(set_key_st)			    	//设置键按下
		{
			delayms(1);set_key();EX0=1;
		}
		if(set_st==1||set_st==2)		//进入调时选中状态后如果长时间无调整则自动退出
		{
			if(z>=300){set_st=0;z=0;}	
		}
		if(set_st==1||set_st==2)y=0;	//系统时基清零
		if(y<120||set_st==1||set_st==2)
		{
			check_shijian();			//读取时间信息
			while(add_key_st&&set_st>0)	//增加键按下
			{
				Set_time(set_st);EX1=1;	
			}								
				
		 }
	   	 load_shijian();	            //将待显示时间内容存至缓冲区准备显示
	     display();				        //显示

	  while(wendu==0)				    //长按显示温度
	  {
	    check_wendu();			        //读取温度信息
		load_wendu();			        //加载温度
		display();					    //显示
	    }
  	}
}

/**扫描延时(调节显示亮度)**/
void delay()/*延时子程序*/
  {
	unsigned int n;
 	for(n=0;n<light;n++);
  }

/***(n)ms延时子程序**/
void delayms(uint n)
{
	uchar i;
	while(n--)
	{
		for(i=0;i<125;i++);
	}
}

/*****初始化定时器*****/
void initTimer(void)
{
 	TMOD=0x1;							//定时器0工作方式1
    TH0=0xab;
 	TL0=0xff;							//赋初值
}

/*****定时器0中断服务程序*****/
void time0(void) interrupt 1 

{
 	TH0=0xab;
 	TL0=0xff;							//重新赋初值
 	x++;y++;z++;
	if(y>=160){y=0;}					//系统时基、工作节拍控制
	if(x>40){k=~k;x=0;}					//0.5秒k取反一次,用于秒的冒号闪烁和调时选中闪烁
    if(k==1)					        //控制秒冒号闪烁
     {dian1=dian3=0x06;dian2=dian4=0x60;}
    else 
     {dian1=dian3=0x00;dian2=dian4=0x00;}
}


/*****外部中断0服务程序*****/
void int0(void) interrupt 0	
{
	EX0=0;
	set_key_st=1;						//开启设置键标志	
}


/*****外部中断1服务程序****/
void int1(void) interrupt 2	
{
	EX1=0;
	add_key_st=1;						//开启增加键标志
} 

/****初始化DS1302*******/
void DS1302_Initial (void)
{
    DS1302_w(0x8e,0x00);				//允许写操作
	DS1302_w(0x8c,0x09);				//年  09
	DS1302_w(0x8a,0x01);				//星期一
	DS1302_w(0x88,0x02);				//月  2
	DS1302_w(0x86,0x10);				//日  16
	DS1302_w(0x84,0x00);				//小时 
	DS1302_w(0x82,0x00);				//分钟
	DS1302_w(0x80,0x00);				//秒
	DS1302_w(0x90,0xa5);				//充电	
	DS1302_w(0x8e,0x80);				//禁止写操作
 }

/*****常用时钟数据读取*****/
void read_clockS(void)
{
	hour = DS1302_r(0x85);			//读取小时数据
	min  = DS1302_r(0x83);			//读取分钟数据
/*在本电子钟中暂不需要读取以下信息,暂时屏蔽*/
//	sec  = DS1302_r(0x81);			//读取秒数据
//	day  = DS1302_r(0x87);			//读取日数据
//	month= DS1302_r(0x89);			//读取月数据
//	week = DS1302_r(0x8b);			//读取星期数据
//	year = DS1302_r(0x8d);			//读取年数据
}

/*****SET键处理程序*****/
void set_key(void)
{
	if(SET==0){set_st++;z=0;}
	if(set_st>2)set_st=0;			//调整功能标志加一
	set_key_st=0;					//关闭设置键标志
}


/*****设置时间函数*****/
void Set_time(unsigned char sel)	//引入调整选择标志
{ 
  	signed char address,item;
  	signed char max,mini;
  	if(sel==1)  {address=0x84; max=23;mini=0;}   	//小时
  	if(sel==2)  {address=0x82; max=59;mini=0;}   	//分钟
/*在本电子钟中暂不需要调整以下信息,暂时屏蔽*/
//	if(sel==3)  {address=0x80; max=0;mini=0;}    	//秒
//  if(sel==4)  {address=0x8c; max=99; mini=0;}  	//年
//  if(sel==5)  {address=0x88; max=12;mini=1;}   	//月
//  if(sel==6)  {address=0x86; max=31;mini=1;}   	//日
//  if(sel==7)  {address=0x8a; max=7;mini=1;}  		//星期  
  	item=((DS1302_r(address+1))/16)*10 + (DS1302_r(address+1))%16;//读取1302某地址上的数值转换成10进制赋给item
	if(ADD==0){item++;z=0;}	
  	if(item>max) item=mini;							//查看数值有效范围   
  	if(item<mini) item=max;           
  	DS1302_w(0x8e,0x00);							//允许写操作
  	DS1302_w(address,(item/10)*16+item%10);		    //转换成16进制写入1302
  	DS1302_w(0x8e,0x80);							//写保护,禁止写操作
	add_key_st=0;									//关闭增加键标志 
}


/*****读取时间*****/
void check_shijian(void)
{
	read_clockS();						//读取时间
	m=hour>>4;							//计算得到小时十位数字
	n=hour&0x0f;						//计算得到小时个位数字
	p=min>>4;							//计算得到分钟十位数字
	t=min&0x0f;							//计算得到分钟个位数字
}


/*****读取温度*****/
void check_wendu(void)
{
	uchar i;
	i=ReadTemperature()-5;				//获取温度值并减去DS18B20的温漂误差
	m=i/100;							//计算得到十位数字
	n=i/10-m*10;						//计算得到个位数字
	p=i-m*100-n*10;						//计算得到小数位数字
}


/****将待显示时间内容存至缓冲区****/
 void load_shijian(void)
{
	uchar a;
	if(set_st==1&&k==1)					//调时,小时位闪烁,x的取反频率为闪烁频率
	{
		for(a=0;a<16;a++){disbuf[a]=0;}
		for(a=16;a<32;a++){disbuf[a]=0;}
	}
	else
	{
		for(a=0;a<16;a++){disbuf[a]=shuzi[m*16+a];}
	    for(a=16;a<32;a++)
	    {
	      disbuf[a]=shuzi1[n*16+a-16];
	      if(a==30) disbuf[a]=dian1;
	      if(a==31)	disbuf[a]=dian2;
	    }
	}

   	if(set_st==2&&k==1)					//调分,分钟位闪烁
	{
		for(a=32;a<48;a++){disbuf[a]=0;}
		for(a=48;a<64;a++){disbuf[a]=0;}
	}
	else
	{
    	for(a=32;a<48;a++)
	   {
	      disbuf[a]=shuzi2[p*16+a-32];
	      if(a==32) disbuf[a]=dian3;
	      if(a==33)	disbuf[a]=dian4;
	   }
    	for(a=48;a<64;a++){ disbuf[a]=shuzi[t*16+a-48];}
	}
	
}

/**将待显示温度内容存至缓冲区**/
void load_wendu(void)
{
	uchar a;
	for(a=0;a<16;a++)
	{
		if(m==0)disbuf[a]=0x00;			//如果十位为0则不显示,目的在于消除前置0
		else disbuf[a]=shuzi3[m*16+a];  //加载温度十位信息
	}										
	for(a=16;a<32;a++)
	{
	  disbuf[a]=shuzi3[n*16+a-16];		//加载温度个位信息
	  if(a==31)	disbuf[a]=0x04;
	 }
	for(a=32;a<48;a++){disbuf[a]=shuzi3[p*16+a-32];}   //加载温度小数位信息
	for(a=48;a<64;a++){disbuf[a]=fuhao[a-48];}		   //加载摄氏度符号
}

/****显示函数****/
void display(void)
{	 
    unsigned char i;
   	count=0x00; 
    gate1=1;
	
    for(i=1;i<=31;i+=2)
	  {   
               			  	       
		   send8bit(i+32);         //由于使用移位寄存74hc595,先发送一列的下半部分        
		   send8bit(i-1+32);       //后发送一列的上半部分,第2个字 
               			   	
		   send8bit(i);            //由于使用移位寄存74hc595,先发送一列的下半部分        
		   send8bit(i-1);          //后发送一列的上半部分,第1个字。
 
          
	       so=0;		 
		   so=1;		           //产生上升沿锁存信号		              
	       lie();                  //一个字的上半部分和下半部分发送完毕点燃该列。
		   delay();                //调用延时子程序
		   gate1=1;                //关列显示
	  }

}


/**机内码发送子程序**/
void send8bit(unsigned int n)
 {
    for(q=0;q<8;q++)
      {
          dat=!((_cror_(disbuf[n],q))&0x01);//右移(7-q)位,从低位到高位取。即595发送,
          clock=0;                          
          clock=1;						    //寄存器时钟上跳沿,将一位数据存入移位寄存器。
		}
 }


/***列扫描***/
void lie()
{
	gate1=0;//允许列选择
	P1=count;
	count++;
	if(count==16)
	  {
	    count=0;
		count++;
	  }
}

⌨️ 快捷键说明

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