首页 > 其他分享 >STM32:rtthread_信号量

STM32:rtthread_信号量

时间:2023-07-14 22:33:07浏览次数:36  
标签:rt 信号量 parent thread object rtthread STM32 RT sem

1 信号量

  信号量是一种用于管理线程间资源关系的内核对象,线程可以获取或释放它从而达到同步或互斥的目的;

  信号量可以运用在多种场合中,形成锁,同步(多个线程可访问同一资源),资源计数等关系,也能方便的用于线程与线程,中断与线程的同步中;

  1.1 semaphore 信号量结构体

//rtdef.h
#ifdef RT_USING_SEMAPHORE
struct rt_semaphore
{
    struct rt_ipc_object parent;                        /**< inherit from ipc_object */
    rt_uint16_t          value;                         /**< value of semaphore. */
};
typedef struct rt_semaphore *rt_sem_t;
#endif

struct rt_ipc_object
{
    struct rt_object parent;                            /**< inherit from rt_object */
    rt_list_t        suspend_thread;                    /**< threads pended on this resource */
};

struct rt_object
{
    char       name[RT_NAME_MAX];                       /**< name of kernel object */
    rt_uint8_t type;                                    /**< type of kernel object */
    rt_uint8_t flag;                                    /**< flag of kernel object */

#ifdef RT_USING_MODULE
    void      *module_id;                               /**< id of application module */
#endif
    rt_list_t  list;                                    /**< list node of kernel object */
};
typedef struct rt_object *rt_object_t;                  /**< Type for kernel objects. */


//IPC flags and control command definitions
#define RT_IPC_FLAG_FIFO                0x00            /**< FIFOed IPC. 先进先出 */
#define RT_IPC_FLAG_PRIO                0x01            /**< PRIOed IPC. 优先级 */

#define RT_IPC_CMD_UNKNOWN              0x00            /**< unknown IPC command */
#define RT_IPC_CMD_RESET                0x01            /**< reset IPC object */

#define RT_WAITING_FOREVER              -1              /**< Block forever until get resource. */
#define RT_WAITING_NO                   0               /**< Non-block. */

  1.2 rt_sem_create 创建信号量

    这个信号量的创建函数还挺简单的嘞,这个信号量信息不多看来很简单;事后也确实很简单;

    信号量的flag建议采用RT_IPC_FLAG_PRIO,可以保证线程的实时性;RT_IPC_FLAG_FIFO属于非实时调度,实时性不如优先级flag方式;

//ipc.c
rt_sem_t rt_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag)
{
    rt_sem_t sem;

    RT_DEBUG_NOT_IN_INTERRUPT;

    /* allocate object */
    sem = (rt_sem_t)rt_object_allocate(RT_Object_Class_Semaphore, name);
    if (sem == RT_NULL)
        return sem;

    /* init ipc object */
    rt_ipc_object_init(&(sem->parent));

    /* set init value */
    sem->value = value;

    /* set parent */
    sem->parent.parent.flag = flag;

    return sem;
}
RTM_EXPORT(rt_sem_create);

   1.3 rt_sem_delete 删除信号量

//ipc.c 
rt_err_t rt_sem_delete(rt_sem_t sem)
{
    RT_DEBUG_NOT_IN_INTERRUPT;

    RT_ASSERT(sem != RT_NULL);

    /* wakeup all suspend threads */
    rt_ipc_list_resume_all(&(sem->parent.suspend_thread));

    /* delete semaphore object */
    rt_object_delete(&(sem->parent.parent));

    return RT_EOK;
}

//在rt_object_delete(rt_object_t object)函数中,主要执行了两个操作,一个是rt_list_remove(&object->list),一个是RT_KERNEL_FREE(object);
//object是指针,作为变量传递赋值的时候,可不等价于传递地址了吗?
//malloc函数在分配地址的时候,会自动先拿出4字节存储分配的内存大小,然后把后面的地址返回;
//所以free内存的时候,不需要传入内存大小,free也知道需要释放的内存大小;

   1.4 rt_sem_take 获取信号量

