RT-Thread PIN设备

news2025/1/10 17:06:15

RT-Thread PIN设备

  • RT-Thread PIN设备驱动框架
    • RT-Thread PIN设备驱动层次图
    • RT-Thread PIN设备注册
      • RT-Thread PIN设备注册函数
    • RT-Thread PIN设备操作函数
      • pin_get
      • pin_mode
      • pin_write
      • pin_read
      • pin_attach_irq
      • pin_detach_irq
      • pin_irq_enable

PIN设备又叫GPIO设备,是MCU输入输出的一种设备,RT-Thread将GPIO抽象成PIN设备,以实现对GPIO的基本操作。
在这里插入图片描述
在这里插入图片描述

比如上面两个GPIO设备,其中一个作为输出控制LED灯的亮灭,一个作为输入判断按键的高低电平。
对于GPIO的操作都有以下几点:

  • 设置GPIO的方向,是作为输入还是输出
  • 设置GPIO的属性,是上拉,下拉,还是推挽、开漏等
  • 设置GPIO的高低电平或者读取GPIO的电平
  • 如果需要中断,还需要设置GPIO的中断
  • 有些GPIO能复用成其他外设功能,比如ADC、UART等

RT-Thread的PIN设备框架就需要实现上面的GPIO基本功能。

RT-Thread PIN设备驱动框架

RT-Thread PIN设备驱动层次图

在这里插入图片描述

RT-Thread PIN设备注册

RT-Thread PIN设备注册函数

int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data)
{
    _hw_pin.parent.type         = RT_Device_Class_Miscellaneous;
    _hw_pin.parent.rx_indicate  = RT_NULL;
    _hw_pin.parent.tx_complete  = RT_NULL;

#ifdef RT_USING_DEVICE_OPS
    _hw_pin.parent.ops          = &pin_ops; 
#else
    _hw_pin.parent.init         = RT_NULL;
    _hw_pin.parent.open         = RT_NULL;
    _hw_pin.parent.close        = RT_NULL;
    _hw_pin.parent.read         = _pin_read;
    _hw_pin.parent.write        = _pin_write;
    _hw_pin.parent.control      = _pin_control;
#endif

    _hw_pin.ops                 = ops; // PIN设备 操作函数
    _hw_pin.parent.user_data    = user_data;

    /* register a character device */
    rt_device_register(&_hw_pin.parent, name, RT_DEVICE_FLAG_RDWR); // 注册PIN设备

    return 0;
}

PIN设备的关键是用户的OPS操作函数

RT-Thread PIN设备操作函数

struct rt_pin_ops
{
    void (*pin_mode)(struct rt_device *device, rt_base_t pin, rt_base_t mode);
    void (*pin_write)(struct rt_device *device, rt_base_t pin, rt_base_t value);
    int (*pin_read)(struct rt_device *device, rt_base_t pin);
    rt_err_t (*pin_attach_irq)(struct rt_device *device, rt_int32_t pin,
                      rt_uint32_t mode, void (*hdr)(void *args), void *args);
    rt_err_t (*pin_detach_irq)(struct rt_device *device, rt_int32_t pin);
    rt_err_t (*pin_irq_enable)(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled);
    rt_base_t (*pin_get)(const char *name);
};

  • pin_mode:设置GPIO的模式,比如上拉下拉。
  • pin_write:设置GPIO的电平状态。
  • pin_read:读取GPIO的电平。
  • pin_attach_irq:绑定GPIO中断。
  • pin_detach_irq:脱离GPIO中断。
  • pin_irq_enable:GPIO中断使能。
  • pin_get:获取GPIO编号。

注意事项:引脚编号
对于MCU厂商来说,会给自家MCU的GPIO进行一个分类,比如STM32的MCU就会以PAX、PBX等名称进行分类,而像NXP的就会以GPIO1_IOX、GPIO2_IOX等名称进行分类。RT-Thread的PIN设备框架为了能做到通用,统一使用了引脚编号这个属性,不管MCU的引脚怎么命名,在RT-Thread里面都是以0、1、2、3等数字进行操作。

