您现在的位置是:网站首页> 硬件

嵌入式相关软硬件技术收集

  • 硬件
  • 2026-09-18
  • 1801人已阅读
摘要

嵌入式相关软硬件技术收集

六合一多功能转串口模块

***避免写驱动:采用串口、网口、蓝牙***

带光耦继电器

带光耦固态继电器

Ardunio其实就是封装了底层调用API,开发者调用这些API编写应用,其实展开就是和普通C开发一样

当在Ardunio IDE选择板子时就是告诉底层API需要的配置参数

1.jpg

OpenCPU = 把单片机内核直接集成在通信模块内部,不用外加 MCU,直接在模块内部写代码、跑程序,不用外部主控


系统集成好物

嵌入式AI辅助学习

咒语收集


硬件部分

linux android开发版香橙派

瑞莎 Radxa 开发板

单片机、嵌入式的大神都平时浏览什么网站?

Arduino nano开发板

esp32 arduino或ESP-32

合宙AIR001 Nano开发板

AI硬件

昂达平板

微软surface3

核桃派


软件部分

嵌入式开源图形库LVGL

把GitHub扔远点,看看这些嵌入式网站

写一个从 USB 设备读取数据的 LINUX 驱动例子代码

libusb 方案实现从 USB 设备读取数据



咒语收集

####【豆包】

Q:有通用嵌入式ubuntu IO数字模拟口的控制库吗?

A:....



嵌入式开源图形库LVGL




把GitHub扔远点,看看这些嵌入式网站

如果你想继续深耕嵌入式,或者确定了就ye 方向,我建议可以看看这些王站,记得马住!

Arduino Project Hub    

✔️Arduino官方的项目分享坪台。这里聚集了大量关于Arduino的开源项目,适合初学者和资深开发者进行硬件和嵌入式开发

STMicroelectronics GitHub    

✔️STM32的官方开源库和项目都托管在STMicroelectronics的GitHub账户下。你可以在这里找到关于STM32、STM8等微控制器的官方示例和库

SourceForge    

✔️一个开源项目托管坪台,尽管规模不如GitHub大,但仍然拥有丰富的嵌入式项目库。适合查找历史较长的嵌入式开源项目

PlatformIO    

✔️一个嵌入式开发生态系统,支持多种嵌入式平台如Arduino、STM32、ESP32等。它有一个丰富的库管理系统,你可以通过PlatformIO的库注册表找到大量开源项目

Hackster.io

✔️一个专注于硬件和嵌入式项目的社区。你可以在这里找到很多关于物联网、智能家居、机器人等领域的开源项目,并有详细的教程帮助你上手

mbed OS    

✔️专为嵌入式和物联网设计的实时操作系统。mbed OS 社区提供了丰富的开源项目,适合开发基于ARM Cortex-M系列的微控制器


写一个从 USB 设备读取数据的 LINUX 驱动例子代码

# Linux USB 设备驱动示例(内核模块,基于 usb-skeleton 模板)

⚠️ 说明:

> 1. 这是**内核态 USB 驱动**,用于匹配自定义 USB 设备,实现从 USB 设备读取数据;不是用户态 libusb。

> 2. 适合学习 USB 驱动框架,实际产品推荐优先用`libusb`用户态方案,避免内核模块风险。

> 3. 内核版本:Linux 5.x/ 6.x 通用;需要内核源码、内核头文件编译。

> 4. 替换 `VENDOR_ID` / `PRODUCT_ID` 为你的 USB 设备 VID/PID。


## 1. 驱动源码 usb_read_demo.c


#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/slab.h>

#include <linux/usb.h>

#include <linux/uaccess.h>


// 替换成你的USB设备VID PID

#define MY_USB_VENDOR_ID  0x1234

#define MY_USB_PRODUCT_ID 0x5678


// 端点定义:假设设备IN端点地址 0x81,批量端点BULK

#define BULK_IN_EP        0x81

#define BULK_IN_BUF_SIZE  512


// 设备私有数据结构