//ipc.c  如果当前信号量值大于0,那么信号量值减1,然后就返回继续执行当前线程函数;说明当前线程使用了一个信号量资源;
//       如果当前信号量值为0,说明没有信号量资源;那就根据time值判断是否等待;
//       如果不等待则直接返回超时函数;如果等待,则将当前线程悬起到suspend_thread,等到有信号量资源的时候再释放;
rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time)
{
    register rt_base_t temp;
    struct rt_thread *thread;

    RT_ASSERT(sem != RT_NULL);

    RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(sem->parent.parent)));

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();

    RT_DEBUG_LOG(RT_DEBUG_IPC, ("thread %s take sem:%s, which value is: %d\n",
                                rt_thread_self()->name,
                                ((struct rt_object *)sem)->name,
                                sem->value));

    if (sem->value > 0)
    {
        /* semaphore is available */
        sem->value --;

        /* enable interrupt */
        rt_hw_interrupt_enable(temp);
    }
    else
    {
        /* no waiting, return with timeout */
        if (time == 0)
        {
            rt_hw_interrupt_enable(temp);

            return -RT_ETIMEOUT;
        }
        else
        {
            /* current context checking */
            RT_DEBUG_IN_THREAD_CONTEXT;

            /* semaphore is unavailable, push to suspend list */
            /* get current thread */
            thread = rt_thread_self();

            /* reset thread error number */
            thread->error = RT_EOK;

            RT_DEBUG_LOG(RT_DEBUG_IPC, ("sem take: suspend thread - %s\n",
                                        thread->name));

            /* suspend thread */
            rt_ipc_list_suspend(&(sem->parent.suspend_thread),
                                thread,
                                sem->parent.parent.flag);

            /* has waiting time, start thread timer */
            if (time > 0)
            {
                RT_DEBUG_LOG(RT_DEBUG_IPC, ("set thread:%s to timer list\n",
                                            thread->name));

                /* reset the timeout of thread timer and start it */
                rt_timer_control(&(thread->thread_timer),
                                 RT_TIMER_CTRL_SET_TIME,
                                 &time);
                rt_timer_start(&(thread->thread_timer));
            }

            /* enable interrupt */
            rt_hw_interrupt_enable(temp);

            /* do schedule */
            rt_schedule();

            if (thread->error != RT_EOK)
            {
                return thread->error;
            }
        }
    }

    RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(sem->parent.parent)));

    return RT_EOK;
}
RTM_EXPORT(rt_sem_take);

   1.5 rt_sem_release 释放信号量

//ipc.c     如果suspend_thread中有等待线程,那么将其恢复,然后rt_schedule,
//          让另外一个等待信号量的suspend_thread有了执行权就相当于这里的信号量加1了;
//          if suspend_thread中没有等待线程,那么当前线程释放了信号量,就把信号量值加1;
rt_err_t rt_sem_release(rt_sem_t sem)
{
    register rt_base_t temp;
    register rt_bool_t need_schedule;

    RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(sem->parent.parent)));

    need_schedule = RT_FALSE;

    /* disable interrupt */
    temp = rt_hw_interrupt_disable();

    RT_DEBUG_LOG(RT_DEBUG_IPC, ("thread %s releases sem:%s, which value is: %d\n",
                                rt_thread_self()->name,
                                ((struct rt_object *)sem)->name,
                                sem->value));

    if (!rt_list_isempty(&sem->parent.suspend_thread))
    {
        /* resume the suspended thread */
        rt_ipc_list_resume(&(sem->parent.suspend_thread));
        need_schedule = RT_TRUE;
    }
    else
        sem->value ++; /* increase value */

    /* enable interrupt */
    rt_hw_interrupt_enable(temp);

    /* resume a thread, re-schedule */
    if (need_schedule == RT_TRUE)
        rt_schedule();

    return RT_EOK;
}
RTM_EXPORT(rt_sem_release);

  1.6 gitee

    rtthread_f1demo: 将rtthread nano3.0.3版本移植到stm32f1上; (gitee.com) 

2 小结

  写demo的时候应该单独开个文件来写的,这样就不用每次都修改main函数了,调用函数例程就叫xx_sample把;

 

标签:rt,信号量,parent,thread,object,rtthread,STM32,RT,sem
From: https://www.cnblogs.com/caesura-k/p/17553370.html

