7. STM32-结合中断来做个红绿灯吧!

既然前几篇介绍了外部中断、Timer中断与USART,那接下来就结合这三种中断来模拟红绿灯出来吧。
这一次会用到定时器(TIM2)、外部中断还有一个USART。
设计想法 :
Timer :红绿灯有一定的时序,可以利用Timer中断来控制。
EXTI : 某些路口有行人按钮,当按下时会从闪黄灯转为正常红绿灯。
USART : 用来模拟路旁的号志控制箱
首先先整理一下程序设计的想法

  1. 利用Timer中断来完成时序的控制
  2. 当UART与EXTI同时触发,UART先行执行直到收到退出指令
  3. EXTI触发後回到预设红绿灯时序,经过n秒後回到闪黄灯
    https://ithelp.ithome.com.tw/upload/images/20220313/20146325teah6FoNqJ.png
    https://ithelp.ithome.com.tw/upload/images/20220313/20146325VLqrO5pY5J.png

实作

第一步先设定LED连接的GPIO脚位,这边我是连接PB13-15一样都设置GPIO_Output
https://ithelp.ithome.com.tw/upload/images/20220313/20146325jYojvLhLOx.png
先来看看优先权如何设定,以上方设计的来看优先权会是USART→EXTI→Timer,在.ioc档当中可以去做设置。在这边中断分组选择4也就是4个bit全用来作为Preemption priority分级。
https://ithelp.ithome.com.tw/upload/images/20220313/201463254FAffVj1TR.png
宣告几个全域变数之後会需要用到~

float timesec; //用来计算秒数的
int mode = 0; //模式  0:闪黄灯(EXTI) 1:红绿灯(Timer) 2:控制箱(USART)
char Rxbuf[1];
char Txbuf[30];

之後可以将各中断回调函数先写好

  1. 外部中断 : 由闪黄灯进入红绿灯时序
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if(GPIO_Pin == GPIO_PIN_13)
	{
		mode = 1;
	}
}
  1. 定时中断 : 控制三种灯号的时间变化
    在这边首先选择TIM2,我设定为0.5s中断一次方便之後计算。
    https://ithelp.ithome.com.tw/upload/images/20220313/20146325ypZ8EY6Dxm.png
    写入定时中断的函数,在这边因为定时器设定为0.5s,所以我对於秒数增加为0.5。
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	 if (htim->Instance == htim2.Instance)
	 {
			timesec+=0.5;
	 }
}
  1. USART : 模拟控制箱控制灯号,判断接收到哪种指令亮起对应灯号
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == huart2.Instance)
	{
		mode = 2;
		HAL_UART_Receive_IT(huart, (uint8_t*)&Rxbuf, 1);
		sprintf(Txbuf, "控制箱模式 : %c\r\n", Rxbuf[0]);
		HAL_UART_Transmit_IT(&huart2, (uint8_t*)&Txbuf, sizeof(Txbuf));
	}
}
  1. Trafficmode: 用来根据mode变数来选择对应的亮灯方式
  • mode 0 : 闪黄灯
  • mode 1 : 红绿灯,藉由外部中断触发进入模式1後启用定时器。到达总时长5秒後会切换为闪黄灯模式。
  • mode 2 : 控制箱,在接收到电脑所传送的指令(R/G/Y/E)後亮起对应灯号。
void Trafficmode(int modex)
{
	switch(modex)
			{
				case 0:
					HAL_GPIO_WritePin(GPIOB, GLED_Pin, RESET);
					HAL_GPIO_WritePin(GPIOB, RLED_Pin, RESET);
					HAL_GPIO_TogglePin(GPIOB, YLED_Pin);
					HAL_Delay(500);
					break;
				case 1:
					HAL_TIM_Base_Start_IT(&htim2); //Start Timer Interrupt
					if(timesec>=0&&timesec<=1.5)
					{
						HAL_GPIO_WritePin(GPIOB, YLED_Pin, RESET);
						HAL_GPIO_WritePin(GPIOB, RLED_Pin, RESET);
						HAL_GPIO_WritePin(GPIOB, GLED_Pin, SET);
					}
					else if(timesec>1.5&&timesec<=2.5)
					{
						HAL_GPIO_WritePin(GPIOB, GLED_Pin, RESET);
						HAL_GPIO_WritePin(GPIOB, YLED_Pin, SET);
					}
					else if(timesec>2.5&&timesec<=5)
					{
						HAL_GPIO_WritePin(GPIOB, YLED_Pin, RESET);
						HAL_GPIO_WritePin(GPIOB, RLED_Pin, SET);
					}
					else
					{
						HAL_TIM_Base_Stop_IT(&htim2);
						timesec=0;
						mode=0;
					}
					break;
				case 2:
					if(Rxbuf[0] == 0x47)  //G
					{
						HAL_GPIO_WritePin(GPIOB, YLED_Pin, RESET);
						HAL_GPIO_WritePin(GPIOB, RLED_Pin, RESET);
						HAL_GPIO_WritePin(GPIOB, GLED_Pin, SET);
					}
					else if(Rxbuf[0] == 0x59) //Y
					{
						HAL_GPIO_WritePin(GPIOB, YLED_Pin, SET);
						HAL_GPIO_WritePin(GPIOB, RLED_Pin, RESET);
						HAL_GPIO_WritePin(GPIOB, GLED_Pin, RESET);
					}
					else if(Rxbuf[0] == 0x52) //R
					{
						HAL_GPIO_WritePin(GPIOB, YLED_Pin, RESET);
						HAL_GPIO_WritePin(GPIOB, RLED_Pin, SET);
						HAL_GPIO_WritePin(GPIOB, GLED_Pin, RESET);
					}
					else
						mode =0;
			}
}

<<:  Python & Celery 学习笔记_任务排程

>>:  【JavaScript】阵列方法之map()

完赛!

今天在网路上看到这张照片,非常的有共鸣,因为人生就是 既便奋战到底,还是有会输得一塌糊涂的一天 但...

【Day 11】Button Template 应用 part 2

昨天原本要连同 Confirm buttom 一起讲的~,但平均一下每天的文章量,今天再接着讲另一个...

Multidimensional Scaling(MDS)

今天想来谈谈一个把高维度资料可视化的应用:MDS,MDS是一种unsupervised machin...

【Day4】音乐分类小实验

资料集 在这个实验里我们用的原始资料集在这里下载 或是直接从这里下载 csv 跟 notebook ...

【後转前要多久】# Day27 Angular - 介绍

终於进入到Angular环节了, 个人学习过程中主要以保哥的Angular教学为主。 Angular...