HNUST-交叉路口交通灯的模拟设计(定时器实现)-嵌入式作业(2024)

1.题目要求(注意这里代码配合湖科大开发板使用)

     基础:

  1. 用左右两个8位数码管显示路口交通灯的倒数计数数字(如01号显示南北秒数、67号管显示东西秒数);
  2. K1键按下一次表示进入红绿黄灯秒数设置状态,此时计数倒计数停止使用K2,K3调整秒数;再按一次K1进入绿设置,再按一次K1进入黄灯秒数设置....,第四次按K1退出设置状态;
  3. 可使用串口通信程序来进行交通灯的秒数设置,参考:-ns45, -we60表示将交通灯的南北和东西秒数分别设置为45S和60S;

     加分项:

  1. 显示和按键处理使用中断或定时器的方式。
  2. 考虑秒数最后5S的闪烁效果
  3. 采用ucOS实时操作系统实现。

2.效果展示(中断实现)

e82c8f411e93481d814ccbe68e812482.png

图2.1显示红绿灯倒计时与灯的类型

最左最右的数码管表示两个方向的倒计时,中间为灯的类型

 LD绿灯‘L’字符, FD黄灯‘F’字符 ,HD红灯‘H’字符

be845b4a65344551aef365dd8c8b6435.png

  图2.2设置模式,设置红灯时间

f0dbf8f0f22c43e18befe1c87a271086.png

   图2.3串口设置

75a89db663a64234bc83f7d9e05a441a.png


3.参考代码(中断实现)

1. main.c

/******************************交通灯显示********************************
 *Id:   2*********
 *Coder:芒果酱
 *Time: 2024.4.23
 ***********************************************************************/

#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "stdlib.h"
#define uchar unsigned char

//-----------------------函数定义----------------------------
void ClearShow(int start, int end);
void InitData(void);
void ModeNowShow(void);
void InitBand(void);
void SettingMode(void);
void ShowNode(void);
void TrafficLightControl(void);

//-----------------------物理量---------------------------
// 数码管当前存储(10为不显示)
int NodeShow[8] = {10, 10, 10, 10, 10, 10, 10, 10};
// 按键当前值(keyup赋值1,keyudowm赋值-1)
int keyup = 0, keydown = 0;

//-----------------------配置表----------------------------
// 红绿灯文字串口输出
char *ledstr[] = {
	"Green",
	"Yellow",
	"Red",
};
// 0表示绿灯 1示黄灯 2表示红灯
int A_lendChangeconfig[] = {0, 1, 2}, // A灯显示顺序表
	B_lendChangeconfig[] = {2, 0, 1}, // B灯显示顺序表
	// 两个数码管显示的什么时间(0绿灯 1黄灯 2红灯),这里表示lendChangeconfig数组的位置
	A_LedNowLocal = 0, // 存储位置(这里0不代表绿灯,只是数组位置,范围0-2)
	B_LedNowLocal = 0, // 存储位置(这里0不代表绿灯,只是数组位置,范围0-2)
	// 注意:绿灯 + 黄灯= 红灯 15s+5s=20s
	LedTime[] = {15, 5, 20},
	// 0绿灯‘L’字符, 1黄灯‘F’字符 ,2红灯‘H’字符
	ShowType[] = {20, 17, 18},
	// 两个数码管当前显示的时间s
	A_LedNowTime = 0,
	B_LedNowTime = 0,
	// 两个数码管当前显示的时间是否闪
	A_Ledflashing = 0,
	B_Ledflashing = 0,
	// 闪烁开始时间s
	FlashingTime = 5,
	// 设置模式判断0为显示模式,1为设置绿灯,2为设置黄灯,3为设置红灯(这里自动计算,无法直接设置)
	ModeNow = 0;

//-------------------------中间变量--------------------------------------
u8 t, len;
long times = 0;

