史上话最少的蓝桥杯嵌入式13届第一场省赛题解

@蓝桥杯嵌入式


蓝桥杯嵌入式13届第一场赛题

提示:本文描述赛题是关于蓝桥杯嵌入式第十三届省赛第一场:

话少,是不可能的,下面是对上述赛题的的一些讲解(不能算讲解,称之为理解吧)

首先来说说我程序的实现步骤吧:

  1. 实现密码输入与判断密码的正误
  2. 使用串口实现密码的更改
  3. 实现PWM的输出
  4. 实现题目中其他外设
  5. 调试程序bug,并完善程序

时钟配置

上面是关于赛题的时钟配置,我们在学习F1平台的时候会配置HCLK为72MHz(这里我理解是将时钟配置成最大,速度快一点),这里配置80MHz我也不知道为啥,对这方面有兴趣的朋友可以分享分享。在debug配置的时候,最好将SW选上,在使用F1平台时候,刚开始使用hal库,由于debug未勾选上,导致芯片下不了程序,但在G4平台中网上的一些视频也没有勾选debug配置,并不会导致芯片锁死。官方给的驱动代码也没有选择。所以对G4来说并没有什么影响,各位兄弟在配置时候还是住点意吧。也有可能芯片是盗版才导致锁死的。

三行按键的理解

    uc_KeyDown = uc_KeyVal & (uc_KeyOld ^ uc_KeyVal);  // Press the key value
    uc_KeyUp = ~ uc_KeyVal & (uc_KeyOld ^ uc_KeyVal);  // Press the key to lift the key value
    uc_KeyOld = uc_KeyVal;

现在我们开始假设

过程1假设第4个被按下也就是’uc_KeyVal = 4(0000 0100)’ 经过’uc_KeyDown’ 中的运算,使得’uc_KeyDown’ 变成了4(0000 0100) uc_KeyUp为0,uc_KeyOld = 4(0000 0100)

过程2:当第4个按键产生下降沿时,按键一直被按下(注意此时的状态是按下,并非按键的不定态)。此时uc_KeyVal 仍然为4(0000 0100)由于在uc_KeyOld 在上一次值的变换,当前的uc_KeyDown变成了0,uc_KeyUp也变成了0,uc_KeyOld还是4

过程3:第4个按键一直按下随后弹起,uc_KeyVal 变为0 。uc_KeyDown变为0,uc_KeyUp变成了4,uc_KeyOld 变为了0。按键识别结束。

定时器的配置

  • 定时器6用于计时5s

在这里插入图片描述

  • 定时器2用来产生PWM脉冲

初始设置频率是1000Hz = 80MHz x106 /[(79 + 1) + (999 + 1)]

对于上述定时器,6开中断进行精准定时,2不需要开启中断。

下面是定时器2设置PWM输出所用的函数。

__HAL_TIM_SET_AUTORELOAD(&htim2, 999);  /* 设置频率1Khz */ 
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, 500); /* 设置占空比为50% = 500/1000 */

到这里我们就结束了,代码里有详细的注释,可以直接下载进行参考,欢迎各位Up进行评论和指正。评论还是在csdn吧,GitHub还是个小白,不咋玩的明白。

下面是部分函数:

  • 定时器6处理
	static uint16_t u16_ms = 0;
	static uint16_t u16_100ms = 0;
	static uint16_t u16_5000ms = 0;
	
	if(htim->Instance == TIM6) {
		
		if(right_flag) { /* 密码输入正确开始计时 */
			u16_ms++;
			if(u16_ms == 5000) {
				right_flag = 0;
				PSD_STA = 0;   /* 切回界面 */
				mima[0] = mima[1] = mima[2] = '@';
				lcd_flag_show = 1;  /* LCD清屏 */
				u16_ms = 0;
			}
		}
		
		if(ld2_YN_flag) {
			u16_5000ms++;
			if(u16_5000ms == 5000) {
				ld2_YN_flag = 0;
				u16_5000ms = 0;
			}
		}
		
		if(++u16_100ms == 100) {
			flag ^= 1;
			u16_100ms = 0;
		}
	}
	HAL_TIM_Base_Start_IT(&htim6)
  • 串口处理函数
