心跳跟随的心形灯(STM32(HAL)+WS2812+MAX30102)
文章目录
- 前言
- 介绍
- 系统框架
- 原项目地址
- 本项目开发开源地址
- 硬件PCB
- 软件功能
- 详细内容
- 硬件外壳制作
- WS2812级联及控制
- MAX30102血氧传感器
- 0.96OLED
- FreeRTOS
- 效果视频
- 总结
前言
在好几年前,我好像就看到了焊武帝 jiripraus在纪念结婚五周年时,制作的一个心跳跟随心形灯,感觉太浪漫了,于是在假期的时候,我也仿照做了一个,虽然还有很多需要完善的地方,但是大致功能已经实现了,下面开源讲讲开源的项目。




介绍
系统框架
心脏的外壳采用紫铜丝或黄铜丝焊接,1mm的铜丝较硬,适合完成外部框架的搭建,0.7mm的铜丝可塑性较好,适合焊接内部的WS2812,整个过程中吗,焊接难度较大,电子器件的固定难度也很大,我内部借助了一些热熔胶固定,有些丑,可以参考 jiripraus的固定方法。
原作者采用的Arduino主控,且没有借助PCB,纯飞铜线完成内部电子器件的连接。
因为我想利用FreeRTOS学习一下实际项目编写,所以将主控更换成了STM32F103C8T6,当然编写了两套代码,先编写了一套裸机开发,测试能够完成所有功能、之后移植了一套FreeRTOS的,都可以运行。
原项目地址
jiripraus项目地址(Arduino):https://www.instructables.com/Beating-LED-Heart/
本项目开发开源地址
裸机开发软件下载(STM32版本):https://download.csdn.net/download/zerokingwang/88173336
FreeRTOS开发软件下载(STM32版本):https://download.csdn.net/download/zerokingwang/88173410
硬件PCB(立创开源)下载链接:https://oshwhub.com/zeroking/my_heart_
所有文件上传到github了,也可以到github下载:https://github.com/VioletJA/MY_HEART
硬件PCB
绘制了包括STM32F103C8T6的最小系统、蜂鸣器、TP4059锂电池充电电路、OLED接口、MAX30102接口等。


软件功能
在没有手指触碰到MAX30102模块时,WS2812进行彩虹灯变换,当手指触碰到时,跟随检测到的心跳进行红色闪烁及蜂鸣器模拟心跳。
详细内容
硬件外壳制作
在3D打印的器件上进行焊接,我先用胶带固定好铜丝,然后再各个连接点进行焊接。
心形3D打印件:https://www.cgtrader.com/items/865899/download-page

WS2812焊接:最好黏在胶带上,固定好大致位置后再进行焊接,我没有找到其他好方法,焊接极其耗时。

WS2812级联及控制


当发送一串数据时,第一个24bits的数据给D1,第n个24bits的数据给第n。(24bit对应三原色,每一色八位)
输出码型通过下图判断,因此每一位的高低都需要进行严格控制


大多数采用的是PWM+DMA的模式,通过传输一串数据,控制不同占空比的PWM完成数据传输
HAL_TIM_PWM_Start_DMA(&ws2812_TIM, ws2812_CHANNEL, (uint32_t *)Pixel_Buf,(Pixel_NUM+1)*24);
参考:STM32系列(HAL库)——F103C8T6驱动WS2812全彩RGB模块(PWM+DMA方式)
但有一点需要注意,必须在PWM的完成回调函数中进行手动关闭DMA传输,否则WS2812颜色不对(应该就是DMA传输出错了)
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance==ws2812_TIM.Instance)HAL_TIM_PWM_Stop_DMA(&ws2812_TIM, ws2812_CHANNEL);
}
其他详细的代码控制都在开源代码中了
MAX30102血氧传感器
参考:【stm32】手把手用cubemx配置血氧传感器(MAX30102)
采用的是中断处理,每次模块发送一个下降沿中断,STM32接收到后进行数据处理。
模块采用IIC进行控制与数据读取,普通采用HAL配置硬件IIC就能够实现,但是在我用STM32F103C6T6进行测试的时候,HAl生成的代码中,IIC引脚不会自动设置为高速,导致运行会出现HAL_ERROR的问题,然而在STM32F103C8T6就已经纠正了这个错误。
void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(i2cHandle->Instance==I2C1){__HAL_RCC_GPIOB_CLK_ENABLE();GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);__HAL_RCC_I2C1_CLK_ENABLE();else if(i2cHandle->Instance==I2C2){__HAL_RCC_GPIOB_CLK_ENABLE();GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);__HAL_RCC_I2C2_CLK_ENABLE();}
}

