第六届蓝桥杯嵌入式省赛程序设计题解析(基于HAL库)

本文详细介绍了如何在STM32G431RBT6开发板上利用Keil5和CubeMX进行环境配置,包括RTC时钟、ADC电压测量、USART通信、LED控制和LCD显示,同时涉及了按键功能、E2PROM存储和Systick定时器的应用。
摘要由CSDN通过智能技术生成

一、题目分析

需要用到的环境以及题目所要求设计的模块

开发板:CT117E-M4 (STM32G431RBT6)

开发环境:Keil5(MDK)+CubeMX

设计任务及要求如下:

1、RTC实时时钟

2、ADC测量R37的输出电压

3、USART串口

4、LED闪烁、LCD显示

5、按键功能

       

二、CubeMX配置

老规矩,我们还是在官方给的液晶驱动程序中的MDK5_LCD_HAL文件中进行修改,再将官方给的i2c_hal.c和i2c_hal.h两个文件分别加入到Src和Inc中,这样可以保留一些最原始的配置,也可以节省一点时间。

1、配置LED和按键

2、配置RTC实时时钟

3、配置ADC

4、配置USART串口

5、配置Project Manager

三、相关代码实现

1、函数相关定义

#include "lcd.h"
#include "stdio.h"
#include "string.h"
#include "i2c_hal.h"

_Bool ui = 0;
_Bool led1_flag = 1;

float r37_volt = 0;
float k = 0.1;

RTC_TimeTypeDef T;
RTC_DateTypeDef D;

u8 time[3] = {0};
u8 time_valid[3] = {0};

u8 tx_buff[20];
u8 rx_buff[20];
u8 rx_date[2];
u8 rx_pointer = 0;

u32 lcd_tick = 0;
u32 key_tick = 0;
u32 led_tick = 0;
u32 rx_tick = 0;
u32 tx_tick = 0;

u8 key3_flag = 0;
u8 led_ctrl = 0x00;

u32 adc_value = 0;

2、LCD模块

void LCD_Proc()
{
	if(uwTick - lcd_tick < 200)
		lcd_tick = uwTick;
	u8 LCD_Buff[20];
	if(ui == 0)
	{
		sprintf((char *)LCD_Buff,"   V1:%4.2fV",r37_volt);
		LCD_DisplayStringLine(Line2,LCD_Buff);
		sprintf((char *)LCD_Buff,"   k:%2.1f",k);
		LCD_DisplayStringLine(Line4,LCD_Buff);
		if(led1_flag == 0)
			sprintf((char *)LCD_Buff,"   LED:%s  ","OFF");
		else
			sprintf((char *)LCD_Buff,"   LED:%s  ","ON");		
		LCD_DisplayStringLine(Line6,LCD_Buff);
		sprintf((char *)LCD_Buff,"   T:%02d-%02d-%02d",T.Hours,T.Minutes,T.Seconds);
		LCD_DisplayStringLine(Line8,LCD_Buff);
		LCD_DisplayStringLine(Line9, (unsigned char *)"                   1");
		
		
	}
	else
	{
		sprintf((char *)LCD_Buff,"      Setting");
		LCD_DisplayStringLine(Line3,LCD_Buff);
		sprintf((char *)LCD_Buff,"     %02d-%02d-%02d",time[0],time[1],time[2]);
		LCD_DisplayStringLine(Line5,LCD_Buff);
		LCD_DisplayStringLine(Line9, (unsigned char *)"                   2");
	}
}

3、LED模块

void LED_Display(u8 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);
}


void LED_Proc()
{
	if(uwTick - led_tick < 200) return;
	led_tick = uwTick;
	if((r37_volt > (3.3 * k)) && led1_flag)
	{
		if(led_ctrl & 0x01)
			led_ctrl &= ~0x01;
		else
			led_ctrl |= 0x01;
	}
	else
		led_ctrl &= ~0x01;
	LED_Display(led_ctrl);
}

4、RTC模块

