首页 > 其他分享 >【总结(三)】单片机重点知识总结记录(串口重定向+按键消抖+延时)

【总结(三)】单片机重点知识总结记录(串口重定向+按键消抖+延时)

时间:2024-12-24 23:56:04浏览次数:6  
标签:总结 HAL void 消抖 Value return Key 串口 GPIO

一.串口重定向

串口重定向代码如下

注意:

  • 要添加头文件include "stdio.h"
  • 要勾选微库,即Use MicroLIB
/**********重定向************/
//串口1
int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
  return ch;
}

int fgetc(FILE * f)
{
  uint8_t ch = 0;
  HAL_UART_Receive(&huart1,&ch, 1, 0xffff);
  return ch;
}
/**********************************/

二.按键消抖算法

延时消抖

uint8_t Key_GetValue(void)
{
	uint8_t value = 0;
	if(HAL_GPIO_ReadPin(GPIOA,KEY_A_Pin) == GPIO_PIN_SET)value = 1;
	if(HAL_GPIO_ReadPin(GPIOA,KEY_B_Pin) == GPIO_PIN_SET)value = 2;
	if(HAL_GPIO_ReadPin(GPIOA,KEY_C_Pin) == GPIO_PIN_SET)value = 3;
	if(HAL_GPIO_ReadPin(GPIOA,KEY_D_Pin) == GPIO_PIN_SET)value = 4;
	return value;
}

uint8_t Key_Scan(void)
{
	uint8_t key_number = 0;
	key_number = Key_GetValue();
	if(key_number != 0)
	{
		mdelay(20);
		while( Key_GetValue() != 0);
		mdelay(20);
		return key_number;
	}
	return 0;
}

三行消抖

主要消抖算法如下:

void Key_RemoveShake(void)
{
	Key_Value = Key_GetValue();//获取按下键值
	Key_Down = Key_Value & (Key_Value ^ Key_Last);//获取下降沿
	Key_Up = ~Key_Value & (Key_Value ^ Key_Last);//获取上升沿
	Key_Last = Key_Value;//键值覆盖
}

若按键共阴(公共端为地),则按下时为下降沿,只需判断下降沿是否存在即可判断是否有按键按下:

uint8_t Key_Press(void)
{
	return Key_Down ? Key_Value : 0;
}

完整代码如下:

//              KEY1   PD8
//              KEY2   PD9
//              KEY3   PD10
//              KEY4   PD11
//              KEY5   PD12
//              KEY6   PD13

#include "Key.h"

uint8_t Key_Value,Key_Down,Key_Up,Key_Last;

uint8_t Key_GetValue(void)
{
	if(HAL_GPIO_ReadPin(GPIOD,KEY1_Pin) == 0)
		return 1;
	if(HAL_GPIO_ReadPin(GPIOD,KEY2_Pin) == 0)
		return 2;
	if(HAL_GPIO_ReadPin(GPIOD,KEY3_Pin) == 0)
		return 3;
	if(HAL_GPIO_ReadPin(GPIOD,KEY4_Pin) == 0)
		return 4;
	if(HAL_GPIO_ReadPin(GPIOD,KEY5_Pin) == 0)
		return 5;
	if(HAL_GPIO_ReadPin(GPIOD,KEY6_Pin) == 0)
		return 6;
	return 0;
}

//以下函数需要在中断中使用,推荐10ms定时器中断
void Key_RemoveShake(void)
{
	Key_Value = Key_GetValue();//获取按下键值
	Key_Down = Key_Value & (Key_Value ^ Key_Last);//获取下降沿
	Key_Up = ~Key_Value & (Key_Value ^ Key_Last);//获取上升沿
	Key_Last = Key_Value;//键值覆盖
}

uint8_t Key_Press(void)
{
	return Key_Down ? Key_Value : 0;
}

三.非阻塞延时

阻塞式延时

直接循环解决 

void delay(u16 num)
{
  u16 i,j;
  for(i=0;i<num;i++)
    for(j=0;j<10000;j++);
}

定时器中断实现 

void udelay(int us)
{
    extern TIM_HandleTypeDef        htim1;
    TIM_HandleTypeDef *hHalTim = &htim1;

    uint32_t ticks;
    uint32_t told, tnow, tcnt = 0;
    uint32_t reload = __HAL_TIM_GET_AUTORELOAD(hHalTim);

    ticks = us * reload / (1000);  /* 假设reload对应1ms */
    told = __HAL_TIM_GET_COUNTER(hHalTim);
    while (1)
    {
        tnow = __HAL_TIM_GET_COUNTER(hHalTim);
        if (tnow != told)
        {
            if (tnow > told)
            {
                tcnt += tnow - told;
            }
            else
            {
                tcnt += reload - told + tnow;
            }
            told = tnow;
            if (tcnt >= ticks)
            {
                break;
            }
        }
    }

}

特别注意:HAL_Delay()也算是阻塞式延时,虽然它使用的是滴答定时器中断来进行读数,但是其延时过程仍为忙等待过程,因此仍是阻塞式延时。

