使用的74hc573驱动数码管
仿真图片:
整个程序的代码:
#include <reg52.h>
#include "stdio.h"//标准输入输出
#include "intrins.h"//函数,使用空指令用到,字符循环移位
#include <math.h>//数学运算
#define uchar unsigned char
#define uint unsigned int
#define DB P0//液晶并行数据接口
#define normal_mode 0x10//显示模式
#define set_mode 0x20//设置模式
sbit hw_dx=P3^5; //使用此引脚接红外探头检测"东西"方向通过的车辆,该引脚会呈现低电平
sbit hw_nb=P3^6; //使用此引脚接红外探头检测"南北"方向通过的车辆,该引脚会呈现低电平
sbit dula=P2^1;//段选信号
sbit wela=P2^0;//位选信号
sbit RS = P1^6;//液晶指令数据信号
sbit E=P1^7;//液晶使能信号
sbit T_IO=P3^3; //clk为DS1302的I/O数据线
sbit T_CLK=P3^2; //DAT为DS1302的时钟信号线
sbit T_RST=P3^4; //RST为DS1302的RST信号线
sbit Data=P3^1; //温湿度IO
sbit dxred=P2^7;//东西方向红灯
sbit dxyellow=P2^6;//东西方向黄灯
sbit dxgreen=P2^5;//东西方向绿灯
sbit nbred=P2^4;//南北方向红灯
sbit nbyellow=P2^3;//南北方向黄灯
sbit nbgreen=P2^2;//南北方向绿灯
sbit key_jinzhi=P1^0;//禁止按键
sbit key_zeng=P1^4;//增按键
sbit key_jian=P1^5;//减按键
sbit key_night=P1^1;//晚上按键
sbit key_dxgreen_nbred=P1^2;//东西绿灯南北红灯
sbit key_dxred_nbgreen=P1^3;//东西红灯南北绿灯
sbit buzzer=P3^0;//蜂鸣器
uchar data set_time=10; //设置方向的时间
uchar data num_che_dx=0; //设置变量用于记录东西通行车量的个数
uchar data num_che_nb=0; //设置变量用于记录南北通行车辆的个数
uchar bdata datbyte;
sbit datbyte0=datbyte^0;
sbit datbyte7=datbyte^7;
uchar time_1302[7]={0x00,0x00,0x00,0x03,0x07,0x03,0x08};//设置时间初始值数组
// 秒 分 时 号 月份 星期 年
//DS1302函数声明
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
void chushi();//红路灯初始化
void display_led();//红绿灯显示
void get_1302(uchar time[]);//获取时间
void write_ds1302(uchar dat);//写入字节
uchar r_1302(uchar add);//读取数据
void w_1302(uchar add,uchar dat);//指定位置写入
uchar read_ds1302(void);//
void init_1302(uchar *time);//1302初始化
void change();//1302数值转换
uchar times[9];//保存时间
uchar date[11];//保存日期
unsigned char key_value;//获取到按键的值
signed char humi_value;//湿度
signed char temp_value;//温度
unsigned char now_window;//当前显示窗口
unsigned char curr_menu;
void delay(uint);//延时
void display(uchar);//数码管显示
uchar num,num1,shi,ge;//数码管十位和个位显示数据
int s=0,n,a,b,c,d,e;//a是总时间增减的基数,b是东西南北一方增或减的基数,c是东西方向增减数,d是南北方向增减数
void delay(uint xms)//延迟x毫秒
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
void hw_dongxi()//东西红外探头
{
if(hw_dx==0) //东西红外探头
{
delay(10); //调用显示,用于延时消抖和按键检测方法基本相同
if(hw_dx==0) //如果确定有车辆经过
{
if(dxgreen==0) //东西通行的时间
{
num_che_dx++ ; //用于记录东西绿灯时经过的车辆数
}
else
{
buzzer=1; //蜂鸣器开
delay(1000);
}
while(!hw_dx); //等待释放
}
}
}
void hw_nanbei()//南北红外探头
{
if(hw_nb==0) //南北红外探头
{
delay(10); //调用显示,用于延时消抖和按键检测方法基本相同
if(hw_nb==0) //如果确定有车辆经过
{
if(nbgreen==0) //东西通行的时间
{
num_che_nb++; //用于记录南北绿灯时经过的车辆数
}
else
{
buzzer=1; //蜂鸣器开
delay(1000);
}
while(!hw_nb); //等待释放
}
}
}
void dxhong_nblv()//东西红灯,南北绿灯
{
dxred=0;
dxyellow=1;
dxgreen=1;
nbred=1;
nbyellow=1;
nbgreen=0;
}
void dxhuang_nblv()//东西黄灯,南北绿灯
{
dxred=1;
dxyellow=0;
dxgreen=1;
nbred=1;
nbyellow=1;
nbgreen=0;
}
void dxlv_nbhong()//东西绿灯,南北红灯
{
dxred=1;
dxyellow=1;
dxgreen=0;
nbred=0;
nbyellow=1;
nbgreen=1;
}
void dxlv_nbhuang()//东西绿灯,南北黄灯
{
dxred=1;
dxyellow=1;
dxgreen=0;
nbred=1;
nbyellow=0;
nbgreen=1;
}
void led_panduan()//led显示判断
{
if(s==60+d)//一次普通循环
{
s=0;
}
if(s==61+d)//晚上时的显示
{
dxred=1;
dxyellow=0;
dxgreen=1;
nbred=1;
nbyellow=0;
nbgreen=1;
}
if(s==62+d)//东西绿灯南北红灯的显示
{
dxlv_nbhong();
}
if(s==63+d)//东西红灯南北绿灯的显示
{
dxhong_nblv();
}
if(s==64+d)//禁止时led的显示
{
dxred=0;
dxyellow=1;
dxgreen=1;
nbred=0;
nbyellow=1;
nbgreen=1;
}
}
void panduan_hw_nb()//南北红外探头判断
{
hw_nanbei();
if(s==0)
{
if(num_che_nb==0) //如果南北方向无车辆通行,表示正常情况
b=b;
else if(num_che_nb<set_time/2) //如果南北方向小于设定值,通行时间减少
{
TR1=0;
TR0=0;
b=b-5;
c=b;
s=0;
num=15+c+a;
num_che_nb=0;
TR1=1;
TR0=1;
if(b==0)
{
b=15;
}
}
else //如果此时南北通行的车辆数大于预设通行量,通行时间增加
{
TR1=0;
TR0=0;
b=b+5;
c=b;
s=0;
num=15+c+a;
num_che_nb=0;
TR1=1;
TR0=1;
if(b==35)
{
b=15;
}
}
}
}
void panduan_hw_dx()//东西红外探头判断
{
hw_dongxi();
if(s==15+c+a)
{
if(num_che_dx==0) //如果东西方向无车辆通行,表示是正常通行量
b=b;
else if(num_che_dx<set_time/2) //如果东西方向小于设定值,通行时间减少
{
TR1=0;
TR0=0;
b=b+5;
c=b;
s=15+c+a;
num=45+d-c-a;
num_che_nb=0;
TR1=1;
TR0=1;
if(b==35)
{
b=15;
}
}
else //如果此时东西通行的车辆数大于预设通行量,通行时间增加
{
TR1=0;
TR0=0;
b=b-5;
c=b;
s=15+c+a;
num=45+d-c-a;
num_che_dx=0;
TR1=1;
TR0=1;
if(b==0)
{
b=15;
}
}
}
}
void panduan_hw()//红外探头判断函数
{
panduan_hw_dx();//东西方向
panduan_hw_nb();//南北方向
}
void key_z()//按键增
{
if(key_zeng==0)
{
delay(10);
if(key_zeng==0)
{
TR1=0;
TR0=0;
a=a+5;
if(a==35)
{
a=0;
}
d=a*2;
s=0;
num=15+c+a;
while(!key_zeng);
TR1=1;
TR0=1;
}
}
}
void key_j()//按键减
{
if(key_jian==0)
{
delay(10);
if(key_jian==0)
{
TR1=0;
TR0=0;
a=a-5;
if(a==-20)
{
a=0;
}
d=a*2;
s=0;
num=15+c+a;
while(!key_jian);
TR1=1;
TR0=1;
}
}
}
void key_n()//按键晚上
{
if(key_night==0)
{
delay(10);
if(key_night==0)
{
TR1=0;
TR0=0;
s=61+d;
e=99;
while(!key_night);
}
}
}
void key_jz()//按键禁止
{
if(key_jinzhi==0)
{
delay(10);
if(key_jinzhi==0)
{
TR1=0;
TR0=0;
s=64+d;
e=99;
while(!key_jinzhi);
}
}
}
void key_nbgreen()//按键东西红灯南北绿灯
{
if(key_dxred_nbgreen==0)
{
delay(10);
if(key_dxred_nbgreen==0)
{
TR1=0;
TR0=0;
s=63+d;
e=99;
while(!key_dxred_nbgreen);
}
}
}
void key_dxgreen()//按键东西绿灯南北红灯
{
if(key_dxgreen_nbred==0)
{
TR1=0;
TR0=0;
s=62+d;
e=99;
while(key_dxgreen_nbred);
}
}
void key()//按键函数,按下按键跳转至函数
{
key_z();
key_j();
key_n();
key_jz();
key_nbgreen();
key_dxgreen();
}
void display_led()//红路灯显示
{
if(s<10+c+a)
dxhong_nblv();
else if(s<15+c+a)
dxhuang_nblv();
else if(s<55+d)
dxlv_nbhong();
else if(s<60+d)
dxlv_nbhuang();
else
led_panduan();
}
/*******************************************************************************
* 函 数 名 : LcdWriteCom
* 函数功能 : 向LCD写入一个字节的命令
* 输 入 : u8com
* 输 出 : 无
*******************************************************************************/
void lcd_wri_com(unsigned char com) //写入命令
{
E = 0; //使能清零
RS = 0; //选择写入命令
dula=0;
dula=1;
DB = com;
dula=0;
delay(5);
E = 1; //写入时序
delay(5);
E = 0;
}
/*******************************************************************************
* 函 数 名 : LcdWriteData
* 函数功能 : 向LCD写入一个字节的数据
* 输 入 : u8dat
* 输 出 : 无
*******************************************************************************/
void lcd_wri_data(unsigned char dat)//写入数据
{
E = 0; //使能清零
RS = 1; //选择写入数据
dula=0;
dula=1;
DB = dat;
dula=0;
delay(5);
E = 1; //写入时序
delay(5);
E = 0;
}
/*******************************************************************************
* 函 数 名 : WriString
* 函数功能 : 刷新屏幕显示
* 输 入 : hang,add,*p
* 输 出 : 无
*******************************************************************************/
void wri_string(unsigned char y,unsigned char x,unsigned char *p)
{
if(y==1)//如果选择第一行
lcd_wri_com(0x80+x);//选中地址
else
lcd_wri_com(0xc0+x);//选中地址
while(*p)
{
lcd_wri_data(*p);//写入数据
p++;
}
}
/*******************************************************************************
* 函 数 名 : lcd_write_char
* 函数功能 :
* 输 入 :
* 输 出 : 无
*******************************************************************************/
void lcd_write_char(unsigned char y, unsigned char x, unsigned char dat) //列x=0~15,行y=0,1
{
unsigned char temp_l, temp_h;
if(y==1)//如果选择第一行
lcd_wri_com(0x80+x);//选中地址
else
lcd_wri_com(0xc0+x);//选中地址
temp_l = dat % 10;
temp_h = dat / 10;
lcd_wri_data(temp_h + 0x30); //convert to ascii
lcd_wri_data(temp_l + 0x30);
}
/*********************光标控制***********************/
void lcd1602_guanbiao(unsigned char y, unsigned char x,unsigned char on_off)
{
if(on_off == 1) //开光标
{
if(y==1)//如果选择第一行
lcd_wri_com(0x80+x);
else
lcd_wri_com(0xc0+x);//将光标移动到秒个位
lcd_wri_com(0x0f);//显示光标并且闪烁
}
else
{
if(y==1)//如果选择第一行
lcd_wri_com(0x80+x);
else
lcd_wri_com(0xc0+x);//将光标移动到秒个位
lcd_wri_com(0x0c); //关光标
}
}
/*******************************************************************************
* 函 数 名 : LcdInit()
* 函数功能 : 初始化LCD屏
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void lcd_init(void) //LCD初始化子程序
{
lcd_wri_com(0x38);//置功能8位双行
lcd_wri_com(0x0c);//显示开关光标
lcd_wri_com(0x06);//字符进入模式屏幕不动字符后移
delay(5);//延时5ms
lcd_wri_com(0x01); //清屏
wri_string(1,0,times);//初始化显示
wri_string(1,6,date);
wri_string(2,0,"H: %RH T: C ");//初始化显示
}
void DHT11_delay_us(unsigned char n)
{
while(--n);
}
void DHT11_delay_ms(unsigned int z)
{
unsigned int i,j;
for(i=z;i>0;i--)
for(j=110;j>0;j--);
}
void DHT11_start()
{
Data=1;
DHT11_delay_us(2);
Data=0;
DHT11_delay_ms(30); //延时18ms以上
Data=1;
DHT11_delay_us(30);
}
unsigned char DHT11_rec_byte() //接收一个字节
{
unsigned char i,dat=0;
for(i=0;i<8;i++) //从高到低依次接收8位数据
{
while(!Data); ////等待50us低电平过去
DHT11_delay_us(8); //延时60us,如果还为高则数据为1,否则为0
dat<<=1; //移位使正确接收8位数据,数据为0时直接移位
if(Data==1) //数据为1时,使dat加1来接收数据1
dat+=1;
while(Data); //等待数据线拉低
}
return dat;
}
void DHT11_receive() //接收40位的数据
{
unsigned char R_H,R_L,T_H,T_L,RH,RL,TH,TL,revise;
DHT11_start();
if(Data==0)
{
while(Data==0); //等待拉高
DHT11_delay_us(40); //拉高后延时80us
R_H=DHT11_rec_byte(); //接收湿度高八位
R_L=DHT11_rec_byte(); //接收湿度低八位
T_H=DHT11_rec_byte(); //接收温度高八位
T_L=DHT11_rec_byte(); //接收温度低八位
revise=DHT11_rec_byte(); //接收校正位
DHT11_delay_us(25); //结束
if((R_H+R_L+T_H+T_L)==revise) //校正
{
RH=R_H;
RL=R_L;
TH=T_H;
TL=T_L;
}
humi_value = RH;
temp_value = TH;
}
}
/******************************************************
** 函数名:init_all_hardware
** 描述 :初始化所有硬件,及其变量参数。
** 输入 :无
** 输出 :无
** 调用 :主程序
******************************************************/
void init_all_hardware(void)
{
lcd_init();
lcd_write_char(2,2,humi_value);
lcd_write_char(2,11,temp_value);
lcd_wri_com(0xcd);
lcd_wri_data(0xdf);
key_value = 20;
now_window = normal_mode;
curr_menu = 0;
}
void display(uchar numdis)
{
shi=numdis/10;//把num的除数给十位
ge=numdis%10;//把num的余数给各位
wela=1;//打开位选
P0=0xaa;//选择数码管的第一个
wela=0;
dula=1;//段选打开
P0=table[shi];
dula=0;
P0=0xff;//消影
delay(7);
wela=1;
P0=0x55;//选择数码管第二个
wela=0;
dula=1;
P0=table[ge];
dula=0;
P0=0xff;
delay(7);
}
void main()//主函数
{
TMOD=0x11;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TH1=(65536-50000)/256;
TL1=(65536-50000)%256;
EA=1;
ET0=1;
TR0=1;
ET1=1;
TR1=1;
b=15;
c=15;
a=0;
d=0;
num=15+c+a;
buzzer=0;
get_1302(time_1302);//获取时间
change(); //时间转换
init_all_hardware();//初始化硬件,
while(1)
{
key();//判断按键是否被按下
panduan_hw();//判断车流量
display_led(); //红绿灯显示
display(e);//数码管显示
get_1302(time_1302);//获取时间
change(); //时间转换
}
}
//DS1302相关函数
/*==========================================
D S 1 3 0 2 初 始 化
===========================================*/
void init_1302(uchar *time)
{uchar i, add;
//uchar time_bcd[7];
add=0x80;//0写入,1读出
w_1302(0x8e,0x00);
for(i=0;i<7;i++)
{w_1302(add,*time);
add+=2;
time++;
}
w_1302(0x8e,0x80);
}
//===========================
// 读取当前时间
//===========================
void get_1302(uchar time[])
{uchar i;
uchar add=0x81;
w_1302(0x8e,0x00);
for(i=0;i<7;i++)
{
time[i]=r_1302(add);
add+=2;
}
w_1302(0x8e,0x80);
}
/*=================================
DS1302写入一个字节(上升沿有效)
=================================*/
void write_ds1302(uchar dat)
{uchar i;
datbyte=dat;
for(i=0;i<8;i++)
{T_IO=datbyte0;
T_CLK=1;
T_CLK=0;
datbyte=datbyte>>1;
}
}
/*=======================================
DS1302读取一个字节(下降沿有效)
=======================================*/
uchar read_ds1302(void)
{uchar i;
for(i=0;i<8;i++)
{datbyte=datbyte>>1;
datbyte7=T_IO;
T_CLK=1;
T_CLK=0;
}
return(datbyte);
}
/*=========================================
指定位置读取数据
=========================================*/
uchar r_1302(uchar add)
{uchar temp,dat1,dat2;
T_RST=0;
T_CLK=0;
T_RST=1;
write_ds1302(add);
temp=read_ds1302();
T_CLK=1;
T_RST=0;
dat1=temp/16;
dat2=temp%16;
temp=dat1*10+dat2;
return(temp);
}
/*==========================================
指定位置写入数据
==========================================*/
void w_1302(uchar add,uchar dat)
{
T_RST=0;
T_CLK=0;
T_RST=1;
write_ds1302(add);
write_ds1302(dat/10<<4|dat%10);
T_CLK=1;
T_RST=0;
}
//DS1302数值转换
void change()
{
// 时 间 的 转 换
times[0]=time_1302[2]/10+'0';
times[1]=time_1302[2]%10+'0';
times[2]=':';
times[3]=time_1302[1]/10+'0';
times[4]=time_1302[1]%10+'0';
// times[5]=':';
// times[6]=time_1302[0]/10+'0';
// times[7]=time_1302[0]%10+'0';
times[5]='\0';
// 日 期 的 转 换
date[0]='2';
date[1]='0';
date[2]=time_1302[6]/10+'0';
date[3]=time_1302[6]%10+'0';
date[4]='/';
date[5]=time_1302[4]/10+'0';
date[6]=time_1302[4]%10+'0';
date[7]='/';
date[8]=time_1302[3]/10+'0';
date[9]=time_1302[3]%10+'0';
date[10]='\0';
}
void T0_time() interrupt 1//定时器0
{
TH0=(65536-50000)/256; //0.05s=50ms
TL0=(65536-50000)%256;
n++;
if(n==20)
{n=0;
s++;
}
}
void T1_time() interrupt 3//定时器1
{
TH1=(65536-50000)/256;//重装初值
TL1=(65536-50000)%256;
num1++;
if(num1==20)//50x20=1s,到了20次说明1s到了
{
num1=0;//把num1清零,重新计数20次
num--;//每一秒num减一
if(num==0)//num到达0s
if(s==15+c+a)
num=45+d-c-a;
else
num=15+c+a;//num重新计数
e=num;
}
}