I/O设备模型

2023-12-16

I/O设备模型

绝大部分的嵌入式系统都包括一些I/O(Input/Outut,输入/输出)设备,例如仪器上的数据显示屏、工业设备上的串口通信、数据采集设备上用于保存数据的Flash或SD卡,以及网络设备的以太网接口等。

I/O设备模型框架

RT-Thread提供了一套简单的I/O设备模型框架,如图所示,它位于硬件和应用程序之间,共分成三层,从下到下分别是I/O设备管理层、设备驱动框架层、设备驱动层。

在这里插入图片描述
应用程序通过I/O设备管理接口获得正确的设备驱动,然后通过这个设备驱动与底层I/O硬件设备进行数据交互。

I/O设备管理层实现了对设备驱动程序的封装。应用程序通过图中的I/O设备管理层提供的标准接口访问底层设备,设备驱动程序的升级、更替不会对上层应用产生影响。这种方式使得设备的硬件操作相关的代码能够独立于应用程序而存在,双方只需关注各自的功能实现,从而降低了代码的耦合型、复杂性,提高了系统的可靠性。

设备驱动框架层是对同类硬件设备驱动的抽象,将不同厂家的同类硬件设备驱动中相同的部分抽取出来,将不同部分留出接口,由驱动程序实现。

设备驱动层是一组驱使硬件设备工作的程序,实现访问硬件设备的功能。
它负责创建和注册I/O设备,对于操作逻辑简单的设备,可以不经过设备驱动框架层,直接将设备注册到I/O设备管理器中。

在这里插入图片描述

  • 设备驱动根据设备模型定义,创建出具备硬件访问能力的设备实例,将该设备通过rt_device_register()接口注册到I/O设备管理器中。
  • 应用程序通过rt_device_find()接口查找到设备,然后使用I/O设备管理接口来访问硬件。

对于另一些设备,如看门狗等,则会将创建的设备实例先注册到对应的设备驱动框架中,再由设备驱动框架向I/O设备管理器进行注册,主要有以下几点:

  • 看门狗设备驱动程序根据看门狗设备模型定义,创建出具备硬件访问能力的看门狗设备实例,并将该看门狗设备通过rt_hw_watchdog_register()接口注册到看门狗设备驱动框架中。
  • 看门狗设备驱动框架通过rt_device_register()接口将看门狗注册到I/O设备管理器中。
  • 应用程序通过I/O设备管理接口来访问看门狗设备硬件。

在这里插入图片描述

I/O设备模型

RT-Thread的设备模型是建立在内核对象模型基础之上的,设备被认为是一类对象,被纳入对象管理器的范畴。每个设备对象都是由基对象派生而来,每个具体设备都可以继承其父类对象的属性,并派生出其私有属性。

在这里插入图片描述

struct rt_object
{
	char name[RT_NAME_MAX];
	rt_uint8_t type;
	rt_uint8_t flag;

	rt_list_t list;
};
typedef struct rt_object *rt_object_t;
struct rt_device
{
	struct rt_obejct parent;
	enum rt_device_class_type type;
	rt_uint16_t flag;
	rt_uint16_t open_flag;

	rt_uint8_t ref_count;
	rt_uint8_t device_id;

