[嵌入式系统-30]:RT-Thread -15- 中断管理与编程接口

目录

前言:

一、RT-Thread 中断工作机制

1.1 中断处理的一般过程如下:

1.2 RT-Thread增加中断处理的一般过程

1.3 中断向量表概述

1.4 中断向量表数据结构示例

1.5 RT-Thread 如何向内核注册中断处理函数:rt_hw_interrupt_install 

1.6 中断服务程序的种类

二、RT-Thread 中断处理过程

2.1 中断处理的基本流程

2.2 中断处理的组成部分

2.2 中断前导程序

2.3 用户中断服务程序

2.3.1 中断的底半部处理

2.4 中断后续程序

三、中断处理:定半部和底半部

3.1 基本概念

3.2 RT-Thead的实现原理

3.3 工作队列代码示例

3.4 rt_work_init 


前言:

说到中断,大家都不会陌生,对于裸机编程,很简单,编写指定的中断服务函数,然后添加到中断向量表中就可以了。

如果工程建立在 RTOS 基础之上,中断是如何管理的呢?本文带你了解 RT-Thread 的中断处理过程,以及如何添加中断服务程序和相关的注意事项。

一、RT-Thread 中断工作机制

1.1 中断处理的一般过程如下:

(1)定义中断服务函数;

(2)将其与 MCU 的中断向量表中的中断向量建立联系;

(3)中断发生时,中断服务程序开始执行,执行完成后,退出中断。

备注:

图中的中断处理程序有两层意思:

(1)没有操作系统时:由硬件的中断控制器完成。

(2)有操作系统时:由操作系统的中断驱动程序完成。

中断向量表也有两层意思:

(1)没有操作系统时:通常采用MCU定义的硬件中断向量表

(2)有操作系统时:通常采用操作系统定义的软件中断向量表

1.2 RT-Thread增加中断处理的一般过程

在RT-Thread中,中断处理是实现实时响应和处理外部事件的重要机制之一。下面是RT-Thread中断处理的一般步骤:

  1. 初始化中断处理:在使用中断之前,需要进行中断的初始化设置。这通常包括设置中断控制器(如ARM的NVIC),注册中断处理函数,并确定中断优先级等。

  2. 编写中断处理函数:在RT-Thread中,中断处理函数是以C语言函数的形式存在的。你需要编写中断处理函数,以完成对特定中断事件的响应。中断处理函数应尽可能地快速执行,通常应该避免执行耗时的操作和阻塞。

  3. 配置中断向量表:在一些架构中,例如ARM Cortex-M,中断向量表是用来存储中断处理函数地址的数据结构。你需要将中断处理函数的地址写入中断向量表,以确保中断事件发生时正确调用对应的中断处理函数。

  4. 使能和禁止中断:在适当的时机,你可能需要使能或禁止特定的中断。RT-Thread提供了API和宏来进行中断的使能和禁止操作,以控制中断的触发和影响。

  5. 中断处理的上下文切换:在多任务系统中,中断处理函数通常运行在中断上下文中。在一些情况下,中断处理函数可能需要与任务进行通信或共享资源。在这种情况下,你需要小心处理中断上下文与任务上下文之间的数据同步和保护。

需要注意的是,由于RT-Thread适用于各种平台和架构,中断处理的具体实现可能会因平台而异。一些平台可能会有额外的中断控制器或机制,需要根据具体平台的文档和要求进行设置和编写中断处理代码。

1.3 中断向量表概述

在 RT-Thread 中,中断向量表是一个存储中断处理函数地址数据结构,它提供了一个中断发生时执行相应中断处理函数的映射关系

中断向量表的具体实现方式和配置方法取决于所使用的处理器架构和编译器