//RTC实时时钟
void RTC_Proc()
{
	HAL_RTC_GetTime(&hrtc,&T,RTC_FORMAT_BIN);
	HAL_RTC_GetDate(&hrtc,&D,RTC_FORMAT_BIN);
}

5、ADC模块

//R37的电压输入
void ADC_Proc()
{
	HAL_ADC_Start(&hadc2);
	adc_value = HAL_ADC_GetValue(&hadc2);
	r37_volt = adc_value * 3.3 / 4095.0f;
}

6、USART模块

//printf重定向输出到串口
struct __FILE
{
  int handle;
 
};
FILE __stdout;
int fputc(int ch, FILE *f)
{
	HAL_UART_Transmit(&huart1,(u8 *)&ch,1,50);
	return ch;
}


//串口发送
void TX_Proc()
{
	if(uwTick - tx_tick < 500) return;
	tx_tick = uwTick;
	if(T.Hours == time_valid[0] && T.Minutes == time_valid[1] && T.Seconds == time_valid[2])
	{
		printf("%4.2f+%3.1f+%02d%02d%02d\n",r37_volt,k,time_valid[0],time_valid[1],time_valid[2]);
	}
}


//串口接收
void RX_Proc()
{
	if(uwTick - rx_tick < 50) return;
	rx_tick = uwTick;
	if(rx_pointer == 5 && rx_buff[0] == 'k' && rx_buff[1] == '0' && rx_buff[2] == '.' && rx_buff[4] == '\n')
	{
		if(rx_buff[3]>='0' && rx_buff[3]<='9')
		{
			k = (rx_buff[3] - '0') / 10.0f;
			printf("ok\n");
			E2PROM_Write(0x01,rx_buff[3] - '0');
		}
		else
		{
			printf("请输入正确的数字!");
		}
	}
	else if(rx_pointer > 0) 
	{
		printf("输入格式有误,请重新输入!\r\n");
	}
	rx_pointer = 0;
	memset(rx_buff,'\0',sizeof(rx_buff));
	
}


//中断回调函数---接收数据
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	rx_tick = uwTick;
	HAL_UART_Receive_IT(&huart1,rx_date,1);
	rx_buff[rx_pointer++] = rx_date[0];
}

7、KEY模块

#define k1 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)
#define k2 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)
#define k3 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)
#define k4 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)
#define key k1|(k2<<1)|(k3<<2)|(k4<<3)|0xf0

u8 Tag;
u8 Cnt;

void KEY_Read()
{
	u8 keydate = (key) ^ 0xff;
	Tag = keydate & (keydate ^ Cnt);
	Cnt = keydate;
}

void KEY_Proc()
{
	if(uwTick - key_tick < 10) return;
	key_tick = uwTick;//过滤掉按键产生的抖动,10ms执行一次
	KEY_Read();
	if(Tag & 0x01)
	{
		led1_flag =! led1_flag;
	}
	if(Tag & 0x02)
	{
		ui =! ui;
		LCD_Clear(White);
		time_valid[0] = time[0];
		time_valid[1] = time[1];
		time_valid[2] = time[2];
	}
	if(Tag & 0x04)
	{
		key3_flag = (key3_flag + 1) % 3;
	}
	if(Tag & 0x08)
	{
		time[key3_flag] ++;
		if(time[0] == 24)
			time[0] = 0;
		if(time[1] == 60)
			time[1] = 0;
		if(time[2] == 60)
			time[2] = 0;
	}
}

四、总结

这届赛题作为蓝桥杯最开始举行的赛题,知识面涉及的还是比较全面的,其中还穿插了E2PROM和USART,这两个考点我认为是最具有挑战性的,以及调节时间的闪烁(这里我没有写出来,如过想要更加细节的实现效果,请转b站老王),我这里也是听了他的讲解才知道Systick系统定时器还能这么用,都不用开TIM定时器了,节省了很多代码,最终也是顺利实现的本届程序设计题的所有功能。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值