	/* device call back */
	rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size);
	rt_err_t (*tx_complete)(rt_device_t dev, void *buffer);

	 /* common device interface */
    rt_err_t  (*init)   (rt_device_t dev);
    rt_err_t  (*open)   (rt_device_t dev, rt_uint16_t oflag);
    rt_err_t  (*close)  (rt_device_t dev);
    rt_size_t (*read)   (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
    rt_size_t (*write)  (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
    rt_err_t  (*control)(rt_device_t dev, int cmd, void *args);
	
	void *user_data;
}

I/O设备类型

enum rt_device_class_type
{
    RT_Device_Class_Char = 0,                           /**< character device */
    RT_Device_Class_Block,                              /**< block device */
    RT_Device_Class_NetIf,                              /**< net interface */
    RT_Device_Class_MTD,                                /**< memory device */
    RT_Device_Class_CAN,                                /**< CAN device */
    RT_Device_Class_RTC,                                /**< RTC device */
    RT_Device_Class_Sound,                              /**< Sound device */
    RT_Device_Class_Graphic,                            /**< Graphic device */
    RT_Device_Class_I2CBUS,                             /**< I2C bus device */
    RT_Device_Class_USBDevice,                          /**< USB slave device */
    RT_Device_Class_USBHost,                            /**< USB host bus */
    RT_Device_Class_USBOTG,                             /**< USB OTG bus */
    RT_Device_Class_SPIBUS,                             /**< SPI bus device */
    RT_Device_Class_SPIDevice,                          /**< SPI device */
    RT_Device_Class_SDIO,                               /**< SDIO bus device */
    RT_Device_Class_PM,                                 /**< PM pseudo device */
    RT_Device_Class_Pipe,                               /**< Pipe device */
    RT_Device_Class_Portal,                             /**< Portal device */
    RT_Device_Class_Timer,                              /**< Timer device */
    RT_Device_Class_Miscellaneous,                      /**< Miscellaneous device */
    RT_Device_Class_Sensor,                             /**< Sensor device */
    RT_Device_Class_Touch,                              /**< Touch device */
    RT_Device_Class_PHY,                                /**< PHY device */
    RT_Device_Class_Security,                           /**< Security device */
    RT_Device_Class_Unknown                             /**< unknown device */
};

其中字符设备、块设备是常用的设备类型,它们的分类依据是设备数据与系统之间的传输处理方式。
字符模式设备允许非结构的数据传输,即通常数据传输采用串行的形式,每次一个字节。字符设备通常是一些简单设备,如串口、按键。

块设备每次传输一个数据块,例如每次传输512个字节数据。这个数据块是硬件强制性的,数据块可能使用某类数据接口或某些强制性的传输协议,否则就可能发生错误。
因此,有时块设备驱动程序对读或写操作必须执行附加的工作。
在这里插入图片描述
当系统服务于一个具有大量数据的写操作时,设备驱动程序必须首先将数据分为多个包,每个包采用设备指定的数据尺寸。
而在实际过程中,最后一部分数据尺寸有可能小于正常的设备块尺寸。
如上图中每个块使用单独的写请求写入到设备中,头3个直接进行写操作。
但最后一个数据块尺寸小于设备块尺寸,设备驱动程序必须使用不同于前3个块的方式处理最后的数据块。
通常情况下,设备驱动程序需要首先执行相对应的设备块的读操作,然后把写入数据覆盖到读出数据上,然后再把这个“合成”的数据块作为一整个块写回到设备中。

例如块4,驱动程序需要先把块4所对应的设备块读出来,然后将需要写入的数据覆盖至从设备块读出的数据上,使其合并成一个新的块,最后再写回到块设备中。

创建和注册I/O设备

驱动层负责创建设备实例,并注册到I/O设备管理器中,可以通过静态声明的方式创建设备实例,也可以用下面的接口进行动态创建:

rt_device_t rt_device_create(int type, int attach_size)
{
	int size;
	rt_device_t device;

	size = RT_ALIGN(sizeof(struct rt_device), RT_ALIGN_SIZE);
	attach_size = RT_ALIGN(attach_size, RT_ALIGN_SIZE);

	size += attach_size;
	device = (rt_device_t)rt_malloc(size);
	if(device)
	{
		rt_memset(device, 0x0, sizeof(struct rt_device));
		device->type = (enum rt_device_class_type)type;
	}
	return device;
}

调用该接口时,系统会从动态堆内存中分配一个设备控制块,大小为struct rt_device和attach_size的和,设备的类型由参数type设定。
设备被创建后,需要实现它访问硬件的操作方法。

struct rt_device_ops
{
    /* common device interface */
    rt_err_t  (*init)   (rt_device_t dev);
    rt_err_t  (*open)   (rt_device_t dev, rt_uint16_t oflag);
    rt_err_t  (*close)  (rt_device_t dev);
    rt_size_t (*read)   (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
    rt_size_t (*write)  (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
    rt_err_t  (*control)(rt_device_t dev, int cmd, void *args);
};
  • init:初始化设备。设备初始化完成后,设备控制块的flag会被置成已激活状态(RT_DEVICE_FLAG_ACTIVATED)。如果设备控制块中的flag标志已经设置成激活状态,那么再运行初始化接口就会立刻返回,而不会重新进行初始化。
rt_err_t rt_device_init(rt_device_t dev)
{
	rt_err_t result = RT_EOK;
	if(dev->init != RT_NULL)
	{
		result = dev->init(dev);
		if (result != RT_EOK)
            {
                RT_DEBUG_LOG(RT_DEBUG_DEVICE, ("To initialize device:%s failed. The error code is %d\n",
                           dev->parent.name, result));
            }
            else
            {
                dev->flag |= RT_DEVICE_FLAG_ACTIVATED;
            }
	}
}
  • open。打开设备。有些设备并不是系统一启动就已经打开开始运行,或者设备需要进行数据收发,但如果上层应用还未准备好,设备也不应该默认已经使能并开始接收数据。所以建议在写底层驱动程序时,在调用open接口时才使能设备。
rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag)
{
	rt_err_t result = RT_EOK;
	RT_ASSERT(dev != RT_NULL);
	RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);

	if(!(dev->flag & RT_DEVICE_FLAG_ACTIVATED))
	{
		if(device_init != RT_NULL)
		{
			result = device_init(dev);
			if (result != RT_EOK)
            {
                RT_DEBUG_LOG(RT_DEBUG_DEVICE, ("To initialize device:%s failed. The error code is %d\n",
                           dev->parent.name, result));

                return result;
            }
		}
		dev->flag |= RT_DEVICE_FLAG_ACTIVATED;
	}
	/* 如果设备是一个独立的设备并且已经打开 */
	if ((dev->flag & RT_DEVICE_FLAG_STANDALONE) &&
        (dev->open_flag & RT_DEVICE_OFLAG_OPEN))
    {
        return -RT_EBUSY;
    }
	/* call device_open interface */
    if (device_open != RT_NULL)
    {
        result = device_open(dev, oflag);
    }
 	else
 	{
 		dev->open_flag = (oflag & RT_DEVICE_OFLAG_MASK);
 	}

	/* set open flag */
    if (result == RT_EOK || result == -RT_ENOSYS)
    {
        dev->open_flag |= RT_DEVICE_OFLAG_OPEN;

        dev->ref_count++;
        /* don't let bad things happen silently. If you are bitten by this assert,
         * please set the ref_count to a bigger type. */
        RT_ASSERT(dev->ref_count != 0);
    }

    return result;
}
  • close:关闭设备,在打开设备时,设备控制块会维护一个打开计数,在打开设备时进行+1操作,在关闭设备时进行-1操作,当计数器变为0时,才会进行真正的关闭操作。
rt_err_t rt_device_close(rt_device_t dev)
{
	rt_err_t result = RT_EOK;
	/* parameter check */
    RT_ASSERT(dev != RT_NULL);
    RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);

	if(dev->ref_count == 0)
		return -RT_ERROR;
	dev->ref_count--;
	if(dev->ref_count != 0)
		return RT_EOK;
	if(dev->close != RT_NULL)
		result = dev->close(dev);
	/* set open flag */
    if (result == RT_EOK || result == -RT_ENOSYS)
    	dev->open_flag = RT_DEVICE_OFLAG_CLOSE;
    return result;
}
  • read。从设备读取数据。参数pos是读取数据的偏移量,但是有些设备并不一定需要指定偏移量,例如串口设备,驱动程序应忽略这个参数。而对于块设备来说,pos以及size都是以块设备的数据块大小为单位的。
    例如块设备的数据块大小是512,而参数中pos=10,size=2,那么驱动程序应该返回设备中第10个块(从第0个块作为起始),共计2个块的数据。这个接口返回的类型是rt_size_t,即读到的字节数或块数目。正常情况下应该返回参数中size的数值,如果返回零需要设置对应的errno值。
