【驱动】USB驱动实例·串口驱动·键盘驱动

USB总线驱动(二)设备驱动ch341以及serial 我们以一个usb设备(ch341)驱动例子来看下用法。 阅读详情

Preface


   USB体系支持多种类型的设备。

   在 Linux内核,所有的USB设备都使用 usb_driver结构描述。

   对于不同类型的 USB设备,内核使用传统的设备驱动模型建立设备驱动描述,然后映射到 USB设备驱动,最终完成特定类型的 USB设备驱动

   USB驱动·入门:http://infohacker.blog.51cto.com/6751239/1226257



USB串口驱动


   USB串口驱动关键是向内核注册串口设备结构,并且设置串口的操作。

   下面是一个典型的USB设备驱动分析。



1、驱动初始化函数


   usb_serial_init()函数是一个典型的 USB设备驱动初始化函数,定义如下:

static int __init usb_serial_init(void)
{
    int i;
    int result;
    usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);    //申请 tty设备驱动描述
    if (!usb_serial_tty_driver)
        return -ENOMEM;
    /* Initialize our global data */
    for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
        serial_table[i] = NULL;
    }
    result = bus_register(&usb_serial_bus_type);    //注册总线
    if (result) {
        err("%s - registering bus driver failed", __FUNCTION__);
        goto exit_bus;
    }
    usb_serial_tty_driver->owner = THIS_MODULE;  //初始化串口驱动描述
    usb_serial_tty_driver->driver_name = "usbserial";    //串口驱动名称
    usb_serial_tty_driver->name =    "ttyUSB";   //设备文件系统存放路径
    usb_serial_tty_driver->major = SERIAL_TTY_MAJOR; //串口设备主设备号
    usb_serial_tty_driver->minor_start = 0;  //串口设备从设备号起始 ID
    usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;    //设备类型
    usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL; //设备子类型
    usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; //设备初始化标志
    usb_serial_tty_driver->init_termios = tty_std_termios;   //串口设备描述
    usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;  //串口设备初始化参数
    tty_set_operations(usb_serial_tty_driver, &serial_ops); //串口设备操作函数
    result = tty_register_driver(usb_serial_tty_driver);    //注册串口驱动
    if (result) {
        err("%s - tty_register_driver failed", __FUNCTION__);
        goto exit_reg_driver;
    }
    /* register the USB driver */
    result = usb_register(&usb_serial_driver);  //注册 USB驱动
    if (result < 0) {
        err("%s - usb_register failed", __FUNCTION__);
        goto exit_tty;
    }
    /* register the generic driver, if we should */
    result = usb_serial_generic_register(debug);
    if (result < 0) {
        err("%s - registering generic driver failed", __FUNCTION__);
        goto exit_generic;
    }
    info(DRIVER_DESC);
    return result;
exit_generic:
    usb_deregister(&usb_serial_driver); //注销串口设备
exit_tty:
    tty_unregister_driver(usb_serial_tty_driver);   //注销 USB串口设备
exit_reg_driver:
    bus_unregister(&usb_serial_bus_type);   //注销总线
exit_bus:
    err ("%s - returning with error %d", __FUNCTION__, result);
    put_tty_driver(usb_serial_tty_driver);
    return result;
}

   函数首先调用 alloc_tty_driver()函数分配一个串口驱动描述符;然后设置串口驱动的属性,包括驱动的主从设备号、设备类型、串口初始化参数等;串口驱动描述符设置完毕后,调用 usb_register()函数注册 USB串口设备。



2、驱动释放函数


   驱动释放函数用来释放 USB串口设备驱动申请的内核资源,函数定义如下:

