草庐IT

【致敬嵌入式攻城狮第2期活动预热征文】【致敬未来的攻城狮计划】连续打卡第10天+使用实时操作系统RTOS

Wu_ShF 2023-10-10 原文

 开启攻城狮的成长之旅!这是我参与的由 CSDN博客专家 架构师李肯http://yyds.recan-li.cn)和 瑞萨MCU (瑞萨电子 (Renesas Electronics Corporation) ) 联合发起的「 致敬未来的攻城狮计划 」的第 10 天,点击查看活动计划详情 (https://bbs.csdn.net/topics/613916237)!


之前的操作都是写好C程序接着就推送到板子上了。

这次我们尝试一下实时操作系统。

线程与队列

以下内容引用自瑞萨官方的用户手册

在我们实际深入进行此练习之前,需要定义将在本章和下一章中使用的一些术语,以确保我们能够达成共识。

线程

首先,需要定义术语“线程”。如果您更习惯于“任务”这个表达方式,只需把线程看作是一种任务。有些人甚至互换使用这两个短语。当使用实时操作系统 (RTOS) 时,单片机上运行的应用程序将拆分为几个较小的半独立代码块,每个代码块通常控制程序的一个方面。这些小片段称为线程。一个应用程序中可以存在多个线程,但是在任何给定时间都只能有一个线程处于活动状态,因为 RA 系列单片机是单核器件。每个线程都有自己的堆栈空间,如果需要安全的上下文,则可以将其置于 MCU 的安全侧。每个线程还分配有优先级(相对于应用程序中的其他线程),并且可以处于不同的状态,例如运行、就绪、阻塞或暂停。在 FreeRTOS™ 中,可以通过调用eTaskGetState()API 函数来查询线程的状态。线程间信号传输、同步或通信是通过信号量、队列、互斥、通知、直接任务通知或者流和消息缓冲区来实现的。

信号量

信号量是 RTOS 的资源,可用于传输事件和线程同步(以产生者-使用者方式)。使用信号量允许应用程序暂停线程,直到事件发生并发布信号量。如果没有 RTOS,就需要不断地轮询标志变量或创建代码来执行中断服务程序 (ISR) 中的某个操作,这会在相当长的一段时间内阻塞其他中断。使用信号量可快速退出 ISR 并 将操作推迟到相关线程。

FreeRTOS 提供计数信号量和二进制信号量。尽管二进制信号量由于仅采用两个值(0 和 1)而非常适合实现任务之间或中断与任务之间的同步,但是计数信号量的计数范围可涵盖 0 到用户在 FSP 配置器中创建信号量期间指定的最大计数。默认值为256,可支持设计人员执行更复杂的同步操作。

每个信号量都有两个相关的基本操作:xSemaphoreTake()(将使信号量递减 1)和xSemaphoreGive()(将使信号量递增 1)。这两个函数有两种形式:一种是可以从中断服务程序内部调用(xSemaphoreTakeFromISR()xSemaphoreGiveFromThread())的形式,另一种则是上述可 以在线程的正常上下文中调用的形式。

队列

我们需要讨论的最后一个术语是队列,即使在本练习中不使用队列,下一章的练习中也会使用。报文队列是线程间通信的主要方法,它允许在任务之间或中断与任务之间发送消息。消息队列中可以有一条或多条消息。数据(也可以是指向更大缓冲区的指针)会复制到队列中,即,它存储的是消息本身而非引用。新消息通常置于队列的末尾,但也可以直接发送到开头。接收到的消息将从前面开始删除。

允许的消息大小可在设计时通过 FSP 配置器指定。默认项大小为 4 个字节,默认队列长度(表示队列中可存储的项数)为 20。所有项的大小必须相同。FreeRTOS 中的队列数没有限制;惟一的限制是系统中可用的存储空间。使用 xQueueSend() 函数将消息放入队列中,并通过xQueueReceive()从队列中读取消息。与信号量一样,函数有两种版本:一种可以从线程的上下文调用,另一种可以从 ISR 内部调用。

创建项目

正常创建项目,在这一页面时选择FreeRTOS

创建线程

添加驱动

为外部中断添加驱动程序

在“Properties”(属性)视图中更改新线程的属性:将“Symbol”(符号)重命名为 led_thread,将“Name”(名称)重命名为 LED Thread。其他属性保持默认值。在“LED Thread Stack” (LED 线程堆) 窗格中,单击“New Stack”(新线程)按钮图标,选择“Driver → Input → External IRQ Driver on r_icu”(驱动程序 → 输入 → r_icu 上的外部 IRQ 驱动程序)

配置驱动

修改通道Channel为 3,因为 S1 所连引脚连接到 IRQ03。

出于相同的原因,将名称更改 为 g_external_irq03 或您喜欢的任何名称。

为中断分配优先级 2,启动期间 FSP 将不会允许该中断。也可以选择任何其他优先级,但开始时最好选择优先级 2,因为即使在较大的系统中,也很少会遇到中断优先级冲突。请注意,优先级 3 是为系统时钟节拍定时器(systick) 保留的,因此不应被其他中断使用