rt_size_t rt_device_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
	/* parameter check */
    RT_ASSERT(dev != RT_NULL);
    RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);

    if (dev->ref_count == 0)
    {
        rt_set_errno(-RT_ERROR);
        return 0;
    }

    /* call device_read interface */
    if(device_read != RT_NULL)
    	return dev->read(dev, pos, buffer, size);
    rt_set_errno(-RT_ENOSYS);
    return 0;
}
  • write:向设备写入数据。参数pos是写入数据的偏移量。与读操作类似,对于块设备来说,pos以及size都是以块设备的数据块大小为单位的。这个接口返回的类型是rt_size_t,即真实写入数据的字节数或块数目。正常情况下应该会返回参数中 size 的数值,如果返回零请设置对应的 errno 值。
rt_size_t rt_device_write(rt_device_t dev,
                          rt_off_t    pos,
                          const void *buffer,
                          rt_size_t   size)
{
    /* parameter check */
    RT_ASSERT(dev != RT_NULL);
    RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);

    if (dev->ref_count == 0)
    {
        rt_set_errno(-RT_ERROR);
        return 0;
    }

    /* call device_write interface */
    if (device_write != RT_NULL)
    {
        return device_write(dev, pos, buffer, size);
    }

    /* set error code */
    rt_set_errno(-RT_ENOSYS);

    return 0;
}
RTM_EXPORT(rt_device_write);
  • control:根据cmd命令控制设备。命令往往是由底层各类设备驱动自定义实现。例如参数RT_DEVICE_CTRL_BLK_GETGEOME,意思是获取块设备的大小信息。