static int __init usb_serial_init(void)
{
    int i;
    int result;
    usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);    //申请 tty设备驱动描述
    if (!usb_serial_tty_driver)
        return -ENOMEM;
    /* Initialize our global data */
    for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
        serial_table[i] = NULL;
    }
    result = bus_register(&usb_serial_bus_type);    //注册总线
    if (result) {
        err("%s - registering bus driver failed", __FUNCTION__);
        goto exit_bus;
    }
    usb_serial_tty_driver->owner = THIS_MODULE;  //初始化串口驱动描述
    usb_serial_tty_driver->driver_name = "usbserial";    //串口驱动名称
    usb_serial_tty_driver->name =    "ttyUSB";   //设备文件系统存放路径
    usb_serial_tty_driver->major = SERIAL_TTY_MAJOR; //串口设备主设备号
    usb_serial_tty_driver->minor_start = 0;  //串口设备从设备号起始 ID
    usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;    //设备类型
    usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL; //设备子类型
    usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; //设备初始化标志
    usb_serial_tty_driver->init_termios = tty_std_termios;   //串口设备描述
    usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;  //串口设备初始化参数
    tty_set_operations(usb_serial_tty_driver, &serial_ops); //串口设备操作函数
    result = tty_register_driver(usb_serial_tty_driver);    //注册串口驱动
    if (result) {
        err("%s - tty_register_driver failed", __FUNCTION__);
        goto exit_reg_driver;
    }
    /* register the USB driver */
    result = usb_register(&usb_serial_driver);  //注册 USB驱动
    if (result < 0) {
        err("%s - usb_register failed", __FUNCTION__);
        goto exit_tty;
    }
    /* register the generic driver, if we should */
    result = usb_serial_generic_register(debug);
    if (result < 0) {
        err("%s - registering generic driver failed", __FUNCTION__);
        goto exit_generic;
    }
    info(DRIVER_DESC);
    return result;
exit_generic:
    usb_deregister(&usb_serial_driver); //注销串口设备
exit_tty:
    tty_unregister_driver(usb_serial_tty_driver);   //注销 USB串口设备
exit_reg_driver:
    bus_unregister(&usb_serial_bus_type);   //注销总线
exit_bus:
    err ("%s - returning with error %d", __FUNCTION__, result);
    put_tty_driver(usb_serial_tty_driver);
    return result;
}



3、串口操作函数


   USB串口设备驱动使用了一个 tty_operations类型的结构,该结构包含了串口的所有操作。定义如下:


static struct tty_operations serial_ops = {
    .open =         serial_open,    //打开串口
    .close =        serial_close,   //关闭串口
    .write =        serial_write,   //串口写操作
    .write_room =       serial_write_room,
    .ioctl =        serial_ioctl,   // I/O控制操作
    .set_termios =      serial_set_termios, //设置串口参数
    .throttle =     serial_throttle,
    .unthrottle =       serial_unthrottle,
    .break_ctl =        serial_break,   // break信号处理
    .chars_in_buffer =  serial_chars_in_buffer, //缓冲处理
    .read_proc =        serial_read_proc,   //串口读操作
    .tiocmget =     serial_tiocmget,    //获取 I/O控制参数
    .tiocmset =     serial_tiocmset,    //设置 I/O控制参数
};

   serial_ops结构变量设置的所有串口操作函数,均使用内核 USB核心提供的标准函数,定义在/drivers/usb/serial/generic.c文件中





USB键盘驱动


   USB键盘驱动与串口驱动结构类似,不同是的使用USB设备核心提供的usb_keyboard_driver结构作为设备核心结构。下面是 USB键盘驱动的重点部分。



1、驱动初始和注销


   USB键盘驱动初始化和注销函数定义如下:

static int __init usb_kbd_init(void)
{
    int result = usb_register(&usb_kbd_driver); //注册 USB设备驱动
    if (result == 0)
        info(DRIVER_VERSION ":" DRIVER_DESC);
    return result;
}
static void __exit usb_kbd_exit(void)
{
    usb_deregister(&usb_kbd_driver);    //注销 USB设备驱动
}


   usb_kbd_init()函数在驱动加载的时候调用,该函数使用 usb_register()函数向内核注册一个 USB设备驱动;usb_kbd_exit()函数在卸载驱动程序的时候调用,该函数使用 usb_deregister()函数注销 USB设备。初始化和注销函数使用了 usb_keyboard结构变量,用于描述 USB键盘驱动程序,定义如下:


//usb_driver结构体
static struct usb_driver usb_keyboard =
{
    .name = "usbkbd",   //驱动名称
    .probe = usb_kbd_probe, //检测设备函数
    .disconnect = usb_kbd_disconnect,   //断开连接函数
    .id_table = usb_kbd_id_table,   //设备 ID
};


   从 usb_keyboard结构定义看出,usb_kbd_probe()函数是设备检测函数;

   usb_kbd_disconnect()函数是断开设备连接。



