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_DELAYticks = 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 informationunion  {uint32_t                    v;     ///< message as 32-bit valuevoid                       *p;     ///< message or mail as void pointerint32_t               signals;     ///< signal flags} value;                             ///< event valueunion  {osMailQId             mail_id;     ///< mail id obtained by \ref osMailCreateosMessageQId       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.mzph.cn/news/604400.shtml

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

相关文章

大学物理实验重点——交直流电桥

直流电桥 惠斯通电桥 平衡条件&#xff1a; 非平衡电桥 为了测量的准确性&#xff0c;在测量的起始点&#xff0c;电桥必须调至平衡&#xff08;&#xff09;&#xff0c;称为预调平衡。这样可使输出只与某一臂电阻变化有关。 平衡时 若 R1、 R2 、 R3 固定&#xff0c; R4 为…

美食管理与推荐系统Python+Django网站系统+协同过滤推荐算法【计算机课设】

一、介绍 美食管理与推荐系统。本系统使用Python作为主要开发语言开发的一个美食管理推荐网站平台。 网站前端界面采用HTML、CSS、BootStrap等技术搭建界面。后端采用Django框架处理用户的逻辑请求&#xff0c;并将用户的相关行为数据保存在数据库中。通过Ajax技术实现前后端的…

期货日数据维护与使用_日数据维护_日数据更新

目录 写在前面&#xff1a; 下载日数据 下载“新增合约”日数据 下载“待更新合约”日数据 日数据文件 “选择日数据所在目录”按钮点击 “执行”按钮点击 sqlite3代码 按钮点击后执行的代码 子线程代码 写在前面&#xff1a; 本文默认已经创建了项目&#xff0c;如…

reiserfs文件系统的磁盘布局

reiserfs文件系统的磁盘布局比较简单&#xff0c;它把整块分区分成相同大小的block块&#xff0c;一个block块的大小默认是4K&#xff0c;而最大块数未2^32次方&#xff0c;即一个分区最大大小为16TB。 reiserfs文件系统分区的前64KB总是为分区标签&#xff08;partition labe…

第九节HarmonyOS 常用基础组件11-TextPicker

1、描述 滑动选择文本内容的组件。 2、接口 TextPicker(options?: {range: string[]|Resource, selected?: number, value?: string}) 3、参数 参数名称 参数类型 必填 描述 range string[]|Resource 是 选择器的数据。 selected number 否 设置默认选中项在…

【普中开发板】基于51单片机的温度报警器LCD1602_可调上下限( proteus仿真+程序+设计报告+讲解视频)

基于51单片机的温度报警器LCD1602_可调上下限 1.主要功能&#xff1a;资料下载链接&#xff1a; 普中开发板实物演示图&#xff1a;2.仿真3. 程序代码4. 设计报告5. 设计资料内容清单 【普中】基于51单片机的温度报警器LCD1602_可调上下限 ( proteus仿真程序设计报告讲解视频&a…

服务器内存不足怎么办?会有什么影响?

服务器内存&#xff0c;也被称为RAM&#xff08;Random Access Memory&#xff09;&#xff0c;是一种临时存储设备&#xff0c;用于临时存放正在运行的程序和数据。它是服务器上的超高速存储介质&#xff0c;可以快速读取和写入数据&#xff0c;提供给CPU进行实时计算和操作。…

跟着小德学C++之安全模块

嗨&#xff0c;大家好&#xff0c;我是出生在达纳苏斯的一名德鲁伊&#xff0c;我是要立志成为海贼王&#xff0c;啊不&#xff0c;是立志成为科学家的德鲁伊。最近&#xff0c;我发现我们所处的世界是一个虚拟的世界&#xff0c;并由此开始&#xff0c;我展开了对我们这个世界…

遇见未来的你——感谢你带给我的感悟

目录 一、背景介绍二、思路&方案三、过程1.都说有的人出生就在罗马而有的人却用一辈子都在去向罗马的路上1.1.物质&#xff1a;1.2.精神&#xff1a; 2.做事情要看大再看细3.心存善念&#xff0c;常怀感恩&#xff0c;从小事做起4.所谓的面子在母爱面前像是一粒微尘5.讲道理…

【强化学习的数学原理-赵世钰】课程笔记(六)随机近似与随机梯度下降

目录 一.内容概述 二.激励性实例&#xff08;Motivating examples&#xff09; 三.Robbins-Monro 算法&#xff08;RM 算法&#xff09;&#xff1a; 1.算法描述 2.说明性实例&#xff08;llustrative examples&#xff09; 3.收敛性分析&#xff08;Convergence analysi…

Spark基础内容

Spark基本介绍 Spark是什么 定义 Apache Spark是用于大规模数据(large-scala data)处理的统一(unified)分析引擎. Spark与MapReduce对比 mapreduce架构图如下: MapReduce的主要缺点&#xff1a; 1- MapReduce是基于进程进行数据处理&#xff0c;进程相对线程来说&#x…

十一、工具盒类(MyQQ)(Qt5 GUI系列)

目录 ​编辑 一、设计需求 二、实现代码 三、代码解析 四、总结 一、设计需求 抽屉效果是软件界面设计中的一种常用形式&#xff0c;可以以一种动态直观的方式在有限大小的界面上扩展出更多的功能。本例要求实现类似 QQ 抽屉效果。 二、实现代码 #include "dialog.…

数据结构实验1:栈和队列的应用

目录 一、实验目的 二、实验原理 1.1栈的基本操作 1.1.1 栈的定义 1.1.2 初始化栈 1.1.3 压栈&#xff08;Push&#xff09; 1.1.4 出栈&#xff08;Pop&#xff09; 1.1.5 判空&#xff08;isEmpty&#xff09; 1.1.6 查看栈顶元素&#xff08;Top&#xff09; 1.1…

el-date-picker日期时间选择器限制可选的日期范围

业务场景&#xff1a;需要限制日期时间选择器可选择的日期&#xff0c;有两种模式&#xff0c; 一种是已知范围&#xff0c;只能选已知范围内的日期&#xff0c; 另一种是知道最近天数&#xff0c;只能选今天往前的天数内的日期&#xff0c;超出不能选。 <el-date-picker v-…

软性演员-评论家算法 SAC

软性演员-评论家算法 SAC 软性演员-评论家算法 SAC优势原理软性选择模型结构目标函数重参数化熵正则化算法步骤代码实现 软性演员-评论家算法 SAC 优势原理 DDPG 的问题在于&#xff0c;训练不稳定、收敛差、依赖超参数、不适应复杂环境。 软性演员-评论家算法 SAC&#xff…

算法通关村番外篇-优先队列

大家好我是苏麟 , 今天聊聊优先队列 . 优先队列 我们了解优先队列之前先说说队列 . 队列的特点是什么&#xff1f; 队列的特点是先进先出&#xff08;FIFO&#xff09;。 入队列&#xff0c;将新元素置于队尾&#xff1a; 出队列&#xff0c;队头元素最先被移出&#xff1a…

从新手到大师:四大编程范式解锁你的编码力!

编程&#xff0c;就是用代码跟计算机交流&#xff0c;告诉它我们想要它做什么。不同的编程范式就是不同的交流方式&#xff0c;每种方式都有自己独特的语法和规则。 今天&#xff0c;我们就来聊聊这四种主要的编程范式&#xff0c;它们分别是命令式、函数式、面向对象和声明式…

Java 堆的设计,如何用堆进行排序

Java 学习面试指南&#xff1a;https://javaxiaobear.cn 1、堆的定义 堆是计算机科学中一类特殊的数据结构的统称&#xff0c;堆通常可以被看做是一棵完全二叉树的数组对象。 1、堆的特性 它是完全二叉树&#xff0c;除了树的最后一层结点不需要是满的&#xff0c;其它的每一层…

听GPT 讲Rust源代码--compiler(33)

File: rust/compiler/rustc_middle/src/macros.rs 在Rust源代码中&#xff0c;rust/compiler/rustc_middle/src/macros.rs文件的作用是定义了一些用于宏展开的辅助宏和宏规则。 首先&#xff0c;这个文件导入了许多其他相关的模块&#xff0c;这些模块定义了编译器内部所需要的…

详解Java中的原子操作

第1章&#xff1a;什么是原子操作 大家好&#xff0c;我是小黑&#xff0c;面试中一个经常被提起的话题就是“原子操作”。那么&#xff0c;到底什么是原子操作呢&#xff1f;在编程里&#xff0c;当咱们谈论“原子操作”时&#xff0c;其实是指那些在执行过程中不会被线程调度…