所需要的知识
这个东西用到的是用到按键中断和定时器两个东西,交通灯主要是有四个方向嘛,分为东西南北,我打算用前四个数码管来显示南北方向的交通灯,然后用后四个数码管用来显示东西方向的交通灯。
描述
红灯时间增加,绿灯时间减少,当处于黄灯状态时数码管和led灯闪烁,默认30秒。黄灯固定3秒
定时器功能
定时器功能主要就是用的Tim3定时器
按键中断
按键中断功能主要用的就是3个按键,一个控制交通灯是否可编辑,一个负责时间+1,一个负责时间-1。
有关交通灯的状态表
状态 | 描述 | 需要处理的逻辑 |
---|---|---|
0 | 南北方向的灯为绿,东西方向的灯为红 | 南北方向的灯的时间减少,东西方向的灯时间增加 |
1 | 南北方向的灯为黄,东西方向的灯为红 | 南北方向的灯的时间减少,东西方向的灯时间增加 |
2 | 南北方向的灯为红,东西方向的灯为绿 | 南北方向的灯的时间增加,东西方向的灯时间减少 |
3 | 南北方向的灯为红,东西方向的灯为黄 | 南北方向的灯的时间增加,东西方向的灯时间减少 |
通过这个状态表很容易将定时器的中断函数给写出来
void TIM3_IRQHandler( void )//Tim3中断函数
{
if( TIM3->SR & 0x0001 && !enable) //溢出中断,处于非可编辑状态,执行以下操作
{
ys = !ys; //
if((devideTwo++)%2==0){//做一个二分频
switch(state){
case 0:secNorth++;secWest--;
break;
case 1:secNorth++;secWest--;
break;
case 2:secNorth--;secWest++;
break;
case 3:secNorth--;secWest++;
break;
}
if(secNorth == 0 && state == 3) //南北方向为绿灯,东西方向为红灯
{
secNorth = 3;
state = 2;
}
if(secNorth == 0 && state == 2){//南北方向为黄灯,东西方向为红灯
secWest = sec;
state = 1;
}
if(secWest == 0 && state == 1) //南北方向为红灯,东西方向为绿灯
{
secWest = 3;
state = 0;
}
if(secWest == 0 && state == 0){//南北方向为绿灯,东西方向为黄灯
secNorth = sec;
state = 3;
}
}
}
TIM3->SR &= ~(1<<0); //清除中断标志位
}
void TimerxInit(u16 arr, u16 psc)
{
RCC->APB1ENR |= 1<<1; //TIM3时钟使能
TIM3->ARR = arr; //设定计数器自动重装值,10为1ms
TIM3->PSC = psc; //预分频器7200,得到10KHZ的计数时钟
TIM3->DIER |= 1<<0; //允许更新中断
TIM3->CR1 |= 0x01; //使能定时器3
MY_NVIC_Init(1, 3, TIM3_IRQChannel, 2); //抢占1,子优先级3,组2
}
按键中断函数
在这里主要用了3个按钮的按键中断,具体代码如下图所示
//外部中断 驱动代码
//外部中断0服务程序
void EXTI0_IRQHandler(void)
{
delay_ms(10);//消抖
if(KEY3==0) //按键3
{
if(enable) sec++;
}
EXTI->PR=1<<0; //清除LINE0上的中断标志位
}
//外部中断1服务程序
void EXTI1_IRQHandler(void)
{
delay_ms(10);//消抖
if(KEY2==0) //按键2
{
if(enable) sec--;
}
EXTI->PR=1<<1; //清除LINE1上的中断标志位
}
//外部中断2服务程序
void EXTI2_IRQHandler(void)
{
delay_ms(10);//消抖
if(KEY1==0) //按键1
{
enable = !enable;//修改编辑状态
}
EXTI->PR=1<<2; //清除LINE2上的中断标志位
}
//外部中断初始化程序
//初始化PC0-2为中断输入.
void EXTIX_Init(void)
{
RCC->APB2ENR|=1<<4; //使能PORTC时钟
GPIOC->CRL&=0XFFFFF000;//PC0-2设置成输入
GPIOC->CRL|=0X00000888;
Ex_NVIC_Config(GPIO_C,0,FTIR);//下降沿触发
Ex_NVIC_Config(GPIO_C,1,FTIR);//下降沿触发
Ex_NVIC_Config(GPIO_C,2,FTIR);//下降沿触发
MY_NVIC_Init(2,2,EXTI0_IRQChannel,2);//抢占2,子优先级2,组2
MY_NVIC_Init(2,1,EXTI1_IRQChannel,2);//抢占2,子优先级1,组2
MY_NVIC_Init(2,0,EXTI2_IRQChannel,2);//抢占2,子优先级1,组2
}
主函数,既然引用了中断,那么主函数就只负责数码管和led灯的展示,具体的代码如下所示
#include "timer.h"
/***************************主函数*****************************/
int main()
{
Stm32_Clock_Init( 6 );
delay_init( 72 );
TimerxInit( 4900,7199 ); 10Khz的计数频率,计数到10000表示1s
EXTIX_Init();//外部中断初始化
LED_Init();//led灯初始化
LED_SEL = 0;
while(1)
{
LED_SEL = !LED_SEL;//当LED_SEL == 1时数码管亮,当LED_SEL==0时led灯亮
//端口复用,在数码管和led灯之间“反复横跳”
DisplayTraffic(LED_SEL);//展示交通灯
}
}
DisplayTraffic(LED_SEL)函数,根据状态来选择如何展示,因为我们的实验版是有8个led灯,所以我用两个灯来表示红绿灯的一个状态,左灯亮表示绿灯,两个灯同时亮表示黄灯,右灯亮表示红灯
void DisplayTraffic(bool a)
{
if(!a){//通过a传来的值看是让led灯亮还是让数码管灯亮
if(!enable)//表示处于非可编辑状态
{
if(state == 2){
if(devideTwo%2 ==0){
SetLed(0, secNorth/10);
delay_ms(1);
SetLed(1, secNorth%10);
delay_ms(1);
SetLed(2, secNorth/10);
delay_ms(1);
SetLed(3, secNorth%10);
delay_ms(1);
}else
{
SetLed(0, 11);
delay_ms(1);
SetLed(1, 11);
delay_ms(1);
SetLed(2, 11);
delay_ms(1);
SetLed(3, 11);
delay_ms(1);
}
}else{
SetLed(0, secNorth/10);
delay_ms(1);
SetLed(1, secNorth%10);
delay_ms(1);
SetLed(2, secNorth/10);
delay_ms(1);
SetLed(3, secNorth%10);
delay_ms(1);
}
if(state == 0){
if(devideTwo%2 ==0){
SetLed(4, secWest/10);
delay_ms(1);
SetLed(5, secWest%10);
delay_ms(1);
SetLed(6, secWest/10);
delay_ms(1);
SetLed(7, secWest%10);
delay_ms(1);
}else
{
SetLed(4, 11);
delay_ms(1);
SetLed(5, 11);
delay_ms(1);
SetLed(6, 11);
delay_ms(1);
SetLed(7, 11);
delay_ms(1);
}
}else{
SetLed(4, secWest/10);
delay_ms(1);
SetLed(5, secWest%10);
delay_ms(1);
SetLed(6, secWest/10);
delay_ms(1);
SetLed(7, secWest%10);
delay_ms(1);
}
}else{
SetLed(0,sec/10);
delay_ms(1);
SetLed(1,sec%10);
delay_ms(1);
}
}
else
{
if(state ==3){
LedValue(se[0]); delay_ms(1);
LedValue(se[2]); delay_ms(1);
LedValue(se[5]); delay_ms(1);
LedValue(se[7]); delay_ms(1);
}
else if(state ==2){
if(ys)
{LedValue(se[0]); delay_ms(1);
LedValue(se[1]); delay_ms(1);
LedValue(se[2]); delay_ms(1);
LedValue(se[3]); delay_ms(1);
}
LedValue(se[5]); delay_ms(1);
LedValue(se[7]); delay_ms(1);
}
else if(state == 1)
{
LedValue(se[1]); delay_ms(1);
LedValue(se[3]); delay_ms(1);
LedValue(se[4]); delay_ms(1);
LedValue(se[6]); delay_ms(1);
}
else
{
LedValue(se[1]); delay_ms(1);
LedValue(se[3]); delay_ms(1);
if(ys){
LedValue(se[4]); delay_ms(1);
LedValue(se[5]); delay_ms(1);
LedValue(se[6]); delay_ms(1);
LedValue(se[7]); delay_ms(1);
}
}
//delay_ms(1);
}
}
若想要源代码请点击这里提取码:argb