2024年蓝桥杯嵌入式省赛笔记(模块搭建以及初始代码)

工程准备工作

选择芯片为STM32G431RBT6

 

 

 

1 LED灯

 1)因为控制LCD屏幕的引脚包括了PC8~PC15所以避免与LED冲突才设置了锁存器,PD2置高则·会将PC8~PC15的电平状态通到LED灯右边,反之则锁住。

2),由比赛官方的原理图可以知道 PC8~PC15引脚加锁存器控制引脚PD2控制,并且这八个LED另一端都接到了高电平,所以我们要让LED点亮要让LED灯另一端为低电平用到 HAL_GPIO_WritePin(); 函数控制 PC8~PC15 引脚的高低电平并且将PD2置为高电平使能锁存器,从而把PC8-PC15的电平输入到LED另一边,再通过锁存器保存LED右边的电平信号。

CubeMx配置部分

 选中PC8~PC15选择GPIO_Output(只是一个完整的工程,所以其他引脚设置,不必在意)

并且将输出电平默认为高 

 

因此代码部分

void LED_DISPLAY(unisgned int LED_STA)
{
    //先将灯全部关闭,再输入要更新(设置)的LED状态
    HAL_GPIO_WritePin(GPIOC ,GPIO_PIN_ALL ,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOC ,(LED_STA << 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_STA = 0x01 则是LED1灯亮其他灭。

 2 LCD

1) 由PC0~PC15 、PB8 、PB5、PB9、PA8控制

CubeMax配置将对应的引脚设置为GPIO-Output就行了然后比赛官方会有LCD的驱动程序

在HAL例程中的inc和src中找到 lcd.c 、lcd.h 、fonts.h三个文件就行了,然后复制到自己的工程

3 按键

        一共有四个按键 ,分别接到了 PB0 ,PB2 ,PB3 ,PA0 对应B1 ,B2 ,B3 ,B4

在CubeMX中选中对应引脚设置为GPIO_Input模式,其他不用设置了。

这里建议用定时器中断检测按键是否摁下。

        如果按键按下则是低电平。

当然别忘记开启定时器中断了

HAL_TIM_Base_Start_IT(&htimx); 如HAL_TIM_Base_Start_IT(&htim15);

        选择一个题目没有用到的定时器

我的预分频 Prescaler选择8000 - 1 ,自动重装载寄存器(Counter Period)选择100-1

用于按键的定时器的中断别忘记勾上了 

Keil中

创建一个 处理中断的文件 interrupt.c

注释中消抖处理原理是第一次 key_judge = 0 判断按键是否按下,若按下则为1(这是第一次中断做的)

第二次进入中断已经经过了10ms,然后再继续判断按键状态,若还是按下则认为是按键按下,并是key_short = 1(时钟频率是80MHz)

#include "interrupt.h"

struct key keys[4] = {0 ,0 ,0};
//中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM15)
	{
        //接收保存按键状态
		keys[0].key_sta = HAL_GPIO_ReadPin(GPIOB ,GPIO_PIN_0);
		keys[1].key_sta = HAL_GPIO_ReadPin(GPIOB ,GPIO_PIN_1);
		keys[2].key_sta = HAL_GPIO_ReadPin(GPIOB ,GPIO_PIN_2);
		keys[3].key_sta = HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_0);
		
		for(int i = 0 ;i < 4 ;i++)
		{
			switch (keys[i].key_judge)
			{
                //按键是否按下
				case 0:
					if(keys[i].key_sta == 0)
					{
						keys[i].key_judge = 1;
					}
				break;
                //消抖处理,若还是低电平,这判断为按键按下
				case 1:
					if(keys[i].key_sta == 0)
					{
						keys[i].key_short = 1;
						keys[i].key_judge = 2;
					}
					else
					{
						keys[i].key_judge = 0;
					}
				break;
             //若还是低电平,则就key_judge不置0,继续等待松手,避免长按造成多次响应
				case 2:
					if(keys[i].key_sta == 1)
					{
						keys[i].key_judge = 0;
					}
				break;
				
			}
		}
		
	}
}

对应头文件interrupt.h

#ifndef __INTERRUPT_H
#define __INTERRUPT_H