int isRxCplt(void) {
	uint8_t i;
	
	if(dex == 0) /* 没有接受到数据 */
		return 0;
	else if(dex != 7) { /* 接收不满7位数据 */ 
		return -1;
	}
	if(rx_buf[3] == '-') {  /* 接收密码数据正确 */
		for(i = 0; i < 3; i++) {
			if(rx_buf[i] < '0' || rx_buf[i] > '9')  /* 前三位接收合法返回错误 */ 
				return -1;
		}
		for(i = 4; i < 7; i++) {
			if(rx_buf[i] < '0' || rx_buf[i] > '9')  /* 后三位接收合法返回错误 */ 
				return -1;
		}
		return 1;
	}
	else return -1; /* 接收到第三个数据不为 '-' 返回错误 */ 
	
	return 0;
}

void Uart_Proc(void) {  
	static __IO uint32_t uwTick_UART_Speed;
	uint8_t tx[21];
	
	if((uwTick - uwTick_UART_Speed) < 100)  return;
	uwTick_UART_Speed = uwTick;
	
	if(isRxCplt() == 1) {
		if((rx_buf[0] == right_mima[0])&&(rx_buf[1] == right_mima[1])&&(rx_buf[2] == right_mima[2])) { /* 发送前三位密码与原始密码相同。则密码正确 */
			/* 修改密码 */
			right_mima[0] = rx_buf[4];
			right_mima[1] = rx_buf[5];
			right_mima[2] = rx_buf[6];
			
			sprintf((char* )tx, "OK\r\n");
			HAL_UART_Transmit(&huart1, tx, strlen((const char* )tx), 50);/* 向上位机发送OK表示修改成功 */
		}
		else {  /* 输入原始密码错误 */
			sprintf((char* )tx, "ERROR\r\n");
			HAL_UART_Transmit(&huart1, tx, strlen((const char* )tx), 50);/* 向上位机发送错误 */
		}
	}
	else if(isRxCplt() == -1){  /* 接受数据不合法 */
		sprintf((char* )tx, "ERROR\r\n");
		HAL_UART_Transmit(&huart1, tx, strlen((const char* )tx), 50);/* 向上位机发送错误 */
	}
	dex = 0;  /* 清除串口接收数组索引 */
}
  • LED处理函数
void LED_Proc(void) {
    static __IO uint32_t uwTick_LED_Speed;
    if((uwTick - uwTick_LED_Speed) < 100)  return;
		uwTick_LED_Speed = uwTick;
	
		LED_CLOSE();  // 关灯
	
		if(right_flag) {  /* 密码输入正确 */
			LED_Disp_OP(LD1);
			pwm_flag = 1;  /* 输出脉冲 */
		}
		else {
			LED_Disp_CL(LD1);
			pwm_flag = 0;  /* 输出脉冲 */
		}

		if(ld2_YN_flag) {
			if(flag)
				LED_Disp_OP(LD2);
			else 
				LED_Disp_CL(LD2);
		}
		else LED_Disp_CL(LD2);
}
  • LCD 处理函数