下面是关于 RT-Thread 中断向量表的一般概述:

  1. 处理器架构的差异: 不同的处理器架构(如 ARM Cortex-M、MIPS、PowerPC 等)可能有不同的中断向量表实现方式和配置方法。在 RT-Thread 中,针对不同的处理器架构会有相应的中断向量表处理机制和相关配置选项。

  2. 存储中断处理函数地址: 中断向量表存储了每个中断号对应的中断处理函数地址。当中断事件发生时,处理器会根据中断号找到相应的中断处理函数地址,并跳转到该地址执行中断处理代码。

  3. 配置方法: 针对特定处理器架构和编译器,配置中断向量表可能会涉及到汇编语言级别的操作,包括将中断处理函数地址写入相应的中断向量表位置。在一些处理器架构中,中断向量表的起始地址可以通过特定的寄存器进行配置,即配置中断向量表的入口地址

  4. 编译器选项: 对于某些处理器架构和编译器,中断向量表的配置可能会涉及编译器选项或宏定义。一些编译器和处理器架构会提供内置的中断向量表处理机制,可以通过编译器选项或宏定义来配置。

  5. RTOS 的支持: 在使用 RT-Thread 这样的实时操作系统时,通常会有相关的 API 和机制来简化中断向量表的配置和中断处理函数的注册。RT-Thread 提供了相应的函数接口来方便用户注册和处理中断。

1.4 中断向量表数据结构示例

在 RT-Thread 中,中断向量表的具体实现方式取决于你所使用的处理器架构和编译器。以下示例以 ARM Cortex-M 处理器为例,演示如何配置中断向量表。

通常来说,在 ARM Cortex-M 处理器中,中断处理函数是存储在中断向量表中的一组指令地址。每个中断号有相应的中断处理函数地址,当中断发生时,处理器会跳转到相应中断号处的指令地址执行中断处理函数。

假设我们有一个简单的中断处理函数 my_interrupt_handler,我们将配置该中断处理函数到指定的中断号。

void my_interrupt_handler(void)
{
    // 中断处理函数的具体实现
    // ...
}

int main(void)
{
    // 将中断处理函数地址写入中断向量表
    // 中断号为IRQ_NUM,这里假设为10
    // 这里假设中断向量表地址为 0x00000000
    unsigned int *vector_table = (unsigned int *)0x00000000;
    
    vector_table[IRQ_NUM + 16] = (unsigned int)my_interrupt_handler;

    // ...其他初始化和操作
}

在这个示例中,我们手动将中断处理函数地址写入中断向量表。假设中断向量表的起始地址为 0x00000000(在实际情况中,中断向量表的地址可能有所不同),我们通过 vector_table[IRQ_NUM + 16] 来将 my_interrupt_handler 函数的地址写入中断向量表的相应位置。这里的 IRQ_NUM + 16 是因为 ARM Cortex-M 处理器的中断向量表中,前面有 16 个存储器位置用于存放特殊异常的处理函数地址。

需要注意的是,这只是一个简单的示例,实际的中断向量表配置和中断处理函数注册会更加复杂,涉及编译器、链接器、处理器架构等方面的配置和使用。具体的配置方法应当参考所使用的处理器架构(比如 ARM Cortex-M)和编译器(比如 GCC)的文档和示例代码,以确保正确的中断向量表配置。

1.5 RT-Thread 如何向内核注册中断处理函数:rt_hw_interrupt_install 

在RT-Thread中,你可以使用 rt_hw_interrupt_install 函数来向注册中断处理函数。这个函数通常用于将中断号、中断处理函数以及附加参数等信息注册到系统中,以便在中断事件发生时调用相应的处理函数。

下面是 rt_hw_interrupt_install 函数的原型:

rt_err_t rt_hw_interrupt_install(int vector, void (*handler)(int vector, void *parameter), void *parameter, const char* name);

参数说明:

  • vector:中断号,代表了中断的向量号。在不同的处理器架构下,中断号的取值范围和含义可能不同。需要根据实际使用的平台和设备手册来确定正确的中断号。
  • handler:中断处理函数的指针。这是一个指向中断处理函数的函数指针。
  • parameter:传递给中断处理函数的参数,如果没有额外参数可传递,可以设为 NULL。
  • name:中断名称,用于标识和描述这个中断,可以用于调试和跟踪。

示例:

void my_interrupt_handler(int vector, void* parameter)
{
    // 中断处理函数的具体实现
    rt_kprintf("Handling interrupt on vector %d\n", vector);
}

int main(void)
{
    // 向系统注册中断处理函数
    rt_hw_interrupt_install(IRQ_NUM, my_interrupt_handler, NULL, "my_interrupt");

    // ...其他初始化和操作
}

在示例中,我们向系统注册了一个叫做 my_interrupt_handler 的中断处理函数,通过 rt_hw_interrupt_install 函数指定了中断号和中断处理函数。当编号为 IRQ_NUM 的中断事件发生时,系统将调用我们注册的 my_interrupt_handler 函数来处理中断。

