STM32F103VBT6 交通灯设计 keil4

所需要的知识

这个东西用到的是用到按键中断和定时器两个东西,交通灯主要是有四个方向嘛,分为东西南北,我打算用前四个数码管来显示南北方向的交通灯,然后用后四个数码管用来显示东西方向的交通灯。

描述

红灯时间增加,绿灯时间减少,当处于黄灯状态时数码管和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

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,针对您的问题,我可以给出以下步骤: 1. 首先需要在Keil5中创建一个新的工程,并选择STM32F103VBT6作为目标芯片。 2. 在工程中添加一个.c文件,并编写流水灯的代码。 3. 在编写代码之前,需要先配置好芯片的时钟和GPIO口。 4. 编写流水灯的代码,可以使用循环和延时函数来实现。 以下是一个简单的流水灯代码示例: ``` #include "stm32f10x.h" int main(void) { GPIO_InitTypeDef GPIO_InitStructure; // 使能GPIOB时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 配置PB0~PB7为推挽输出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); while (1) { // 点亮PB0 GPIO_SetBits(GPIOB, GPIO_Pin_0); // 延时 Delay(1000000); // 熄灭PB0,点亮PB1 GPIO_ResetBits(GPIOB, GPIO_Pin_0); GPIO_SetBits(GPIOB, GPIO_Pin_1); Delay(1000000); // 熄灭PB1,点亮PB2 GPIO_ResetBits(GPIOB, GPIO_Pin_1); GPIO_SetBits(GPIOB, GPIO_Pin_2); Delay(1000000); // 熄灭PB2,点亮PB3 GPIO_ResetBits(GPIOB, GPIO_Pin_2); GPIO_SetBits(GPIOB, GPIO_Pin_3); Delay(1000000); // 熄灭PB3,点亮PB4 GPIO_ResetBits(GPIOB, GPIO_Pin_3); GPIO_SetBits(GPIOB, GPIO_Pin_4); Delay(1000000); // 熄灭PB4,点亮PB5 GPIO_ResetBits(GPIOB, GPIO_Pin_4); GPIO_SetBits(GPIOB, GPIO_Pin_5); Delay(1000000); // 熄灭PB5,点亮PB6 GPIO_ResetBits(GPIOB, GPIO_Pin_5); GPIO_SetBits(GPIOB, GPIO_Pin_6); Delay(1000000); // 熄灭PB6,点亮PB7 GPIO_ResetBits(GPIOB, GPIO_Pin_6); GPIO_SetBits(GPIOB, GPIO_Pin_7); Delay(1000000); // 熄灭PB7 GPIO_ResetBits(GPIOB, GPIO_Pin_7); } } void Delay(__IO uint32_t nCount) { for (; nCount != 0; nCount--); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值