【备战蓝桥杯】考前快速大纲

ADC采集

  1. CubeMX配置
    比如题目要求使用R37来调节输出的占空比(14th省赛),那就需要用到ADC采集。
    在这里插入图片描述
    在这里插入图片描述
  2. 代码
double getADC(ADC_HandleTypeDef *hadc)
{
	unsigned int value = 0;
	//开启转换ADC并且获取值
	HAL_ADC_Start(hadc);
	value = HAL_ADC_GetValue(hadc);
	//ADC值的转换 3.3V是电压 4096是ADC的精度为12位也就是2^12=4096
	return value*3.3/4096;
}

ADC的hal库函数在 stm32g4xx_hal_adc.h拉到最后。
在这里插入图片描述

输入捕获

  1. CubeMX配置
    开启定时器某一个通道的“输入直接比较”模式。
    在这里插入图片描述
  2. 代码
    比如题目要求“通过PA7来测量输入信号的频率”(14th省赛)。
/* 定时器回调函数*/
uint16_t f = 0;
// 保存TIMx_CCR的值
uint32_t  cclValue = 0;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
//	// 保存TIMx_CCR的值
//	uint32_t  cclValue = 0;
	// 定时器3时执行该段
	if(htim->Instance == TIM3)
	{
		cclValue = __HAL_TIM_GET_COUNTER(&htim3);
		__HAL_TIM_SetCounter(&htim3, 0);
		f = 1000000 / cclValue;
		HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_2); // 这里使用中断,而非轮询方法
	}
}

  1. 定时功能
    插播一下,比如题目要求“保持时间超过2s的输入信号才纳入统计”,那需要定时器来实现2s定时。
    使用刚才那个定时器3,把它的内部时钟源打开。
    在这里插入图片描述
    在stm32g4xx_it.c 中找到 tim3的句柄。
void TIM3_IRQHandler(void)
{
  /* USER CODE BEGIN TIM3_IRQn 0 */

  /* USER CODE END TIM3_IRQn 0 */
  HAL_TIM_IRQHandler(&htim3);
  /* USER CODE BEGIN TIM3_IRQn 1 */
	if(sysCount[2] < 2000) // 既然tim3已经配置好了是1Hz,那就计数2k次来表示2s
	sysCount[2]++;
  /* USER CODE END TIM3_IRQn 1 */
}

eeprom读写(IIC通信)

EEPROM可以简单理解为是一个掉电不丢失的存储模块,相对于g431,它是一个从机,所以呢,需要用软件IIC来进行主从机的通信。

  1. CubeMX配置
    先将官方资源包里的“i2c - hal.c”和“i2c - hal.h”复制到我们的工程目录下,可以看到里面已经对 PB6 和PB7 做好了初始化,那就将PB6、PB7配置为输出(相当于IIC通信中的SCL和SDA线)。
    另外,题目要求“电压参数写入E2PROM内部地址0,频率参数写入E2PROM内部地址1”(13th国赛),根据E2PROM手册对每一位对应解读,其bit0为R/W,bit3-1为从机地址。
  2. 代码
/***************************************
* 函数功能:读取eeprom相应位置的值
* 函数参数:unsigned char ucAddr:读取的地址
* 函数返回值:ucRes:读取到的值
***************************************/
unsigned char readEepromByBit(unsigned char ucAddr)
{
	unsigned char ucRes = 0;
	
	//发送起始信号
	I2CStart();
	//发送设备地址
	I2CSendByte(0xa0);
	//等待应答
	I2CWaitAck();
	//发送读取地址
	I2CSendByte(ucAddr);
	//等待应答
	I2CWaitAck();
	//发送停止信号
	I2CStop();
	
	//发送起始信号
	I2CStart();
	//发送读取数据命令
	I2CSendByte(0xa1);
	//等待应答
	I2CWaitAck();
	//接收数据
	ucRes = I2CReceiveByte();
	//发送应答
	I2CSendNotAck();
	//发送停止信号
	I2CStop();
	
	return ucRes;
}

/***************************************
* 函数功能:向eeprom对应地址写入数据
* 函数参数:unsigned char ucAddr:写入的地址
*			unsigned char ucData:写入的数据
* 函数返回值:无
***************************************/
void writeEepromByBit(unsigned char ucAddr,unsigned char ucData)
{
	//发送起始信号
	I2CStart();
	//发送设备地址
	I2CSendByte(0xa0);
	//等待应答
	I2CWaitAck();
	
	//发送写入地址
	I2CSendByte(ucAddr);
	//发送应答
	I2CSendAck();
	//发送写入数据
	I2CSendByte(ucData);
	//等待应答
	I2CWaitAck();
	
	//发送停止信号
	I2CStop();
}

uart串口通信

题目要求“使用USB转串口功能完成查询功能:PC端通过串口调试助手向设备发送字符‘X’返回当前频率参数,串口通信波特率设置9600”(13th国赛)。除了要安装串口调试助手,我们还要在CubeMX中打开任意一个USART。

  1. CubeMX配置
    在这里插入图片描述
    使用USART1,将Mode设置为异步,下面的参数设置将波特率改为题目要求的9600。
    NVIC Settings 打开串口接收中断。
  2. 代码
    (1)串口发送
/* 串口发送函数原型 */
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout)

/* 举个使用例子 */
char usartTemp[10];
sprintf(usartTemp, "X:%d\r\n", freq);
HAL_UART_Transmit(&huart1,(uint8_t*)usartTemp,sizeof(char)*strlen(usartTemp),10); //第二个参数强制转换uint8_t*
/* 这样串口助手就可以收到G431发送过来的信息了,显示在接收区。 */