1.6 中断服务程序的种类

中断服务程序可以根据其功能和处理范围分为不同的种类。在嵌入式系统中常见的中断服务程序包括以下几种:

  1. 系统中断服务程序(System Interrupt Service Routine):系统中断服务程序由操作系统内核提供,用于处理与系统运行状态相关的中断事件,例如时钟中断、定时器中断、异常处理等。这些中断属于系统级的中断,对于整个系统的运行状态和调度具有重要意义。

  2. 设备中断服务程序(Device Interrupt Service Routine):设备中断服务程序用于处理硬件设备产生的中断事件,包括外部设备(如串口、网卡、显示设备)、内部设备(如定时器、DMA 控制器等)。设备中断服务程序通常由驱动程序中实现,用于响应设备产生的中断并进行相应的数据处理和状态更新。

  3. 用户自定义中断服务程序(User-Defined Interrupt Service Routine):用户自定义中断服务程序是用户编写的用于处理特定应用需求的中断处理程序。通过操作系统提供的接口,用户可以注册自己的中断服务程序,以响应特定的中断事件并执行特定的应用逻辑。

  4. 异常处理程序Exception Handling Routine):异常处理程序用于处理处理器产生的异常情况,例如除零错误、非法指令等。这些异常的处理可能需要特殊的中断服务程序来进行系统状态的恢复和错误处理。

以上种类涵盖了中断服务程序在嵌入式系统中的常见应用范围。不同种类的中断服务程序对系统的稳定性、性能和功能实现起着不同的作用,合理地设计和编写中断服务程序是嵌入式系统开发中的重要任务。

二、RT-Thread 中断处理过程

2.1 中断处理的基本流程

在 RT-Thread 中,中断处理过程包括中断的触发中断的响应中断的处理

下面是一般情况下 RT-Thread 中断处理的基本流程:

  1. 中断触发:中断是由外部事件触发的,比如硬件设备的状态变化(如定时器溢出、外部 IO 端口的改变等)。当外部事件满足中断触发条件时,处理器会引发中断。

  2. 中断响应:当中断触发时,处理器会立即暂停正在执行的程序,保存当前的上下文(包括程序计数器、寄存器等),然后转向处理相应中断的中断服务程序(ISR)。

  3. 中断服务程序的执行:在 RT-Thread 中,通常会有预定义中断服务程序来处理特定的中断事件。中断服务程序一般会做一些必要的准备工作,然后执行用户注册的中断处理函数

  4. 中断处理函数的执行:用户可以注册自己的中断处理函数来处理特定中断事件。当中断服务程序执行到这一步时,会调用用户注册的中断处理函数来执行真正的中断处理工作。

  5. 中断处理完成:当中断处理函数执行完成后,控制流会返回到中断服务程序,它会做一些清理工作,恢复之前被中断的程序的上下文,然后将控制返回给之前正在执行的程序。

在 RT-Thread 中,通常会提供相应的 API 函数来注册和处理中断。通过这些 API 函数,用户可以注册自定义的中断处理函数,并与硬件中断相对应。另外,RT-Thread 还提供了一些针对中断处理的专用数据结构和函数,如中断服务程序、中断控制器等,以便操作和管理中断处理过程。

总的来说,RT-Thread 提供了完善的中断处理机制和相关的 API 函数,使得用户可以方便地注册、管理和处理中断,实现对外部事件的及时响应和处理。建议用户查阅 RT-Thread 相关文档以获取更详细、针对性的中断处理方法和示例代码。

2.2 中断处理的组成部分

