心跳跟随的心形灯(STM32(HAL)+WS2812+MAX30102)

news2024/12/27 4:05:32

文章目录

  • 前言
  • 介绍
    • 系统框架
    • 原项目地址
    • 本项目开发开源地址
    • 硬件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测量的心率不准等等,但是目前打算就先这样结束,先继续学习吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/840008.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

10 日志系统(下)

10 日志系统&#xff08;下&#xff09; 本文内容 日志系统分为两部分&#xff0c;其一是单例模式与阻塞队列的定义&#xff0c;其二是日志类的定义与使用。 本篇将介绍日志类的定义与使用&#xff0c;具体的涉及到基础API&#xff0c;流程图与日志类定义&#xff0c;功能实现…

Android 刷新与显示

目录 屏幕显示原理&#xff1a; 显示刷新的过程 VSYNC机制具体实现 小结&#xff1a; 屏幕显示原理&#xff1a; 过程描述&#xff1a; 应用向系统服务申请buffer 系统服务返回一个buffer给应用 应用开始绘制&#xff0c;绘制完成就提交buffer&#xff0c;系统服务把buffer数据…

第三章 CUDA编译器环境配置篇

cuda教程目录 第一章 指针篇 第二章 CUDA原理篇 第三章 CUDA编译器环境配置篇 第四章 kernel函数基础篇 第五章 kernel索引(index)篇 第六章 kenel矩阵计算实战篇 第七章 kenel实战强化篇 第八章 CUDA内存应用与性能优化篇 第九章 CUDA原子(atomic)实战篇 第十章 CUDA流(strea…

Fatal error, can‘t open config file ‘/myredis/redis.conf‘: No such file or directory

在学习Redis到主从复制部分&#xff0c;进行相关练习&#xff0c;基本过程如下 1.首先将redis.conf文件cp到自建myredis文件夹中&#xff0c;并配置不同端口号的redis.conf redisXXXX.confd的配置内容如下 &#xff1a; include /myredis/redis.conf pidfile /var/run/redis_…

压力测试与测试工具jmeter的介绍

目录 一、性能指标 二、jmeter &#xff08;一&#xff09;JMeter 安装 &#xff08;二&#xff09;JMeter 压测示例 1、添加线程组 2、添加 HTTP 请求 3、添加监听器 4、启动压测&查看分析结果 &#xff08;三&#xff09;JMeter Address Already in use 错误解决 压力测…

Flutter运行app时向logcat输出当前打开的界面路径且点击可跳转

当一个项目大了目录文件多了&#xff0c;我们往往会为了找到一个文件花费大量的时间和精力&#xff0c;为了快捷方便的调试我们的项目&#xff0c;我们往往需要在打开app运行的时候需要知道当前打开的界面的文件在哪儿&#xff0c;我们这个代码就能快捷的知道我们app正在打开的…

《HeadFirst设计模式(第二版)》第五章代码——单例模式

代码文件目录&#xff1a; 初始版本&#xff1a; package Chapter5_SingletonPattern.origin;/*** Author 竹心* Date 2023/8/5**/public class Singleton {private static Singleton uniqueInstance;private Singleton(){}public static Singleton getInstance(){if(uniqueIn…

2023牛客暑期多校训练营6-A Tree

2023牛客暑期多校训练营6-A Tree https://ac.nowcoder.com/acm/contest/57360/A 文章目录 2023牛客暑期多校训练营6-A Tree题意解题思路代码 题意 解题思路 最大价值和这个数据范围&#xff0c;一眼 d p dp dp。 直接在树上并不好处理&#xff0c;问题是如何有效转化、处理…

黑马程序员SpringMVC练手项目

目录 1、需求 2、项目准备 pom.xml SQL jdbc.properties log4j.properties applicationContext.xml spring-mvc.xml web.xml 3、工作流程 4、难点 项目已经上传到gitee&#xff1a;https://gitee.com/xzl-it/my-projects 1、需求 SpringMVC项目练习&#xff1a;数…

每日一题——反转单链表

反转单链表 题目链接 下面主要介绍两种方法&#xff1a; 方法一&#xff1a; 利用三个指针变量进行反转 具体过程如图所示&#xff1a; 注意&#xff1a;循环的结束的条件为cur NULL而不是next NULL 实现代码&#xff1a; struct ListNode* reverseList(struct ListNode* …

STL容器适配器 -- stack和queue(使用+实现)(C++)

stack和queue stackstack的介绍stack的使用stack的实现 queuequeue的介绍queue的使用queue的实现 deque简单介绍deque&#xff08;双端队列&#xff09;双开口连续打引号的原因 deque底层结构deque的迭代器封装结构&#xff08;复杂&#xff09;deque的优缺点 栈和队列数据结构…

LLM reasoners 入门实验 24点游戏

LLM reasoners Ber666/llm-reasoners 实验过程 实验样例24games&#xff0c;examples/tot_game24&#xff0c;在inference.py中配置使用代理和open ai的api key。 首先安装依赖 git clone https://github.com/Ber666/llm-reasoners cd llm-reasoners pip install -e .然后…

JVM入门到精通

一、JVM概念 1.1、什么是JVM Java Virtual Machine&#xff1a;Java虚拟机&#xff0c;用来保证Java语言跨平台 Java虚拟机可以看做是一台抽象的计算机&#xff0c;如同真实的计算机那样&#xff0c;它有自己的指令集以及各种运行时内存区域 Java虚拟机与Java语言并没有必然…

Maven-搭建私有仓库

使用NEXUS REPOSITORY MANAGER 3在Windows上搭建私有仓库。 NEXUS REPOSITORY MANAGER 3 是一个仓库管理系统。 下载NEXUS3 官网上是无法下载的,所以网上搜nexus-3.18.1-01-win64就能搜到,下载即可。 安装NEXUS3 下载nexus-3.18.0-01-win64.zip至相应目录下(路径不要有中文)。 …

[Realtek sdk-3.4.14b]RTL8197FH-VG+RTL8812F WiFi开启访客网络之后无法扫描到SSID问题分析及解决方案

问题描述 realtek sdk-3.4.14b 开启访客网络之后,发现无法扫描到SSID,可以看到接口已经up,但是设备无法搜到WiFi热点 问题分析 查看网口状态 ifconfig查看wlan0-va0接口TX/RX的数据包都是0,表示没有发送或者接收到数据包,正常wifi启动之后,都会有Beacon包发出,也会接…

【Redis】——RDB快照

Redis 是内存数据库&#xff0c;但是它为数据的持久化提供了两个技术&#xff0c;一个是AOF日志&#xff0c;另一个是RDB快照&#xff1a; AOF 文件的内容是操作命令&#xff1b;RDB 文件的内容是二进制数据。 RDB 快照就是记录某一个瞬间的内存数据&#xff0c;记录的是实际…

Vue中,$forceUpdate()的使用

在Vue官方文档中指出&#xff0c;$forceUpdate具有强制刷新的作用。 那在vue框架中&#xff0c;如果data中有一个变量:age&#xff0c;修改他&#xff0c;页面会自动更新。 但如果data中的变量为数组或对象&#xff0c;我们直接去给某个对象或数组添加属性&#xff0c;页面是识…

JMeter 4.x 简单使用

文章目录 前言JMeter 4.x 简单使用1. 启动2. 设置成中文3. 接口测试3.1. 设置线程组3.2. HTTP信息请求头管理器3.3. 添加HTTP请求默认值3.4. 添加HTTP cookie 管理3.5. 添加http请求3.5.1. 添加断言 3.6. 添加监听器-查看结果树3.7. 添加监听器-聚合报告 4. 测试 前言 如果您觉…

TBB库中实现协程(coroutine)的源码说明

源码请见: https://github.com/oneapi-src/oneTBB/blob/master/src/tbb/co_context.h 在windows系统&#xff0c;TBB(也就是intel 的 oneTBB库)&#xff0c;通过windwos fiber(纤程)来实现协程(coroutine)。 创建一个协程,代码很简洁: inline void create_coroutine(corouti…