STM32_HAL Freertos按键控制LED

设置GPIO引脚

根据电路图,K0为用户按键,连接在PA0引脚,当K0按下时接地,引脚电平低电平。在CubeMX中设置PA0,将IO设置为输入,上拉(上拉外部悬空时,引脚为高电平)。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

添加Freertos任务

在freertos任务中,添加按键任务,通过myTask_Key不断读入PA0的引脚状态。添加一个消息队列用来给LED任务传递读取的内容。
在这里插入图片描述

完成任务代码

osMessageQId PWM_QueueHandle;

osMessageQDef(PWM_Queue, 16, uint16_t);
PWM_QueueHandle = osMessageCreate(osMessageQ(PWM_Queue), NULL);
void StartTask_Key(void const * argument)
{//按键读取状态并发送消息
  /* USER CODE BEGIN StartTask_Key */
  /* Infinite loop */
  for(;;)
  {
		if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==0){
			osDelay(20);//消抖
			if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==0){
				while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==0){
				}
				osMessagePut(PWM_QueueHandle,0x01,1);
			}
			
		}		
  }
  /* USER CODE END StartTask_Key */
}
/* USER CODE END Header_StartTask_LED */
void StartTask_LED(void const * argument)
{
  /* USER CODE BEGIN StartTask_LED */
  /* Infinite loop */
	
	int LEDDelay = 100;
	osEvent QueueEvent;
	
  for(;;)
  {
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
		osDelay(LEDDelay);
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
		osDelay(LEDDelay);
		
		QueueEvent= osMessageGet(PWM_QueueHandle,1);
		if((uint8_t)QueueEvent.value.v == 0x01)
		{
			LEDDelay+=100;
		}
  }
}

消息队列

Freertos中提供了消息队列用于传递消息。以下是消息队列常用函数

//1、创建消息队列
osMessageQId osMessageCreate (const osMessageQDef_t *queue_def, osThreadId thread_id);
 
//2、往消息队列里面写消息
osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec);
 
//3、从消息队列中获取消息,把消息拿走
osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec);
 
//4、从消息队列中获取一个消息,但是不拿走,只是看一眼
osEvent osMessagePeek (osMessageQId queue_id, uint32_t millisec);
 
//5、获取消息队列中的消息数量
uint32_t osMessageWaiting(osMessageQId queue_id);
 
//6、获取消息队列还剩多少空间
uint32_t osMessageAvailableSpace(osMessageQId queue_id);
 
//7、删除消息队列
osStatus osMessageDelete (osMessageQId queue_id)

创建消息队列

/**
* @brief 创建并初始化一个消息队列
* @参数 queue_def     所定义的队列\ref osMessageQ.
* @参数  thread_id    线程ID(一般也用不上就用NULL)
* @返回值 返回消息队列的句柄,也就是消息队列的ID 
*/
osMessageQId osMessageCreate (const osMessageQDef_t *queue_def, osThreadId thread_id)
{
  (void) thread_id;
  
#if( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
     //如果同时支持动态创建和静态创建
  if ((queue_def->buffer != NULL) && (queue_def->controlblock != NULL)) {
    return xQueueCreateStatic(queue_def->queue_sz, queue_def->item_sz, queue_def->buffer, queue_def->controlblock);
  }
  else {
    return xQueueCreate(queue_def->queue_sz, queue_def->item_sz);
  }
#elif ( configSUPPORT_STATIC_ALLOCATION == 1 )
//如果只支持静态创建
  return xQueueCreateStatic(queue_def->queue_sz, queue_def->item_sz, queue_def->buffer, queue_def->controlblock);
#else  
//如果只支持动态创建
  return xQueueCreate(queue_def->queue_sz, queue_def->item_sz);
#endif
}

消息队列的要素:

  uxQueueLength:队列的长度,就是有多少个数据的意思
  uxItemSize:每个数据单元的大小

下面创建一个队列深度为16,每个消息单元为uint8_t的消息队列

//定义消息队列的ID
osMessageQId myQueue01Handle;
 
//定义消息队列的名称,大小,类型
osMessageQDef(myQueue01, 16, uint8_t);
 
//创建消息队列
myQueue01Handle = osMessageCreate(osMessageQ(myQueue01), NULL);

往消息队列中写消息