中断处理由以下几个组成部分组成:

  1. 中断控制器(Interrupt Controller):中断控制器是硬件设备,用于管理和控制中断。中断控制器负责检测中断请求、分发中断信号以及协调多个中断的优先级和屏蔽等。操作系统和驱动程序通过中断控制器与硬件设备进行交互,实现中断的管理和处理。

  2. 中断触发(Interrupt Triggering):中断的触发是由外部事件引起的,例如定时器的溢出、外部 I/O 端口的信号变化等。中断触发是中断处理的起始点

  3. 上下文保存与恢复(Context Save and Restore):在触发中断后,处理器需要保存当前被中断的任务(或者中断处理程序)的上下文,包括程序计数器、寄存器和其他关键寄存器的值等。保存现场的目的是为了在中断处理完成后,能够正确恢复之前被中断的任务的执行环境。

  4. 中断服务程序(Interrupt Service Routine,ISR)-- 内核:中断服务程序是用于响应和处理特定中断事件的代码段。当中断触发后,控制流会转移到相应的中断服务程序中执行相应的操作。中断服务程序根据中断类型和需求的不同,可能由操作系统内核提供的系统中断服务程序,或者由用户自定义的中断服务程序实现

  5. 中断处理函数(Interrupt Handler)-- 用户:中断处理函数是由用户编写的用于处理特定中断事件的函数。在内核的断服务程序中,当相应的中断类型触发时,会调用用户注册的中断处理函数来执行实际的中断处理工作。

  6. 中断处理完成(Interrupt Handling Completion):当中断处理函数执行完成后,需要进行清理工作并将控制流返回到原来的上下文中,恢复之前被中断的任务的执行。这个过程包括恢复被保存的上下文环境,重新设置相关寄存器的值等。

这些组成部分共同作用,实现对中断事件的及时响应和处理。不同的平台和操作系统可能有不同的中断处理机制和实现方式,用户在开发过程中需要了解所使用平台和操作系统的中断处理机制,并根据具体需求进行相应的配置和编码。

RT-Thread 将中断处理程序分为三部分:

  • 中断前导程序 =》 中断现场保护
  • 内核中断服务程序 + 用户中断处理函数
  • 中断后续程序 =》 中断现场恢复

2.2 中断前导程序

中断前导程序完成的工作为:

  • 保存 CPU 中断现场。不同 CPU 架构的实现方式有差异
  • 通知内核进入中断状态。通过调用 rt_interrupt_enter() 函数来完成。

rt_interrupt_enter() 函数定义如下:

void rt_interrupt_enter(void)
{
  rt_base_t level;
  level = rt_hw_interrupt_disable();
  rt_interrupt_nest ++;
  rt_hw_interrupt_enable(level);
}

2.3 用户中断服务程序

RT-Thread 的用户中断服务程序的内部实现,有两种情况:

  • 中断服务程序不进行线程切换。退出中断模式后,返回被中断的线程。
  • 中断处理过程中需要进行线程切换。这种情况下,会调用 rt_hw_context_switch_interrupt() 函数进行上下文切换,该函数跟 CPU 架构相关。

以 Cortex-M 架构为例,rt_hw_context_switch_interrupt() 函数的实现流程如下图所示。将设置需要切换的线程 rt_interrupt_to_thread 变量,然后触发 PendSV 异常。PendSV 异常是专门用来辅助上下文切换的,且被初始化为最低优先级的异常 。

2.3.1 中断的底半部处理

一个中断发生时,中断服务程序处理过程需要的时间有时候比较耗时。这种情况可以将该终端分割为两部分:

  • 中断上半部分。
  • 中断下半部分。

上半部分取得硬件状态和数据,打开被屏蔽的中断,给相关的线程发送一条通知,然后退出中断服务程序。

下半部分通过用户线程实现,线程接收到通知后,对状态或数据进行处理。

2.4 中断后续程序

中断后续程序主要完成的工作为:

  • 通知内核离开中断状态。通过调用 rt_interrupt_leave() 函数,将全局变量 rt_interrupt_nest 减 1。代码如下:
void rt_interrupt_leave(void)
{
  rt_base_t level;
  level = rt_hw_interrupt_disable();
  rt_interrupt_nest --;
  rt_hw_interrupt_enable(level);
}
  • 恢复中断前的 CPU 上下文。如果在中断处理过程中未进行线程切换,那么恢复 from 线程的 CPU 上下文;如果在中断中进行了线程切换,那么恢复 to 线程的 CPU 上下文。

三、中断处理:定半部和底半部

3.1 基本概念