//-----------------------定时器相关函数----------------------------
// 数码管
void Timer2Init(u16 arr, u16 psc)
{
	RCC->APB1ENR |= 1 << 0;					// TIM2时钟使能
	TIM2->ARR = arr;						// 设定计数器自动重装值,10为1ms
	TIM2->PSC = psc;						// 预分频器7200,得到10KHZ的计数时钟
	TIM2->DIER |= 1 << 0;					// 允许更新中断
	TIM2->CR1 |= 0x01;						// 使能定时器3
	MY_NVIC_Init(1, 2, TIM2_IRQChannel, 2); // 抢占1,子优先级2,组2
}
// 秒时间
void Timer3Init(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(3, 3, TIM3_IRQChannel, 3); // 抢占3,子优先级3,组3
}
// 按键
void Timer4Init(u16 arr, u16 psc)
{
	RCC->APB1ENR |= 1 << 2;					// TIM2时钟使能
	TIM4->ARR = arr;						// 设定计数器自动重装值,10为1ms
	TIM4->PSC = psc;						// 预分频器7200,得到10KHZ的计数时钟
	TIM4->DIER |= 1 << 0;					// 允许更新中断
	TIM4->CR1 |= 0x01;						// 使能定时器3
	MY_NVIC_Init(4, 4, TIM4_IRQChannel, 3); // 抢占4,子优先级4,组3
}

// 显示定时器
void TIM2_IRQHandler(void)
{
	if (TIM2->SR & 0x0001) // 溢出中断
	{
		ShowNode();
	}
	TIM2->SR &= ~(1 << 0); // 清除中断标志位
}
// 时钟定时器
void TIM3_IRQHandler(void)
{
	if (TIM3->SR & 0x0001) // 溢出中断
	{
		// AB倒计时
		if (A_LedNowTime != 0)
			A_LedNowTime--;
		if (B_LedNowTime != 0)
			B_LedNowTime--;
	}
	TIM3->SR &= ~(1 << 0); // 清除中断标志位
}
// 按键定时器
void TIM4_IRQHandler(void)
{
	if (TIM4->SR & 0x0001) // 溢出中断
	{
		if (KEY1 == 0)
		{
			keyup = 1; // 设置keyup标志
		}
		if (KEY2 == 0)
		{
			keydown = -1; // 设置keydown标志
		}
		if (KEY3 == 0)
		{
			// 进入设置
			ModeNow = (++ModeNow) % 4;
			// 清除缓存区显示(1-8数码管内容)
			ClearShow(1, 8);
		}
	}
	TIM4->SR &= ~(1 << 0); // 清除中断标志位
}

//-----------------------初始化相关函数----------------------------
// 板子初始化函数
void InitBand()
{
	// 系统频率
	Stm32_Clock_Init(6);
	// 延时启动
	delay_init(72);
	// 数码管显示定时器
	Timer2Init(9, 7199);
	// 倒计时定时器 10Khz的计数频率,计数到10000表示1s
	Timer3Init(9999, 7199);
	// 按键读取定时器(设置999用来消抖)
	Timer4Init(999, 7199);
	// 串口初始化为9600
	uart_init(72, 9600);
	// led初始化
	LED_Init();
	// 按键初始化
	KEY_Init();
	// 屏蔽LED
	LED_SEL = 0;
}

// 数据初始化函数
void InitData()
{
	// 显示归位
	A_LedNowLocal = 0;
	B_LedNowLocal = 0;
	// 计算初始的时间
	A_LedNowTime = LedTime[A_lendChangeconfig[A_LedNowLocal]];
	B_LedNowTime = LedTime[B_lendChangeconfig[B_LedNowLocal]];
}

//-----------------------运行模式相关函数----------------------------
// 模式选择函数
void ModeNowShow()
{
	if (ModeNow == 0)
	{
		// 红绿灯模式
		TrafficLightControl();
	}
	else
	{
		// 设置模式
		SettingMode();
	}
}