2、设备检测函数


   设备检测函数在插入 USB设备的时候被USB文件系统调用,负责检测设备类型是否与驱动相符。如果设备类型与驱动匹配,则向 USB核心注册设备。

   函数定义如下:


static int usb_kbd_probe(struct usb_interface *iface,
             const struct usb_device_id *id)
{
    struct usb_device *dev = interface_to_usbdev(iface);
    struct usb_host_interface *interface;
    struct usb_endpoint_descriptor *endpoint;
    struct usb_kbd *kbd;
    struct input_dev *input_dev;
    int i, pipe, maxp;
    interface = iface->cur_altsetting;
    if (interface->desc.bNumEndpoints != 1)  //检查设备是否符合
        return -ENODEV;
    endpoint = &interface->endpoint[0].desc;
    if (!(endpoint->bEndpointAddress & USB_DIR_IN))
        return -ENODEV;
    if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)
        return -ENODEV;
    pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);  //创建端点的管道
    maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
    kbd = kzalloc(sizeof(struct usb_kbd), GFP_KERNEL);
    input_dev = input_allocate_device();    //分配 input_dev结构体
    if (!kbd || !input_dev) //分配设备结构占用的内存
        goto fail1;
    if (usb_kbd_alloc_mem(dev, kbd))
        goto fail2;
    kbd->usbdev = dev;
    kbd->dev = input_dev;
    if (dev->manufacturer)   //检查制造商名称
        strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name));
    if (dev->product) {  //检查产品名称
        if (dev->manufacturer)
            strlcat(kbd->name, " ", sizeof(kbd->name));
        strlcat(kbd->name, dev->product, sizeof(kbd->name));
    }
    if (!strlen(kbd->name))
        snprintf(kbd->name, sizeof(kbd->name),
             "USB HIDBP Keyboard %04x:%04x",
             le16_to_cpu(dev->descriptor.idVendor),
             le16_to_cpu(dev->descriptor.idProduct));
    usb_make_path(dev, kbd->phys, sizeof(kbd->phys));
    strlcpy(kbd->phys, "/input0", sizeof(kbd->phys));
    //初始化输入设备
    input_dev->name = kbd->name;  //输入设备名称
    input_dev->phys = kbd->phys;  //输入设备物理地址
    usb_to_input_id(dev, &input_dev->id);    //输入设备 ID
    input_dev->cdev.dev = &iface->dev;
    input_dev->private = kbd;
    input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
    input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA);
    for (i = 0; i < 255; i++)
        set_bit(usb_kbd_keycode[i], input_dev->keybit);
    clear_bit(0, input_dev->keybit);
    input_dev->event = usb_kbd_event;
    input_dev->open = usb_kbd_open;
    input_dev->close = usb_kbd_close;
    //初始化中断 urb
    usb_fill_int_urb(kbd->irq, dev, pipe,
             kbd->new, (maxp > 8 ? 8 : maxp),
             usb_kbd_irq, kbd, endpoint->bInterval);
    kbd->irq->transfer_dma = kbd->new_dma;
    kbd->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
    kbd->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
    kbd->cr->bRequest = 0x09;
    kbd->cr->wValue = cpu_to_le16(0x200);
    kbd->cr->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);
    kbd->cr->wLength = cpu_to_le16(1);
    //初始化中断 urb
    usb_fill_control_urb(kbd->led, dev, usb_sndctrlpipe(dev, 0),
                 (void *) kbd->cr, kbd->leds, 1,
                 usb_kbd_led, kbd);
    kbd->led->setup_dma = kbd->cr_dma;
    kbd->led->transfer_dma = kbd->leds_dma;
    kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
    input_register_device(kbd->dev); //注册输入设备
    usb_set_intfdata(iface, kbd);   //设置接口私有数据
    return 0;
fail2:  usb_kbd_free_mem(dev, kbd);
fail1:  input_free_device(input_dev);
    kfree(kbd);
    return -ENOMEM;
}


   函数一开始检测设备类型,如果与驱动程序匹配,则创建 USB设备端点,分配设备驱动结构占用的内存。分配好设备驱动使用的结构后,申请一个键盘设备驱动节点,然后设置键盘驱动,最后设置 USB设备的中断 URB和控制 URB,供 USB设备核心使用。



3、设备断开连接函数


   在设备断开连接的时候,USB文件系统会调用 usb_kbd_disconnect()函数,释放设备占用的资源。

   函数定义如下:


