嵌入式 STM32、RTOS、Linux 开发

泵浦激光器同步控制

这个项目是我在一家公司里面实现的,所以大部分代码不能开源出来,不够有些细节还是可以讨论。

技术栈

功能实现

该通信协议的波特率为 9600,采用 16 进制接收和发送,包含以下部分: - 帧头 - 数据长度 - 数据地址位 - 数据位 - 校验位

此外,还制作了一些光电检测电路,例如 OPT4001。关于如何提高灵敏度: - 首先需要屏蔽掉外接的光噪声 - 加入滤波电路减少参考电压噪声 - 或者采用前置放大器放大信号增加分辨率 - 同时在软件上采用滑动窗口平均滤波

940nm 泵浦激光器项目

这个项目从方案调研、、芯片选型和硬件的制作、还有系统的设计都是我自己查阅资料和文献得来的,所以有问题可以邮箱联系我,或者可以看我GitHub上的开源代码。

项目地址

SMBUS通信

SMBUS通信并非一种常见的通信方式,因此需要查阅SMBUS通信的源码,这里我是看的ST公司的源码文档,里面详细记录了SMBUS通信。 SMBUS通信是什么?SMBus(System Management Bus)是由Intel于1995年推出的两线制串行通信总线,专为系统管理任务(如电源控制、温度监控等)设计,其基于I2C协议但针对可靠性和管理功能进行了优化。物理层采用开漏设计的SMBCLK(时钟线)和SMBDATA(数据线),需外接上拉电阻(通常至3.3V或5V),并遵循严格的电压阈值(如VIL=0.8V, VIH=2.1V)以增强抗噪能力,标准速率范围为10 kHz至100 kHz。协议层通过强制超时机制(如35ms无响应自动复位)、PEC校验(数据包错误检查)和预定义命令集(如0x44读取温度、0x14控制风扇)提升可靠性,同时支持扩展功能如SMBALERT#中断信号和主机通知协议,允许从设备主动上报事件。相较于I2C,SMBus在电气规范、超时限制及校验机制上更为严格,但速率通常较低(I2C可达5 MHz)。其广泛应用于笔记本电脑电池管理、服务器散热控制及嵌入式系统硬件监测等场景,开发时需注意上拉电阻匹配、协议合规性及工具调试,成为高可靠系统管理的核心通信方案

ST官方手册

技术栈

(一)硬件设计

(二)芯片通信

(三)PID 算法

增加了积分限幅、输出限幅等设置,并且给调节过程配置了缓上升调节,以达到安全性,可以设置步长、斜率速度。
自整定 PID: - 利用 ZN 法,改变输入输出,获取 PID 波形的一个震荡周期 - 根据 ZN 公式计算 PID 参数

自适应 PID: - 当误差很大时,只采用 P 调节 - 当误差逐渐变小时,引入积分 - 当误差最小时,加入微分

使用 MATLAB 系统函数辨别工具箱,将输入输出数据传给 MATLAB,获取 PID 控制器的系统函数,然后进一步获取 P、I、D 参数。
先找大致的 P、I、D 参数,然后再微调。
比例项用于快速响应误差,积分项用于消除稳态误差,微分项用于抑制系统的振荡。 其实PID有很多高级的用法,但是我觉得最适合工程的PID才是最好的,模糊控制、神经网络等等都可以结合PID

(四)上位机设计

包含串口收发数据解析、PID 参数设定协议解析。

1.串口收发数据

定义接收环形缓冲区,包含以下内容: - 数据指针 - 头指针 - 尾指针 - 当前缓冲区存储的数据量 - 队列最大的数据量

2.PID 串口解析协议

数据帧格式: - 帧头:0x59485a43 - 命令码 - 数据 - 校验和

接收缓冲区同样使用环形缓冲区,包含以下内容: - 数据指针 - 头指针 - 尾指针 - 当前帧的长度 - 是否找到帧头的标志位

(五)Freertos部分

对于这部分的软件架构设计呢,我主要是分成三部分的大内容,首先是恒流任务和恒温任务,他们的优先级都是一样的,然而串口的优先级是最高的。我们都知道Freertos是基于优先级调度任务的,同等优先级是基于时间片的,所以这里用二值信号量去判断是否串口中断是否来临,那么这样就可以有效的阻塞串口处理函数。串口触发时间呢,则采用事件组去触发任务,数据的传输则用消息队列,获取电流,获取温度,获取风扇的转速等等这些。

1. 任务模块划分

2. 任务调度策略

3. 同步与通信机制

(六)问题与解答

  1. 为什么项目里面通信协议不用 1 个字节的帧头,而用 4 个字节的帧头?
  1. 假如数据包的发送中的数据长度后面一段帧的内容丢失了,而下位机的内容是否需要一直检查帧长度不对,等待下一帧的发送,这样应该怎么解决?
  1. Makefile 的使用,如何开启/关闭 warning 和 error 提示?
  1. C/C++ 的区别?讲一下具体?

智能车载终端项目