堆元素的灰色条表示此驱动程序是模块实例,只能由另一个 FSP 模块实例引用

添加信号量

来自瑞萨用户手册的指示

在“LED Thread Objects”(LED 线程对象)窗格中单击“New Object”(新对象)按钮。如果看到的不是此窗格,而是“HAL/Common Objects”(HAL/通用对象)窗格,则突出显示“Threads”(线 程)窗格中的“LED Thread”(LED 线程),随即将显示此窗格。

添加一个二进制信号量。

我们需要在按下按钮时通知 LED 线程。将信号量的“Symbol”(符号)属性更改为 g_s1_semaphore,并将“Memory Allocation”(存储器分配)保留为“Static”(静态)。

修改完成后的界面。

如果没有找到IRQ模式,只有输入输出模式,则需要在左上的Pin Configuration中选择RA2E1 CPK

FSP 配置器中的最后一步是将 S1 连接的 I/O 引脚配置为 IRQ03 输入。为此,请激活配置器中的“Pins” (引脚)选项卡,展开“Ports → P0”(端口 → P0),然后选择 P004。在 CPK-RA2L1/RA2E1 评估板上, 这是 S1 连接的端口。在右侧的“Pin Configuration”(引脚配置)窗格中,为其指定符号名称 SW1 。

配置驱动

我们使用一个八位无符号整型来存储电平状态。

打开并启用连接到板上 S1 的 IRQ03。为此,请使用 IRQ FSP 驱动程序的打开和使能功能。 完成后,初始化即完成。

g_external_irq03.p_api->open (g_external_irq03.p_ctrl, g_external_irq03.p_cfg);

g_external_irq03.p_api->enable (g_external_irq03.p_ctrl);

在 while(1) 循环内部,需要添加一些语句并删除预写的 vTaskDelay(1); 语句。

在官方手册中,我们调用LED使用的是BSP提供的board_leds.h头文件,头文件内写好了LED结构体,并存储了各个主板的LED信息。而这次,目录中可能没有这个文件,因此我们需要用上一次中使用的新方法。

R_IOPORT_PinWrite (&g_ioport_ctrl, BSP_IO_PORT_05_PIN_01, led_level);

While(1) 循环中的最后一条语句是调用 xSemaphoreTake(),将信号量的地址和常量 portMAX_DELAY 作为参数。后一个参数将通知 RTOS 无限期地暂停线程,直到从 IRQ03 中断服务程序调 用的回调函数中释放信号量为止。

while (1)
{
    R_IOPORT_PinWrite (&g_ioport_ctrl, BSP_IO_PORT_05_PIN_01, led_level);
    if (led_level == BSP_IO_LEVEL_HIGH)
    {
        led_level = BSP_IO_LEVEL_LOW;
    }
    else
    {
        led_level = BSP_IO_LEVEL_HIGH;
    }
    xSemaphoreTake(g_s1_semaphore, portMAX_DELAY);
}

最后要执行的操作是添加回调函数本身。该函数应尽可能短,因为它将在中断服务程序的上下文中执行。 编写此函数十分简单:只需转到“Project Explorer”(项目资源管理器)中的“Developer AssistanceLED Threadg_external_irq03 External IRQ Driver on r_icu”(开发人员帮助 → LED 线程 → r_icu 上的 g_external_irq03 外部 IRQ 驱动程序),然后将所出现列表末尾的回调函数定义拖放到源文件中。

void external_irq03_callback(external_irq_callback_args_t *p_args)

如上图,回调函数内添加了一些内容:

FSP_PARAMETER_NOT_USED(p_args);

xSemaphoreGiveFromISR(g_s1_semaphore, NULL);

第一行中的宏将告知编译器回调函数不使用参数 p_args,从而避免编译器发出警告,而第二行中的宏则在每次按下按钮 S1 时释放信号量。注意,必须使用 give 系列函数的中断保存版本,因为此函数调用发生在 ISR 的上下文内。此调用的第二个参数是 *pxHigherPriorityTaskWoken。如果可能有一个或多个任 务由于信号量发生阻塞并等待该信号量变为可用状态,并且其中一个任务的优先级高于发生中断时执行的任 务,则此参数将在调用 xSemaphoreGiveFromISR() 后变为 true。在这种情况下,应在退出中断之前执行 上下文切换。由于在我们的示例中,没有其他任务依赖于此信号量,因此可以将此参数设置为 NULL

来自官方手册的完整代码

我目前编译存在一些问题,等我研究研究,再发一篇博客分享一下。

#include “led_thread.h” 

