当前位置: 首页 > article >正文

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

一.串口重定向

串口重定向代码如下

注意:

  • 要添加头文件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;
        }
        
    }
}

http://www.kler.cn/a/449202.html

相关文章:

  • 拦截器魔法:Spring MVC中的防重放守护者
  • 贪心算法求解跳跃游戏
  • 维克日记:私密写作新选择,轻松记录生活点滴
  • 功能很强大的单点登录协议 SAML 2.0详解
  • Aec-Library-Website 项目常见问题解决方案
  • Java字符串的|分隔符转List实现方案
  • B6充电器模式
  • Net9为PDF文字替换,使用Spire.PDF版本10.12.4.1360
  • Paddle OCR 中英文检测识别 - python 实现
  • PostgreSQL编译安装教程
  • C++ 的IO流
  • 如何找到一篇文献/论文/会议的引用,以及分清自己使用的引用格式
  • 20241230 机器学习ML -(1)线性回归(scikitlearn)
  • 标贝科技受邀出席2024ADD数据应用场景大会 共议数据要素发展新契机
  • 基于SSM+Vue的心理咨询问诊系统+LW示例参考
  • 基于Vue.js和SpringBoot的笔记记录分享网站的设计与实现(文末附源码)
  • PHP 新手教程:从入门到构建简单网页
  • 感知机与逻辑回归的异同点
  • 【CDN】快速了解CDN是什么?以及工作原理和应用场景
  • 事件响应基本流程
  • Why SAP TM?
  • 《深入浅出 Servlet:Java Web 开发的基石》(一)
  • Adversarial Machine Learning(对抗机器学习)
  • 【国产NI替代】基于STM32+FPGA的8振动+4温度(16bits)数据采集板卡解决方案,支持全国产
  • [创业之路-207]:《华为战略管理法-DSTE实战体系》- 6-什么是目标管理、什么是过程管理、什么是闭环管理?
  • Docker 入门:如何使用 Docker 容器化 AI 项目(一)