struct my_usb_dev {

    struct usb_device *udev;

    struct usb_interface *intf;

    char *bulk_in_buf;

    dma_addr_t bulk_in_dma;

};


// USB设备匹配表

static const struct usb_device_id my_usb_table[] = {

    { USB_DEVICE(MY_USB_VENDOR_ID, MY_USB_PRODUCT_ID) },

    { }

};

MODULE_DEVICE_TABLE(usb, my_usb_table);


// 中断回调:批量IN传输完成回调

static void my_usb_bulk_in_callback(struct urb *urb)

{

    struct my_usb_dev *dev = urb->context;

    int status = urb->status;


    switch(status) {

        case 0:

            // 读取成功,urb->actual_length 是读到的字节数

            pr_info("USB read ok, len=%d, data: %*ph\n",

                    urb->actual_length,

                    urb->actual_length, dev->bulk_in_buf);

            break;

        case -ENOENT:

        case -ECONNRESET:

        case -ESHUTDOWN:

            pr_info("USB urb cancelled\n");

            return;

        default:

            pr_err("USB bulk in error status:%d\n", status);

            break;

    }


    // 重新提交URB,持续轮询读取(按需开启)

    // usb_submit_urb(urb, GFP_ATOMIC);

}


// 设备probe:匹配到USB设备时调用

static int my_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)

{

    struct usb_device *udev = interface_to_usbdev(intf);

    struct my_usb_dev *dev;

    struct urb *urb;

    int ret;


    pr_info("my usb driver probed, vid=%04x,pid=%04x\n",

            le16_to_cpu(udev->descriptor.idVendor),

            le16_to_cpu(udev->descriptor.idProduct));


    // 分配私有数据

    dev = kzalloc(sizeof(*dev), GFP_KERNEL);

    if (!dev) return -ENOMEM;


    dev->udev = udev;

    dev->intf = intf;


    // 分配DMA缓冲区(USB传输必须DMA对齐)

    dev->bulk_in_buf = usb_alloc_coherent(udev, BULK_IN_BUF_SIZE, GFP_KERNEL, &dev->bulk_in_dma);

    if (!dev->bulk_in_buf) {

        kfree(dev);

        return -ENOMEM;

    }


    // 创建URB(USB请求块,核心通信载体)

    urb = usb_alloc_urb(0, GFP_KERNEL);

    if (!urb) {

        usb_free_coherent(udev, BULK_IN_BUF_SIZE, dev->bulk_in_buf, dev->bulk_in_dma);

        kfree(dev);

        return -ENOMEM;

    }


    // 初始化BULK IN URB

    usb_fill_bulk_urb(urb, udev,

                      usb_rcvbulkpipe(udev, BULK_IN_EP),

                      dev->bulk_in_buf,

                      BULK_IN_BUF_SIZE,

                      my_usb_bulk_in_callback,

                      dev);


    // 保存urb到私有结构体,方便disconnect释放

    usb_set_intfdata(intf, dev);


    // 提交URB,发起一次读操作

    ret = usb_submit_urb(urb, GFP_KERNEL);

    if (ret) {

        pr_err("submit urb failed: %d\n", ret);

        usb_free_urb(urb);

        usb_free_coherent(udev, BULK_IN_BUF_SIZE, dev->bulk_in_buf, dev->bulk_in_dma);

        kfree(dev);

        return ret;

    }


    pr_info("probe success, bulk in urb submitted\n");

    return 0;

}


// disconnect:设备拔下时调用,资源释放

static void my_usb_disconnect(struct usb_interface *intf)

{

    struct my_usb_dev *dev = usb_get_intfdata(intf);

    struct urb *urb;


    usb_set_intfdata(intf, NULL);

    if (!dev) return;


    // 取消URB传输

    urb = usb_get_urb(dev->udev->urb);

    usb_kill_urb(urb);

    usb_free_urb(urb);


    // 释放DMA内存

    usb_free_coherent(dev->udev, BULK_IN_BUF_SIZE, dev->bulk_in_buf, dev->bulk_in_dma);

    kfree(dev);

    pr_info("my usb device disconnected\n");

}


