【51单片机学习笔记】基于STC89C52制作的交通信号灯

   
一、简介

    近来学(玩)了下已经好久没碰的51,心血来潮自己DIY了一个交通信号灯模型。没有什么创新之处,就是复(dao)习(gu)复(dao)习(gu)了下51的定时器中断、外部中断以及最小系统电路,熟悉了下74HC595的用法和数码管。因为好久没碰51了导致数码管的顺序记反了 懒得再改电路了,于是将错就错就按反着的顺序搞下去了。由于快考试了事情也比较多,基本是隔三差五得做,时间战线拉得比较长。。。当然这些都无关紧要了,主要还是培养下自己分文件模块化编程的习惯嘛,文件分的比较细致,看上去舒服 .

    因为是完全自己设计的嘛难免很多疏漏之处。当然由于这个电路比较简单方案和其他人雷同了也是正常现象,说明英雄所见略同嘛~ 。在此开源大家共同学习,希望各路大神能指点迷津,欢迎大家来喷~~~~


    废话不多说了。先介绍下功能:

1)为了可拓展性,我将单片机所有的引脚全部引出,后期可拓展或改做它用,每个IO引出两排排针接线更舒服。
2)为了后期如果能做其他实验不产生干扰,外围电路基本全部采用杜邦线接线,不直接接在IO上了。其中595的VCC放置了一个跳线帽作为VCC供电。
3)本人本着尽量少地用飞线地原则,能往正面跳就先跳线,但是到了2位数码管空间不算多了,也做的比较累了,就偷懒全用了飞线。
4)晶振用了12MHz插在了单片机旁。采用12MHz地原因是定时器时间好计算,没用串口不需要很精确地波特率。插在外面没焊死仅仅因为板子空间不够了,而我不像飞线。。。
5)因为东西向的灯是同步的,南北向的灯也是同步的,所以一个方向上的三色交通灯我选择了分别并联的方式,没全部并联是斟酌了下IO的驱动能力和后期的可拓展性还有一定条件下节省IO接口,故总共用了6个IO口控制交通灯,欢迎大家来喷~~~
6)本次模拟仅为理想情况,以一分钟为一周期红绿交替指示。在还剩3秒时黄灯闪烁,当然也是为了简化程序所有的黄灯一起闪。
7)通过外部中断选择工作/休息模式。休息模式下所有LED(包括数码管)同步闪烁,直到将拨盘开关拨回(有延误时间。。。)。

    想到的大概就这么多吧,详细功能不介绍了,直接上代码参考。

二、原理图


      
     元件清单:

STC89C52RC  x1
74HC595  x1
10K排阻  x1
12Mhz晶振  x1
选择开关  x1
独立按键  x1
30pF电容  x3
10K电阻  x1
1K电阻  x1
220Ω电阻  x20
红色LED  x3
黄色LED  x3
绿色LED  x3
2位数码管  x1

      
     proteus 8 仿真原理图


          【51单片机学习笔记】基于STC89C52制作的交通信号灯_第1张图片

三、部分源程序

    程序基于Keil 5 C语言编写,部分程序有注释

1.文件结构


                            【51单片机学习笔记】基于STC89C52制作的交通信号灯_第2张图片

所有头文件均放置在USER_Config.h头文件中

main.c                   主函数
it.c                         中断服务函数
delay.c                  延时函数
74HC595.c           595驱动函数
LED.c                   交通灯
SEG.c                   数码管

2.头文件

USER_Config.h
/******************************************

			USER HEARD		2017/6/4

*******************************************/

#ifndef _USERCONFIG_H_
#define _USERCONFIG_H_
/*    定义数据类型    */
#define uchar unsigned char
#define uint unsigned int
#define NOP() _nop_()
	
#include 
#include 
#include "interrupt.h"
#include "delay.h"
#include "74HC595.h"
#include "SEG.h"
#include "LED.h"


/*    宏定义引脚    */
#define SEG   P0
#define LEDs  P2
	
/*    74HC595驱动    */
sbit S_CLK  =  P1^0;
sbit R_CLK  =  P1^1;
sbit MOSIO  =  P1^2;

/*    数码管位选    */
sbit SEG1   =  P0^0;
sbit SEG2   =  P0^1;

/*    交通灯    */
sbit XR     =  P2^0;
sbit XY     =  P2^1;
sbit XG     =  P2^2;
sbit YR     =  P2^3;
sbit YY     =  P2^4;
sbit YG     =  P2^5;

/*    选择开关    */
sbit SW			=	 P3^2;

#endif

其他头文件大同小异就不贴了。

3.it.c

/******************************************

				中断服务程序
				
				by LZK    2017/6/17
				
******************************************/
#include "USER_Config.h"

uint Num_Min = 0;//分钟计数器
uchar Num_Sec = 0;//秒钟计数器
uchar Number = 60;//计数器
uchar Mark = 0;//标记