rt_err_t rt_device_control(rt_device_t dev, int cmd, void *arg)
{
    /* parameter check */
    RT_ASSERT(dev != RT_NULL);
    RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);

    /* call device_write interface */
    if (device_control != RT_NULL)
    {
        return device_control(dev, cmd, arg);
    }

    return -RT_ENOSYS;
}
RTM_EXPORT(rt_device_control);
  • 当一个动态创建的设备不再需要使用时可以通过如下函数来销毁。
void rt_device_destroy(rt_device_t dev)
{
	rt_object_detach(&(dev->parent));
	rt_free(dev);
}
  • 设备被创建后,需要注册到I/O设备管理器中,应用程序才能够访问。
rt_err_t rt_device_register(rt_device_t dev, const char *name, rt_uint16_t flags)
{
	if (dev == RT_NULL)
        return -RT_ERROR;

    if (rt_device_find(name) != RT_NULL) //应当避免重复注册已经注册的设备,已经注册相同名字的设备。
        return -RT_ERROR;

	rt_object_init(&(dev->parent), RT_Object_Class_Device, name);
	dev->flag = flags;
	dev->ref_count = 0;
	dev->open_flag = 0;
	return RT_EOK;
}

flags参数支持下列参数:

#define RT_DEVICE_FLAG_RDONLY       0x001 /* 只读 */
#define RT_DEVICE_FLAG_WRONLY       0x002 /* 只写  */
#define RT_DEVICE_FLAG_RDWR         0x003 /* 读写  */
#define RT_DEVICE_FLAG_REMOVABLE    0x004 /* 可移除  */
#define RT_DEVICE_FLAG_STANDALONE   0x008 /* 独立   */
#define RT_DEVICE_FLAG_SUSPENDED    0x020 /* 挂起  */
#define RT_DEVICE_FLAG_STREAM       0x040 /* 流模式  */
#define RT_DEVICE_FLAG_INT_RX       0x100 /* 中断接收 */
#define RT_DEVICE_FLAG_DMA_RX       0x200 /* DMA 接收 */
#define RT_DEVICE_FLAG_INT_TX       0x400 /* 中断发送 */
#define RT_DEVICE_FLAG_DMA_TX       0x800 /* DMA 发送 */

设备流模式RT_DEVICE_FLAG_STREAM参数用于向串口终端输出字符串,当输出字符是"\n"时,自动在前面补一个“\r”。

当设备注销后,设备将从设备管理器中移除,但不会释放设备控制块占用的内存。

看门狗设备注册示例

