FreeRTOS学习--41讲 信号量

news2025/4/24 15:11:52

信号量的定义

        是一种解决同步问题的机制,实现对共享资源的有序访问

信号量特点:

        当计数值大于0,代表有信号量资源;释放信号量,信号量计数值+1;获取则-1

队列和信号量的差异

二值信号量:

                 a.相当于队列长度等于1的队列

                  b.通常用于互斥访问或任务同步

                  c.只有空与满两种情况

使用二值信号量过程

        创建二值信号量->释放二值信号量->获取二值信号量

动态方法创建二值信号量 xSemaphoreCreateBinary()

释放二值信号量 BaseType_t  xSemaphoreGive(QueueHandle_t  xSemaphore)

参数:目标信号量        返回值:pdPASS 释放成功,errQUEUE_FULL 释放失败

获取二值信号量 BaseType_t     xSemaphoreTake(QueueHandle_t  xSemaphore,xBlockTime)

参数:目标信号量,阻塞时间        返回值:pdTRUE 获取成功,pdFALSE 获取失败

二值信号量代码

// freertos_demo.c

#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
#include "./MALLOC/malloc.h"
/*FreeRTOS************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/*******************************************************************************/
/*FreeRTOS配置*/

/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define START_TASK_PRIO         1
#define START_TASK_STACK_SIZE   128
TaskHandle_t    start_task_handler;
void start_task( void * pvParameters );

/* TASK1 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK1_PRIO         2
#define TASK1_STACK_SIZE   128
TaskHandle_t    task1_handler;
void task1( void * pvParameters );


/* TASK2 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK2_PRIO         3
#define TASK2_STACK_SIZE   128
TaskHandle_t    task2_handler;
void task2( void * pvParameters );

/***************************************************************************************/
QueueHandle_t semphore_handle;                      //定义队列句柄
/**
 * @brief       FreeRTOS例程入口函数
 * @param       无
 * @retval      无
 */
void freertos_demo(void)
{    
    semphore_handle = xSemaphoreCreateBinary();     //创建二值信号量
    if(semphore_handle != NULL)
    {
        printf("二值信号量创建成功!!!\r\n");
    }
    xTaskCreate((TaskFunction_t         )   start_task,
                (char *                 )   "start_task",
                (configSTACK_DEPTH_TYPE )   START_TASK_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   START_TASK_PRIO,
                (TaskHandle_t *         )   &start_task_handler );
    vTaskStartScheduler();
}


void start_task( void * pvParameters )
{
    taskENTER_CRITICAL();               /* 进入临界区 */
    xTaskCreate((TaskFunction_t         )   task1,
                (char *                 )   "task1",
                (configSTACK_DEPTH_TYPE )   TASK1_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK1_PRIO,
                (TaskHandle_t *         )   &task1_handler );
                
    xTaskCreate((TaskFunction_t         )   task2,
                (char *                 )   "task2",
                (configSTACK_DEPTH_TYPE )   TASK2_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK2_PRIO,
                (TaskHandle_t *         )   &task2_handler );
                             
    vTaskDelete(NULL);
    taskEXIT_CRITICAL();                /* 退出临界区 */
}

/* 任务一,释放二值信号量 */
void task1( void * pvParameters )
{
    uint8_t key = 0;
    BaseType_t err;
    while(1) 
    {
        key = key_scan(0);
        if(key == KEY0_PRES)        //判断按键是否按下
        {
            if(semphore_handle != NULL)
            {
                err = xSemaphoreGive(semphore_handle); //释放二值信号量
                if(err == pdPASS)
                {
                    printf("信号量释放成功!!\r\n");
                }else printf("信号量释放失败!!\r\n");
            }
            
        }
        vTaskDelay(10);
    }
}

/* 任务二,获取二值信号量 */
void task2( void * pvParameters )
{
    uint32_t i = 0;
    BaseType_t err;
    while(1)
    {
        err = xSemaphoreTake(semphore_handle,portMAX_DELAY); /* 获取信号量并死等 */
        if(err == pdTRUE)
        {
            printf("获取信号量成功\r\n");            //任务始终处于阻塞状态,一旦有信号产生就解除阻塞,因为抢占优先级高,发生任务切换
        }else printf("已超时%d\r\n",++i);
        
    }
}