pin_get

pin_get函数的作用是获取MCU的引脚编号。下面以STM32为例进行说明

#define PIN_NUM(port, no) (((((port)&0xFu) << 4) | ((no)&0xFu)))
/* e.g. PE.7 */
static rt_base_t stm32_pin_get(const char *name)
{
    rt_base_t pin = 0;
    int hw_port_num, hw_pin_num = 0;
    int i, name_len;

    name_len = rt_strlen(name);

    if ((name_len < 4) || (name_len >= 6)) // 判断传入的引脚名字长度是否非法
    {
        goto out;
    }
    if ((name[0] != 'P') || (name[2] != '.')) // 判断传入的引脚名字的第0和第2位是否非法
    {
        goto out;
    }

    if ((name[1] >= 'A') && (name[1] <= 'Z')) // 判断传入的引脚范围是否非法
    {
        hw_port_num = (int)(name[1] - 'A');
    }
    else
    {
        goto out;
    }

    for (i = 3; i < name_len; i++) // 计算引脚编号
    {
        hw_pin_num *= 10;
        hw_pin_num += name[i] - '0';
    }

    pin = PIN_NUM(hw_port_num, hw_pin_num); // 返回引脚编号

    return pin;

out:
    rt_kprintf("Px.y  x:A~Z  y:0-15, e.g. PA.0\n");
    return -RT_EINVAL;
}

比如传入的引脚名字为PB.0,那么通过计算可以得到PB.0的引脚编号为16。不同的MCU计算方法可能会不一样,但是道理都是一样的,就是将引脚名称全部转化为引脚编号

pin_mode

pin_mode作用是设置GPIO引脚的模式

/*
device :设备句柄
pin    :引脚编号
mode   :引脚模式
*/

void (*pin_mode)(struct rt_device *device, rt_base_t pin, rt_base_t mode);

RT-Thread提供以下几种GPIO的引脚模式

模式说明
PIN_MODE_OUTPUT输出模式
PIN_MODE_INPUT输入模式
PIN_MODE_INPUT_PULLUP输入上拉
PIN_MODE_INPUT_PULLDOWN输入下拉
PIN_MODE_OUTPUT_OD开漏输出
下面以STM32为例进行说明

static void stm32_pin_mode(rt_device_t dev, rt_base_t pin, rt_uint8_t mode)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    if (PIN_PORT(pin) >= PIN_STPORT_MAX) // 判断输入的引脚编号是否非法
    {
        return;
    }

    /* Configure GPIO_InitStructure */
    GPIO_InitStruct.Pin = PIN_STPIN(pin);
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

    if (mode == PIN_MODE_OUTPUT) // 配置引脚为输出模式
    {
        /* output setting */
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
    }
    else if (mode == PIN_MODE_INPUT) // 配置引脚为输入模式
    {
        /* input setting: not pull. */
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
    }
    else if (mode == PIN_MODE_INPUT_PULLUP) // 配置引脚为上拉输入模式
    {
        /* input setting: pull up. */
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
    }
    else if (mode == PIN_MODE_INPUT_PULLDOWN) // 配置引脚为下拉输入模式
    {
        /* input setting: pull down. */
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        GPIO_InitStruct.Pull = GPIO_PULLDOWN;
    }
    else if (mode == PIN_MODE_OUTPUT_OD) // 配置引脚为开漏输出模式
    {
        /* output setting: od. */
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
    }

    HAL_GPIO_Init(PIN_STPORT(pin), &GPIO_InitStruct); // 配置GPIO
}

如果MCU还有其他的模式配置可以自行添加

pin_write

pin_write作用是设置GPIO引脚的电平状态

/*
device :设备句柄
pin    :引脚编号
value  :输出电平
*/

void (*pin_write)(struct rt_device *device, rt_base_t pin, rt_base_t value);

RT-Thread提供以下的电平