**
* @简介 往消息队列中写消息
* @参数  queue_id  消息队列的ID.
* @参数  info      消息内容,发送的消息需要强制转化为uint32_t类型
* @参数  millisec  超时时间.
* @返回值 状态信息,是否写入成功
*/
osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec)
{
  portBASE_TYPE taskWoken = pdFALSE;
  TickType_t ticks;
  
  ticks = millisec / portTICK_PERIOD_MS; //超时时间转换为tick单位
  if (ticks == 0) {
    ticks = 1;
  }
  
  //Cortex-M3支持两种操作模式handler模式和thread模式,
  if (inHandlerMode()) { //handler模式就用中断的方式发送消息
    if (xQueueSendFromISR(queue_id, &info, &taskWoken) != pdTRUE) {
      return osErrorOS;
    }
    portEND_SWITCHING_ISR(taskWoken);
  }
  else { //thread模式
    if (xQueueSend(queue_id, &info, ticks) != pdTRUE) {
      return osErrorOS;
    }
  }
  
  return osOK;
}

往消息队列中写个0x08进去,超时时间1ms;

osMessagePut(myQueue01Handle,0x08,1);

从消息队列中获取消息

/**
* @brief 从消息队列中获取一个消息,没消息就等消息
* @param  queue_id  消息队列的ID
* @param  millisec  超时时间
* @retval event 返回event
*/
osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec)
{
  portBASE_TYPE taskWoken;
  TickType_t ticks;
  osEvent event;
  
  event.def.message_id = queue_id;
  event.value.v = 0;
  
  if (queue_id == NULL) {  //找不到消息队列,那就报错
    event.status = osErrorParameter;
    return event;
  }
  
  taskWoken = pdFALSE;
  
  ticks = 0;
  if (millisec == osWaitForever) { //超时时间设置为portMAX_DELAY
    ticks = portMAX_DELAY;
  }
  else if (millisec != 0) {
    ticks = millisec / portTICK_PERIOD_MS; //超时时间转化为TICK单位
    if (ticks == 0) {
      ticks = 1;
    }
  }
  
  if (inHandlerMode()) { //中断里面获得消息
    if (xQueueReceiveFromISR(queue_id, &event.value.v, &taskWoken) == pdTRUE) {
      /* We have mail */
      event.status = osEventMessage;
    }
    else { 
      event.status = osOK;
    }
    portEND_SWITCHING_ISR(taskWoken);
  }
  else {//线程模式获得消息,把消息存到&event.value.v中
    if (xQueueReceive(queue_id, &event.value.v, ticks) == pdTRUE) {
      /* We have mail */
      event.status = osEventMessage;
    }
    else {
      event.status = (ticks == 0) ? osOK : osEventTimeout;
    }
  }
  
  return event;
}

event结构体

typedef struct  {
  osStatus                 status;     ///< status code: event or error information
  union  {
    uint32_t                    v;     ///< message as 32-bit value
    void                       *p;     ///< message or mail as void pointer
    int32_t               signals;     ///< signal flags
  } value;                             ///< event value
  union  {
    osMailQId             mail_id;     ///< mail id obtained by \ref osMailCreate
    osMessageQId       message_id;     ///< message id obtained by \ref osMessageCreate
  } def;                               ///< event definition
} osEvent;

event结构体主要包含3个内容:

status:这个成员用于存储事件或错误的状态码。可能包含有关事件状态或错误信息的信息。
value:这是一个联合体(union),它提供了不同类型的事件值的存储方式:
	v:作为一个32位无符号整数存储事件的数值信息。
	p:作为一个指向 void 类型的指针,用于存储事件或邮件的数据。
	signals:这个成员用于存储信号标志,可能是一些特定的信号标志或标志组。
def:也是一个联合体,用于存储事件的定义信息。
	mail_id:如果是邮件相关的事件,则存储邮件的ID,这个ID可能是通过 osMailCreate 创建的。
	message_id:如果是消息相关的事件,则存储消息的ID,这个ID可能是通过 osMessageCreate 创建的。

消息队列发送与接收实验(传递一个数据)

知道了消息队列的发送和接收函数就可以做一些简单的实验。建两个任务,如果的创建这里不解释,请参考任务创建章节。一个任务往队列中写消息,一个任务从队列中读消息。