//freertos_demo.h

#ifndef __FREERTOS_DEMO_H
#define __FREERTOS_DEMO_H

void freertos_demo(void); 

#endif

main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/SDRAM/sdram.h"
#include "./MALLOC/malloc.h"
#include "freertos_demo.h"
#include "./BSP/TIMER/btim.h"

int main(void)
{
    HAL_Init();                                 /* 初始化HAL库 */
    sys_stm32_clock_init(360, 25, 2, 8);        /* 设置时钟,180Mhz */
    delay_init(180);                            /* 延时初始化 */
    usart_init(115200);                         /* 串口初始化为115200 */
    led_init();                                 /* 初始化LED */
    key_init();                                 /* 初始化按键 */
    sdram_init();                               /* SRAM初始化 */
    lcd_init();                                 /* 初始化LCD */
    
    my_mem_init(SRAMIN);                        /* 初始化内部内存池 */
    my_mem_init(SRAMEX);                        /* 初始化外部内存池 */
    my_mem_init(SRAMCCM);                       /* 初始化CCM内存池 */
    
    freertos_demo();
}

计数型信号量:

                         a.队列长度大于1的队列

                         b.适用场景 事件计数,资源管理

创建计数型信号量函数

        xSemaphoreCreateCounting(uxMaxCount,uxInitialCount)

        参数:计数最大值,计数初始值                返回值:队列(QueueHandle_t 型)

获取信号量当前计数值

        uxSemaphoneGetCount(QueueHandle_t  xSemaphore)

        参数:目标信号量句柄                             返回值:整数(UBaseType_t 型)

计数型信号实验代码

//freertos_demo.c

#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
#include "./MALLOC/malloc.h"
/*FreeRTOS****************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/***************************************************************************************/
/*FreeRTOS配置*/

/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define START_TASK_PRIO         1
#define START_TASK_STACK_SIZE   128
TaskHandle_t    start_task_handler;
void start_task( void * pvParameters );

/* TASK1 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK1_PRIO         2
#define TASK1_STACK_SIZE   128
TaskHandle_t    task1_handler;
void task1( void * pvParameters );


/* TASK2 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK2_PRIO         3
#define TASK2_STACK_SIZE   128
TaskHandle_t    task2_handler;
void task2( void * pvParameters );

/************************************************************************************/
QueueHandle_t count_semphore_handle;            //定义队列变量
/**
 * @brief       FreeRTOS例程入口函数
 * @param       无
 * @retval      无
 */
void freertos_demo(void)
{    
    count_semphore_handle = xSemaphoreCreateCounting(100 , 0);  /* 创建计数型信号量 */
    if(count_semphore_handle != NULL)
    {
        printf("计数型信号量创建成功!!!\r\n");
    }
    xTaskCreate((TaskFunction_t         )   start_task,
                (char *                 )   "start_task",
                (configSTACK_DEPTH_TYPE )   START_TASK_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   START_TASK_PRIO,
                (TaskHandle_t *         )   &start_task_handler );
    vTaskStartScheduler();
}


void start_task( void * pvParameters )
{
    taskENTER_CRITICAL();               /* 进入临界区 */
    xTaskCreate((TaskFunction_t         )   task1,
                (char *                 )   "task1",
                (configSTACK_DEPTH_TYPE )   TASK1_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK1_PRIO,
                (TaskHandle_t *         )   &task1_handler );
                
    xTaskCreate((TaskFunction_t         )   task2,
                (char *                 )   "task2",
                (configSTACK_DEPTH_TYPE )   TASK2_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK2_PRIO,
                (TaskHandle_t *         )   &task2_handler );
                             
    vTaskDelete(NULL);
    taskEXIT_CRITICAL();                /* 退出临界区 */
}

/* 任务一,释放计数型信号量 */
void task1( void * pvParameters )
{
    uint8_t key = 0;
    while(1) 
    {
        key = key_scan(0);
        if(key == KEY0_PRES)
        {
            if(count_semphore_handle != NULL)           //判断信号量不为空
            {
                xSemaphoreGive(count_semphore_handle);      /* 释放信号量 */
            }
        }
        vTaskDelay(10);
    }
}