// 红绿灯控制与显示函数
void TrafficLightControl()
{
	int temptime = times % 10000;
	// 闪烁显示,这里可以控制闪烁速度
	if (A_Ledflashing == 1 && (temptime > 0 && temptime < 5000))
	{
		//不显示
		NodeShow[1] = 10;
		NodeShow[0] = 10;
	}
	else
	{
		// 第一个灯显示
		NodeShow[0] = A_LedNowTime / 10;
		if (NodeShow[0] == 0)
		{
			NodeShow[0] = 10; // 0限制不显示
		}
		NodeShow[1] = A_LedNowTime % 10;
	}
	// 闪烁显示,这里可以控制闪烁速度
	if (B_Ledflashing == 1 && (temptime > 0 && temptime < 5000))
	{
		//不显示
		NodeShow[6] = 10;
		NodeShow[7] = 10;
	}
	else
	{
		// 第二个灯显示
		NodeShow[6] = B_LedNowTime / 10;
		if (NodeShow[6] == 0)
		{
			NodeShow[6] = 10; // 0限制不显示
		}
		NodeShow[7] = B_LedNowTime % 10;
	}
	// 如果两个灯到了0,进入下一个灯的显示(如:绿灯->黄灯)
	if (A_LedNowTime == 0)
	{
		// 下一个灯
		A_LedNowLocal = (++A_LedNowLocal) % 3;
		// 下一个灯的时间
		A_LedNowTime = LedTime[A_lendChangeconfig[A_LedNowLocal]];
	}
	if (B_LedNowTime == 0)
	{
		// 下一个灯
		B_LedNowLocal = (++B_LedNowLocal) % 3;
		// 下一个灯的时间
		B_LedNowTime = LedTime[B_lendChangeconfig[B_LedNowLocal]];
	}
	// AB闪烁控制判断
	if (A_LedNowTime <= FlashingTime)
		A_Ledflashing = 1;
	else
		A_Ledflashing = 0;

	if (B_LedNowTime <= FlashingTime)
		B_Ledflashing = 1;
	else
		B_Ledflashing = 0;

	// 显示灯的类别
	NodeShow[3] = ShowType[A_lendChangeconfig[A_LedNowLocal]];
	NodeShow[4] = ShowType[B_lendChangeconfig[B_LedNowLocal]];
	// 不显示2、5数码管
	NodeShow[2] = 10;
	NodeShow[5] = 10;
}

// 设置模式函数
void SettingMode()
{
	// '设置数字'存储变量
	int SetTime01 = 0,
		SetTime02 = 0;
	// 自动计算红灯时间
	LedTime[2] = LedTime[0] + LedTime[1];
	// 计算每个位的数
	SetTime01 = LedTime[ModeNow - 1] / 10;
	SetTime02 = LedTime[ModeNow - 1] % 10;
	// 1为设置绿灯
	if (ModeNow == 1)
	{
		// 显示字母Ld
		NodeShow[0] = 20;
		NodeShow[1] = 15;
	}
	// 2为设置黄灯
	if (ModeNow == 2)
	{
		// 显示字母Fd
		NodeShow[0] = 17;
		NodeShow[1] = 15;
	}
	// 3为设置红灯
	if (ModeNow == 3)
	{
		// 显示字母Hd
		NodeShow[0] = 18;
		NodeShow[1] = 15;
	}
	// 显示‘-’
	NodeShow[2] = 28;
	NodeShow[3] = ModeNow;
	// 显示‘-’
	NodeShow[4] = 28;
	// 显示设置的数字
	NodeShow[5] = SetTime01;
	NodeShow[6] = SetTime02;
	// 按键控制,<3限制按键控制范围
	if (ModeNow < 3)
	{
		// 设置数据,>0
		if (LedTime[ModeNow - 1] > 1)
		{
			//+keydowm(keydowm==-1)
			LedTime[ModeNow - 1] = LedTime[ModeNow - 1] + keydown;
			// 清除按键标志
			keydown = 0;
		}
		// 设置数据,<99
		if (LedTime[ModeNow - 1] < 99)
		{
			//+keyup(keyup==1)
			LedTime[ModeNow - 1] = LedTime[ModeNow - 1] + keyup;
			// 清除按键标志
			keyup = 0;
		}
	}
	NodeShow[7] = 10;
	// 更新显示数据
	InitData();
}

//-----------------------显示相关函数----------------------------
// 数码管显示函数
void ShowNode()
{ // 变量定义
	uchar i, icode;
	// 屏蔽LED
	LED_SEL = 0;
	// 8位显示
	for (i = 0; i < 8; i++)
	{
		// 第i位数码管显示数字
		icode = NodeShow[i];
		// 显示数字
		SetLed(i, icode);
		// 频率控制(显示亮度控制,数值越大显示越亮)
		delay_us(100);
	}
}

// 清除指定区域显示 1-8数码管内容函数
void ClearShow(int start, int end)
{
	for (int i = start - 1; i < (end); i++)
	{
		// 用10去除原来的数据
		NodeShow[i] = 10;
	}
}