//Task02用来往队列中写消息
//按键按下再松开就往队列中发送数据0x08
void StartTask02(void const * argument)
{
 
  for(;;)
  {
 
    if(HAL_GPIO_ReadPin(KEY_1_GPIO_Port,KEY_1_Pin) == GPIO_PIN_RESET)
    {
      HAL_Delay(20);
      while(HAL_GPIO_ReadPin(KEY_1_GPIO_Port,KEY_1_Pin) == GPIO_PIN_RESET);
      osMessagePut(myQueue01Handle,0x08,1);
    }
    osDelay(1);
  }
 
}
 
 
//Task03用来从队列中读消息
//消息内容如果是8的话就发送一些内容出去
//读队列任务也不添加阻塞
void StartTask03(void const * argument)
{
 
  osEvent QueueEvent;
  uint8_t Tx_Buffer[] = "FreeRTOS queue test\r\n";
 
  for(;;)
  {
  
    QueueEvent = osMessageGet (myQueue01Handle, osWaitForever);
    
    if((uint8_t)QueueEvent.value.v == 8)
    {
      HAL_UART_Transmit(&huart1,Tx_Buffer,sizeof(Tx_Buffer),10);
    }
    osDelay(1);
    
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/298401.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

物联网云平台源码,Spring Cloud智慧工地源码,建筑施工智能化管理

智慧工地以物联网云平台为核心&#xff0c;基于智慧工地物联网云平台与现场多个子系统的互联&#xff0c;实现现场各类工况数据采集&#xff0c;存储、分析与应用。通过接入智慧工地物联网云平台的多个子系统板块&#xff0c;根据现场管理实际需求灵活组合&#xff0c;实现一体…

Mac Parallels19.1.0 Install CentOS7.9

0、资源准备 # centos7.9镜像一份 链接: https://pan.baidu.com/s/1acIjUnsTGhk_2cYCZLSoGg?pwd6666 提取码: 6666 --来自百度网盘超级会员v7的分享1、打开PD 2、选择镜像进行安装 指定镜像名称 创建 进行密码设置 安装目的地点开后直接点击完成 网络和主机名称 开…

cad快速看图软件免费版(手机在线cad快速看图)

cad快速看图软件免费版(手机在线cad快速看图) 很多机械设计师日常工作过程中涉及到多种格式的cad图纸&#xff0c;cad图纸大多都需要cad设计软件才能打开&#xff0c;然而很多小伙伴并没有下载相应的cad设计软件&#xff0c;这种情况下如何进行cad快速看图呢&#xff1f; 今天…

【开源项目】WPF 扩展组件 -- Com.Gitusme.Net.Extensiones.Wpf

一、项目简介 Com.Gitusme.Net.Extensiones.Wpf 是一款 Wpf 扩展组件。基于.Net Core 3.1 开发&#xff0c;当前最新 1.0.1 版本。包含 核心扩展库&#xff08;Com.Gitusme.Net.Extensiones.Core&#xff09;、视频渲染&#xff08;Com.Gitusme.Media.Video&#xff09;、串口…

刚学C/C++,使用的是CLion,想要在同一个项目里面运行多个相互独立脚本?

前言&#xff1a; 正常来说&#xff0c;一般一个项目只会有一个程序入口点。C和C程序的入口点是main函数。在一个项目中&#xff0c;只能有一个main函数&#xff0c;否则编译器会不知道从哪个main函数开始执行。 但是&#xff0c;作为初学者&#xff0c;我就是想用CLio…

Redis(Nosql数据库)

目录 一.SQL 与 NoSQL 的区别&#xff1f; 二.Redis Redis 为什么那么快&#xff1f; 三.Redis的安装 安装redis&#xff1a; 创建redis工作目录&#xff1a; 修改redis配置文件&#xff1a; redis-cli 命令行工具&#xff1a; redis-benchmark 测试工具&#xff1a; …

插槽slot涉及到的样式污染问题

1. 前言 本次我们主要结合一些案例研究一下vue的插槽中样式污染问题。在这篇文章中&#xff0c;我们主要关注以下两点: 父组件的样式是否会影响子组件的样式&#xff1f;子组件的样式是否会影响父组件定义的插槽部分的样式&#xff1f; 2. 准备代码 2.1 父组件代码 <te…

Linux驱动开发(1)-最简单的字符设备驱动开发例子

1.简介 字符设备驱动&#xff1a;按照字节流进行读写操作的设备&#xff0c;例如点灯、按键、IIC、SPI、LCD。 Linux系统中一切皆文件&#xff0c;驱动加载成功&#xff0c;就会在/dev目录生成文件&#xff0c;对文件操作&#xff0c;则可实现对硬件操作。应用程序运行在用户…

Vue新手村(一)

目录 1、Vue简介——Vue的特点 2、Vue的第一个页面 3.Vue的简单使用介绍 3.1、{{ }}的使用 3.2、v-text和v-html 3.2.1、v-text和{{ }}的区别 3.2.2、v-html和v-text的区别 3.3、v-on【事件绑定】 3.3.1、绑定事件的语法 3.3.2、语法简化 3.3.3、传参 3.4、v-show和…

excel统计分析——两因素有重复方差分析

参考资料&#xff1a;生物统计学 无重复观测值的两因素方差分析只能研究两个因素的主效应&#xff0c;不能考察因素间的交互作用&#xff0c;只有在确定因素间不存在交互作用时才能进行无重复观测值的试验和分析。为了准确估计因素的主效应、交互作用和随机误差&#xff0c;每个…

设计模式之原型模式【创造者模式】

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

第121场双周赛题解:揭秘算法竞赛中的数位挑战与解题策略

需要多掌握解题套路 比赛地址 100157. 大于等于顺序前缀和的最小缺失整数 class Solution:def missingInteger(self, nums: List[int]) -> int:# Step 1: Find the longest consecutive prefixi 0 for i in range(1, len(nums)):if nums[i] ! nums[i - 1] 1:breakelse:…

Zookeeper三节点搭建

一、安装前准备 安装JDK&#xff08;之前已经安装了&#xff09; 拷贝apache-zookeeper-3.5.7-bin.tar.gz安装包到Linux系统下 解压到指定目录 在/opt/module/zookeeper-3.5.7/这个目录下创建zkData&#xff0c;在/opt/module/zookeeper-3.5.7/zkData目录下创建一个myid的…

第 121 场 LeetCode 双周赛题解

A 大于等于顺序前缀和的最小缺失整数 模拟&#xff1a;先求最长顺序前缀的和 s s s &#xff0c;然后从 s s s 开始找没有出现在 n u m s nums nums 中的最小整数 class Solution { public:int missingInteger(vector<int> &nums) {unordered_set<int> vis(…

MySQL数据管理(二)

DML语言 DML &#xff08;数据操作语&#xff09;&#xff1a;用于操作数据库对象中所包含的数据 DML包括&#xff1a; INSERT&#xff08;添加数据语句&#xff09;UPDATE&#xff08;更新数据语句&#xff09;DELETE&#xff08;删除数据语句&#xff09; 一、添加数据 …

Matlab三维绘图

绘制三维图plot3 t0:pi/50:10*pi; xsin(t); ycos(t); zt; plot3(x,y,z); 产生栅格数据点meshgrid 这个接口在绘制三维图像里面相当重要&#xff0c;很多时候要将向量变成矩阵才能绘制三维图。 x0:0.5:5; y0:1:10; [X,Y]meshgrid(x,y); plot(X,Y,o); x和y是向量&#xff0c;…

qt三大控件

1.QListWidget控件 先在ui界面将 QListWidget拖出来竖直对齐 再去代码中实现文本插入 两种插入方式 方法1 //listWidget使用 有左右中间对齐需求QListWidgetItem * itemnew QListWidgetItem("床前明月光"); // //上面只是独立的一句话,没有关联起来ui-&g…

Android AAudio

文章目录 基本概念启用流程基本流程HAL层对接数据流计时模型调试 基本概念 AAudio 是 Android 8.0 版本中引入的一种音频 API。 AAudio 提供了一个低延迟数据路径。在 EXCLUSIVE 模式下&#xff0c;使用该功能可将客户端应用代码直接写入与 ALSA 驱动程序共享的内存映射缓冲区…

HarmonyOS4.0系统性深入开发15Want概述

Want概述 Want的定义与用途 Want是对象间信息传递的载体&#xff0c;可以用于应用组件间的信息传递。其使用场景之一是作为startAbility()的参数&#xff0c;包含了指定的启动目标以及启动时需携带的相关数据&#xff0c;如bundleName和abilityName字段分别指明目标Ability所…

模拟算法(模拟算法 == 依葫芦画瓢)万字

模拟算法 基本思想引入算法题替换所有的问号提莫攻击Z字形变换外观数列数青蛙 基本思想 模拟算法 依葫芦画瓢解题思维要么通俗易懂&#xff0c;要么就是找规律&#xff0c;主要难度在于将思路转换为代码。 特点&#xff1a;相对于其他算法思维&#xff0c;思路比较简单&#x…