/* 任务二,获取计数型信号量 */
void task2( void * pvParameters )
{
    BaseType_t err = 0;
    while(1)
    {
        err = xSemaphoreTake(count_semphore_handle,portMAX_DELAY); /* 获取信号量并死等 */
        if(err == pdTRUE)
        {
            printf("信号量的计数值为:%d\r\n",(int)uxSemaphoreGetCount(count_semphore_handle));//获取信号量计数值
        }
        vTaskDelay(1000);   //延迟1秒,任务依旧是就绪态
    }
}

互斥信号量:

                 a.拥有优先级继承的二值信号量

                 b.同步应用中二值信号量最适合

                 c.只能用于任务中,不能用于中断服务函数

                 d.优先级继承的含义:

当一个互斥信号量正在被一个低优 先级的任务持有时,如果此时有个高优先级的任务也尝试获取这个互斥信号量,那么这个高优 先级的任务就会被阻塞。不过这个高优先级的任务会将低优先级任务的优先级提升到与自己相 同的优先级,这个过程就是优先级继承。优先级继承尽可能的减少了高优先级任务处于阻塞态 的时间,并且将“优先级翻转”的影响降到最低

使用:a.将FreeRTOSConfig.h中configUSE_MUTEXES置1

           b.创建互斥信号量(会自动释放一次)->获取信号量->释放信号量

 动态创建:xSemaphoreCreateMutex()  无参   

                        返回值:NULL 创建失败,队列(QueueHandle_t 型)创建成功

其他API函数与二值信号量一致,除了中断部分API,因为互斥信号量不能在中断中使用

互斥信号代码

//freertos_demo.c

#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
#include "./MALLOC/malloc.h"
/*FreeRTOS************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/************************************************************************************/
/*FreeRTOS配置*/

/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define START_TASK_PRIO         1
#define START_TASK_STACK_SIZE   128
TaskHandle_t    start_task_handler;
void start_task( void * pvParameters );

/* TASK1 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK1_PRIO         2
#define TASK1_STACK_SIZE   128
TaskHandle_t    low_task_handler;
void low_task( void * pvParameters );


/* TASK2 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK2_PRIO         3
#define TASK2_STACK_SIZE   128
TaskHandle_t    middle_task_handler;
void middle_task( void * pvParameters );


/* TASK3 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK3_PRIO         4
#define TASK3_STACK_SIZE   128
TaskHandle_t    high_task_handler;
void high_task( void * pvParameters );

/************************************************************************************/
QueueHandle_t mutex_semphore_handle;
/**
 * @brief       FreeRTOS例程入口函数
 * @param       无
 * @retval      无
 */
void freertos_demo(void)
{    
    mutex_semphore_handle = xSemaphoreCreateMutex();    /* 创建互斥信号量,并且主动释放一次信号量 */
    if(mutex_semphore_handle != NULL)
    {
        printf("互斥信号量创建成功!!!\r\n");
    }                                                   //会自动释放,所以不用主动释放
    
    xTaskCreate((TaskFunction_t         )   start_task,
                (char *                 )   "start_task",
                (configSTACK_DEPTH_TYPE )   START_TASK_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   START_TASK_PRIO,
                (TaskHandle_t *         )   &start_task_handler );
    vTaskStartScheduler();
}


void start_task( void * pvParameters )
{
    taskENTER_CRITICAL();               /* 进入临界区 */
    xTaskCreate((TaskFunction_t         )   low_task,
                (char *                 )   "low_task",
                (configSTACK_DEPTH_TYPE )   TASK1_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK1_PRIO,
                (TaskHandle_t *         )   &low_task_handler );
                
    xTaskCreate((TaskFunction_t         )   middle_task,
                (char *                 )   "middle_task",
                (configSTACK_DEPTH_TYPE )   TASK2_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK2_PRIO,
                (TaskHandle_t *         )   &middle_task_handler );
                
    xTaskCreate((TaskFunction_t         )   high_task,
                (char *                 )   "high_task",
                (configSTACK_DEPTH_TYPE )   TASK3_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK3_PRIO,
                (TaskHandle_t *         )   &high_task_handler );
                             
    vTaskDelete(NULL);
    taskEXIT_CRITICAL();                /* 退出临界区 */
}