0.96OLED
在屏幕调试中,由于1616的字看上去太小了,于是我调整为2424的大小,这个时候,网上的一些库就不够用了,需要看懂是如何完成一个汉字的显示。
利用PCtoLCD2002完成取字模,一般设置如下


数据如下:
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x08,0x10,0x70,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x80,0xC0,0xF8,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0xC0,0x04,0x18,0xF0,0xE0,0x00,0x00},
{0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x1F,0x18,0x10,0x10,0x10,0x10,0x10,0x10,0x18,0x1F,0x08,0x00,0x00,0x00,0x00,0x00},/*"心",0*/
网上一般说取数据是按照一行一行来的,一个数据代表的是8位,不足8位的按照8位算。
但是我实际测试,是按列算的,例如第一个数据0x00,表示第一列中的前八个点全没有点亮,第二个0x00代表的是第二列数据的前8个也全部没有点亮,当前8行的所有列都完成后,计算中间8行,一列一列,之后计算下面8行(24*24的数据)
例如下图:

而我们采用的低位在前时:

当第一个格子点亮时,对应的就是0x01
在OLED汉字显示的函数中,需要将汉字分为三上中下,完成三次打印,组成一个完整的汉字
//显示24*24汉字
void OLED_ShowCHinese24(uint8_t x,uint8_t y,uint8_t no)
{ uint8_t t;OLED_Set_Pos(x,y); for(t=0;t<24;t++){OLED_WR_Byte(CHI_24_24[3*no][t],OLED_DATA);} OLED_Set_Pos(x,y+1); for(t=0;t<24;t++){ OLED_WR_Byte(CHI_24_24[3*no+1][t],OLED_DATA);}OLED_Set_Pos(x,y+2); for(t=0;t<24;t++){ OLED_WR_Byte(CHI_24_24[3*no+2][t],OLED_DATA);}
}
FreeRTOS
在移植操作系统的时候,创建了两个任务,一个完成WS2812和蜂鸣器的控制,一个完成MAX30102和OLED的控制。
其中出现了一些跨任务的信号量,尝试利用任务通知方式进行数据保护,但是效果不佳,最后还是利用了临界区保护,在信号改写的地方进行了保护(临界区时间太长,系统会崩溃)