相关文章

  • STM32笔记(3) RS485&MODBUS
    RS485通信以及modbus通信协议硬件层:rs485解决的是数据传输的问题,如何将0/1传输到另一端主机或从机将TTL电平通过485芯片转换成差分信号抗干扰能力强,传输距离远485芯片中集成了发送器和接收器:连接单片机io引脚通过高低电平来决定是发送方还是接收方两线半双工软件......
  • STM32:rtthread_消息队列
    1消息队列  消息队列是一种常用的线程间异步通讯方式;   消息队列能够接收来自线程或中断中不固定长度的消息,并把消息缓存在自己的内存空间中,供线程间进行异步通讯;  1.1结构体定义//rtconfig.h源码默认注释掉未开启,用到消息队列的时候需要自己开启;#defineRT_USI......
  • STM32笔记(3) 按键驱动
    include"key.h"defineKEY1(GPIOA->IDR&(0X1<<0))defineKEY2(GPIOC->IDR&(0X1<<4))defineKEY3(GPIOC->IDR&(0X1<<5))defineKEY4(GPIOC->IDR&(0X1<<6))voidKEY_Config(void)//key1按键{......
  • STM32笔记(2)时钟源 NOP延时
    时钟用哪个外设就要开他对应的时钟例子:RCC->APB2ENR|=(0x01<<3);//时钟需要在APB2上开启对应的时钟拓展:系统时钟如何配置staticvoidSetSysClockTo72(void){__IOuint32_tStartUpCounter=0,HSEStatus=0;/*SYSCLK,HCLK,PCLK2andPCLK1configuration----......
  • STM32笔记 晶振 GPIO 寄存器
    晶振:在各种电路中,产生震荡频率的元器件(频率越高,单片机运行的速度越快)。2个外部:通过晶振高速:HSE--4~16MHz(咱们使用8MHz)--整个单片机提供时钟低速:LSE--32.768KHz--RTC提供(实时时钟)2个内部:通过RC振荡电路高速:HSI--8MHz低速:LSI--40KHz--看门狗定时器GPIO:管......
  • stm32cubemx
    一、STM32CubeMX是干嘛的?STM32CubeMX是ST意法半导体近几年来大力推荐的STM32芯片图形化配置工具,目的就是为了方便开发者,允许用户使用图形化向导生成C初始化代码,可以大大减轻开发工作,时间和费用,提高开发效率。STM32CubeMX几乎覆盖了STM32全系列芯片。二、如何安装STM32Cu......
  • STM32:rtthread_f1移植
    本文开始移植rtthread的代码到正点原子的板子上;参考资料为野火的教程,需要搭配野火教程使用;使用源码是作为pack包放在arm-keil官网下载的nano3.0.3版本;nano版本精简方便解构;gittee上的master版本组件又多又杂不利于初学;本来想用3.1.5版本源码的,但是移植过程会有代码报错又莫名其......
  • [STM32]STM32双机串口通信
    [STM32]STM32双机串口通信上一篇的通信方案在发送端高强度通信下寄了,发现是函数HAL_UART_Transmit()的锅,一个函数居然能跑0.3s左右。。。于是打算选用DMA收发数据,但是DMA在接收数据时遇到一些玄学问题,于是改用DMA发送数据,串口IDLE中断接收数据的策略。cubeMX配置接收端部分开......
  • [STM32 HAL]一种可能不错的DMA处理串口数据方案
    [STM32HAL]一种可能不错的DMA处理数据方案原文链接:https://blog.csdn.net/youmeichifan/article/details/51750435?spm=1001.2014.3001.5506本文配置稍有不同,大体类似。MX配置开启USART1,使能USART1全局中断,打开RX,TX的DMA通道,均为normal模式,内存地址自增,使能TX对应DMA的中断,RX......
  • [STM32]STM32双机蓝牙串口通信
    [STM32]STM32双机蓝牙串口通信期末考完力,虽然GPA--,但也终于有空搓一搓32了蓝牙模块配置我们先配置蓝牙模块,需要主从兼容,配置过程可以参考这个博客:https://blog.csdn.net/m0_59113542/article/details/122028037?spm=1001.2014.3001.5506cubeMX配置然后就是MX里的配置。PS:两......