STM32_HAL Freertos按键控制LED

news2024/12/31 6:38:13

设置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);
    
  }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】Linux基础之权限

目录 一、Linux中的用户1.1 用户之间的身份切换1.2 指令提权 二、权限管理2.1 文件权限2.2 权限操作2.3 chown和chgrp 三、文件类型四、目录文件的权限操作五、权限掩码六、粘滞位 一、Linux中的用户 Linux中主要有两种用户&#xff1a; root&#xff0c;超级用户非root&…

x-cmd pkg | trdsql - 能对 CSV、LTSV、JSON 和 TBLN 执行 SQL 查询的工具

目录 简介首次用户技术特点竞品和相关作品进一步阅读 简介 trdsql 是一个使用 sql 作为 DSL 的强大工具: 采用 SQL 对 CSV、LTSV、JSON 和 TBLN 文件执行查询与 MySQL&#xff0c;Postgresql&#xff0c;Sqlite 的 Driver 协同&#xff0c;可以实现对应数据库的表与文件的 JO…

Python Asyncio网络编程方法全面解析与实战应用!

更多Python学习内容&#xff1a;ipengtao.com Python的asyncio库是一种强大的异步编程工具&#xff0c;它使得编写高效的网络应用程序变得更加容易。在本文中&#xff0c;我们将深入探讨使用asyncio进行网络编程的方法&#xff0c;包括异步IO、协程、事件循环等方面的内容&…

Long类型转换精度丢失问题解决

问题: 启动前端项目 页面传递的ID 和数据库保存的ID不一致 原因&#xff1a;给前端返回的id为long类型&#xff0c;在转换json传递到前端以后精度丢失&#xff0c;所以前端给我们的id也是丢失精度的id,不能查询数据。 因为js数字类型最大长度为16位&#xff0c;而java的long类…

【强力推荐】GitCode AI开源搜索,面向开发者的专业AI搜索

一、GitCode AI开源搜索是什么&#xff1f; GitCode AI开源搜索 是面开发者的 AI 开源搜索工具&#xff0c;目的是为了帮助开发者快速寻找开源项目代码、解决开发问题和快速寻找答案&#xff0c;帮助开发者提升效率的同时利用代码仓托管能力建立自己个人知识库。 二、GitCode…

如何才能成长为一个架构师?

很多技术小伙伴都在问我&#xff0c;架构师是不是很牛逼&#xff0c;那么为什么自己不能成长为一名优秀的架构师呢&#xff1f;而总是作为工程师资源被项目打包带走&#xff0c;并周而复始的完成领导的业务开发需求任务。 架构师的工作职责&#xff1f; 为了方便技术小伙伴理…

带修莫队 P1903 题解

Part # 0. 前言 \text{Part \# 0. 前言} Part # 0. 前言 这个蒟蒻刚学带修莫队&#xff0c;所以 介绍带修莫队的部分比较简略&#xff0c;大家可以去参考一下 OI-wiki 或者其他大佬的博客&#xff1a;&#xff09; 本文参考了洛谷题解。 Part # 1. 带修莫队 \text{Part \# 1.…

OSPF 路由协议原型系统设计与实现

1.题目描述 参考计算机网络教材 164 页 OSPF 路由协议工作原理&#xff0c;在此基础上&#xff0c;实现一个简单的原型系统。主 要完成工作有&#xff1a;路由节点泛洪发布本地节点的链路信息&#xff0c;其它节点接收信息&#xff0c;构造网络拓扑&#xff0c;然后利 用 Dijk…

Linux第18步_安装“Ubuntu系统下的C语言编译器GCC”

Ubuntu系统没有提供C/C的编译环境&#xff0c;因此还需要手动安装build-essential软件包&#xff0c;它包含了 GNU 编辑器&#xff0c;GNU 调试器&#xff0c;和其他编译软件所必需的开发库和工具。本节用于重点介绍安装“Ubuntu系统下的C语言编译器&#xff27;&#xff23;&a…

如何解决找不到mfc100u.dll无法运行程序问题,分享四种靠谱的方法