/* 任务一,低优先级任务 */
void low_task( void * pvParameters )
{
    while(1) 
    {
        printf("low_task获取信号量\r\n");
        xSemaphoreTake(mutex_semphore_handle,portMAX_DELAY);//获取互斥信号量
        printf("low_task正在运行!!!\r\n");
        delay_ms(3000);
        printf("low_task释放信号量\r\n");
        xSemaphoreGive(mutex_semphore_handle); //释放互斥信号量
        vTaskDelay(1000);
    }
}

/* 任务二,中优先级任务 */
void middle_task( void * pvParameters )
{
    while(1)
    {
        printf("middle_task正在运行!!!\r\n");
        vTaskDelay(1000);
    }
}

/* 任务三,高优先级任务 */
void high_task( void * pvParameters )
{
    while(1)
    {
        printf("high_task获取信号量\r\n");
        xSemaphoreTake(mutex_semphore_handle,portMAX_DELAY);
        printf("high_task正在运行!!!\r\n");
        delay_ms(1000);
        printf("high_task释放信号量\r\n");
        xSemaphoreGive(mutex_semphore_handle); 
        vTaskDelay(1000);
    }
}

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

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

相关文章

用idea跑起十多年前的项目

一、eclipse的项目 先删掉一些eclipse的配置文件 二、在idea中导入项目 1、导入成功后,先【锤一下】 2、然后发现编译不通过,非常多的报错信息,逐一解决报错 (1)tomcat7配置报错 (2)先删除tom…

将本地工作空间robot_ws上传到gitee仓库

git config --global user.name "geniusChinaHN" git config --global user.email "12705243geniuschinahnuser.noreply.gitee.com" cd ~/robot_ws #git init#创建原始仓库时候用 git add . git commit -m "上传文件内容描述" #git remote add r…

【教程】Typecho Joe主题开启并修复壁纸相册不显示问题

转载请注明出处:小锋学长生活大爆炸[xfxuezhang.cn] 背景说明 Joe主题本身支持“壁纸”功能,其实就是相册。当时还在网上找了好久相册部署的开源项目,太傻了。 但是网上教程很少,一没说如何开启壁纸功能,二没说开启后为…

Java Log 学习笔记

