I/O设备模型

news2024/11/19 5:32:30

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

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

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

相关文章

视频剪辑:视频创意制作,背景图片融合视频制作画中画效果

随着社交媒体的兴起&#xff0c;视频制作不再仅仅是专业人士的专利。每个人都可以通过一些技巧&#xff0c;创作出独特而富有吸引力的视频内容。视频剪辑是一种非常重要的技术&#xff0c;它能让视频从平淡无奇变为生动有趣。背景图片融合视频制作画中画效果&#xff0c;也能增…

App自动化测试之Appium 环境搭建保姆级教程(全网最全)

前言 APP自动化测试运行环境比较复杂&#xff0c;稍微不注意安装就会失败。我见过不少朋友&#xff0c;装了1个星期&#xff0c;Appium 的运行环境还没有搭好的。 搭建环境本身不是一个有难度的工作&#xff0c;但是 Appium 安装过程中确实存在不少隐藏的比较深的坑&#xff…

fragment常用知识点

fragment基本使用 摘自官网的代码示例 class ExampleActivity : AppCompatActivity(R.layout.example_activity) {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 注意这里有判断&#xff0c;当saveInstanceState为空时再创建。…

git提交代码报错Git: husky > pre-commit

目录 git提交代码报错原因解决方法&#xff08;三种&#xff09;1、第一种2、第二种3、第三种 git提交代码报错原因 这个问题是因为当你在终端输入git commit -m “XXX”,提交代码的时候,pre-commit(客户端)钩子&#xff0c;它会在Git键入提交信息前运行做代码风格检查。如果代…

53 代码审计-TP5框架及无框架变量覆盖反序列化

目录 演示案例:Metinfo-无框架-变量覆盖-自动审计或搜索phpmyadmin-无框架-反序列化-自动审计或搜索Thinkphp5-有框架-搭建使用入口访问调试SQL等 演示案例: Metinfo-无框架-变量覆盖-自动审计或搜索 变量覆盖会直接覆盖原始变量&#xff0c;来形成新的变量值 搜索关键字或者…

智慧社区前景无限,科技引领未来发展

社区是城镇化发展的标志&#xff0c;作为人类现代社会的生活的基本圈子&#xff0c;是人类生活离不开的地方&#xff0c;社区人口密度大、车辆多&#xff0c;管理无序&#xff0c;社区的膨胀式发展多多少少带来一定的管理上的缺失。社区作为智慧城市建设的重要一环&#xff0c;…

zedbox 实现配置 yolov5

Stereolabs 的 ZED Box 是一款由 NVIDIA Jetson™ 提供支持的紧凑型网关&#xff0c;用于在移动和现场情况下挑战 AIoT&#xff08;物联网&#xff09;。它旨在将空间感知和理解带到边缘&#xff0c;并聚合、处理和分析来自 3D 传感器和设备的数据。 相关内容 1.win10下 cud…

A-23 P离子交换树脂:高效去除无机有机污染物的新选择

在当今水处理行业中&#xff0c;高效、环保的离子交换树脂备受关注。本文将为您介绍一款具有卓越性能的碱性季胺基阴离子交换树脂——Tulsion A-23 P。通过分析其特性和应用&#xff0c;展示其在水处理领域的优势。 一、Tulsion A-23 P离子交换树脂的特性 物理化学稳定性&#…

Connection refused: no further information

解决目录 一、报错信息二、解决方法 一、报错信息 二、解决方法 1、报错原因是开启了代理&#xff0c;像AS是绝对不能开代理的。 2、设置为No proxy&#xff0c;然后Apply再选择OK&#xff0c;重新同步。 要远离消耗你的人和事&#xff0c;不要花费任何情绪或者精力在他们身…

【排序算法】快速排序

一&#xff1a;基本概念 1.1 介绍 快速排序由C. A. R. Hoare在1962年提出&#xff0c;它是一种基于二叉树结构的交换排序算法&#xff0c;它采用了一种分治的策略&#xff0c;通常称其为分治法。该方法的基本思想是&#xff1a;先从数列中取出一个数作为基准数&#xff0c;然…

【MySQL系列】Centos安装MySQL

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

10天玩转Python第1天:python基础知识与常用开发工具全面详解

这里写自定义目录标题 1.课程之前1.1 课程介绍1.2 今日内容1.3 Python 介绍[了解]1.4 语言的分类 2 Python 环境配置2.1 Python 解释器的安装2.2 pycharm 的配置安装2.3 路径的选择(建议) 3 使用 pycharm 书写代码3.1 双击打开 pycharm 软件3.2 创建新 项目3.3 配置项目的路径和…

网工内推 | 项目经理专场,最高20K*13薪,软考证书优先

01 Trasen 招聘岗位&#xff1a;大项目经理&#xff08;医疗行业/HIS&#xff09; 职责描述&#xff1a; 1.负责项目按计划完成交付并顺利验收结项&#xff1b; 2.参与项目前期预算、评审、方案设计等&#xff1b; 3.负责具体项目实施&#xff0c;制定项目计划、组织项目资源、…

wvp gb28181 pro 配置https访问

准备工作 必须要有域名。虽然数字证书也有ip证书,但是会很麻烦,多数ca机构验证服务器需要用到80或443端口,也就是必须先备案,所以最好还是使用域名证书。购买域名证书。根据安全级别要求自行配置。单域名(不支持通配符的),阿里云的域名都是可以免费申请的。完成域名到服…

jieba,一个结巴的Python库

微信公众号&#xff1a;愤怒的it男&#xff0c;超多Python技术干货文章。 一、jieba的简介 在自然语言处理任务时&#xff0c;中文文本需要通过分词获得单个的词语&#xff0c;此时一个好的分词工具是非常有必要的。jieba分词是一个开源项目&#xff0c;地址为&#xff1a;git…

Python从入门到精通四:Python循环语句

前言 循环普遍存在于日常生活中&#xff0c;同样&#xff0c;在程序中&#xff0c;循环功能也是至关重要的基础功能。 为什么学习循环语句 循环在程序中同判断一样&#xff0c;也是广泛存在的&#xff0c;是非常多功能实现的基础&#xff1a; while循环的基础语法 学习目标&…

竞赛保研 LSTM的预测算法 - 股票预测 天气预测 房价预测

0 简介 今天学长向大家介绍LSTM基础 基于LSTM的预测算法 - 股票预测 天气预测 房价预测 这是一个较为新颖的竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-senior/postgraduate 1 基于 Ke…

基于Qt的登录页面设计

题目&#xff1a; 完善对话框&#xff0c;点击登录对话框&#xff0c;如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出提示”登录成功“&#xff0c;提供一个Ok按钮&#xff0c;用户点击Ok后&#xff0c;关闭登录界面&#xff0c;跳转到其他界面 如果账号和…

leetcode 股票DP系列 总结篇

121. 买卖股票的最佳时机 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。 只能进行一次交易 很简单&#xff0c;只需边遍历边记录最小值即可。 class Solution { public:int maxProfit(vector<int>& prices) {int res …

Java:字符流 文件输出 与 读入 方法

Java&#xff1a;字节流 文件输出与读入方法 并 实现文件拷贝 文章目录 字符流FileReaderFileWrite 字符流 字符流底层就是字节流。 字符流 字节流 字符集 特点&#xff1a; 输入流&#xff1a;一次读入一个字节&#xff0c;遇到中文时&#xff0c;一次读多个字节。 输出流…