这个项目需要用到一个IMX6ULL开发板,正点原子和韦东山的都可以,然后买一个usb摄像头,就可以了。

项目地址

技术栈

功能设计

驱动设计

(一)QT 设计

1. 音乐播放器

主要用到了 QMediaPlayer 这个类,通过 stateChanged(QMediaPlayer::State state) 判断状态,从而知道媒体何时暂停、播放或停止(前提是知道路径)。

2. 视频播放器

同样用到了 QMediaPlayer 类,但需要使用 setVideoOutput(QVideoWidget*) 设置视频输出。

3. 倒车界面

显示 AP3216 读取的光传感器距离,通过 500ms 的定时器实时读取距离信息,并传递到 QString 上显示。

4. USB 相机

实现步骤

  1. 使用 V4L2 API 打开摄像头设备,配置格式(例如 YUV),并开始捕获帧。
  2. 将捕获的帧数据读取到内存中。
  3. 将数据转换为 Qt 可以处理的格式(例如 QImage),可能需要进行 YUV 转 RGB 的步骤。
  4. 将转换后的图像数据发送到 Qt 界面进行显示,例如通过信号槽机制更新 QLabelQGraphicsView 的内容。

5.天气界面

利用 IP 地址实现对天气的获取: - 使用 IP 地址归属地查询当前位置,位置信息在查询天气时也会用到。 - 调用与天气相关的 API(例如中华万年历 API)获取本地天气信息。 - 推荐使用中华万年历 API 的原因: - 数据与中国天气网一致。 - 返回的数据是 JSON 格式,方便解析。 - 查询方便,支持城市名称或城市 ID 查询。 - 使用 QNetworkAccessManager 发送网络请求,解析 JSON 数据。 - 定时器(1 小时触发一次)用于定时更新天气数据。

6.语音识别界面

(二)驱动设计

1. 音频驱动模块

2. AP3216 距离读取

3. DHT11 芯片驱动

4.GPS 定位

5.USB 摄像头驱动

6.LCD 驱动

在 LCDinfo 节点下,修改为适配自己分辨率型号的配置。

(三)提问问题

1.音乐播放器

问题:你如何实现音乐播放器的播放、暂停和停止功能?
答案:音乐播放器主要使用了 QMediaPlayer 类。通过监听 stateChanged 信号,可以判断播放器的状态(播放、暂停、停止)。当状态变化时,根据 state 的值执行相应的操作,例如播放时调用 play(),暂停时调用 pause(),停止时调用 stop()。播放器需要提前知道媒体文件的路径。

2.视频播放器

问题:视频播放器和音乐播放器的区别是什么?
答案:视频播放器同样使用 QMediaPlayer 类,但需要通过 setVideoOutput(QVideoWidget*) 设置视频输出的显示界面。音乐播放器只需要处理音频流,而视频播放器需要同时处理音频和视频流。

3.倒车界面

问题:倒车界面如何实时更新光传感器的距离信息?
答案:倒车界面通过定时器(500ms 触发一次)实时读取 AP3216 光传感器的距离信息。读取到的数据通过 QString 传递到界面上显示。

4.USB 相机

问题:如何实现 USB 相机的视频显示?
答案:使用 V4L2_open() 函数打开摄像头设备(如 /dev/video2),配置为 MJPG 格式,并设置分辨率。通过 mmap 将内核缓冲区映射到用户空间。定时器(30ms 触发一次)从缓冲区读取帧数据,并显示在 QLabel 上。

5.天气信息

问题:如何通过 IP 地址获取天气信息?
答案:使用 QNetworkAccessManager 发送网络请求,调用中华万年历 API 获取天气信息。API 返回的数据是 JSON 格式,通过解析 JSON 数据获取天气信息。定时器(1 小时触发一次)用于定时更新天气数据。

问题:为什么选择中华万年历 API?
答案:中华万年历 API 的数据与中国天气网一致,返回的数据是 JSON 格式,方便解析,且查询方便(支持城市名称或城市 ID)。

6.语音识别

问题:如何实现语音识别功能?
答案:使用 QAudioRecorder 类实现录音功能。通过 QAudioEncoderSettings 设置音频参数(编码格式、采样率、通道数等)。调用 record()pause()stop() 函数完成录音。录音数据上传到语音识别服务端进行识别。

7.音频驱动

问题:如何配置 WM8960 音频驱动?
答案:使用 I2S 接口配置 WM8960 音频编解码芯片。修改内核配置,使能 WM8960 驱动。移植 alsa-lib 和 alsa-utils 源码,确保设备节点路径一致。通过配置实现录音、播放音乐和播放视频的功能。

8. 距离读取

问题:如何实现 AP3216 距离读取?
答案:在 I2C1 节点下添加 AP3216 设备子节点,包含 compatible 和 reg 信息。编写 AP3216 驱动,通过 i2c_transfer 函数读取传感器数据。 DHT11 温湿度传感器的单总线协议编写: - 在进行数据读取过程中需要 local_irq_disable 屏蔽中断标志位,从而禁止内核的抢占。