参考文章: 1.Java 日志从入门到实战 2.Java日志框架的发展历史,你不想了解一下吗 背景 想自定义 logback 配置文件进行日志分级别记录到不同文件,遇到了几个问题(使用的是 spring-boot 构建的项目,spring-boot 版本为…

开源可观测性平台Signoz(四)【链路监控及数据库中间件监控篇】

转载说明:如果您喜欢这篇文章并打算转载它,请私信作者取得授权。感谢您喜爱本文,请文明转载,谢谢。 前文链接: ​​开源可观测性平台Signoz系列(一)【开篇】​​ ​​开源可观测性平台Signoz&…

记录一下imx6ull linux 5.10.9多点电容触摸屏驱动报错问题解决方法

最近再研究如何将linux 5.10.9移植到imx6ull,用的原子的开发板,在移植电容触摸屏驱动时报错gpio gpiochip0: (209c000.gpio): gpiochip_lock_as_irq: tried to flag a GPIO set as output for IRQ,如下图: 该错误的意思就是尝试将…

MongoDB Certified Associate Developer 认证考试心得

介绍 前段时间通过了 MongoDB Associate Developer 考试,也记下了一些心得,结果忘记发出来了,现在重新整理下。通过考试后证书是这样的: MongoDB 目前有两个认证证书 1. MongoDB Associate Developer 认证掌握使用MongoDB 来构建现代应用…

前端八股文(工程化篇)

目录 1.常用的git命令有哪些? 2.git rebase和git merge的区别 3.有哪些常见的Loader和Plugin? 4.webpack的构建流程 5.bundle,chunk,module是什么? 6.如何提高webpack的打包速度 7.vite比webpack快在哪里 8.说一下你对Monorepo的理解 …

EOS开发Ubuntu安装EOSIO.CDT(Install the EOSIO.CDT)

EOS开发Ubuntu安装EOSIO.CDT(Install the EOSIO.CDT) EOSIO.CDT介绍:EOSIO合约开发工具包,简称CDT,是与合约编译相关的工具集合。而且后续教程主要使用 CDT 来编译合约和生成 ABI,不要忽略。 刚才我们安装好…

欢迎来到Web3.0的世界:Solidity智能合约安全漏洞分析

智能合约概述 智能合约是运行在区块链网络中的一段程序,经由多方机构自动执行预先设定的逻辑,程序执行后,网络上的最终状态将不可改变。智能合约本质上是传统合约的数字版本,由去中心化的计算机网络执行,而不是由政府…

汽车制造厂批量使用成华制造弹簧平衡器

数年来,成华制造都在不断的向各行各界输出着自己的起重设备,与众多企业达成合作,不断供应优质产品。近些年,成华制造以其卓越的产品质量和高效的生产能力,成功实现了弹簧平衡器的大规模批量供应,为重庆数家…

【开源】基于Vue+SpringBoot的就医保险管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 科室档案模块2.2 医生档案模块2.3 预约挂号模块2.4 我的挂号模块 三、系统展示四、核心代码4.1 用户查询全部医生4.2 新增医生4.3 查询科室4.4 新增号源4.5 预约号源 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVue…

【Vue2+3入门到实战】(16)VUEVue路由的重定向、404、编程式导航、path路径跳转传参 详细代码示例

目录 一、Vue路由-重定向1.问题2.解决方案3.语法4.代码演示 二、Vue路由-4041.作用2.位置3.语法4.代码示例 三、Vue路由-模式设置1.问题2.语法 四、编程式导航-两种路由跳转方式1.问题2.方案3.语法4.path路径跳转语法5.代码演示 path跳转方式6.name命名路由跳转7.代码演示通过n…

工程(十七)——自己数据集跑R2live

博主创建了一个科研互助群Q:772356582,欢迎大家加入讨论。 r2live是比较早的算法,编译过程有很多问题,通过以下两个博客可以解决 编译R2LIVE问题&解决方法-CSDN博客 r2live process has died 问题解决了_required process …

优化算法3D可视化

编程实现优化算法,并3D可视化 1. 函数3D可视化 分别画出 和 的3D图 import numpy as np from matplotlib import pyplot as plt import torch# 画出x**2 class Op(object):def __init__(self):passdef __call__(self, inputs):return self.forward(inputs)def for…

【软考】系统集成项目管理工程师【总】

引言 本来整理这篇文章的目的是方便自己23年考试用的 效果不错 目标完成。 接下来的目标是把这篇文章 做成参加该软考 小伙伴的唯一参考资料(有它就够了)来持续更新。。。 这篇文章我将当作一个长周期(以年为单位)项目运维起来&am…

【Web】vulhub-httpd apache解析漏洞复现(1)

目录 ①CVE-2017-15715 ②apache_parsing_vulnerability ①CVE-2017-15715 贴出源码&#xff1a; <?php if(isset($_FILES[file])) {$name basename($_POST[name]);$ext pathinfo($name,PATHINFO_EXTENSION);if(in_array($ext, [php, php3, php4, php5, phtml, pht]))…

linux常见基础指令

入门常见基础指令 ls、stat、 pwd 、cd、tree、 whoami、 touch、 mkdir、 rm 、 man、 cp、mv、cat、tac、echo、>、 >>、 < 、more、 less、 head、 tail、date、 cal、 find、 which、alias、whereis、grep、zip与unzip、 tar、bc、uname、xargs... 热键Tab、…

时序分解 | Matlab实现贝叶斯变化点检测与时间序列分解

时序分解 | Matlab实现贝叶斯变化点检测与时间序列分解 目录 时序分解 | Matlab实现贝叶斯变化点检测与时间序列分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现贝叶斯变化点检测与时间序列分解 1.Matlab实现贝叶斯变化点检测与时间序列分解&#xff0c;完…

STM32——通用计时器

通用计时器框图 1.时钟源 1&#xff09;内部时钟(CK_INT) 2&#xff09;外部时钟模式 1&#xff1a;外部输入引脚(TIx)&#xff0c;x1&#xff0c;2&#xff08;即只能来自于通道 1 或者通道 2&#xff09; 3&#xff09;外部时钟模式 2&#xff1a;外部触发输入(ETR) 4&#…