static void usb_kbd_disconnect(struct usb_interface *intf)
{
    struct usb_kbd *kbd = usb_get_intfdata (intf);
    usb_set_intfdata(intf, NULL);   //设置接口私有数据为 NULL
    if (kbd) {
        usb_kill_urb(kbd->irq);  //终止 URB
        input_unregister_device(kbd->dev);   //注销输入设备
        usb_kbd_free_mem(interface_to_usbdev(intf), kbd);   //释放设备驱动占用的内存
        kfree(kbd);
    }
}

   usb_kbd_disconnect()函数释放 USB键盘设备占用的 URB资源,然后注销设备,最后调用usb_kbd_free_mem()函数,释放设备驱动结构变量占用的内存。


本文出自 “成鹏致远” 博客,请务必保留此出处http://infohacker.blog.51cto.com/6751239/1227045

STM32 USB复合设备实战:HID键盘+双CDC虚拟串口实现 USB复合设备允许单个物理设备同时提供多种功能接口,在嵌入式系统中应用广泛,例如同时实现人机交互与数据传输。理解其核心在于合理配置USB描述符,通过接口关联描述符将多个接口正确组合,使主机识别为多个独立逻辑设备。基于STM32与CubeMX进行开发,可高效完成时钟、外设与USB协议栈初始化,再扩展描述符和类驱动,实现HID键盘与多路CDC虚拟串口的共存。这种方案在自定义键盘、USB转多串口工具及产线自动化测试治具中极具实用价值,既节省USB口资源,又简化线缆管理。本文完整记录了STM32上HID键盘与两路C 阅读详情

相关推荐

别再乱打驱动了!聊聊Zadig的正确打开方式与HID设备避雷

本文深入探讨了Zadig在HID设备驱动管理中的正确使用方法与潜在风险。通过分析驱动冲突的典型表现和恢复方案,帮助用户避免键盘鼠标等输入设备失效的问题,并提供专业场景下的安全操作指南与进阶工具链推荐。

weixin_33507732的博客 236

USB 3G卡热插拔那些事3------usb serial驱动

上一节我们已经把3G识别出来并且可以工作了,具体3G卡拨号这一块我们稍后会讲到,这里先提下,首先就是pppd拨号程序,可以网上下载最新版源码自己编译安装,我是利用evdo拨号,当然还有其他方式。这里是用户空间如何建立ppp连接,在内核层就是ppp协议以及tty模块,在往下就是wcdma模块驱动(上一节我们已经讲过)。下面就说说usb serial驱动. 在之前我们知道uevent事件,但是对于它

landishu的专栏 1295

使用USB Gadget框架让USB变成串口设备

使用USB Gadget框架定义特殊的USB设备

birdring_0xx0的博客 4892

usb-serial分析

重要文件由usb-serial.c ; generic.c ; usb.c ; option.c 从module_init(usb_serial_init)开始 //按照tty驱动结构,先创建"tty_driver"对象 alloc_tty_driver(SERIAL_TTY_MINIOR) 注册总线usb-serial,之后很多驱动及设备都会注册到该总线上 bus_register(&

7832

实现FPGA串口通信的USB串口驱动安装指南

USB串口驱动程序是连接USB(通用串行总线)接口与传统串口设备(如串行端口设备)之间的桥梁,它扮演了翻译官的角色,将USB总线的数据传输协议转换为串口设备能理解的通信协议。没有有效的驱动程序,USB设备无法被操作系统识别和正确使用。

weixin_42581003的博客 1119

USB转串口驱动:实现现代与传统技术的无缝对接

本文还有配套的精品资源,点击获取 简介:USB转串口驱动允许通过USB接口与传统串行设备通信,解决了现代计算机系统中串口设备的兼容问题。通过模拟虚拟串口(COM端口),使得操作系统可以像处理传统串口一样管理USB设备。该驱动基于CDC类驱动标准,是USB设备与系统之间的一个关键软件层,负责翻译USB通信协议。安装过程包括下载、安装、配置和测试四个步骤。此外,数据线驱动确保U...

weixin_26854475的博客 3304

Linux USB串口驱动代码分析