电平状态说明
PIN_LOW低电平
PIN_HIGH高电平
下面以STM32为例进行说明
static void stm32_pin_write(rt_device_t dev, rt_base_t pin, rt_uint8_t value)
{
    GPIO_TypeDef *gpio_port;
    uint16_t gpio_pin;

    if (PIN_PORT(pin) < PIN_STPORT_MAX) // 判断输入的引脚编号是否非法
    {
        gpio_port = PIN_STPORT(pin);
        gpio_pin = PIN_STPIN(pin);

        HAL_GPIO_WritePin(gpio_port, gpio_pin, (GPIO_PinState)value); // 设置GPIO电平
    }
}

pin_read

pin_read作用是读取GPIO引脚的电平状态

/*
device :设备句柄
pin    :引脚编号
返回值: GPIO电平
*/

int (*pin_read)(struct rt_device *device, rt_base_t pin);
电平状态说明
PIN_LOW低电平
PIN_HIGH高电平
下面以STM32为例进行说明
static rt_ssize_t stm32_pin_read(rt_device_t dev, rt_base_t pin)
{
    GPIO_TypeDef *gpio_port;
    uint16_t gpio_pin;
    GPIO_PinState state = GPIO_PIN_RESET;

    if (PIN_PORT(pin) < PIN_STPORT_MAX) // 判断输入的引脚编号是否非法
    {
        gpio_port = PIN_STPORT(pin);
        gpio_pin = PIN_STPIN(pin);
        state = HAL_GPIO_ReadPin(gpio_port, gpio_pin); // 读取GPIO电平
    }
    else
    {
        return -RT_EINVAL;
    }

    return (state == GPIO_PIN_RESET) ? PIN_LOW : PIN_HIGH; // 返回高或低
}

pin_attach_irq

pin_attach_irq作用是绑定GPIO引脚中断

/*
device :设备句柄
pin    :引脚编号
mode   :引脚中断类型
hdr    :引脚中断函数
args   :中断函数参数
返回值:错误代码
*/

rt_err_t (*pin_attach_irq)(struct rt_device *device, rt_int32_t pin,
                      rt_uint32_t mode, void (*hdr)(void *args), void *args);

RT-Thread提供以下的引脚触发类型

触发类型说明
PIN_IRQ_MODE_RISING上升沿触发
PIN_IRQ_MODE_FALLING下升沿触发
PIN_IRQ_MODE_RISING_FALLING双边沿触发
PIN_IRQ_MODE_HIGH_LEVEL高电平触发
PIN_IRQ_MODE_LOW_LEVEL低电平触发

引脚的中断绑定函数需要在程序中进行保存,所以可以建一张中断表保存引脚的中断函数,当中断来临的时候,再通过查表的方式进行调用。下面以STM32为例进行说明

// 引脚的中断表
static struct rt_pin_irq_hdr pin_irq_hdr_tab[] =
{
        {-1, 0, RT_NULL, RT_NULL},
        {-1, 0, RT_NULL, RT_NULL},
        {-1, 0, RT_NULL, RT_NULL},
        {-1, 0, RT_NULL, RT_NULL},
        {-1, 0, RT_NULL, RT_NULL},
        {-1, 0, RT_NULL, RT_NULL},
        {-1, 0, RT_NULL, RT_NULL},
        {-1, 0, RT_NULL, RT_NULL},
        {-1, 0, RT_NULL, RT_NULL},
        {-1, 0, RT_NULL, RT_NULL},
        {-1, 0, RT_NULL, RT_NULL},
        {-1, 0, RT_NULL, RT_NULL},
        {-1, 0, RT_NULL, RT_NULL},
        {-1, 0, RT_NULL, RT_NULL},
        {-1, 0, RT_NULL, RT_NULL},
        {-1, 0, RT_NULL, RT_NULL},
};