9. GPS 数据解析

问题:如何解析 GPS 数据?
答案:使用 Eco 模块通过串口通信,解析 GPS 数据(例如 RMC、GGA、VTG 等)。通过 strsplit 函数分割字符串,将数据写入结构体中。

10.摄像头帧格式

问题:USB 摄像头驱动的定时器为什么要每隔 30ms 读取一次数据?
答案:30ms 定时器对应每秒 30 帧,这是常见的流畅视频显示的帧率。 USB 摄像头帧格式转换: - 摄像头读取的帧格式需要从 YUV 转换为 JPEG 格式

问题:对于摄像头读取的格式有没有做变换?
答案:做了变换。通常 USB 摄像头读取的是 YUV 格式的视频数据,需要编写一个 YUV 转 JPEG 格式的函数进行读取。关键函数是 libjpeg 库中的 jpeg_compress 函数。

基于线程池的并发服务器

开源项目,b站随便找一个就可以,这个主要是让我熟悉操作系统的一些条件变量、自旋锁和socket套接字概念的。

技术栈

(一)线程池的原理

线程池分为三部分: 1. 任务队列:用于存储待处理的任务,工作线程从队列中获取任务进行处理。 - 通过线程池的 API 接口,将待处理的任务添加到任务队列中。 - 已处理的任务会被从任务队列中删除。 - 线程池的使用者(调用线程池函数往队列添加任务的线程)是生产者线程。

  1. 工作线程:任务队列的消费者,负责从队列中读取任务并执行。
  1. 管理者线程:只能有一个,负责管理线程池的运行状态。

(二)Socket 通信

服务器端的通信流程: 1. 创建 socket 描述符。 2. 使用 bind 绑定 IP 和端口。 3. 调用 listen 进入监听状态。 4. 调用 accept 接受客户端的连接请求。 5. 通过 connect 与客户端建立连接,完成通信。

(三)多线程

服务端主线程在这里的主要任务是:按照Socket通信流程往下走,并发操作在哪里呢? 第四步的accept接受到客户端的连接请求后,创建子线程pthread_create让通信的处理流程则是在子线程中运行,然后调用pthread_detach去回收子线程资源 注意是用detach而不是用join函数 阻塞。然后再close(fd)关闭文件描述符。通信的流程都在子线程的working里面。 那么需要给子线程传进去一些参数:信息结构体sockinfo{sockadd_in addr,int fd} 需要有socket的地址和 文件描述符fd。

(四)线程同步

线程同步体现在那里? 多个线程对同一个资源需要同时读写操作,就需要同步操作了。 之前提到声明了一个全局的结构体数组sockinfo infos[512] 在主线程中要确定数组fd的数量 而这里是不需要线程同步的。 在线程池中是需要进行线程同步的。

(五)套接字使用线程池的思路:

(六)线程池实现思路

基于空谱结合的卷积神经网络高光谱图像分类

这个项目是我结合实验室的一个成像模型的预训练,就是需要通过实验室特有的成像模型获取数据,然后对数据进行处理分类。大家有时间可以去看看关联成像,这部分也是我实验室的一个研究方向,但是这个跟嵌入式没啥关系,当作一个拓展吧。

技术栈

算法步骤

输入数据为尺寸 526×345×111 的光谱图像,设计轻量化卷积神经网络:

  1. 光谱降维 :用 1×1 卷积将 111 通道压缩至 32 通道,去冗余降复杂度。
  2. 空间特征提取 :堆叠多个 3×3 卷积块,后接最大池化层,网络加深时缩小空间尺寸(345×526→10×16),通道数翻倍(32→64→128→256→512),平衡信息损失与语义表达。
  3. 全局特征融合 :以全局平均池化(GAP)替代全连接层,压缩特征图至 512 维向量,防参数爆炸。
  4. 分类与优化 :经 Dropout 和 Softmax 输出概率,用批量归一化(BatchNorm)加速训练防过拟合。

美赛 M 奖项目介绍

这个比赛离我很久远了,很多内容都想不起来了,但是还是去翻翻往年题目去作了一些总结,为什么我要写这个呢,因为某菊厂给我免笔试就是因为这个,哈哈哈是不是很值得?菊厂的笔试还是很难的,所以大家有时间要多比赛。

技术栈

项目内容

以经纬度为输入,用 K-means 聚类算法划成 8 区域,参考火势强度作权重,轮廓系数评指标,输出中心坐标、火点数量、总火势强度。设计单位区域无人机需求数公式,指标含火势总量、无人机灭火能力、紧急系数、火势扩散速度。用模拟退火算法求全局最优分配,随机分配无人机,满足总数量约束,目标函数为灭火时间 + 权重因子 × 未覆盖惩罚,引入交叉验证评聚类模型。

我参与过的一些硬件电路设计:

虽然画得一般,但也是自己设计的,也花了一点心思:

点击查看pump_contrl电路PCB

点击查看pump_driver电路PCB

点击查看其他硬件1

点击查看其他硬件2