在实时操作系统 RT-Thread 中,中断处理通常被划分为"顶半部"(Top Half)和"底半部"(Bottom Half):

  1. 顶半部(Top Half):顶半部是中断处理的第一个阶段,也是实时要求较高、执行时间较短的阶段。在这个阶段,主要完成的任务包括中断响应、执行必要的硬件处理、快速处理数据等。顶半部应该尽可能地快速执行完毕,并尽可能地禁用其他中断,以保证实时性和响应性。顶半部通常不涉及阻塞型操作、不涉及较长时间的计算或 I/O 操作

  2. 底半部(Bottom Half):底半部是中断处理的第二个阶段,也是相对较慢、执行时间较长的阶段。在底半部中,可以处理复杂、耗时的任务,如更新软件状态、进行资源管理、执行延迟的操作、进行阻塞处理等。底半部的执行不受实时要求,可以在稍后的时间点甚至在系统空闲时完成。

顶半部和底半部的划分有助于提高系统的实时性和可靠性。通过将中断处理过程分为两个阶段,可以保证在顶半部尽快响应中断、处理紧急任务,而将较慢、较耗时的任务推迟到底半部执行,以避免由于长时间中断处理而导致系统响应性下降。

请注意,顶半部和底半部的划分是 RT-Thread 中的概念,在其他操作系统或实时系统中,可能采用不同的术语或概念来描述中断处理的阶段划分。

3.2 RT-Thead的实现原理

在 RT-Thread 操作系统中,顶半部和底半部的实现基于软中断和工作队列,其原理如下:

  1. 顶半部(Top Half):

    • 顶半部主要负责快速响应中断、处理硬件相关任务以及其他关键任务。在 RT-Thread 中,通常会创建一个软中断作为顶半部的处理入口。当中断发生时,会触发相应的软中断处理函数,该函数会尽快完成中断处理所需的关键任务
    • 顶半部的实现原理是通过在响应中断时,调用相应的软中断处理函数来快速处理中断,保证了实时性和响应性。软中断的设计避免了在中断服务程序中处理复杂的任务和长时间的计算,从而提高了系统的性能和可靠性。
  2. 底半部(Bottom Half):

    • 在 RT-Thread 中,底半部一般通过工作队列来实现。底半部主要用于处理那些不需要立即处理的、可以延迟执行的任务,例如更新软件状态、执行延迟的操作等。当底半部任务需要执行时,会被提交到工作队列中,稍后由工作队列调度执行。
    • 底半部的实现原理是通过将需要延迟执行的任务提交到工作队列中,由工作队列在系统空闲或者特定时间点执行相应的任务,以避免阻塞顶半部的处理过程,确保顶半部的实时性。

综上所述,RT-Thread 中的顶半部和底半部通过软中断和工作队列的机制实现。顶半部通过软中断快速处理关键任务,保证了中断服务程序的实时性;底半部则通过工作队列实现延迟处理,避免阻塞顶半部的执行,提高系统的性能和可靠性。RT-Thread通过顶半部和底半部共同完成中断处理

3.3 工作队列代码示例

工作队列是一种常用的用于延迟执行任务的机制,在中断处理中经常被使用。在 RT-Thread 操作系统中,可以通过工作队列来实现中断处理的部分任务延迟执行。

以下是一个使用工作队列实现中断处理的代码示例:

#include <rtthread.h>

// 中断处理函数
void interrupt_handler(void *parameter)
{
    // 处理中断事件...

    // 提交任务到工作队列,即把interrupt_task后处理函数提交到工作队,等待后处理
    rt_work_submit(interrupt_task, parameter);
}

// 工作队列任务函数
void interrupt_task(void *parameter)
{
    // 执行中断处理的部分任务...
}

int main(void)
{
    // 初始化工作队列
    static struct rt_work interrupt_work;
    rt_work_init(&interrupt_work, interrupt_task, RT_NULL);

    // 注册中断
    interrupt_register(interrupt_handler);

    while (1)
    {
        // 其他任务处理...

        // 在适当的时机处理工作队列任务
        rt_work_schedule();
    }
}

在上述示例中,中断处理函数 interrupt_handler 负责处理中断事件。当中断发生时,调用 rt_work_submit 将部分任务提交到工作队列 interrupt_work 中。工作队列会在适当的时机调度执行中断任务,执行任务函数 interrupt_task

需要注意的是,工作队列的执行时机由调度器决定。在循环中的 rt_work_schedule 函数会调度工作队列中的任务进行执行。调用该函数时,如果有任务在工作队列中等待执行,RT-Thread 调度器会选择一个合适的时机来执行其中的任务。