static rt_err_t stm32_pin_attach_irq(struct rt_device *device, rt_base_t pin,
                                     rt_uint8_t mode, void (*hdr)(void *args), void *args)
{
    rt_base_t level;
    rt_int32_t irqindex = -1;

    if (PIN_PORT(pin) >= PIN_STPORT_MAX) // 判断引脚编号是否非法
    {
        return -RT_ENOSYS;
    }

    irqindex = bit2bitno(PIN_STPIN(pin)); // 通过引脚编号反推得到中断号
    if (irqindex < 0 || irqindex >= (rt_int32_t)ITEM_NUM(pin_irq_map)) // 判断中断号是否非法
    {
        return -RT_ENOSYS;
    }

    level = rt_hw_interrupt_disable(); // 关闭中断
    if (pin_irq_hdr_tab[irqindex].pin == pin &&
        pin_irq_hdr_tab[irqindex].hdr == hdr &&
        pin_irq_hdr_tab[irqindex].mode == mode &&
        pin_irq_hdr_tab[irqindex].args == args) // 是否重复注册引脚中断
    {
        rt_hw_interrupt_enable(level);
        return RT_EOK;
    }
    if (pin_irq_hdr_tab[irqindex].pin != -1) // 中断号是否已经被注册
    {
        rt_hw_interrupt_enable(level);
        return -RT_EBUSY;
    }
    // 更新中断表
    pin_irq_hdr_tab[irqindex].pin = pin; 
    pin_irq_hdr_tab[irqindex].hdr = hdr;
    pin_irq_hdr_tab[irqindex].mode = mode;
    pin_irq_hdr_tab[irqindex].args = args;
    rt_hw_interrupt_enable(level); // 开启中断

    return RT_EOK;
}
rt_inline void pin_irq_hdr(int irqno) 
{
    if (pin_irq_hdr_tab[irqno].hdr) // 通过查表执行中断函数
    {
        pin_irq_hdr_tab[irqno].hdr(pin_irq_hdr_tab[irqno].args);
    }
}

上面的函数通过引脚编号得到相应的引脚中断号,然后将引脚的中断函数注册进中断表,当中断来临的时候通过pin_irq_hdr函数在中断表找到相应的中断函数然执行。

pin_detach_irq

pin_detach_irq作用是解绑GPIO引脚中断

/*
device :设备句柄
pin    :引脚编号
返回值: 错误代码
*/

rt_err_t (*pin_detach_irq)(struct rt_device *device, rt_int32_t pin);

下面以STM32为例进行说明

static rt_err_t stm32_pin_dettach_irq(struct rt_device *device, rt_base_t pin)
{
    rt_base_t level;
    rt_int32_t irqindex = -1;

    if (PIN_PORT(pin) >= PIN_STPORT_MAX) // 判断引脚编号是否非法
    {
        return -RT_ENOSYS;
    }

    irqindex = bit2bitno(PIN_STPIN(pin));
    if (irqindex < 0 || irqindex >= (rt_int32_t)ITEM_NUM(pin_irq_map)) // 判断中断号是否非法
    {
        return -RT_ENOSYS;
    }

    level = rt_hw_interrupt_disable(); // 关闭中断
    if (pin_irq_hdr_tab[irqindex].pin == -1) // GPIO引脚中断没有中断
    {
        rt_hw_interrupt_enable(level);
        return RT_EOK;
    }
    // 将GPIO中断号对应的中断表索引属性清空
    pin_irq_hdr_tab[irqindex].pin = -1;
    pin_irq_hdr_tab[irqindex].hdr = RT_NULL;
    pin_irq_hdr_tab[irqindex].mode = 0;
    pin_irq_hdr_tab[irqindex].args = RT_NULL;
    rt_hw_interrupt_enable(level);

    return RT_EOK;
}

pin_irq_enable

pin_irq_enable作用是使能GPIO引脚中断

/*
device :设备句柄
pin    :引脚编号
enabled: 使能
返回值: 错误代码
*/
rt_err_t (*pin_irq_enable)(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled);

以下以STM32为例