// USB驱动操作结构体

static struct usb_driver my_usb_driver = {

    .name       = "my_usb_read_drv",

    .id_table   = my_usb_table,

    .probe      = my_usb_probe,

    .disconnect = my_usb_disconnect,

};


// 模块入口出口

static int __init my_usb_init(void)

{

    return usb_register(&my_usb_driver);

}


static void __exit my_usb_exit(void)

{

    usb_deregister(&my_usb_driver);

}


module_init(my_usb_init);

module_exit(my_usb_exit);


MODULE_LICENSE("GPL");

MODULE_AUTHOR("Embedded Engineer");

MODULE_DESCRIPTION("Linux USB bulk IN read demo driver");



## 2. Makefile

obj-m += usb_read_demo.o

# 内核源码目录,根据你的系统修改

KERNELDIR ?= /lib/modules/$(shell uname -r)/build

PWD := $(shell pwd)


all:

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules


clean:

$(MAKE) -C $(KERNELDIR) M=$(PWD) clean



## 3. 编译 & 加载命令

# 编译

make

# 加载内核模块

sudo insmod usb_read_demo.ko


# 查看内核打印

dmesg -w


# 卸载模块

sudo rmmod usb_read_demo


## 4. 关键知识点说明

1. **URB(USB Request Block)**

Linux USB 子系统所有通信都靠 URB。批量 IN 端点用于从 USB 设备**读数据**;OUT 端点是主机发数据给设备。`usb_fill_bulk_urb` 填充批量传输;`usb_submit_urb` 提交 URB,异步接收,数据到了自动调用回调函数。

2. **缓冲区**

USB 传输必须使用`usb_alloc_coherent`分配 DMA 连续内存,不能直接用`kmalloc`,避免 DMA 缓存一致性问题。

3. **端点类型**

- Bulk(批量):U 盘、USB 串口,大数据,非实时;本示例用 BULK IN

- Interrupt(中断端点):鼠标键盘,小数据,低延迟

- Isochronous(同步):USB 摄像头音频,实时允许丢包


## 5. 重要限制 & 优化方向

- 上面示例是**异步 URB**,读到数据在回调函数打印;如果想做同步读取(阻塞读),可以用`usb_bulk_msg`(简单,但不适合高速持续流)。

> 同步读简易 API 示例(阻塞):


> char buf[128];

> int ret, actual_len;

> ret = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, BULK_IN_EP),

> buf, sizeof(buf), &actual_len, 1000); // timeout ms

> if(ret ==0) pr_info("sync read len:%d\n", actual_len);


- 内核模块调试麻烦,**优先推荐用户态 libusb**,不需要编译内核模块,不需要签名。

- 如果你的设备是 USB CDC 虚拟串口,不要自己写 USB 驱动,Linux 自带`cdc-acm`,直接用 `/dev/ttyACM0`。


## 6. 用户态 libusb 版本(备选方案,推荐)

如果你不需要内核驱动,只需要应用层读取 USB 设备,我可以给一份 libusb C 代码,不需要内核模块。


libusb 方案实现从 USB 设备读取数据

# libusb 用户态读取 USB 设备完整示例(不需要内核驱动!)

> 优势:用户态,不用编译 ko、不用内核模块签名,Linux/macOS/Windows 都能跑;适合自定义 USB 设备(BULK IN 端点上传数据)。

> 原理:libusb 直接和内核 usbcore 交互,通过`libusb_submit_transfer`提交异步传输,也可以用同步 API 简单读取。

> 环境:Ubuntu/Debian:`sudo apt install libusb-1.0-0-dev`


## 1. libusb 同步读取版本(简单,适合低速,阻塞式)

`libusb_bulk_transfer` 同步阻塞函数,等待设备返回数据或者超时。


#include <stdio.h>

#include <stdlib.h>

#include <libusb-1.0/libusb.h>


// ========== 配置项,修改成你的设备VID/PID/端点 ==========