void led_thread_entry(void *pvParameters)
{
    FSP_PARAMETER_NOT_USED (pvParameters);
    extern bsp_leds_t g_bsp_leds;
    bsp_leds_t Leds = g_bsp_leds;

    uint8_t led_level = BSP_IO_LEVEL_HIGH;

    g_external_irq03.p_api->open (g_external_irq03.p_ctrl, g_external_irq03.p_cfg);
    g_external_irq03.p_api->enable (g_external_irq03.p_ctrl);
    while (1)
    {
        g_ioport.p_api->pinWrite (&g_ioport_ctrl, Leds.p_leds[BSP_LED_LED1], led_level);

        if (led_level == BSP_IO_LEVEL_HIGH)
        {
            led_level = BSP_IO_LEVEL_LOW;
        }
        else
        {
            led_level = BSP_IO_LEVEL_HIGH;
        }

        xSemaphoreTake (g_s1_semaphore, portMAX_DELAY);
    }
}
/* callback function for the SW1 push button; sets the semaphore */void external_irq03_callback(
        external_irq_callback_args_t *p_args)
{
    FSP_PARAMETER_NOT_USED (p_args);
    xSemaphoreGiveFromISR (g_s1_semaphore, NULL);
}

有关【致敬嵌入式攻城狮第2期活动预热征文】【致敬未来的攻城狮计划】连续打卡第10天+使用实时操作系统RTOS的更多相关文章

  1. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

    我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

  2. 电脑0x0000001A蓝屏错误怎么U盘重装系统教学 - 2

      电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。  准备工作:  1、U盘一个(尽量使用8G以上的U盘)。  2、一台正常联网可使用的电脑。  3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。  4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。  U盘启动盘制作步骤:  注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注

  3. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  4. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

  5. ruby - 在没有基准或时间的情况下用 Ruby 测量用户时间或系统时间 - 2

    因为我现在正在做一些时间测量,我想知道是否可以在不使用Benchmark类或命令行实用程序time的情况下测量用户时间或系统时间。使用Time类只显示挂钟时间,而不显示系统和用户时间,但是我正在寻找具有相同灵active的解决方案,例如time=TimeUtility.now#somecodeuser,system,real=TimeUtility.now-time原因是我有点不喜欢Benchmark,因为它不能只返回数字(编辑:我错了-它可以。请参阅下面的答案。)。当然,我可以解析输出,但感觉不对。*NIX系统的time实用程序也应该可以解决我的问题,但我想知道是否已经在Ruby中实

  6. 由于 libgmp.10.dylib 的问题,Ruby 2.2.0 无法运行 - 2

    我刚刚安装了带有RVM的Ruby2.2.0,并尝试使用它得到了这个:$rvmuse2.2.0--defaultUsing/Users/brandon/.rvm/gems/ruby-2.2.0dyld:Librarynotloaded:/usr/local/lib/libgmp.10.dylibReferencedfrom:/Users/brandon/.rvm/rubies/ruby-2.2.0/bin/rubyReason:Incompatiblelibraryversion:rubyrequiresversion13.0.0orlater,butlibgmp.10.dylibpro

  7. ruby - 以毫秒为单位获取当前系统时间 - 2

    在Ruby中,以毫秒为单位获取自纪元(1970)以来的当前系统时间的正确方法是什么?我试过了Time.now.to_i,好像不是我想要的结果。我需要结果显示毫秒并且使用long类型,而不是float或double。 最佳答案 (Time.now.to_f*1000).to_iTime.now.to_f显示包含十进制数字的时间。要获得毫秒数,只需将时间乘以1000。 关于ruby-以毫秒为单位获取当前系统时间,我们在StackOverflow上找到一个类似的问题:

  8. ruby - ri 有空文件 – Ubuntu 11.10, Ruby 1.9 - 2

    我正在运行Ubuntu11.10并像这样安装Ruby1.9:$sudoapt-getinstallruby1.9rubygems一切都运行良好,但ri似乎有空文档。ri告诉我文档是空的,我必须安装它们。我执行此操作是因为我读到它会有所帮助:$rdoc--all--ri现在,当我尝试打开任何文档时:$riArrayNothingknownaboutArray我搜索的其他所有内容都是一样的。 最佳答案 这个呢?apt-getinstallri1.8编辑或者试试这个:(非rvm)geminstallrdocrdoc-datardoc-da

  9. ruby-on-rails - gem install rmagick -v 2.13.1 错误 Failed to build gem native extension on Mac OS 10.9.1 - 2

    我已经通过提供MagickWand.h的路径尝试了一切,我安装了命令工具。谁能帮帮我?$geminstallrmagick-v2.13.1Buildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingrmagick:ERROR:Failedtobuildgemnativeextension./Users/ghazanfarali/.rvm/rubies/ruby-1.8.7-p357/bin/rubyextconf.rbcheckingforRubyversion>=1.8.5...yescheckingfor/

  10. ruby-on-rails - 如何构建复杂的 Rails 系统 - 2

    关闭。这个问题需要更多focused.它目前不接受答案。想改进这个问题吗?更新问题,使其只关注一个问题editingthispost.关闭8年前。Improvethisquestion我们有以下(以及更多)系统,我们将数据从一个应用推送/拉取到另一个:托管CRM(InsideSales.com)Asterisk电话系统(内部)横幅广告系统(openx,我们托管)潜在客户生成系统(自行开发)电子商务商店(spree,我们托管)工作板(本土)一些工作网站抓取+入站工作提要电子邮件传送系统(如Mailchimp,自主开发)事件管理系统(如eventbrite,自主开发)仪表板系统(大量图表和

随机推荐