static rt_err_t stm32_pin_irq_enable(struct rt_device *device, rt_base_t pin,
                                     rt_uint8_t enabled)
{
    const struct pin_irq_map *irqmap;
    rt_base_t level;
    rt_int32_t irqindex = -1;
    GPIO_InitTypeDef GPIO_InitStruct;

    if (PIN_PORT(pin) >= PIN_STPORT_MAX) // 判断引脚编号是否非法
    {
        return -RT_ENOSYS;
    }

    if (enabled == PIN_IRQ_ENABLE) // 如果引脚中断使能
    {
        irqindex = bit2bitno(PIN_STPIN(pin));
        if (irqindex < 0 || irqindex >= (rt_int32_t)ITEM_NUM(pin_irq_map))  // 判断中断号是否非法
        {
            return -RT_ENOSYS;
        }

        level = rt_hw_interrupt_disable(); // 关中断

        if (pin_irq_hdr_tab[irqindex].pin == -1) // 如果中断号没有注册
        {
            rt_hw_interrupt_enable(level);
            return -RT_ENOSYS;
        }

        irqmap = &pin_irq_map[irqindex];

        /* Configure GPIO_InitStructure */
        GPIO_InitStruct.Pin = PIN_STPIN(pin);
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        switch (pin_irq_hdr_tab[irqindex].mode)  // 设置GPIO中断模式
        {
        case PIN_IRQ_MODE_RISING:
            GPIO_InitStruct.Pull = GPIO_PULLDOWN;
            GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; // 上升沿触发
            break;
        case PIN_IRQ_MODE_FALLING:
            GPIO_InitStruct.Pull = GPIO_PULLUP;
            GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;  // 下升沿触发
            break;
        case PIN_IRQ_MODE_RISING_FALLING:
            GPIO_InitStruct.Pull = GPIO_NOPULL;
            GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;  // 双边沿触发
            break;
        }
        HAL_GPIO_Init(PIN_STPORT(pin), &GPIO_InitStruct);
 		// 使能GPIO中断
        HAL_NVIC_SetPriority(irqmap->irqno, 5, 0);
        HAL_NVIC_EnableIRQ(irqmap->irqno);
        pin_irq_enable_mask |= irqmap->pinbit;

        rt_hw_interrupt_enable(level);
    }
    else if (enabled == PIN_IRQ_DISABLE) // 引脚中断不使能
    {
        irqmap = get_pin_irq_map(PIN_STPIN(pin));
        if (irqmap == RT_NULL)
        {
            return -RT_ENOSYS;
        }

        level = rt_hw_interrupt_disable();

        HAL_GPIO_DeInit(PIN_STPORT(pin), PIN_STPIN(pin));

        pin_irq_enable_mask &= ~irqmap->pinbit;
#if defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32G0)
        if ((irqmap->pinbit >= GPIO_PIN_0) && (irqmap->pinbit <= GPIO_PIN_1))
        {
            if (!(pin_irq_enable_mask & (GPIO_PIN_0 | GPIO_PIN_1)))
            {
                HAL_NVIC_DisableIRQ(irqmap->irqno);
            }
        }
        else if ((irqmap->pinbit >= GPIO_PIN_2) && (irqmap->pinbit <= GPIO_PIN_3))
        {
            if (!(pin_irq_enable_mask & (GPIO_PIN_2 | GPIO_PIN_3)))
            {
                HAL_NVIC_DisableIRQ(irqmap->irqno);
            }
        }
        else if ((irqmap->pinbit >= GPIO_PIN_4) && (irqmap->pinbit <= GPIO_PIN_15))
        {
            if (!(pin_irq_enable_mask & (GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 |
                                         GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15)))
            {
                HAL_NVIC_DisableIRQ(irqmap->irqno);
            }
        }
        else
        {
            HAL_NVIC_DisableIRQ(irqmap->irqno);
        }
#else
        if ((irqmap->pinbit >= GPIO_PIN_5) && (irqmap->pinbit <= GPIO_PIN_9))
        {
            if (!(pin_irq_enable_mask & (GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9)))
            {
                HAL_NVIC_DisableIRQ(irqmap->irqno);
            }
        }
        else if ((irqmap->pinbit >= GPIO_PIN_10) && (irqmap->pinbit <= GPIO_PIN_15))
        {
            if (!(pin_irq_enable_mask & (GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15)))
            {
                HAL_NVIC_DisableIRQ(irqmap->irqno);
            }
        }
        else
        {
            HAL_NVIC_DisableIRQ(irqmap->irqno);
        }
#endif
        rt_hw_interrupt_enable(level);
    }
    else
    {
        return -RT_ENOSYS;
    }

    return RT_EOK;
}

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

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