(2)串口接收

/* 串口接收中断函数原型 */
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

/* 使用实例 */

/* 初始化打开接收中断*/
HAL_UART_Receive_IT(&huart1,(uint8_t *)&_ucRxbuff,sizeof(_ucRxbuff)); 

/* 逻辑处理函数 */
void uart_process(void)
{
	if(ucRxbuff[0] == 'X')
	{
		sprintf(usartTemp, "X:%d\r\n", freq);
	}
}

/* LCD显示 */
sprintf(displayTemp[1],"      X=%d      ", freq);
LCD_DisplayStringLine(Line3,(uint8_t*)displayTemp[1]);

按键消抖、长短按

在之前的文章《软硬件对按键消抖》中有提到两种消抖方法:逻辑运算消抖和定时器中断消抖。二者的区别以及优劣势也都做了分析。
这里再附一种状态机思想,可以同时实现按键消抖、长短按以及双击单击(当然,要搭配定时器中断来使用)。

/* .h */
// 按键结果结构体 需要注意的是任意俩者不能够同时为1
struct keys{
	//按键单次按下  0-无效   1-按键按下
	int flag;
	//双击按键的标志 0-无效  1-双次按下
	int doubleFlag;
	//长按按键的标志 0-无效   1-长按
	int longFlag;
};

//按键状态判断的结构体
struct keyState{
	//记录按键状态机的状态
	unsigned char judgeSate;
	//记录按键的状态
	unsigned char keyState;
	//记录按键是否双击 双击就会计时
	unsigned char doubleClickTimerFlag;
	//记录按键按下的时间
	int keyTime;
	//记录按键双击的时间
	unsigned char doubleClickTime;
};

/*@copyright 博主:黑心萝卜三条杠
*/
//定义一个按键结构体数组变量 其中包含按键是否按下  是否长按  是否双击
struct keys key[4] = {0,0,0,0};

/****************************************************************************************************
 * 函数功能:按键扫描函数 注意此函数放在定时器中断(10ms)中的使用效果最佳 否则双击与长按会出现问题
 * 函数参数:无
 * 函数返回值:无 
*****************************************************************************************************/
void scanKeyUseStructAndTime(void)
{
	static struct keyState _key[4];
	
	//获取按键的最新状态
	_key[0].keyState = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
	_key[1].keyState = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
	_key[2].keyState = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
	_key[3].keyState = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
	
	//处理按键的最新状态
	for(int i=0;i<4;i++){
		switch (_key[i].judgeSate){
			//按键第一次按下
			case 0:
				if(_key[i].keyState == 0){
					//跳转按键的状态
					_key[i].judgeSate=1;
					//清空按键时间
					_key[i].keyTime=0;
				}
				break;
			//按键第二次按下 两次相隔10ms可以起到消抖作用	
			case 1:
				//按键再次按下 跳转按键状态
				if(_key[i].keyState == 0)
					_key[i].judgeSate=2;
				//上一次按键按下是抖动按下 属于无效状态 应该退回最开始的状态
				else 
					_key[i].judgeSate=0;
				break;
			//确定按键按下后的处理过程
			case 2:
				//等待松开过程,且非长按键
				if((_key[i].keyState==1) && _key[i].keyTime<30){	
					//可能双击按键的第一次,进入计时
					if(_key[i].doubleClickTimerFlag == 0) {
						_key[i].doubleClickTimerFlag = 1;
						_key[i].doubleClickTime = 0;
					}
					//在计时范围内又按了一次
					else{
						key[i].doubleFlag=1;//双击情况
						_key[i].doubleClickTimerFlag = 0;
					}
					_key[i].judgeSate = 0;
				}
				//松开且是长按键
				else if(_key[i].keyState==1 && _key[i].keyTime>=30)
				{
					_key[i].judgeSate = 0;
					key[i].longFlag = 1;
				
				}
				//按下 且为长按键
				else 
					_key[i].keyTime++;
				break;
		}
		//按键单次按下
		if(_key[i].doubleClickTimerFlag == 1 && _key[i].doubleClickTime >= 25) {
			key[i].flag = 1;
			_key[i].doubleClickTimerFlag = 0;
		}
		//按键双击 双击计时
		else if(_key[i].doubleClickTimerFlag == 1){
			_key[i].doubleClickTime++;
		}
	}
}

相关推荐

  1. 复习二

    2024-04-08 21:18:05       17 阅读
  2. 快速排序板子(备战

    2024-04-08 21:18:05       37 阅读
  3. 准备— — c/c++

    2024-04-08 21:18:05       17 阅读
  4. 备战8.快乐的跳

    2024-04-08 21:18:05       14 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-08 21:18:05       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-08 21:18:05       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-08 21:18:05       20 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-08 21:18:05       20 阅读

热门阅读

  1. Acwing2024蓝桥杯贡献法

    2024-04-08 21:18:05       13 阅读
  2. KVM基础管理命令

    2024-04-08 21:18:05       13 阅读
  3. C++(10): std::map、std::multimap与std::unordered_map

    2024-04-08 21:18:05       10 阅读
  4. VUE 实现路由的基本原理

    2024-04-08 21:18:05       11 阅读
  5. 如何进行Python代码的调试和测试?

    2024-04-08 21:18:05       11 阅读
  6. C# 一种基于 event 和 委托的事件机制

    2024-04-08 21:18:05       14 阅读
  7. pytest中文使用文档----11测试的参数化

    2024-04-08 21:18:05       14 阅读
  8. Llama Index的NodeParser详解

    2024-04-08 21:18:05       14 阅读
  9. 常用查找算法(一)

    2024-04-08 21:18:05       17 阅读