蓝桥杯嵌入式第十三届省赛第一场--程序设计部分

文章描述了一个嵌入式系统的初始化过程,涉及GPIO、TIM定时器、UART通信和LCD显示,以及按键处理和中断管理,展示了如何在蓝桥杯竞赛中实现密码验证和PWM控制功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题:

代码:

main.c

extern struct key keys[4];
extern uint frq;
extern double duty;
extern char rxdata[30];
extern uint8_t rxdat;
extern uchar rx_p;

int F=2000,D=10;
int view=1;
char B1='@',B2='@',B3='@';
char right_pwd[5]="123";
char old_pwd[5]="123";
char new_pwd[5];
int pwd=0;
int main(void)
{

  HAL_Init();
  SystemClock_Config();

  MX_GPIO_Init();
  MX_TIM4_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  MX_USART1_UART_Init();

  HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);//PWM脉冲输出初始化
  HAL_TIM_Base_Start_IT(&htim4);//按键的定时器
	
  LCD_Init();
  LCD_SetBackColor(Black);
  LCD_SetTextColor(White);
  LCD_Clear(Black);
	
  HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);//输入捕获
	
  HAL_UART_Receive_IT(&huart1,&rxdat,1);//开启中断
	
  LED_Display(0x00);

  while (1)
  {
		lcd_proc();//LCD
		key_proc();//按键部分
		if(rx_p!=0)//串口  检测串口接收数据位数
		{
			int temp=rx_p;
			HAL_Delay(1);
			if(temp==rx_p) uart_rx();//接收完毕 开始处理
		}
  }
}

main函数主要为初始化。

void lcd_proc(void)
{
	char text[30];
	
	if(view)
	{
		sprintf(text,"       PSD    ");
		LCD_DisplayStringLine(Line1,(unsigned char*)text);
		sprintf(text,"    B1:%c    ",B1);
		LCD_DisplayStringLine(Line3,(unsigned char*)text);
		sprintf(text,"    B2:%c    ",B2);
		LCD_DisplayStringLine(Line4,(unsigned char*)text);
		sprintf(text,"    B3:%c    ",B3);
		LCD_DisplayStringLine(Line5,(unsigned char*)text);
	}else
	{
		sprintf(text,"       STA    ");
		LCD_DisplayStringLine(Line1,(unsigned char*)text);
		sprintf(text,"    F:%dHz    ",F);
		LCD_DisplayStringLine(Line3,(unsigned char*)text);
		sprintf(text,"    D:%d%%    ",D);
		LCD_DisplayStringLine(Line4,(unsigned char*)text);
		
		LED_Display(0x01);
		HAL_Delay(5000);
		LED_Display(0x00);
		view=!view;
	}
}

根据题目所需显示相应界面。

在此题目中,由于STA界面是静态的,只会有一种结果,所以其实可以直接将页面写死,直接输出2000Hz和10%。

void key_proc(void)
{
	if(keys[0].single_flag==1)//密码 B1
	{
		if(!view)//保证按键只在PSD界面有效,下同
		{
			keys[0].single_flag=0;
			return;
		}
		if(B1=='@')
			B1='0';
		else
		{
			if(B1=='9') B1='0';
			else B1++;
		}
		
		keys[0].single_flag=0;//预防一次按下多次响应
	}else if(keys[1].single_flag==1)//密码 B2
	{
		if(!view)
		{
			keys[0].single_flag=0;
			return;
		}
		if(B2=='@')
			B2='0';
		else
		{
			if(B2=='9') B2='0';
			else B2++;
		}
		keys[1].single_flag=0;
	}else if(keys[2].single_flag==1)//密码 B3
	{
		if(!view)
		{
			keys[0].single_flag=0;
			return;
		}
		if(B3=='@')
			B3='0';
		else
		{
			if(B3=='9') B3='0';
			else B3++;
		}
		keys[2].single_flag=0;
	}else if(keys[3].single_flag==1)//密码确认
	{
		char input[3];
		sprintf(input,"%c%c%c",B1,B2,B3);
		//密码正确
		if(!strcmp(input,right_pwd))
		{
			pwd=0;
            //将PA1的PWM输出调整为:2000Hz,占空比为:10%
            //F=主频/预分配系数/重装载值
            //F=80000000/(40-1)/(1000-1)
            //Duty=pulse/重装载值
            //Duty=100/(1000-1)
			__HAL_TIM_SET_PRESCALER(&htim2, 40-1);                  //设置预分频系数
			__HAL_TIM_SET_AUTORELOAD(&htim2, 1000-1);                //设置重装载值
			__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,100);
			B1='@',B2='@',B3='@';//重置密码
			view=!view;//切换界面
			LCD_Clear(Black);
		}else
		{
			pwd++;
			if(pwd>=3)//密码连续输入错误三次及以上
			{
				for(int i=0;i<25;i++)//LED2闪烁5s
				{
					LED_Display(0x02);
					HAL_Delay(100);
					LED_Display(0x00);
					HAL_Delay(100);
				}
				LED_Display(0x00);
			}
			B1='@',B2='@',B3='@';
		}
		keys[3].single_flag=0;
	}
}