通过工作队列的延迟执行机制,可以将中断处理过程中的一部分任务从中断上下文移至工作队列上下文,减小中断服务程序的执行时间,提高系统的实时性和响应能力

3.4 rt_work_init 

在 RT-Thread 中, rt_work_init 函数用于初始化工作结构体和与之关联的工作函数。以下是 rt_work_init 的基本用法:

#include <rtthread.h>

static struct rt_work my_work;
void work_entry(void *parameter)
{
    /* 执行工作队列中的任务 */
}

int main(void)
{
    /* 初始化工作结构体,并绑定工作函数 */
    rt_work_init(&my_work, work_entry, RT_NULL);

    /* 提交工作到工作队列 */
    rt_work_submit(&my_work);

    return 0;
}

  • 19
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 嵌入式实时操作系统RTOS)是一种专门为嵌入式系统设计的操作系统,它具有实时性、可靠性、高效性等特点。RT-Thread是一款开源的嵌入式实时操作系统,它采用了轻量级的内核设计,支持多种处理器架构和多种外设驱动,具有灵活的可扩展性和易用性。RT-Thread的设计和实现涉及到内核、任务调度、内存管理、设备驱动、文件系统等多个方面,需要深入理解嵌入式系统的原理和技术。 ### 回答2: 嵌入式实时操作系统(Real-Time Operating System,RTOS)是指专门为嵌入式系统设计的操作系统,它具有小巧、高效、可靠等特点。其中,rt-thread是一个轻量级、开源、可裁剪的实时操作系统内核,其设计简单、可靠性高、实时性好、灵活性强、可移植性强等特点,被广泛应用于各种嵌入式系统中。 rt-thread的设计理念是以线程为中心,支持多线程应用程序的同时,同时支持时钟中断、定时器、信号量、互斥锁、信号、消息队列等机制,使其能够更好地适应实时应用需求。rt-thread采用分层设计,底层由硬件驱动层和操作系统内核层组成,上层可根据应用需求进行定制。rt-thread内核采用模块化设计,不同的模块可以互相独立运行,也可以进行组合和交错。 rt-thread还支持多种调试和优化技术,如GDB、OCD等调试器,并集成了实时性能分析、内存泄漏检测等优化工具。除此之外,rt-thread还提供了工具链、文档、示例程序等支持,方便用户集成和使用。 总的来说,rt-thread是一个高度可定制化、可裁剪、高效、灵活的嵌入式实时操作系统内核,能够满足不同实时应用场景的需求,其应用范围涵盖了智能家居、工业控制、医疗设备、智能交通、消费电子等领域。 ### 回答3: 嵌入式实时操作系统RTOS)是一种用于嵌入式系统操作系统,其主要目标是提供实时性、可靠性和高效性。RT-Thread是一种轻量级、开源、可裁剪的RTOS,旨在满足小型嵌入式设备的要求。它支持多任务、软件定时器、线程同步和通信机制,并提供了多种驱动程序和应用程序框架。RT-Thread有着许多优秀的特性,例如快速启动、低占用率、模块化、兼容性、扩展性、可裁剪和易用性等。 RT-Thread的设计基于三大核心要素:线程、事件和信号量。通过这些要素,RT-Thread实现了多任务调度和同步机制。此外,RT-Thread还提供了丰富的IPC机制,包括邮箱、消息队列和信号量等,以便实现线程之间的通信和同步。 RT-Thread的高可裁剪性也是其最大的特点之一。用户可以根据实际需求进行系统裁剪和优化,从而获得最小、最高效的系统。这种裁剪性基于RT-Thread内核代码的高度模块化,为用户提供了方便的系统配置和扩展接口RT-Thread的驱动程序也是其核心之一。RT-Thread提供了许多通用设备驱动,例如串口、SPI、I2C、USB、以太网等,方便用户快速实现硬件和软件的整合。 RT-Thread的开发也非常方便,支持多种开发环境和编译器,包括Keil、IAR和GCC等,使开发人员能够在各种平台和系统中进行开发工作。 总之,RT-Thread是一种优秀的嵌入式实时操作系统,具有方便的裁剪性、高效的多任务调度和同步机制、丰富的IPC机制和通用设备驱动程序等特点,非常适合小型嵌入式设备的开发使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

文火冰糖的硅基工坊

你的鼓励是我前进的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值