相关文章

每日一练:攻防世界:qr-easy

本题思路与CTFSHOW: 36D杯 misc ez-qrcode思路相同 工具链接&#xff1a;补全二维码QRazyBox - QR Code Analysis and Recovery Toolkit (h3110w0r1d.com) 1.首先&#xff0c;我们需要基于上图的干净图像。 此二维码的大小为 29x29&#xff0c;版本V的大小为N N&#xff0c;…

基于STM32和人工智能的智能四轴飞行器系统

目录 引言环境准备智能四轴飞行器系统基础代码实现&#xff1a;实现智能四轴飞行器系统 4.1 数据采集模块4.2 数据处理与分析4.3 控制系统4.4 用户界面与数据可视化应用场景&#xff1a;智能飞行器管理与优化问题解决方案与优化收尾与总结 1. 引言 随着无人机技术的发展&…

Mybatis认识与学习

前言 在客户端工具中&#xff0c;编写增删改查的SQL语句&#xff0c;发给MySQL数据库管理系统&#xff0c;由数据库管理系统执行SQL语句并返回执行结果。 增删改操作&#xff1a;返回受影响行数 查询操作&#xff1a;返回结果集(查询的结果) 我们做为后端程序开发人员&#xff…

操作系统笔记(自用随笔)

如有错误&#xff0c;欢迎指正&#xff01;&#xff01;&#xff01;

SpringBoot快速入门-上

Apache Tomcat Apache Tomcat是一个开源的Servlet 或 web容器&#xff0c;它实现了Java Servlet、JavaServer Pages (JSP)、Java Unified Expression Language (JUEL) 和 Java WebSocket 规范。 使用 官网下载 安装:绿色版 , 直接解压 卸载:直接删除目录 改编码: # conf/l…

超大cvs文件导入MySQL

1 XXX.cvs 太大 使用cvs拆分HugeCSVSplitter_jb51工具进行拆分&#xff0c;Line Count 设置为1,000,000 注意&#xff1a;1 拆分后除第一个子cvs文件含有标题外&#xff0c;其他的子文档都不含有标题行&#xff1b; 2 后一个文档的第一行为前一个文档的…

python将数据保存到文件的多种实现方式

&#x1f308;所属专栏&#xff1a;【python】✨作者主页&#xff1a; Mr.Zwq✔️个人简介&#xff1a;一个正在努力学技术的Python领域创作者&#xff0c;擅长爬虫&#xff0c;逆向&#xff0c;全栈方向&#xff0c;专注基础和实战分享&#xff0c;欢迎咨询&#xff01; 您的…

关于FPGA对 DDR4 (MT40A256M16)的读写控制 3

关于FPGA对 DDR4 &#xff08;MT40A256M16&#xff09;的读写控制 3 语言 &#xff1a;Verilg HDL 、VHDL EDA工具&#xff1a;ISE、Vivado、Quartus II 关于FPGA对 DDR4 &#xff08;MT40A256M16&#xff09;的读写控制 3一、引言二、DDR的功能性描述三、SDRAM设备中模式寄存器…

基于IDEA的Maven简单工程创建及结构分析

目录 一、用 mvn 命令创建项目 二、用 IDEA 的方式来创建 Maven 项目。 &#xff08;1&#xff09;首先在 IDEA 下的 Maven 配置要已经确保完成。 &#xff08;2&#xff09;第二步去 new 一个 project &#xff08;创建一个新工程&#xff09; &#xff08;3&#xff09;…