如注释。

void uart_rx(void)
{
	//接收到了
	if(rx_p>0)
	{
		if(rx_p==7)//接收的数据符不符合题目要求
		{
			sscanf(rxdata,"%3s-%3s",old_pwd,new_pwd);//数据格式为:xxx-xxx
			if(!strcmp(old_pwd,right_pwd))//判断一下旧密码是否与当前密码一致
			{
				strcpy(right_pwd,new_pwd);//密码更改
			}else//否则报错
			{
				char temp[20];
				sprintf(temp,"Old password is wrong!\r\n");
				HAL_UART_Transmit(&huart1,(uint8_t *)temp,strlen(temp),50);
			}
		}else
		{
			char temp[20];
			sprintf(temp,"Error\r\n");
			HAL_UART_Transmit(&huart1,(uint8_t *)temp,strlen(temp),50);
		}
		rx_p=0;//很重要!要置0
		memset(rxdata,0,30);
	}
}

如注释。

interrupt.c

#include "interrupt.h"
#include "usart.h"
struct key keys[4];

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM4)//判断中断来源
	{
        //读取引脚的值
		keys[0].key_status=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
		keys[1].key_status=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
		keys[2].key_status=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
		keys[3].key_status=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
		
        //状态机消抖
		for(int i=0;i<4;i++)
		{
			switch(keys[i].judge_status)
			{
				case 0:
				{
					if(keys[i].key_status==0)
					{
						keys[i].judge_status=1;
						keys[i].key_time=0;
					}
				}
				break;
				case 1:
				{
					if(keys[i].key_status==0)
					{
						keys[i].judge_status=2;
					}else
					{
						keys[i].judge_status=0;
					}
				}
				break;
				case 2:
				{
					if(keys[i].key_status==0)
					{
						keys[i].key_time++;
						if(keys[i].key_time>=70)
						{
							keys[i].long_flag=1;
						}
					}else
					{
						keys[i].judge_status=0;
						if(keys[i].key_time<70)
						{
							keys[i].single_flag=1;
						}
					}
				}
				break;
			}
		}
	}
}

double ccrl_vala=0,ccrl_valb=0;
uint frq=0;
double duty=0;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM3)
	{
		if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_1) //中断消息来源 选择直接输入的通道
		{
			//读取定时器的计时值
			ccrl_vala=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);
			ccrl_valb=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2);
			//将定时器的计时值清零
			__HAL_TIM_SetCounter(htim,0);
			//计算频率 主频/分频系数/计时值
			frq=(80000000/80)/ccrl_vala;
			//占空比计算
			duty=(ccrl_valb/ccrl_vala)*100;
			HAL_TIM_IC_Start(htim,TIM_CHANNEL_1);
			HAL_TIM_IC_Start(htim,TIM_CHANNEL_2);
		}
		
	}
}

char rxdata[30];
uint8_t rxdat;
uchar rx_p;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	rxdata[rx_p++]=rxdat;
	HAL_UART_Receive_IT(&huart1,&rxdat,1);
}

关于状态机消抖的详细解释,请移步:蓝桥杯嵌入式第十二届省赛--程序设计部分-优快云博客

interrupt.h

#ifndef _INTERRUPT_H_
#define _INTERRUPT_H_

#include "main.h"
#include "stdbool.h"
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);

struct key
{
	bool single_flag;
	bool long_flag;
	uint key_time;
	uint key_status;
	uint judge_status;
};

#endif

led.c

#include "led.h"

void LED_Display(uchar dsLED)
{
		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOC,dsLED<<8,GPIO_PIN_RESET);
		HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}

led.h

#ifndef __LED_H__
#define __LED_H__

#include "main.h"
void LED_Display(uchar dsLED);

#endif

----THE END-----

有关蓝桥杯嵌入式的模块知识请参考如下:

蓝桥杯嵌入式模块学习系列

【蓝桥杯嵌入式学习G431】模块一:LED-优快云博客

【蓝桥杯嵌入式学习G431】模块二:LCD-优快云博客

【蓝桥杯嵌入式学习G431】模块三:KEY-优快云博客

【蓝桥杯嵌入式学习G431】模块四:PWM-优快云博客

【蓝桥杯嵌入式学习G431】模块五:USART-优快云博客

(还有几个模块没更新~)


有关蓝桥杯嵌入式历届真题请参考如下:

蓝桥杯嵌入式历届真题系列

蓝桥杯嵌入式第十二届省赛--程序设计部分-优快云博客

蓝桥杯嵌入式第十三届省赛第一场--程序设计部分-优快云博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值