#include "main.h"
#include "stdbool.h"
struct key
{
    /*根据judge值做出相应的判断
	  0 :判断按键是否为按下
      1 :继续判断按键是否按下,若按下则short = 1
      2 :松手检测*/
    int key_judge;
    /*每次进入中断就读取按键的电平状态*/
	bool key_sta;
    /*按键短按标志位*/
	bool key_short;

};



#endif

 这里需要根据需求写代码,由于当时刷的题目并没有要求按键长按和按两下的操作,所有我只写了短按的操作

 4 ADC模块

原理图中有两个电位器 分别接到了 PB15(R37)和PB12(R38)

这个最简单选择电位器所接到的引脚选择ADCx_INx,然后在ADCx对应的通道上选择single-ended

 

 

keil代码部分

这样就返回了电压值0~3.3

#include "MyADC.h"

double GET_ADC(ADC_HandleTypeDef *pin)
{
	unsigned int adc;
    //开启adc
	HAL_ADC_Start(pin);
    //调用函数获取adc值
	adc = HAL_ADC_GetValue(pin);
	
	return adc*3.3/4096;
}

5 定时器

 5.1 定时器生产PWM波

本例用PA7输出PWM

选中PA7并挑选一个CHx,建议用TIM3_CH2 ,带N的是生成互补的PWM考试基本上用不到

根据所选择的定时器和通道配置模式

时钟源选择internal Clock ,在相应通道上选择PWM generation CH2 

pwm波的频率 = (时钟源频率)/(预分频数 * 重装载值) 

如果我们要设置 PWM波频率为 1000Hz 则 (预分频数 * 重装载值)  = 80M/1k =80000

建议重装载值选择 100 这样比较寄存器值就是占空比(这是在题目要求占空比精度为1及以上的时候,偶尔会有带小数的情况) 

这是默认初始比较值,可以根据题目需求设置初始比较寄存器值 

 

然后在主函数初始化时开启PWM

	HAL_TIM_PWM_Start(&htim3 ,TIM_CHANNEL_2);

5.2 定时器输入捕获

        先选定一个定时器通道作为输入捕获的通道,拿十四届蓝桥杯省赛为例,要求PA7引脚作为输入捕获的通道,用于捕获来自PA1的PWM波形.

         然后时钟源选择内部时钟,将对应通道选为 input capture direct mode .预分频选小一点,自动重装载值选择默认的最大值

         输入捕获通道就选默认的上升沿触发,输入捕获原理是当捕获通道检测到上升沿时,开始计数,当遇到第二个上升沿时触发捕获的中断,然后我们在中断函数里面获取定时器计数的值,然后将定时器时钟频率除以计数值就是所测量的PWM的频率。

        代码如下

只需将frq外部应用就行了 

uint16_t tim_counter = 0 ,frq = 0;

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    //确认定时器
	 if(htim -> Instance == TIM3)
	 {
    //获取计数值
		 tim_counter = HAL_TIM_ReadCapturedValue(htim ,TIM_CHANNEL_2);、
    //将计数值清零
		 __HAL_TIM_SetCounter(htim ,0);
    //求出频率
		 frq = (80000000/80)/tim_counter;
    //继续开启捕获中断
		 HAL_TIM_IC_Start(htim ,TIM_CHANNEL_2);
		 
	 }

}

        在main.c初始化中使用HAL_TIM_IC_Start_IT(&htim3 ,TIM_CHANNEL_2);开启捕获中断 

 6 USART串口

 在connectivity中找到对应的串口

这里用USART1

选择Asynchronous ,波特率根据需求选择(题目基本上是9600)

并且开启中断 

 

串口发送

 主要使用HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout)

可以参考我写的方式

char text[30];
sprintf(text ,"your string");
HAL_UART_Transmit(&huart1 ,(uint8_t *)text ,strlen(text) ,50);

 串口接收

和按键一样,写在interrupt.c

这里是值接收一个字符的写法

其中 HAL_UART_Receive_IT(&huart1 ,&rx_data ,1);可以写在主函数前作为开启串口中断的函数

uint8_t rx_flag = 0;
uint8_t rx_data;
char rx_da;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(rx_flag == 0)
	{
	    HAL_UART_Receive_IT(&huart1 ,&rx_data ,1);
	    rx_da = rx_data;
	    rx_flag = 1;
	}
	
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值