4、USB serial 驱动代码分析 文件: drivers/usb/serial/usb-serial.c usb_serial_init(void) |---alloc_tty_driver /*分配serial驱动,最多支持512个USB Serial*/ | |---tty_alloc_driver | |---_...

羊脂球的博客 779

你不必懂AI,但必须会用AI:写给所有焦虑中的职场人

AI时代不必焦虑学技术,关键在于用AI解决实际问题。文章指出,99%的人只需成为AI使用者而非建造者,核心竞争力在于结合业务痛点运用AI工具提升效率。与其盲目学习工具,不如梳理工作流程,识别可优化环节,让AI赋能重复性、标准化任务。行业经验与AI工具的结合才是真正的职场护城河。建议从具体工作场景出发,寻找匹配的AI解决方案,迈出应用第一步。

hundred98的博客 715

【驱动】USB驱动实例·串口驱动·键盘驱动【转】

转自:http://www.cnblogs.com/lcw/p/3159370.htmlPreface USB体系支持多种类型的设备。 在 Linux内核,所有的USB设备都使用 usb_driver结构描述。 对于不同类型的 USB设备,内核使用传统的设备驱动模型建立设备驱动描述,然后映射到 USB设备驱动,最终完成特定...

weixin_34228662的博客 196

如何用zemax导入solidworks装配体

在zemax使用中,常常需要导入各种零件。如果光机结构较为复杂,那么手工一个一个加载零件,还需要在zmx文件中调整object的位置,非常麻烦。如果能将solidworks的装配体模型直接导入,则可以大幅减小工作量。具体过程为(非序列模式下): 1、新建或打开一个zemax空文件 2、在元件编辑器中,找到一个空文件,双击或直接展开三角符,在类型中找到zemax里的solidworks装配体,如图。...

wojiaoyyy的博客 1万+

从HPPC测试到Simulink仿真:锂电池二阶RC模型参数辨识完整流程

本文详细介绍了从HPPC测试到Simulink仿真的锂电池二阶RC模型参数辨识完整流程。通过HPPC测试获取实验数据,利用Simulink的Parameter Estimation工具进行参数辨识和模型验证,为BMS算法开发提供精确的电池模型。文章涵盖测试设计、数据预处理、模型搭建及工程应用等关键步骤,助力新能源电池研发。

whisky的博客 683

linux控制器与设备驱动,Linux设备驱动入门