在日常使用电脑的过程中&#xff0c;我们可能会遇到各种问题&#xff0c;其中之一就是找不到mfc100u.dll的困扰。这个问题主要是因为mfc100u.dll是Microsoft Foundation Class&#xff08;MFC&#xff09;库中的一个版本特定的DLL文件&#xff0c;它是Visual Studio 2010及更早…

java 音乐会售票平台系统Myeclipse开发mysql数据库struts2结构java编程计算机网页项目

一、源码特点 java 音乐会售票平台系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助struts2框架开发mvc模式&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发 环境为TOCAT7.0,Myeclipse8.5开发&#xff0c;数据…

Video classification with UniFormer基于统一分类器的视频分类

本文主要介绍了UniFormer: Unified Transformer for Efficient Spatial-Temporal Representation Learning 代码&#xff1a;https://github.com/Sense-X/UniFormer/tree/main/video_classification UNIFormer 动机 由于视频具有大量的局部冗余和复杂的全局依赖关系&#xf…

企业一线员工定岗定编全解析

引言&#xff1a;在生产制造企业中&#xff0c;由于一线员工工作内容单一&#xff0c;与产量线性关系明显&#xff0c;因此针对一线员工的定编方法最简单有效的就是通过数据计算的方式。人力资源专家——华恒智信根据多年以来对生产制造企业定岗定编的关注与研究得出的经验&…

第7章-第5节-Java中的比较器comparator和泛型的简单说明

1、 引入 上个章节中我们在使用TreeSet保存自定义数据类型的时候&#xff0c;类必须要实现Comparable这个接口&#xff0c;然后重写CompareTo这个方法&#xff0c;这个必须是在具体的自定义类内部去写&#xff0c;有时不方便&#xff0c;每遇到一个都要在那个类内部去写这个Co…

如何把电脑中的项目快速传进Github中?

一、打开GitHub网站:https:github.com 登录自己的个人账号 1.新建一个项目 2.用鼠标直接拖拽电脑中的项目文件夹与文件到新创建的项目中点击保存即可。

Xfs文件系统磁盘布局

目录 一&#xff0c;CentOS下Xfs文件系统的安装 二&#xff0c;准备工作 三&#xff0c;AG结构 四&#xff0c;AG超级块 五&#xff0c;AG空闲磁盘空间管理 六&#xff0c;ABTB的Btree 七&#xff0c;ABTB/ABTC的节点块管理 八&#xff0c;inode节点管理 九&#xff0…

Redis 键中冒号的用途是什么?可以使匹配查询更快吗?

Redis 键中冒号的用途是什么在Redis中&#xff0c;冒号&#xff08;:&#xff09;用作键的分隔符&#xff0c;它的主要作用是创建层次结构和命名空间。通过在键中使用冒号&#xff0c;可以将键分为多个部分&#xff0c;从而更好地组织和管理数据。 以下是冒号在Redis键中的用途…

PyTorch|构建自己的卷积神经网络——卷积层

在构建我们的网络时&#xff0c;我们需要用到卷积层提取特征&#xff0c;来看到一些特别的东西&#xff0c;当图片经过卷积层&#xff0c;图片尺寸一般会变化。 当我们构建网络时&#xff0c;我们需要确定各个层的参数&#xff0c;而这些参数&#xff0c;则是要提前计算的&…

【Python常用函数】一文让你彻底掌握Python中的numpy.append函数

大数据时代的到来,使得很多工作都需要进行数据挖掘,从而发现更多有利的规律,或规避风险,或发现商业价值。而大数据分析的基础是学好编程语言。本文和你一起来探索Python中的append函数,让你以最短的时间明白这个函数的原理。也可以利用碎片化的时间巩固这个函数,让你在处…

【数据分享】2024年我国主要城市地铁站点和线路数据

地铁站点与线路数据是我们经常会用到的一种基础数据。去哪里获取该数据呢&#xff1f; 今天我们就给大家分享一份2024年1月采集的全国有地铁城市的地铁站点与线路数据&#xff0c;数据格式为shp&#xff0c;数据坐标为wgs1984地理坐标。数据中不仅包括地铁&#xff0c;也包括轻…