void Timer_Init()
{
	TMOD = 0x11;//定时器0定时器1为工作方式1
	/*  装载初值  */
	TH0 = (65536-50000)/256;
	TL0 = (65536-50000)%256;
	TH1 = (65536-50000)/256;
	TL1 = (65536-50000)%256;
	
	EA = 1;//开总中断
	/*  开启定时器中断  */
	ET0 = 1;//定时器0
	ET1 = 1;//定时器1
	/*  启动定时器  */
	TR0 = 1;//定时器0
	TR1 = 1;//定时器1
	/*  外部中断  */
	EX0 = 1;
	IT0 = 0;
}

void Int0_Select() interrupt 0
{
	Num_Min = 0;
	Num_Sec = 0;
	Number = 60;
	Mark = 0;
	Calculate(Number);
	LED_Relax();
}

void T0_Time() interrupt 1 
{
	/*  重装初值  */
	TH0 = (65536-50000)/256;
	TL0 = (65536-50000)%256;
	Num_Sec++;
	if(Num_Sec==20)
	{
		Num_Sec = 0;
		Number--;
		Calculate(Number);
	}
}

void T1_Time() interrupt 3
{
	
	/*  重装初值  */
	TH1 = (65536-50000)/256;
	TL1 = (65536-50000)%256;
	Num_Min++;
	if(Num_Min==60*20)
	{
		Num_Min = 0;
		Number = 60;
		Mark = ~Mark;
	}	
}

4.delay.c

/*************************************

		延时函数库	By LZK
		
		频率:12MHz


*************************************/
#include "USER_Config.h"

/*    延时x*9us    */
void delay_8us(uint x)
{							
	uint i,j;
	for(i=0;i

/*************************************

		595发送数据	By LZK
		
		频率:12MHz
		
		2017/6/5


*************************************/
#include "USER_Config.h"

void HC595SendData(uchar SendVal)
{
	unsigned char i;

	for(i=0;i<8;i++)
	{
		MOSIO=SendVal>>7;
		SendVal<<=1;

		S_CLK=0;
		NOP();
		NOP();
		S_CLK=1;

	}

	R_CLK=0;
	NOP();
	NOP();
	R_CLK=1;

}

6.LED.c

/**********************************

		LEDs Control
		
		控制交通灯
		
		by LZK    2017/6/17
		
**********************************/
#include "USER_Config.h"

extern uchar Number;
extern uchar Mark;

void LED_Init()
{
	LEDs = 0xff;
	//SW = 0;
}

void Select()
{
	uchar sw = SW;
	switch(sw)
	{
		case 0:
			LED_Relax();
		break;
		case 1:
			LED_Control();
		break;
	}
}

void LED_Relax()
{
	uint x = 10000;
	SEG = 0xff;
	LEDs = 0xff;
	while(x--)
		HC595SendData(~0x00);
	
	x = 10000;
	SEG = 0x00;
	LEDs = 0x00;
	while(x--)
		HC595SendData(~0x00);
}
	
void LED_Control()
{
	/*  黄灯判断  */
	if(Number <= 3)
	{
		XY=~XY;
		YY=~YY;
		delay(100);
	}
	else
	{
		XY = 1;
		YY = 1;
	}
	
	/*  路口选择  */
	XR =  Mark;
	XG = ~Mark;
	YR = ~Mark;
	YG =  Mark;
	
	/*  显示  */
	Display();
}

7.SEG.c
/*************************************

		数码管显数	By LZK
		
		频率:12MHz
		
		2017/6/5


*************************************/
#include "USER_Config.h"

uchar code NUM[]={0x3f,0x30,0x6d,0x79,0x72,0x5b,0x5f,0x31,0x7f,0x7b,0x77,0x7c,0x39,0x5e,0x79,0x71};
uchar value[2];

void Calculate(uint num)
{
	value[0] = num%10;
	value[1] = num/10;
}

void Display()
{
	//发送十位数
	HC595SendData(NUM[value[1]]);
	SEG = 0x01;
	delay_8us(25);
	//消隐
	HC595SendData(0x00);
	delay_8us(25);
	//发送个位数
	HC595SendData(NUM[value[0]]);
	SEG = 0x02;
	delay_8us(25);
	//消隐
	HC595SendData(0x00);
	delay_8us(25);
}

8.main.c

/*************************************************

		交通信号灯			by LZK
		
		Date:2017/6/4
		
		通过定时器0读秒,通过定时器1换方向
		通过Calculate传送数字
		
**************************************************/

#include 
#include "USER_Config.h"

extern uchar Number;

void main()
{
	
	Timer_Init();
	LED_Init();
	
	while(1)
	{
		LED_Control();
	}
}





四、成果展示

【51单片机学习笔记】基于STC89C52制作的交通信号灯_第3张图片 【51单片机学习笔记】基于STC89C52制作的交通信号灯_第4张图片 【51单片机学习笔记】基于STC89C52制作的交通信号灯_第5张图片 【51单片机学习笔记】基于STC89C52制作的交通信号灯_第6张图片

五、总结

    第一次发博客,如有不妥的地方请大家多指教


网盘分享:

链接:http://pan.baidu.com/s/1skIP6f7 密码:1eey




你可能感兴趣的:(单片机学习)