【windows|003】计算机硬件基础及存储单位

&#x1f341;博主简介&#xff1a; &#x1f3c5;云计算领域优质创作者 &#x1f3c5;2022年CSDN新星计划python赛道第一名 &#x1f3c5;2022年CSDN原力计划优质作者 &#x1f3c5;阿里云ACE认证高级工程师 &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&…

阿里云平台创建设备及连接

使用阿里云平台创建项目&#xff0c;利用MQTT.fx软件配置相关的连接&#xff0c;在软件上完成消息的订阅与推送&#xff0c;与手机APP进行同步数据。了解MQTT相关的协议。 1.注册阿里云平台账号&#xff0c;完成实名注册&#xff01; 618创新加速季_新迁入云享5亿算力补贴-阿里…

005-OSPF基本配置

OSPF基本配置 OSPF (Open Shortest Path First) 是一种链路状态路由协议&#xff0c;它属于内部网关协议&#xff08;IGP&#xff09;类别&#xff0c;用于在自治系统&#xff08;AS&#xff09;内部路由 IP 数据包。OSPF 通过使用 Dijkstra 算法计算最短路径树来确定到达每个…

电影时间首页(HTML+css)

使用HTMLcss制作的一个简单的电影时间首页 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>电影时间首页</title></head><body><!--header begin--><div style"height: 63px;">&…

从0开始开发一个简单web界面的学习笔记(HTML类)

文章目录 什么是HTML页面vscode 开放工具搭建第一个HTML页面编写vscode 如何快速生成代码框架html标签——注释、标题、段落、换行标签格式化标签img 标签(src 属性01)img 属性02(alt、title、width/height、border)a标签href属性a标签target属性表格标签01 基本属性表格标签02…

随想录Day63 | 单调栈 42. 接雨水 84.柱状图中最大的矩形

随想录Day63 | 单调栈 42. 接雨水 84.柱状图中最大的矩形 42. 接雨水 题目链接 42 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 第一次提交 class Solution { public:int trap(vector<int>…

买家用洗地机需要注意什么?全面评测热门洗地机品牌

对于忙碌的打工族来说&#xff0c;“做家务”是一件非常消费时间精力的事情&#xff0c;但它又是生活中的一部分&#xff0c;为了解决这些矛盾点&#xff0c;越来越多的清洁家电涌向市场&#xff0c;像集扫地、吸尘、洗地为一体的洗地机&#xff0c;在推拉之间便把脏污处理干净…

英码科技携手昇腾打造“三位一体”智慧化工解决方案,使能化工产业管理更高效、智能

我国是世界公认的化工大国。然而&#xff0c;大部分化工园区的日常管理方式较为传统&#xff0c;各园区、厂区的门禁、视频、停车场等子系统犹如一个个独立的“岛屿”&#xff0c;每个“岛屿”需要耗费大量人力及时间成本进行巡检、记录、上报&#xff0c;且不能做到全域、全时…

JavaFX DatePicker

JavaFX DatePicker允许从给定日历中选择一天。DatePicker控件包含一个带有日期字段和日期选择器的组合框。JavaFX DatePicker控件使用JDK8日期时间API。 import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.DatePicker; import j…

C语言之操作符

目录 一、二进制 原码、反码、补码 二、移位操作符 位操作符 三、 逗号表达式 四、下标访问[]、函数调用() 五. 操作符的属性 整型提升 算术转换 六、总结 一、二进制 其实2进制、8进制、10进制、16进制是数值的不同表示形式而已。 其实10进制是生活中经常使用的&am…

docker容器中连接宿主机mysql数据库

最近要在docker中使用mysql数据库&#xff0c;首先考虑在ubuntu的镜像中安装mysql&#xff0c;这样的脚本和数据库都在容器中&#xff0c;直接访问localhost&#xff1a;3306&#xff0c;脚本很简单&#xff0c;如下&#xff1a; import pymysql# 建立数据库连接 db pymysql.…