void LCD_Proc(void) {
	static __IO uint32_t uwTick_LCD_Speed = 0; 
	
	if(uwTick - uwTick_LCD_Speed < 100) return;  /* 函数刷新频率 */
	uwTick_LCD_Speed = uwTick;
	
	if(lcd_flag_show == 1) {  /* 从STA界面切回PSD界面 需要清屏一次 */
		lcd_flag_show = 0;
		LCD_Clear(White);
	}
	
	/* 默认输出方波,占空比为50% */ 
	/* 在LED_Proc()中实现pwm_flag的控制 */
	if(pwm_flag == 0) {  /* 输出方波,占空比为50% */ 
		__HAL_TIM_SET_AUTORELOAD(&htim2, 999);  /* 设置频率1Khz */ 
		__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, 500); /* 设置占空比为50% = 500/1000 */ 
	}
	else if(pwm_flag == 1) {  /* 密码正确输出脉冲,占空比为50% */ 
		__HAL_TIM_SET_AUTORELOAD(&htim2, 499);  /* 设置频率2Khz = 80Mhz/[(AUTORELOAD+1) + 80] 其中80为cubemx配置 */ 
		__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, 50); /* 设置占空比为10% = 50/500*/ 			
	}
	
	if(PSD_STA == 0) {  /* 在PSD界面 */
		sprintf((char* )Lcd_Disp_String, (const char* )"       P S D       ");
		LCD_DisplayStringLine(Line2, Lcd_Disp_String);
		
		sprintf((char* )Lcd_Disp_String, (const char* )"    B1 : %c", mima[0]);
		LCD_DisplayStringLine(Line4, Lcd_Disp_String);
		sprintf((char* )Lcd_Disp_String, (const char* )"    B2 : %c", mima[1]);
		LCD_DisplayStringLine(Line5, Lcd_Disp_String);
		sprintf((char* )Lcd_Disp_String, (const char* )"    B3 : %c", mima[2]);
		LCD_DisplayStringLine(Line6, Lcd_Disp_String);
		
	}
	else if(PSD_STA == 1) {  /* 在STA界面 */
		memset(Lcd_Disp_String, '\0', sizeof(Lcd_Disp_String));
		sprintf((char* )Lcd_Disp_String, (const char* )"       S T A       ");
		LCD_DisplayStringLine(Line2, Lcd_Disp_String);
		
		if(pwm_flag == 1) { freq = 2000; D_Pwm = 10; } /* 密码正确后输出脉冲,占空比为10% */ 
		else { freq = 1000; D_Pwm = 50; }  /* 5s后输出方波,占空比为50% */ 

		sprintf((char* )Lcd_Disp_String, (const char* )"    F : %04dHz", freq);
		LCD_DisplayStringLine(Line4, Lcd_Disp_String);
		sprintf((char* )Lcd_Disp_String, (const char* )"    D : %02d%%", D_Pwm);
		LCD_DisplayStringLine(Line5, Lcd_Disp_String);
	}
	

}
  • 按键处理
void B4(void) {
    if(PSD_STA == 0) {
        if((right_mima[0] == mima[0])&&(right_mima[1] == mima[1])&&(right_mima[2] == mima[2])) { /* 密码正确 */
            error_num = 0;
						right_flag = 1;
            PSD_STA = 1;  // 密码正确进入界面二
            LCD_Clear(White);  /* 密码正确进行清屏 */
        }
        else {  /* 密码错误 */
            if(++error_num >= 3) {  /* 密码错误大于3次 */
								ld2_YN_flag = 1;    /* LD2闪烁报警 */ 
            }
						right_flag = 0;
            mima[0] = mima[1] = mima[2] = '@';
        }
    }
}

void B3(void) {
	if(PSD_STA == 0) {
		if(++mima[0] > '9')
            mima[0] = '0';
	}
}

void B2(void) {
	if(PSD_STA == 0) {
		if(++mima[1] > '9')
            mima[1] = '0';
	}
}

void B1(void) {
	if(PSD_STA == 0) {
		if(++mima[2] > '9')
            mima[2] = '0';
	}
}
  • 主函数
int main(void)
{
 	HAL_Init();
 	SystemClock_Config();
 	
	MX_TIM6_Init();
	MX_USART1_UART_Init();
	MX_TIM2_Init();
	
	LCD_Init();  /*  LCD初始化 */
	LCD_Clear(White);
	LCD_SetBackColor(White);   // 背景颜色
	LCD_SetTextColor(Blue);    // 文本颜色
	HAL_TIM_Base_Start_IT(&htim6);  /* 基础定时器6(1ms)中断开启 */
	HAL_UART_Receive_IT(&huart1, &rx, 1);  /* 打开异步串口1通信 */
	HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
	__HAL_TIM_SET_AUTORELOAD(&htim2, 999);  /* 设置频率1Khz */ 
	__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, 500); /* 设置占空比为50% = 500/1000 */ 
	
  while (1)
  {
	LED_Proc();
    LCD_Proc();
	Key_Proc();
	Uart_Proc();
  }
  return 0;
}

下面是关与源代码的链接:
13届省赛第一场

希望可以帮助到大家。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值