struct rt_device_ops
{
    /* common device interface */
    rt_err_t  (*init)   (rt_device_t dev);
    rt_err_t  (*open)   (rt_device_t dev, rt_uint16_t oflag);
    rt_err_t  (*close)  (rt_device_t dev);
    rt_size_t (*read)   (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
    rt_size_t (*write)  (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
    rt_err_t  (*control)(rt_device_t dev, int cmd, void *args);
};

const static struct rt_device_ops wdt_ops =
{
	rt_watchdog_init,
	rt_watchdog_open,
	rt_watchdog_close,
	RT_NULL,
	RT_NULL,
	rt_watchdog_control
};

rt_err_t rt_hw_watchdog_register(struct rt_watchdog_device *wtd,
                                 const char                *name,
                                 rt_uint32_t                flag,
                                 void                      *data)
{
    struct rt_device *device;
    RT_ASSERT(wtd != RT_NULL);

    device = &(wtd->parent);

    device->type        = RT_Device_Class_Miscellaneous;
    device->rx_indicate = RT_NULL;
    device->tx_complete = RT_NULL;

    device->ops         = &wdt_ops;
    device->user_data   = data;

    /* register a character device */
    return rt_device_register(device, name, flag);
}

访问I/O设备

应用程序通过I/O设备管理接口来访问硬件设备,当设备驱动程序实现后,应用程序就可以访问该硬件。
在这里插入图片描述
在这里插入图片描述
设备驱动框架层在components/drivers里面查找。
设备驱动层在libraries/HAL_Drivers

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

I/O设备模型 的相关文章

  • texlive支持中文的简单方法

    1 确保tex文件的编码方式是UTF 8 2 在文档开始处添加一行命令即可 即 usepackage UTF8 ctex 如下所示 documentclass article usepackage UTF8 ctex begin artic
  • 线程和进程的区别(面试必备)

    参考文章 https www jianshu com p 2dc01727be45 线程与进程的区别通俗的解释 https www jianshu com p 8ad441510860 附加可参考文章 https baijiahao bai
  • CentOS 7 关闭网络限制

    1 安装CentOS 7 3操作系统mini版本即可 2 设置关闭Selinux 编辑 etc selinux config vi etc selinux config SELINUX disabled 重启机器 查看selinux状态 s
  • 操作系统学习(九)进程通信

    一 知识总览 二 定义 进程通信是指进程之间的信息交换 每个进程都拥有自己的内存空间 是相互独立的 这样在每个进程执行时 才不会被其他进程所干扰 三 进程通信的方式 1 共享存储 1 两个进程对共享区的访问必须是互斥的 即在同一时间内 只允
  • Client-Server问题

    1 实验内容与要求 需要创建客户Client和服务器Server两个进程 它们通过管道进行通信 Client进程派生3个生产者线程 一个管道线程 共享一个20个slots的缓冲区 每个生产者线程随机产生一个数据 打印出来自己的id 进程 线
  • 设备管理过程

    复杂度2 5 机密度2 5 最后更新2021 04 19 AIX中对设备会有如下五个操作 define aix下能看到设备的定义 但驱动程序并没有加载或初始化 该设备不可用 lsdev看到设备时defined 很多逻辑设备 vg lv等 只
  • office2013 excel 打开时提示excel词典xllex.dll文件丢失或损坏

    今天打开Excel时 发现报错 xllex dll文件丢失或损坏 我用的是office2013 网上找了好多都是2007的dll文件 导入不了 于是乎重装office 问题解决 但还是把xllex dll烤出来做个备份吧 参考下面步骤即可
  • win10 Enable developer Mode

    经过漫长的安装过程 win10终于装上了vs2015 rc 写个小程序试试 结果提示 根据提示打开 设置 更新 for developer 据说应该有这么个界面 但是这个界面根本出不来 直接闪退的说 翻 MSDN 终于翻出了解决方法 htt
  • nslookup命令详解

    nslookup命令用于查询DNS的记录 查看域名解析是否正常 在网络故障的时候用来诊断网络问题 nslookup的用法相对来说还是蛮简单的 主要是下面的几个用法 1 直接查询 这个可能大家用到最多 查询一个域名的A记录 nslookup
  • Linux系统编程:多线程交替打印ABC

    引言 分享关于线程的一道测试题 因为网上基本都是Java的解决方法 决定自己写一篇来记录一下线程的学习 问题描述 编写一个至少具有三个线程的程序 称之为线程 A B 和 C 其中线程 A 输出字符 A 线程 B 输出字符 B 线程 C 输出
  • LWIP在STM32上的移植

    本文做记录摘抄 加上自己的体会 文章标题 STM32使用LWIP实现DHCP客户端 http www cnblogs com dengxiaojun p 4379545 html 该文章介绍了几点 LWIP源码的内容 关键点 1 inclu
  • 程序员的自我修养——链接、装载与库

    1 温故而知新 操作系统概念 北桥 连接高速芯片 系统调用接口 以软件中断的方式提供 如Linux使用0x80号中断作为系统调用接口 多任务系统 进程隔离 设备驱动 直接使用物理内存的弊端 地址空间不隔离 内存使用效率低 程序运行的地址不确
  • Elasticsearch 日志

    下载并安装 Filebeat 首次使用 Filebeat 请参阅入门指南 复制代码片段 curl L O https artifacts elastic co downloads beats filebeat filebeat 7 2 0
  • Linux alien命令

    一 简介 alien是一个用于在各种不同的Linux包格式相互转换的工具 其最常见的用法是将 rpm转换成 deb 或者反过来 二 安装 http toutiao com a6188997768449360129 三 实例 http www
  • Linux常用命令记录

    文章目录 1 软件安装 安装软件 来自源服务器 安装 deb软件 来自本地 deb文件 修复依赖关系 卸载软件 2 文件 文件夹操作 删除文件夹 移动文件 文件重命名 3 程序查看 处理 进程查看 查看端口占用情况 强制终止程序 4 解压文
  • 内存管理——分页分段

    一 分页存储管理 1 页面与页框 1 页面 将一个进程的逻辑地址空间分成若干个大小相等的片 称为页面或页 并为各页加以编号 2 页框 相应于页面 把内存空间分成和页面相同大小的若干个存储块 称为 物理 块或页框 frame 3 页内碎片 在
  • OS——文件管理系统磁盘的结构之搞清盘面和柱面

    如上图 每个柱面有三个盘面 即就是3个磁道 柱面可以抽象的理解成是一个套一个的立体的同心圆柱体 例 2019年408真题 磁盘有300个柱面 每个柱面有10个磁道 每个磁道有200个扇区 扇区大小为512B 则磁盘容量 分析 每个柱面有10
  • CentOS Linux服务器安全设置

    转自 http www osyunwei com archives 754 html 引言 我们必须明白 最小的权限 最少的服务 最大的安全 所以 无论是配置任何服务器 我们都必须把不用的服务关闭 把系统权限设置到最小话 这样才能保证服务器
  • Linux(12):磁盘配额(Quota)与进阶文件系统管理

    磁盘配额 Quota 的应用与实作 Quota 的一般用途 针对 www server 例如 每个人的网页空间的容量限制 针对 mail server 例如 每个人的邮件空间限制 针对 file server 例如 每个人最大的可用网络硬盘
  • I/O设备模型

    I O设备模型 绝大部分的嵌入式系统都包括一些I O Input Outut 输入 输出 设备 例如仪器上的数据显示屏 工业设备上的串口通信 数据采集设备上用于保存数据的Flash或SD卡 以及网络设备的以太网接口等 I O设备模型框架 R

随机推荐

  • CleanMyMac X这一款mac电脑清理垃圾文件软件好用吗?

    CleanMyMac X您的 Mac 极速如新 点按一下 即可优化调整整个 Mac畅享智能扫描 这款超级简单的工具用于优化您的 Mac 只需点按一下 即可运行所有任务 让您的 Mac 保持干净 快速并得到最佳防护 CleanMyMac 是一
  • 【git教程】

    目录 git与SVN的区别 集中式与分布式的区别 Windows上安装Git 创建版本库 仓库 repository 将文件添加到repository 报错处理 查看仓库的状态 版本回退 工作区和暂存区 管理
  • EasyRecovery2024国内免费的电脑数据恢复软件(一键备份还原)

    EasyRecovery2024是coco玛奇朵Ontrack 的技术杰作 它是一个硬盘数据恢复工具 能够帮你恢复丢失的数据以及重建文件系统 其 Professioanl 专业 版更是囊括了磁盘诊断 数据恢复 文件修复 E mail 修复等
  • FL Studio2024年最新中文版本如何下载?

    FL Studio是款专业的音频录制编辑软件 受到了广大制作人的喜爱 但有很多人不知道FL Studio应该如何使用 和小编一起往下看吧 FL Studio是款专业的音频录制编辑软件 可以针对作曲者的要求编辑出不同音律的节奏 例如鼓 镲 锣
  • fl studio2024中文版下载安装教程 亲测有效

    fl studio是一款功能强大的编曲软件 今天小编就为大家带来了详细的安装教程 需要的朋友一起看看吧 fl studio2024是一款功能强大的编曲软件 也就是众所熟知的水果软件 它可以编曲 剪辑 录音 混音 让您的计算机成为全功能录音室
  • CleanMyMac X2024值不值得下载?

    macOS已经成为最受欢迎的桌面操作系统之一 它提供了直观 简洁的用户界面 使用户可以轻松使用和管理系统 macOS拥有丰富的应用程序生态系统 还可以与其他苹果产品和服务紧密协作 如iPhone iPad 用户可以通过iCloud同步和共享
  • FL Studio水果软件最新版本号V21.0.3.3517内置中文补丁,可以切换成中文界面。

    FL Studio 21 0 3 3517 Producer Edition 全称Fruity Loops Studio 21 Producer Edition 就是大家熟悉的水果编曲软件 一个全能的音乐制作软件 包括编曲 录音 剪辑和混音
  • CorelDRAW2024好不好用?比其他矢量图设计软件有哪些优势

    CorelDRAW作为一款专业的矢量设计图软件 备受招聘公司 业内人士青睐 CorelDRAW是一款广泛应用于图形设计 图像编辑和排版的软件 其强大的功能和灵活性使其在设计师和艺术家中备受欢迎 然而 在进行CorelDRAW账户注册时 一些
  • EasyRecovery(数据恢复软件) 2024中文绿色无需激活版下载

    EasyRecovery 是一款功能强大且专业的数据恢复软件 软件能够对电脑误删的文件进行恢复 包括格式化硬盘是数据恢复 手机U盘数据恢复等 小编今天给大家带来的是根据官软件解压后直接使用 感兴趣的朋友快来下载使用吧 EasyRecover
  • FL Studio20官方版怎么下载安装?2024最新版图文详细教程

    水果音乐制作软件FL Studio2024是一款功能强大的软件音乐制作环境或数字音频工作站 DAW 本文主要针对FL Studio 2024怎么安装 来为大家带来了水果软件FL Studio 2024安装图文详细教程 水果音乐制作软件FL
  • CorelDRAW2024中文版怎么免费下载?

    CorelDRAW是一款综合性强大的专业平面设计软件 其功能覆盖了矢量图形设计 高级文字编辑 精细绘图以及多页文档和页面设计 该软件不仅适用于广告设计 包装设计 还广泛应用于出版 网页设计和多媒体制作等多个领域 下面就给大家介绍一下Core
  • 操作系统内部机制学习

    切换线程时需要保存什么 函数需要保存吗 函数在Flash上 不会被破坏 无需保存 函数执行到了哪里 需要保存吗 需要保存 全局变量需要保存吗 全局变量在内存上 无需保存 局部变量需要保存吗 局部变量在栈里 也是在内存里 只要避免栈不会被破坏
  • 物联网网关

    物联网网关是 连接物联网设备和互联网的重要桥梁 它负责将物联网设备采集到的数据进行处理 存储和转发 使其能够与云端或其它设备进行通信 物联网网关的作用是实现物联网设备与云端的无缝连接和数据交互 物联网网关功能 数据采集 物联网网关可以从物联
  • CorelDRAW2024版本什么时候更新?有哪些新功能

    CorelDRAW2024 简称CDR 是一款专业的图形设计软件 该软件是加拿大Corel公司开发的一款功能强大的专业平面设计软件 矢量设计软件 矢量绘图软件 这款矢量图形制作工具软件广泛应用于商标设计 标志制作 封面设计 CIS设计 产品
  • BSP制作

    STM32系列驱动介绍 在RT Thread实时操作系统中 各种各样的设备驱动是通过一套I O设备管理框架来实现的 设备管理框架给上层应用提供了一套标准的设备操作API 开发者通过调用这些标准设备操作API 可以高效地完成和底层硬件外设的交
  • 正则表达式的资源

    https www regular expressions info index html https regex101 com
  • UART设备

    UART简介 UART Universal Asynchronous Receiver Transmitter 通用异步收发传输器 UART作为异步串口通信协议的一种 工作原理是将传输数据的每个字符一位接一位地传输 是在应用程序开发过程中使
  • 欧盟eDelivery的AS4解决方案

    为实现绿色和数字欧洲的愿景 欧盟启动了 数字欧洲计划 DEP 总预算为75 9亿欧元 重点是将数字技术带给企业 公民和公共行政部门 它将建立数字能力和基础设施 并以创建数字市场为目标 主要通过与成员国在先进计算和数据 人工智能和网络安全 私
  • HAL库学习

    CMSIS简介 CMSIS Cortex Microcontroller Software Interface Standard 微控制器软件接口标准 由ARM和其合作的芯片厂商 ST NXP 软件工具厂商 KEIL IAR 共同制定的标准
  • I/O设备模型

    I O设备模型 绝大部分的嵌入式系统都包括一些I O Input Outut 输入 输出 设备 例如仪器上的数据显示屏 工业设备上的串口通信 数据采集设备上用于保存数据的Flash或SD卡 以及网络设备的以太网接口等 I O设备模型框架 R