您现在的位置是:网站首页> 硬件
嵌入式相关软硬件技术收集
- 硬件
- 2026-09-18
- 1801人已阅读
嵌入式相关软硬件技术收集
***避免写驱动:采用串口、网口、蓝牙***
带光耦继电器
带光耦固态继电器
Ardunio其实就是封装了底层调用API,开发者调用这些API编写应用,其实展开就是和普通C开发一样
当在Ardunio IDE选择板子时就是告诉底层API需要的配置参数

OpenCPU = 把单片机内核直接集成在通信模块内部,不用外加 MCU,直接在模块内部写代码、跑程序,不用外部主控
嵌入式AI辅助学习
硬件部分
软件部分
咒语收集
####【豆包】
Q:有通用嵌入式ubuntu IO数字模拟口的控制库吗?
A:....
嵌入式开源图形库LVGL
把GitHub扔远点,看看这些嵌入式网站
如果你想继续深耕嵌入式,或者确定了就ye 方向,我建议可以看看这些王站,记得马住!
✔️Arduino官方的项目分享坪台。这里聚集了大量关于Arduino的开源项目,适合初学者和资深开发者进行硬件和嵌入式开发
✔️STM32的官方开源库和项目都托管在STMicroelectronics的GitHub账户下。你可以在这里找到关于STM32、STM8等微控制器的官方示例和库
✔️一个开源项目托管坪台,尽管规模不如GitHub大,但仍然拥有丰富的嵌入式项目库。适合查找历史较长的嵌入式开源项目
✔️一个嵌入式开发生态系统,支持多种嵌入式平台如Arduino、STM32、ESP32等。它有一个丰富的库管理系统,你可以通过PlatformIO的库注册表找到大量开源项目
✔️一个专注于硬件和嵌入式项目的社区。你可以在这里找到很多关于物联网、智能家居、机器人等领域的开源项目,并有详细的教程帮助你上手
✔️专为嵌入式和物联网设计的实时操作系统。mbed OS 社区提供了丰富的开源项目,适合开发基于ARM Cortex-M系列的微控制器
# 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 设备完整示例(不需要内核驱动!)
> 优势:用户态,不用编译 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 驱动对比

## 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`,否则回调永远不触发。
上一篇:常用电路常识及器件工具使用
下一篇:CNC数控相关