/*****************************************USB主机与设备驱动*主机侧:由底到高:USB主机控制器硬件-->*USB主机控制器驱动-->USB核心层-->USB*设备驱动层*设备侧:UDC驱动程序、GadgetAPI和Gadget*驱动程序*逻辑组织:设备(1)配置(n)*配置(1)接口...

weixin_36026999的博客 148

SpringBoot实现快速导入EXCEL

MaterialMonitorController.java @Log(title = "物料监测", businessType = BusinessType.IMPORT) @RequiresPermissions("system:materialMonitor:import") @PostMapping("/importData") @ResponseBody ...

LEN程序员的一生 4816

第10课【STM32 USB通讯协议实战】HID键盘+CDC虚拟串口组合设备

HID报文描述符可能是所有USB描述符中最复杂的,抽象的概念相当多,理解起来也需要一定的时间。但是复杂的定义带来的却是报文易用性和灵活性,它几乎可以描述任何形式的数据,而且长度都由开发者来定义,形式也较为简洁清晰。

PORKWOTONLEE的博客 1万+

YOLO26 标签分配机制:STAL 小目标感知分配策略

YOLO26提出的STAL标签分配策略通过尺度感知机制优化了小目标检测性能。该方法根据目标面积将检测对象分为小、中、大三类,分别采用差异化的分配参数(TopK数量、IoU阈值和中心度权重),特别是对小目标采用更宽松的匹配条件和更高的中心度权重。实验结果表明,STAL策略显著提升了小目标检测精度(AP_small),同时保持了整体检测性能(mAP),为解决目标检测中尺度不平衡问题提供了有效方案。

一键难忘的博客 784

uniapp:实现APP获取陀螺仪数据、加速传感器、线性加速传感器,uniApp实时监听陀螺仪【XYZ】数据及停止监听与资源释放等功能示例源码,根据需求做功能(完美兼容Android安卓、苹果ios)

uniapp陀螺仪,uniapp加速传感器,uniapp线性加速传感器,APP陀螺仪数据,uniapp app 端获取陀螺仪数据示例代码,手机中获取陀螺仪的数据,uniApp实时获取陀螺仪xyz数据,android陀螺仪方向,获得陀螺仪传感器,处理传感器数据,停止监听与资源释放,Android使用陀螺仪,uniapp苹果ios陀螺仪,uni-app设备之(加速计,罗盘,陀螺仪)插件安卓/IOS APP提供了获取陀螺仪数据的能力,手机陀螺仪传感器获得手机自身旋转的角度,陀螺仪获取旋转角度,陀螺仪、加速度传感器

✅ 精选推荐文章 4265

嵌入式LINUX设备驱动开发详解

<br />嵌入式Linux设备驱动是嵌入式系统中十分重要的组成部分。本书详细讲解了嵌入式Linux的各种设备驱动,包括字符设备驱动、数字显示驱动、键盘驱动、A/D驱动、D/A驱动、LCD驱动、触摸屏驱动、CAN总线驱动、IIC总线驱动、音频总线驱动、IDE接口驱动、闪存芯片驱动、USB驱动、串口驱动、网络设备驱动等,并结合大量实例进行讲解,读者可以快速熟悉和掌握相关知识。 <br />  本书内容丰富,专业性和实用性强,适合嵌入式系统设计人员以及高校相关专业师生学习和使用。<br /> <br />图书比

spoft的专栏 491

Unity之如何实现TTS文本转语音(真人发音)

微软Azure TTS 文本转语音 服务 将文本转换为逼真的语音的语音服务功能 支持个各国语言,各种中文各种方言,支持不同音色男音女音 支持离线和在线版本

TxNet 5478

USB 串口驱动分享

本文深入探讨USB串口驱动的工作原理与实现方法。首先分析USB与UART的技术差异,包括通信方式、传输速率等关键特性。接着详细解析驱动架构,重点介绍Linux系统中的usbserial框架和Windows WDM模型。在实现层面,文章阐述了数据传输流程、设备枚举过程以及串口参数配置等技术细节。针对开发实践,提供了基于CP2102芯片的驱动开发实例和调试技巧。最后讨论了性能优化策略和常见问题解决方案,并展望了USB4标准等未来发展趋势。

Mr_-G,一名勤奋底层软件开发工程师的博客 3155

基于 YOLOv26 的陶瓷产品缺陷检测系统:智能视觉质检方案

本文提出了一种基于YOLOv26深度学习模型的陶瓷产品智能缺陷检测系统。该系统针对陶瓷生产中的裂纹、气泡、釉面缺陷等8类常见质量问题,采用YOLOv26目标检测算法实现高精度自动化检测。系统架构包含数据采集、预处理、YOLOv26检测和后处理四个模块,具有多类别分类、实时推理和强鲁棒性等技术优势。文章详细介绍了数据预处理与增强方法,并提供了Python代码实现示例。该方案可显著提升陶瓷产品质量检测效率,替代传统人工检测方式,为陶瓷制造业提供智能化质检解决方案。

一键难忘的博客 786

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

Linux Ubuntu18.04系统 USB转串口驱动安装,查看串口号

When you plugin your USB-UART converter, and run “> ls /dev/tty*”, if you don’t see the /dev/ttyUSB0 (or similar), your Linux does not detect your USB-UART device. 当插入USB设备后,在终端运行 ls /dev/tty* 时,若没有找到类似 /dev/ttyUSB0 的内容,说明Linux没有检测到设备。 We need to insta

Electrical_IT的博客 1万+

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

FPGA基础入门【13】开发板USB键盘控制,教你做硬核键盘侠

键盘 对键盘来说,它用的是扫描码,每个按键对应一个代码,当一个按键被按下,每100ms会重复发送一次;当这个按键被松开,一个0xF0被发出,跟着是那个被松开的按键。那些可以被shift的按键,比如大小写字母和可以代表符号的数字键,它的扫描码后面会跟着shift码,FPGA需要根据这个来决定用哪个ASCII字符。有些按键,比如Ctrl和Alt被按下时,会在扫描码前先发一个E0,当它们被松开时,会发E...

qimoDIY的博客 2万+

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

上一篇: 【驱动】USB驱动·入门
下一篇: 【电子基础】液晶显示器原理·LCD驱动基础
成鹏致远
博客等级 码龄14年 50粉丝 132原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值