效果视频
心跳跟随心形灯
总结
通过制作这个小项目,还是学习了HAL的IIC配置,PWM的DMA模式,WS2812的控制,OLED屏幕控制,FreeRTOS也理解更多了一点,当然还只是刚开始入门,要学的东西还是有很多,在这个小项目中,还有很多bug和不完善的地方,比如说MAX30102测量的心率不准等等,但是目前打算就先这样结束,先继续学习吧。
相关文章:
心跳跟随的心形灯(STM32(HAL)+WS2812+MAX30102)
文章目录 前言介绍系统框架原项目地址本项目开发开源地址硬件PCB软件功能 详细内容硬件外壳制作WS2812级联及控制MAX30102血氧传感器0.96OLEDFreeRTOS 效果视频总结 前言 在好几年前,我好像就看到了焊武帝 jiripraus在纪念结婚五周年时,制作的一个心跳跟…...
5. 服务发现
当主机较少时,在抓取配置中手动列出它们的IP地址和端口是常见的做法,但不适用于较大规模的集群。尤其不适用使用容器和基于云的实例的动态集群,这些实例经常会变化、创建或销毁的情况。 Prometheus通过使用服务发现解决了这个问题࿱…...
算法备案背后的原因:确保技术透明度与公正
随着现代技术的发展,算法逐渐渗透到我们日常生活的各个方面,从金融决策到个性化的商品推荐,再到医疗诊断和司法系统。然而,这种无所不在的应用也带来了一系列的社会和伦理问题,尤其是在算法的透明度和公正性上。这正是…...
Linux centos 常用命令 【持续更新】
一、查看文件信息 indoe和目录项 # df命令查看每个硬盘分区的inode总数和已经使用的数量 df -i# 查看inode的大学 xfs_growfs /dev/sda1|grep "isize"# 查看文件的indoe号码 ls -istat查看文件信息 # 文件的详细信息 stat anaconda-ks.cfg # -t参数是在一行内输出…...
《使用 VMware 在 Windows 上搭建 Linux 系统的完整指南》
《使用 VMware 在 Windows 上搭建 Linux 系统的完整指南》 1、准备工作1.1 安装 VMware 软件1.2 下载 Linux 发行版镜像文件1.3 安装SSH工具 2、创建新的虚拟机2.1 VMware页面2.2 打开VMware页面并点击创建新的虚拟机,选择自定义2.3 选择系统兼容性,默认…...
大数据Flink(六十):Flink 数据流和分层 API介绍
文章目录 Flink 数据流和分层 API介绍 一、Flink 数据流...
软件测试面试题——如何测试App性能?
为什么要做App性能测试? 如果APP总是出现卡顿或网络延迟的情况,降低了用户的好感,用户可能会抛弃该App,换同类型的其他应用。如果APP的性能较好,用户体验高,使用起来丝滑顺畅,那该应用的用户粘…...
玩转C链表
链表是C语言编程中常用的数据结构,比如我们要建一个整数链表,一般可能这么定义: struct int_node {int val;struct int_node *next;}; 为了实现链表的插入、删除、遍历等功能,另外要再实现一系列函数,比如:…...
MySQL表的基础的增删改查
增(insert into) 插入所有列的数据 不写具体列名要确保字段都对应正确 -- 假设你有一个名为 "employees" 的表,有多个列 INSERT INTO employees VALUES (101, Alice, Manager, 50000);插入指定列的数据 -- 假设你有一个名为 "students" 的表&…...
数字化车间
一、数字化车间概述 数字化车间是以现代化信息、网络、数据库、自动识别等技术为基础,通过智能化、数字化、MES系统信息化等手段融合建设的数字化生产车间,精细地管理生产资源、生产设备和生产过程。随着工业4.0概念的提出,未来的工业和制造…...
基础堆排序
目录 基础堆排序 一、概念及其介绍 二、适用说明 三、过程图示 基础堆排序...
ISC 2023 | 赛宁网安验证评估 重磅发布
8月9日-10日,第十一届互联网安全大会(简称ISC 2023)在北京国家会议中心隆重举办。作为本次大会的战略合作伙伴(最高级别),赛宁网安主办 “安全验证评估论坛”,邀请邬江兴院士与业界专家共同…...
浅谈AI浪潮下的视频大数据发展趋势与应用
视频大数据的发展趋势是多样化和个性化的。随着科技的不断进步,人们对于视频内容的需求也在不断变化。从传统的电视节目到现在的短视频、直播、VR等多种形式,视频内容已经不再是单一的娱乐方式,更是涉及到教育、医疗、商业等各个领域。 为了满…...
github 无语的问题,Host does not existfatal: Could not read from remote repository.
Unable to open connection: Host does not existfatal: Could not read from remote repository. image.png image.png image.png Please make sure you have the correct access rights and the repository exists. 如果github desktop和git pull 和git clone全部都出问题了&…...
机器学习基础之《特征工程(4)—特征降维—案例》
一、探究用户对物品类别的喜好细分 1、找到用户和物品类别的关系 数据如下: (1)order_products__prior.csv:订单与商品信息 字段:order_id,product_id,add_to_cart_order,reordered…...
docker 删除镜像文件
docker 容器里面太多镜像,D盘满了 四 查看和移除镜像 1 查看镜像 docker images 2 移除镜像命令 docker rmi 镜像名称 # 只输入前四位即可 五 实际有效操作 清除所有不使用的资源 docker system prune 这个命令将会删除所有不使用的镜像、容器和数据卷等资…...
ArcGIS Pro 基础安装与配置介绍
ArcGIS Pro ArcGIS Pro作为ESRI面向新时代的GIS产品,它在原有的ArcGIS平台上继承了传统桌面软件(ArcMap)的强大的数据管理、制图、空间分析等能力,还具有其独有的特色功能,例如二三维融合、大数据、矢量切片制作及发布…...
剑指 Offer 13. 机器人的运动范围
地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如&am…...
技术应用:Docker安全性的最佳实验|聊聊工程化Docker
🔥 技术相关:《技术应用》 ⛺️ I Love you, like a fire! 文章目录 首先,使用Docker Hub控制访问其次,保护密钥写在最后 不可否认,能生存在互联网上的软件都是相互关联的,当我们开发一款应用程序时&#x…...
【Tomcat】Tomcat部署及优化
Tomcat 它是一个免费、开源的web应用服务器;基于java代码开发的软件;处理动态请求和基于Java代码的页面开发; 可以在html当中写入Java代码,Tomcat可以解析html页面当中的Java代码,执行动态请求以及动态页面 缺点&#…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
计算机基础知识解析:从应用到架构的全面拆解
目录 前言 1、 计算机的应用领域:无处不在的数字助手 2、 计算机的进化史:从算盘到量子计算 3、计算机的分类:不止 “台式机和笔记本” 4、计算机的组件:硬件与软件的协同 4.1 硬件:五大核心部件 4.2 软件&#…...
毫米波雷达基础理论(3D+4D)
3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文: 一文入门汽车毫米波雷达基本原理 :https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...