#define VID        0x1234

#define PID        0x5678

#define BULK_IN_EP 0x81  // IN端点,主机读设备

#define TIMEOUT_MS 1000  // 超时时间ms

#define BUF_LEN    512


int main(void)

{

    libusb_context *ctx = NULL;

    libusb_device_handle *devh = NULL;

    int ret;

    unsigned char buf[BUF_LEN];

    int actual_len;


    // 1. 初始化libusb上下文

    ret = libusb_init(&ctx);

    if(ret < 0) {

        fprintf(stderr, "libusb init failed: %s\n", libusb_strerror(ret));

        return -1;

    }


    // 开启调试日志(可选,0关闭,1~4等级)

    libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, 2);


    // 2. 打开指定VID PID设备

    devh = libusb_open_device_with_vid_pid(ctx, VID, PID);

    if(!devh) {

        fprintf(stderr, "cannot open usb device %04x:%04x\n", VID, PID);

        libusb_exit(ctx);

        return -1;

    }


    // 3. 如果内核已经加载了默认驱动,需要detach

    if(libusb_kernel_driver_active(devh, 0) == 1) {

        printf("kernel driver active, detach it\n");

        ret = libusb_detach_kernel_driver(devh, 0);

        if(ret != 0) {

            fprintf(stderr, "detach kernel driver failed\n");

            libusb_close(devh);

            libusb_exit(ctx);

            return -1;

        }

    }


    // 4. 申请接口0

    ret = libusb_claim_interface(devh, 0);

    if(ret < 0) {

        fprintf(stderr, "claim interface failed: %s\n", libusb_strerror(ret));

        libusb_close(devh);

        libusb_exit(ctx);

        return -1;

    }


    printf("device open success, start read data...\n");


    // 循环读取

    while(1)

    {

        // 同步批量IN传输:主机从USB设备读数据

        ret = libusb_bulk_transfer(devh, BULK_IN_EP, buf, BUF_LEN, &actual_len, TIMEOUT_MS);

        if(ret == 0)

        {

            printf("recv %d bytes: ", actual_len);

            for(int i = 0; i < actual_len; i++)

            {

                printf("%02x ", buf[i]);

            }

            printf("\n");

        }

        else if(ret == LIBUSB_ERROR_TIMEOUT)

        {

            // 超时,正常,继续循环

            continue;

        }

        else

        {

            fprintf(stderr, "bulk transfer error: %s\n", libusb_strerror(ret));

            break;

        }

    }


    // 释放资源

    libusb_release_interface(devh, 0);

    libusb_close(devh);

    libusb_exit(ctx);

    return 0;

}



## 2. Makefile


CC = gcc

CFLAGS += -Wall

LDFLAGS += -lusb-1.0


all: libusb_read


libusb_read: libusb_read.c

$(CC) $(CFLAGS) -o libusb_read libusb_read.c $(LDFLAGS)


clean:

rm -f libusb_read



## 3. 编译与运行


# 编译

make


# 权限问题解决:两种方案

# 方案1:sudo运行(临时)

sudo ./libusb_read


# 方案2:udev规则,免sudo(推荐嵌入式长期使用)

# 创建 /etc/udev/rules.d/99-myusb.rules

# SUBSYSTEM=="usb", ATTRS{idVendor}=="1234", ATTRS{idProduct}=="5678", MODE="0666"

# 然后 sudo udevadm control --reload-rules && sudo udevadm trigger

 

> ⚠️ 重点:`libusb_detach_kernel_driver`

> 如果这个 USB 设备已经被系统自带驱动占用(比如 cdc-acm),libusb 无法接管,必须 detach;

> 一旦 detach,原来的内核驱动就失效,程序退出后会自动恢复。


## 4. libusb 异步版本(高性能,推荐大数据持续采集)

同步`libusb_bulk_transfer`会阻塞线程,高速数据流场景用**异步 transfer**,类似内核 URB 机制。


#include <stdio.h>

#include <stdlib.h>