非阻塞延时

         实际上裸机应该是不能实现真正意义上的非阻塞延时的,即处理器在延时过程中去完成别的任务,但是一般来说换个名字我们可能更熟悉——时间片轮询。

        当我们配置一个毫秒级的定时器中断时,在其中定义一个时间标志,进行自增或自减后判断是否到达对应时间然后在函数外执行相应功能。

uint16_t Timer_1000ms = 0,Timer_1000ms_Flag = 0;

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim == (&htim2))
    {
        ++Timer_1000ms;
        if(Timer_1000ms >= 1000)
        {
            Timer_1000ms_Flag = 1;
            Timer_1000ms = 0;
        }
    }
}

void Task1()
{
    //...
}

int main(void)
{
    while(1)
    {
        if(Timer_1000ms_Flag == 1)
        {
            Task1();
            Timer_1000ms_Flag = 0;
        }
        
    }
}

标签:总结,HAL,void,消抖,Value,return,Key,串口,GPIO
From: https://blog.csdn.net/2203_75993546/article/details/143157930

相关文章

  • LeetCode题练习与总结:翻转对--493
    一、题目描述给定一个数组 nums ,如果 i<j 且 nums[i]>2*nums[j] 我们就将 (i,j) 称作一个重要翻转对。你需要返回给定数组中的重要翻转对的数量。示例1:输入:[1,3,2,3,1]输出:2示例2:输入:[2,4,3,5,1]输出:3注意:给定数组的长度不会超过50000。......
  • LeetCode题练习与总结:构造矩形--492
    一、题目描述作为一位web开发者,懂得怎样去规划一个页面的尺寸是很重要的。所以,现给定一个具体的矩形页面面积,你的任务是设计一个长度为L和宽度为W且满足以下要求的矩形的页面。要求:你设计的矩形页面必须等于给定的目标面积。宽度 W 不应大于长度 L ,换言之,要求 L>......
  • GIS 文件格式 及 常规应用总结
    文章目录GIS中常见的文件格式以及再次打开注意事项资源网站应用地图瓦片数据地形数据倾斜模型QGS应用矢量数据格式栅格数据格式数据库格式更改图层样式更改图层范围导出为不同分辨率图片导出矢量文件直接保存图层通过打印布局导出使用插件导出tiff图片前端处理方......
  • C++11特性总结
    C++11包括大量的新特性:主要特征像lambda表达式和移动语义,实用的类型推导关键字auto,更简单的容器遍历方法,和大量使模板更容易使用的改进。这一系列教程将包含所以以上特性。  很明显,C++11为C++带来了大量的新特性。C++11将修复大量缺陷和降低代码拖沓,比如lambda表达式的支持......
  • 最终总结
    SpringBootWeb案例前端web开发:技术描述HTML用于构建网站的基础结构的css用于美化页面的,作用和化妆或者整容作用一样JavaScript实现网页和用户的交互Vue主要用于将数据填充到html页面上的Element主要提供了一些非常美观的组件Nginx一款web服务器软......
  • 学期总结——插入排序(从io,循环到类,时间复杂度,循环不变式)
    以插入算法的实现为例,从一开始写下思路,到证明循环不变式,从完全在主函数中书写,到把某些步骤写成函数,再到把这一算法写成类,而后分析时间复杂度目录算法的实现思路(循环不变式)做法完全在主函数中书写(实现一)将“交换”写成函数将“排序”写成函数将几乎所有步骤都写成函数(......
  • 2024集训D11总结
    集训D11总结模拟赛总结T1题意\(k\)个大小为\(s_i\)的连通块,用\(k-1\)条边联通,设\(d_i\)为第\(i\)个连通块的度数(只考虑连的\(k-1\)条边).每种连边方案的权值为\(\prod\limits_id_i\),求所有方案的权值和.题解这个性质看一眼就能联想到经典的图......
  • 如何用SSCOM测试串口
    本文参考《工业计算机硬件技术支持手册》第2章内容编写。一)准备:先按要求将待测试的串口和工装机上的串口连接起来。连线及其他具体操作内容有点多,请参阅《工业计算机硬件技术支持手册》第2章。二)测试:1,打开SSCOM串口测试软件,选择需要测试的串口。2,点击“打开串口”。注:......
  • Socat 命令总结
    事以密成,语以泄败。导航介绍基本语法用法示例回显输入回显输入overTCP/UDP正向连接shell反向连接shell端口转发网络服务文件传输管道传输加密传输TUN网络杂项介绍Socat是一个功能强大的网络工具(相当于是增强版netcat),它可以在两个数据流之间建立......
  • AI科研助手开发总结:向量与数据权限的应用(一)
    一、业务场景1.1概述大语言模型(LLM)作为自然语言处理领域的核心技术,具有丰富的自然语言处理能力。LLM在处理特定领域的知识时存在一定的局限性,特别对于垂直领域内,或者企业内部等私域专属知识。通常通常采用向量数据方案对知识进行扩充。向量数据库在AI应用中提供了强大的数......