//-----------------------串口相关-----------------------------
// 串口字符串中的具体信息并且设置
void ConfigLEDShow(int i, int SetTime)
{
	switch (i)
	{
	case 1:
		LedTime[2] = SetTime;
		break;
	case 2:
		LedTime[0] = SetTime;
		break;
	case 3:
		LedTime[1] = SetTime;
		break;
	case 4:
		A_LedNowTime = SetTime;
		break;
	case 5:
		B_LedNowTime = SetTime;
		break;
	default:
		break;
	}
}
// 获取串口字符串中的具体信息
char *GetStrInfo()
{
	// 长度不够判断
	if (len <= 3)
		return "\nERROR:len too low";
	//变量定义
	int num = 0, NumLength = len - 3;
	char str[NumLength], temp;
	//读取数据大小
	for (int i = 0; i < NumLength; i++)
	{
		temp = USART_RX_BUF[3 + i];
		// 存在其他字符判断
		if (temp >= '0' && temp <= '9')
			str[i] = temp;
		else
			return "\nERROR:String have 'abc...'"; 
	}
	// char数组转int
	const char *ptr = str;
	while (*ptr)
	{
		num *= 10;
		num += *ptr - '0';
		ptr++;
	}
	// 配置程序
	ConfigLEDShow((USART_RX_BUF[1] - '0'), num);
	// 返回信息
	return "\nSucess";
}
// 输出串口信息
void PrintMsg()
{
	printf("\n\n----Now LED Config,your can input:\"(2)12\"----");
	printf("\n(1)Red Time(Can't Change):%d", LedTime[2]);
	printf("\n(2)Green Time:%d", LedTime[0]);
	printf("\n(3)Yellow Time:%d", LedTime[1]);
	printf("\n(4)NS Now Time:%d (Min:1,Max:%d,Type:%s)", A_LedNowTime, LedTime[A_lendChangeconfig[A_LedNowLocal]], ledstr[A_lendChangeconfig[A_LedNowLocal]]);
	printf("\n(5)WE Now Time:%d (Min:1,Max:%d,Type:%s)", B_LedNowTime, LedTime[B_lendChangeconfig[B_LedNowLocal]], ledstr[B_lendChangeconfig[B_LedNowLocal]]);
	printf("\n------------------------------\n");
}
// 串口函数
void Serial()
{

	if (USART_RX_STA & 0x80) // 7位STA0-6数据,7-8标志与长度
	{
		len = USART_RX_STA & 0x3f; // 得到此次接收到的数据长度,6位
		// 输出结果
		printf(GetStrInfo());
		printf(" : ");
		// 返回结果
		for (t = 0; t < len; t++)
		{
			USART1->DR = USART_RX_BUF[t];
			while ((USART1->SR & 0X40) == 0)
				; // 等待发送结束
		}
		printf("\n"); // 插入换行

		len = 0;
		PrintMsg();
		USART_RX_STA = 0;
	}
	else
	{
		times++;
		if (times % 200000 == 0)
		{
			times = 0;
			PrintMsg();
		}
	}
}

//-----------------------主函数----------------------------
int main()
{
	// 板子初始化
	InitBand();
	// 数据初始化
	InitData();
	// 主循环
	while (TRUE)
	{
		// 当前模式控制显示
		ModeNowShow();
		// 串口配置函数
		Serial();
	}
}

//--------------------使用教程---------------------------------
// 最左最右的数码管表示两个方向的倒计时,中间为灯的类型
// LD绿灯‘L’字符, FD黄灯‘F’字符 ,HD红灯‘H’字符
// 按键1进入设置,按键2设置减小,按键3设置增加,跳出即可设置完成

//---------------------附件-----------------------------
/*
导入下面这里的库文件,学校提供
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "usart.h"
#include "key.h"

(重要)注意这里要修改led.c变量segTable为
 u8 segTable[] =
	0x3f,//0
	0x06,//1
	0x5b,//2
	0x4f,
	0x66,//数字4
	0x6d,
	0x7d,
	0x07,
	0x7f,
	0x6f,
	0x00,
	0x77,
	0x7C,
	0x39,
	0x58,
	0x5E,
	0x79,
	0x71,
	0x76,
	0x74,
	0x38,
	0x54,
	0x37,
	0x5C,
	0x73,
	0x50,
	0x78,
	0x3E,
	0x40
*/

 2.项目地址

gitee地址:MGJ520/HNUST_Traffic_lights (gitee.com)


4.附件及其重要事项

1. 注意这里要修改led.c变量segTable

2. HNUST湖南科技大学嵌入式开发板使用-2024-CSDN博客

  • 8
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值