#include <libusb-1.0/libusb.h>


#define VID        0x1234

#define PID        0x5678

#define BULK_IN_EP 0x81

#define BUF_LEN    512


libusb_context *ctx = NULL;

libusb_device_handle *devh = NULL;


// 传输完成回调

void transfer_cb(struct libusb_transfer *transfer)

{

    if(transfer->status == LIBUSB_TRANSFER_COMPLETED)

    {

        printf("async recv %d bytes: ", transfer->actual_length);

        for(int i=0; i<transfer->actual_length; i++){

            printf("%02x ", transfer->buffer[i]);

        }

        printf("\n");

    }

    else if(transfer->status == LIBUSB_TRANSFER_TIMED_OUT)

    {

        // timeout

    }

    else

    {

        fprintf(stderr, "transfer error status=%d\n", transfer->status);

        libusb_free_transfer(transfer);

        return;

    }


    // 重新提交,持续循环读取

    int ret = libusb_submit_transfer(transfer);

    if(ret != 0)

    {

        fprintf(stderr, "resubmit transfer failed %s\n", libusb_strerror(ret));

        libusb_free_transfer(transfer);

    }

}


int main(void)

{

    int ret;

    unsigned char *buf;

    libusb_transfer *xfer;


    ret = libusb_init(&ctx);

    if(ret < 0) return -1;


    devh = libusb_open_device_with_vid_pid(ctx, VID, PID);

    if(!devh) {

        libusb_exit(ctx);

        return -1;

    }


    if(libusb_kernel_driver_active(devh,0))

        libusb_detach_kernel_driver(devh,0);

    libusb_claim_interface(devh,0);


    // 分配transfer对象

    xfer = libusb_alloc_transfer(0);

    buf = malloc(BUF_LEN);


    // 填充bulk transfer

    libusb_fill_bulk_transfer(xfer, devh, BULK_IN_EP, buf, BUF_LEN, transfer_cb, NULL, 1000);


    // 提交异步传输

    ret = libusb_submit_transfer(xfer);

    if(ret != 0) {

        fprintf(stderr, "submit transfer failed %s\n", libusb_strerror(ret));

        libusb_free_transfer(xfer);

        free(buf);

        libusb_release_interface(devh,0);

        libusb_close(devh);

        libusb_exit(ctx);

        return -1;

    }


    printf("async transfer started\n");


    // libusb事件循环

    while(1)

    {

        ret = libusb_handle_events_completed(ctx, NULL);

        if(ret < 0)

            break;

    }


    libusb_cancel_transfer(xfer);

    libusb_free_transfer(xfer);

    free(buf);

    libusb_release_interface(devh,0);

    libusb_close(devh);

    libusb_exit(ctx);

    return 0;

}



## 5. libusb 整体执行流程(对比前面内核驱动)


程序启动

    ↓

libusb_init() 创建上下文

    ↓

libusb_open_device_with_vid_pid() 根据VID/PID找到usb设备

    ↓

libusb_detach_kernel_driver() 剥离内核驱动(如有)

    ↓

libusb_claim_interface() 抢占USB接口

    ↓

同步:libusb_bulk_transfer 发起IN传输,阻塞等待完成

异步:libusb_submit_transfer提交传输,注册回调;libusb_handle_events 循环处理事件


USB设备返回数据 → libusb内核底层 → 用户态回调函数执行



## 6. libusb vs 内核 USB 驱动对比

QQ_1788917297568.png


## 7. 常用调试命令

# 查看USB设备VID PID端点

lsusb

lsusb -t

lsusb -v -d 1234:5678


## 8. 常见踩坑

1. **端点地址写错**:IN 端点最高位是 1(0x81),OUT 是 0x01;这个是最常见错误。

2. `claim_interface`失败:内核驱动没 detach,或者接口号不对。

3. 数据乱码:设备包长和 buffer 不匹配,注意`actual_len`才是真实收到字节。

4. 异步模式:必须持续调用`libusb_handle_events`,否则回调永远不触发











Top