一、实现功能
本设计主要是介绍了单片机控制下的交通灯控制系统,详细介绍了其硬件和软件设计,并对其各功能模块做了详细介绍,其主要功能和指标如下:
东西、南北两干道交于十字路口,各干道有一组红、绿、黄三个指示灯,指挥车辆和行人安全通行。南北方向为主干道,通行时间为9秒;东西方向为支干道,通行时间为15秒。通行时间最后2秒,绿灯灭,黄灯常亮,黄灯亮完变更通行车道。通行时间由数字显示器显示。
紧急情况:按下紧急模式按键,所有方向亮红灯,数码管显示00,再按一次按键退出紧急情况。
开机上电便处于正常运行状态,南北方向通行9秒后变为东西方向通行12秒,如此循环一次,使得东西方向和南北方向交替通行。 显示系统则显示到下一次改变通行方向所剩的时间,利于司机调整车辆状况。每到通行方向转换时,正在通行的方向绿灯熄灭,变为黄灯常亮,提醒司机注意通行方向的改变,避免不必要的危险。
延时方法可以有两种,一种是利用内部定时器才生溢出中断来确定1秒的时间,另一种是采用软延时的方法。本程序的倒计时采用软件延时。
二、主要原件介绍
1、主控制器选择
主控芯片采用STM32F103C6单片机,STM32F103C6是STM32系列单片机的典型产品,STM32单片机有很多个系列,其中包括基本型、USB基本型、增强型以及互联型几大系列,这写系列的STM32单片机都是具有性能高、功耗低、成本低等特点。
这是是一款ARM M3内核的增强型微控制器,这款内核的工作频率是能够达到72MHz的,它拥有着128K字节的闪存和极其丰富的外设,如GPIO口,串口,定时器,中断,数模转换,实时时钟,看门狗,SPI,IIC,CAN总线等部分组成。STM32F103系列单片机的性能在同一个类别的产品中是最高的,它能够在-40°C -85°C温度下正常地进行工作,工作的电压范围为2V-3.6V,具有低功耗的节能工作模式,闪存存储器的容量为64K字节。
电源电路:电源由USB接口提供5V直流电。
复位电路:按键SW1接入高电平到STM32内部NRST引脚,NRST上脉冲只要持续大于300ns的即可触发单片机复位。
晶振电路:外接8M晶振,通过倍频产生最高72MHz工作频率。
下载电路:选用SWD下载电路,只需要引出SWDIO、SWCLK、VCC3.3V、GND,在MDK下载选项中选择SWD即可下载程序到单片机上。
2、指示灯及倒计时模块
设计电路中每个路口的控制信号灯应有三个,即红灯、黄灯、绿灯各一个。因此,本电路的设计中应用到红灯、黄灯、绿灯个四个。同一方向的两个路口的同一颜色指示灯是同时亮灭,为简化电路,可让这两个灯接同一引脚。这样可用P1口控制所有的指示灯。 按照设计,指示灯采用红/绿/黄三种发光二极管。
倒计时模块利用四个两位数码管,因为南北方向和东北方向的倒计时时间是一样的,所以倒计时实际上只有两个显示。
三、模块代码
1、定时器
//通用定时器3中断初始化
//arr:自动重装值。
//psc:时钟预分频数
//定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft us.
//Ft=定时器工作频率,单位:Mhz
//这里使用的是定时器3
void TIM3_Init(uint16_t arr, uint16_t psc)
{
TIM3_Handler.Instance=TIM3; //通用定时器3
TIM3_Handler.Init.Prescaler=psc; //分频系数
TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP; //向上计数器
TIM3_Handler.Init.Period=arr; //自动装载值
TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;//时钟分频因子
HAL_TIM_Base_Init(&TIM3_Handler);
HAL_TIM_Base_Start_IT(&TIM3_Handler); //使能定时器3和定时器3更新中断:
TIM_IT_UPDATE
}
//定时器底册驱动,开启时钟,设置中断优先级
//此函数会被HAL_TIM_Base_Init()函数调用
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM3)
{
__HAL_RCC_TIM3_CLK_ENABLE(); //使能TIM3时钟
HAL_NVIC_SetPriority(TIM3_IRQn,1,0); //设置中断优先级,抢占优先级1,子优先级3
HAL_NVIC_EnableIRQ(TIM3_IRQn); //开启ITM3中断
}
}
2、指示灯
从硬件原理上看,单片机IO口控制输出低电平的时候指示灯点亮,单片机IO口控制输出高电平的时候指示灯灭。
具体代码如下:
if(mode) //mode=0,表示进入南北通行模式(南北绿灯+南北黄灯)
{
LED_NBR_OF();LED_NBY_OF();LED_NBG_ON(); //南北方向,亮绿灯
LED_DXR_ON();LED_DXY_OF();LED_DXG_OF(); //东西方向,亮红灯
if(temp_bei == 0) //南北方向,倒计时结束时
{
if(temp_xi == 0) //多出来3秒的东西方向,也倒计时结束了
{
mode = 0; //进入东西方向绿灯模式
temp_xi = xi_dong_time; //提前更新东西方向的倒计时时间
temp_bei = temp_xi + YELLOW_TIME; //更新南北方向的时间,为东西方向+3秒
LED_NBR_ON();LED_NBY_OF();LED_NBG_OF(); //南北方向,亮红灯
LED_DXR_OF();LED_DXY_OF();LED_DXG_ON(); //东西方向,亮绿灯
}
else //南北方向已经结束,但是东西方向多出来的3秒未结束(3秒黄灯时间)
{
temp_xi--; //剩余的3秒,倒计时-1秒
// temp_bei = temp_xi;//南北方向黄灯时间
LED_NBR_OF();LED_NBY_ON();LED_NBG_OF(); //南北亮黄灯
LED_DXR_ON();LED_DXY_OF();LED_DXG_OF(); //东西亮红灯
}
}
else
{
temp_bei--; //南北方向。计时为-1秒
temp_xi = temp_bei + YELLOW_TIME; //更新东西方向的倒计时时间
}
}
3、数码管显示
switch(led_temp)
{
case 0:
SEG_1(0);SEG_2(1);SEG_3(1);SEG_4(1); //打开第一个数码管
Dsg_Display(data_table[0]); //将第一个数送至数码管
break;
case 1:
SEG_1(1);SEG_2(0);SEG_3(1);SEG_4(1); //打开第二个数码管
Dsg_Display(data_table[1]); //将第二个数送至数码管
break;
case 2:
SEG_1(1);SEG_2(1);SEG_3(0);SEG_4(1); //打开第三个数码管
Dsg_Display(data_table[2]); //将第三个数送至数码管
break;
case 3:
SEG_1(1);SEG_2(1);SEG_3(1);SEG_4(0); //打开第四个数码管
Dsg_Display(data_table[3]); //将第四个数送至数码管
break;
}
该函数用于动态扫描数码管。输入参数 led_temp==0 表示需要显示的第一位,如赋值2表示从第三个数码管开始显示,如输入0表示从第一个显示。先清除数据,清段锁存。然后选择位码。开位锁存将数据存在位锁存器,选择到了需要显示的数码管。位锁存完成后将数据写进段锁存数据,将需要显示的数据写到数码管中。
四、部分源程序代码
#include <stdlib.h>
#include <string.h>
#include "main.h"
#include "smg.h"
#include "ds18b20.h"
#include "beep.h"
#include "key.h"
#include "timer.h"
#include "delay.h"
#define SPEED 101 //因电脑配置不同,导致仿真速度有区别,如果需要实时倒计时趋于1秒,修改这个值
#define YELLOW_TIME 3 //黄灯时间(秒)
void SystemClock_Config(void);
uint8_t data_table[4] = {10,10,10,10}; //显示缓存数组
uint8_t bei_nan_time = 10; //南北方向默认时间(秒)
uint8_t xi_dong_time = 15; //东西方向默认时间(秒)
uint8_t temp_bei = 10; //南北倒计时,显示临时缓存变量
uint8_t temp_xi = 15 + YELLOW_TIME;//东西倒计时,显示临时缓存变量
uint8_t mode = 1; /*mode =1,南北方向;mode =0,东西方向*/
uint8_t emg_mode = 0; /*emg_mode =0,正常;emg_mode =1,紧急停止,时间为0,所有方向亮红灯*/
uint8_t set_mode = 0; /*set_mode =0,不设置;set_mode =1,设置南北方向时间;set_mode =2,设置东西方向时间*/
uint16_t time_update = 101; //1秒计时变量
int main(void)
{
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
// delay_init(10); //初始化延时函数
TIM3_Init(1800-1, 18-1); // 10ms,数码管刷新用
Key_Init(); //按键中断初始化
Led_Init(); //指示灯的初始化
SEG_Init(); //数码管引脚初始化
while(1)
{
if(time_update > SPEED && set_mode == 0) //计时达到1秒且未进入设置模式
{
time_update = 0; //重置1秒钟倒计时时间
if(mode) //mode=0,表示进入南北通行模式(南北绿灯+南北黄灯)
{
LED_NBR_OF();LED_NBY_OF();LED_NBG_ON(); //南北方向,亮绿灯
LED_DXR_ON();LED_DXY_OF();LED_DXG_OF(); //东西方向,亮红灯
if(temp_bei == 0) //南北方向,倒计时结束时
{
if(temp_xi == 0) //多出来3秒的东西方向,也倒计时结束了
{
mode = 0; //进入东西方向绿灯模式
temp_xi = xi_dong_time; //提前更新东西方向的倒计时时间
temp_bei = temp_xi + YELLOW_TIME; //更新南北方向的时间,为东西方向+3秒
LED_NBR_ON();LED_NBY_OF();LED_NBG_OF(); //南北方向,亮红灯
LED_DXR_OF();LED_DXY_OF();LED_DXG_ON(); //东西方向,亮绿灯
}
标签:SEG,LED,temp,数码管,交通灯,STM32,单片机,mode,方向
From: https://blog.csdn.net/2301_77540368/article/details/143327008