STM32 ws2812b多屏驱动程序

news2024/11/27 8:34:41

文章目录

  • 前言
  • 一、ws2812b的数据传输以及屏幕的组合
  • 二、代码
    • ws2812screen.c文件
    • ws2812screen.h文件
    • 主函数


前言

在上篇文章中使用了stm32的dma+tim的方式点亮了ws2812b的灯
但是我的需求不仅仅是点亮他,我需要他像屏幕一样显示某一些东西,ws2812显示有一个开源库AWTRIX
这个库需要使用上位机不是很符合我的需求。
所以自己写了一个屏幕的驱动,后续会不断在此基础上改进。
例如我使用的是一个5*5的小ws2812b的屏幕

在这里插入图片描述

但是我需要把多个屏幕组合起来。当点亮某个屏幕的时候不能总是一个个按照他的数据方向一个个数。所以我们就需要对每个灯珠进行重映射–也就是通过【x】【y】的方式来点亮屏幕。
在这里插入图片描述

2023/7/17 可以多块屏幕组合进行显示,可以设置数据流动方向

一、ws2812b的数据传输以及屏幕的组合

ws2812b的数据传输是有方向的以我买的屏幕为例.
绿色的是板子的第一个灯,按照这个数据流向。

在这里插入图片描述
当把多个板子组合在一起的时候
数据就是这样子流向

在这里插入图片描述
再有多行板子的时候
在这里插入图片描述
当弄清楚了数据的流向以后就需要明确板子的行列关系.

在这里插入图片描述
在这里插入图片描述

二、代码

ws2812screen.c文件

本代码段分别有initializeLedMapping(int boardRows, int boardCols, int rows, int cols)
其中的几个参数需要根据上面的自己填写。
void setLedColor(int x, int y, uint32_t colorValue) 是给点设置颜色的。设置完以后还要调用上篇文章的中
void WS2812_Send (void)进行发送。
你还可以调用void drawDigit(int digit, int startX, int startY, uint32_t colorValueOn, uint32_t colorValueOff) 这个函数来显示阿拉伯数字
void drawColon(int x, int y, uint8_t on,uint32_t colorValueOn) 函数是显示冒号的,为后续做时钟做准备。

显示3x5的阿拉伯数字的二维布尔数组的定义
显示一个阿拉伯数字最少需要3*5的灯珠

效果
在这里插入图片描述

#include "ws2812screen.h"

#include "stdio.h"
#include "stdlib.h"


int** ledMapping;

int totalBoards;
int ledsPerBoard;  // LEDs per board
int rowsPerBoard;  // Rows per board
int colsPerBoard;  // Columns per board


///*
//int boardCount	几行小板子
//int boardCols		几列小板子
//int rows		小板子中灯的行数
//int cols		小板子中灯的列数
//*/
void initializeLedMapping(int boardRows, int boardCols, int rows, int cols)
{
    totalBoards = boardRows*boardCols;
    rowsPerBoard = rows;
    colsPerBoard = cols;
    ledsPerBoard = rows * cols;  // Calculate total LEDs per board
	
    // Allocate memory for the mapping table  为映射表分配内存
    ledMapping = malloc(sizeof(int*) * totalBoards * colsPerBoard);  

    for(int i = 0; i < totalBoards; ++i)
    {
        for(int j = 0; j < colsPerBoard; ++j)
        {
            ledMapping[i*colsPerBoard+j] = malloc(sizeof(int) * rowsPerBoard * boardRows);  

            for(int m = 0; m < rowsPerBoard * boardRows; ++m)
            {
                int panelIdx = i / boardCols;
                int panelLoc = i % boardCols;
                
                int localRow = m / rows;
                int localCol = m % rows;

                //检查它是偶数列还是奇数列
                if((panelLoc*colsPerBoard + j) % 2 == 0) 
                {
                    // 奇数 go from bottom to top
                    ledMapping[i*colsPerBoard+j][m] = (panelIdx * rowsPerBoard + localRow) * totalBoards * ledsPerBoard 
                                                    + panelLoc * ledsPerBoard + j * rows + localCol;
                }
                else 
                {
                    // 偶数 go from top to bottom
                    ledMapping[i*colsPerBoard+j][m] = (panelIdx * rowsPerBoard + localRow) * totalBoards * ledsPerBoard 
                                                    + panelLoc * ledsPerBoard + j * rows + rows - 1 - localCol;
                }
            }
        }
    }
}


//void initializeLedMapping(int boardCount, int rows, int cols)
//{
//    totalBoards = boardCount;
//    rowsPerBoard = rows;
//    colsPerBoard = cols;
//    ledsPerBoard = rows * cols;  // Calculate total LEDs per board
//	
//    int panelIdx = i / 5;  // 获取面板的索引
//    int localX = i % 5;  // 获取在面板内的x坐标

//    // Allocate memory for the mapping table
//    ledMapping = malloc(sizeof(int*) * totalBoards * colsPerBoard);  // 5 columns per board

//    for(int i = 0; i < totalBoards * colsPerBoard; ++i)
//    {
//        ledMapping[i] = malloc(sizeof(int) * rowsPerBoard);  // 5 leds per column

//        for(int j = 0; j < rowsPerBoard; ++j)
//        {
//            if((i % colsPerBoard) % 2 == 0)// 用于判断在当前面板内,LED的列号是奇数还是偶数
//            {
//                // 奇数列从下到上
//                ledMapping[i][j] = (i / colsPerBoard * ledsPerBoard) + (i % colsPerBoard * rowsPerBoard) + j;
//            }
//            else
//            {
//                // 偶数列从上到下
//                ledMapping[i][j] = (i / colsPerBoard * ledsPerBoard) + (i % colsPerBoard * rowsPerBoard) + (rowsPerBoard-1 - j);
//            }
//        }
//    }
//}

//int** ledMapping;
//int totalBoards;
//int ledsPerBoard = 25;  // 5*5

//void initializeLedMapping(int boardCount)
//{
    int panelIdx = i / 5;  // 获取面板的索引
    int localX = i % 5;  // 获取在面板内的x坐标
//    totalBoards = boardCount;

//    // Allocate memory for the mapping table
//    ledMapping = malloc(sizeof(int*) * totalBoards * 5);  // 5 columns per board

//    for(int i = 0; i < totalBoards * 5; ++i)
//    {
//        ledMapping[i] = malloc(sizeof(int) * 5);  // 5 leds per column

//        for(int j = 0; j < 5; ++j)
//        {
//            if((i % 5) % 2 == 0)// 用于判断在当前面板内,LED的列号是奇数还是偶数
//            {
//                // 奇数列从下到上
//                ledMapping[i][j] = (i / 5 * ledsPerBoard) + (i % 5 * 5) + j;
//            }
//            else
//            {
//                // 偶数列从上到下
//                ledMapping[i][j] = (i / 5 * ledsPerBoard) + (i % 5 * 5) + (4 - j);
//            }
//        }
//    }
//}

void setLedColor(int x, int y, uint32_t colorValue) 
{
	
	Set_LED_HEX(ledMapping[x][y], colorValue);
}


void cleanupLedMapping(void)
{
    for(int i = 0; i < totalBoards * 5; ++i)
    {
        free(ledMapping[i]);
    }

    free(ledMapping);
}
/*
你可以用 initializeLedMapping() 来初始化你的映射表,
用 setLedColor() 来设置LED颜色,最后用 cleanupLedMapping() 来释放内存。
注意,这个版本的代码使用了动态内存分配,
所以你需要确保在不再需要映射表的时候调用 cleanupLedMapping() 来避免内存泄漏。
*/


uint8_t digits[10][5][3] = {
    {{1, 1, 1}, {1, 0, 1}, {1, 0, 1}, {1, 0, 1}, {1, 1, 1}}, // 0
    {{0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}}, // 1
    {{1, 1, 1}, {0, 0, 1}, {1, 1, 1}, {1, 0, 0}, {1, 1, 1}}, // 2
    {{1, 1, 1}, {0, 0, 1}, {1, 1, 1}, {0, 0, 1}, {1, 1, 1}}, // 3
    {{1, 0, 1}, {1, 0, 1}, {1, 1, 1}, {0, 0, 1}, {0, 0, 1}}, // 4
    {{1, 1, 1}, {1, 0, 0}, {1, 1, 1}, {0, 0, 1}, {1, 1, 1}}, // 5
    {{1, 1, 1}, {1, 0, 0}, {1, 1, 1}, {1, 0, 1}, {1, 1, 1}}, // 6
    {{1, 1, 1}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1}}, // 7
    {{1, 1, 1}, {1, 0, 1}, {1, 1, 1}, {1, 0, 1}, {1, 1, 1}}, // 8
    {{1, 1, 1}, {1, 0, 1}, {1, 1, 1}, {0, 0, 1}, {1, 1, 1}}, // 9
};
// 显示3x5的阿拉伯数字的二维布尔数组的定义


void drawDigit(int digit, int startX, int startY, uint32_t colorValueOn, uint32_t colorValueOff) 
{
    for(int y = 0; y < 5; y++) 
		{
        for(int x = 0; x < 3; x++) 
				{
            if(digits[digit][y][x]) 
						{
                setLedColor(startX + x, startY + y, colorValueOn);
            } 
						else 
						{
                setLedColor(startX + x, startY + y, colorValueOff);
            }
        }
    }
}
void drawColon(int x, int y, uint8_t on,uint32_t colorValueOn) 
{
    // 冒号由两个点表示
    setLedColor(x, y, on ? colorValueOn : 0x000000);   // top dot
    setLedColor(x, y + 2, on ? colorValueOn : 0x000000);   // bottom dot
}

ws2812screen.h文件

#ifndef __WS2812_SCREEN_H

#define __WS2812_SCREEN_H
#include "main.h"

#include "ws2812b.h"

//void initializeLedMapping(int boardCount);
//void initializeLedMapping(int boardCount, int rows, int cols);
void initializeLedMapping(int boardRows, int boardCols, int rows, int cols);

void setLedColor(int x, int y, uint32_t colorValue);
void cleanupLedMapping(void);

void drawDigit(int digit, int startX, int startY, uint32_t colorValueOn, uint32_t colorValueOff);
void drawColon(int x, int y, uint8_t on,uint32_t colorValueOn) ;

#endif

主函数


	initializeLedMapping(1,4,5,5);
	
	
	drawDigit(1,0,0,0x0F000F,0x000000);
	drawDigit(3,4,0,0x0F000F,0x000000);
	drawColon(7, 1, 1,0x0F000F);
	drawDigit(1,8,0,0x0F000F,0x000000);
	drawDigit(4,12,0,0x0F000F,0x000000);		

	WS2812_Send();

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		drawColon(7, 1, 1,0x0F000F);
		WS2812_Send();
		HAL_Delay(1000);
		drawColon(7, 1, 0,0x0F000F);
		WS2812_Send();
		HAL_Delay(1000);
  }

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

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

相关文章

深入学习 Redis - 全局命令、过期策略如何实现、高效定时器原理

目录 Redis 全局命令 get 和 set keys keys 使用注意事项 exists exists 使用注意事项 del del 使用注意事项 expire 【面试经典】redis 中 key 的过期策略是怎么实现的&#xff1f; 定时器实现原理&#xff08;非 Redis 实现&#xff0c;拓展&#xff09; 1.基于 …

21 - 队列 - 循环队列——队列的顺序表示和实现

前面我们学习数组队列,链式队列,我们今天来学习循环队列。 队列的定义 队列(Queue)也是一种线性表, 但是它仅能在一端进行插入,而另一端进行删除的操作 ,插入的一端称为 队尾rear,删除的一端称为 队头front 。 向一个栈插入新元素又称作进队或入队, 从一个栈删除元素…

从实体按键看 Android 车载的自定义事件机制

在汽车数字化、智能化变革的进程中&#xff0c;越来越多的车机设计或部分、或全部地舍弃了实体按键&#xff0c;进而把车主操作的入口转移到了车机 UI 以及语音助手。 但统一、高效的零层级 UI 颇为困难&#xff0c;语音的准确率、覆盖率亦不够完善&#xff0c;那么在当下的阶段…

【数据结构】文件的归并排序

目录 1、归并排序引申出的问题 2、磁盘与文件的关系---包含与被包含的关系 3、思路&#xff1a; 4、代码实现 1、归并排序引申出的问题 归并排序是最常用的外排序的方法&#xff08;但归并排序既可进行内部排序也可进行外部排序&#xff09;&#xff0c;外排序就是在磁盘中…

LLaMA(Open and Efficient Foundation Language Models )论文解读(二)

此篇博客主题:LLAMA模型数据、训练时长、功耗及碳排放量 LLaMA: Open and Efficient Foundation Language Models paper https://arxiv.org/pdf/2302.13971v1.pdf 1 训练样本 Overall, our entire training dataset contains roughly 1.4T tokens after tokenization. For mo…

2023年Q2京东厨卫大电市场分析报告(京东运营数据分析)

随着新产品推广和消费需求升级&#xff0c;今年Q2&#xff0c;京东厨卫大电市场的销售额突破百亿&#xff0c;从同环比来看均呈增长趋势。百亿市场中&#xff0c;油烟机、电热水器、燃气热水器这三大品类占据较大份额&#xff0c;这一期&#xff0c;我们重点来看一下京东厨卫大…

怎么用Postman脚本中发送请求

Postman的Collection(集合)/Folder(集合的子文件夹)/Request(请求)都有Pre-request script和Tests两个脚本区域, 分别可以在发送请求前和请求后使用脚本(基于Javascript实现各种操作) 在遇到有依赖的接口时,比如需要登录或者需要从前一个接口的结果中获取参数时,我们往往需要在…

vscode 调试(linux )

一、配置程序运行依赖 1, 打开配置文件&#xff08;launch.json) (1) 从工具栏打开Run–>Add Configuration… &#xff08;2&#xff09;查看配置文件&#xff08;launch.json&#xff09; 2&#xff0c;添加配置 (1) 配置可执行程序&#xff08;program&#xff09;…

ceph存储的应用

ceph存储的应用 一&#xff1a;创建 CephFS 文件系统 MDS 接口1.服务端操作1&#xff09;在管理节点创建 mds 服务2&#xff09;查看各个节点的 mds 服务3&#xff09;创建存储池&#xff0c;启用 ceph 文件系统4&#xff09;查看mds状态&#xff0c;一个up&#xff0c;其余两个…

reggie优化01-缓存短信验证码和菜品数据

1、缓存短信验证码 1.1 Redis配置类RedisConfig 在config包下&#xff0c;创建Redis配置类RedisConfig&#xff1a; 纳入Git管理&#xff1a; package com.itheima.reggie.config;import org.springframework.cache.annotation.CachingConfigurerSupport; import org.sprin…

接口自动化测试框架unittest和pytest差异比较

前言 说到 Python 的单元测试框架&#xff0c;想必接触过 Python 的朋友脑袋里第一个想到的就是unittest。 的确&#xff0c;作为 Python 的标准库&#xff0c;它很优秀&#xff0c;并被广泛用于各个项目。但你知道吗&#xff1f;其实在 Python 众多项目中&#xff0c;主流的单…

【ROS机械臂入门教程】

首先声明一下&#xff0c;此项目是参考B站哈萨克斯坦UP的【ROS机械臂入门教程】&#xff0c;前期以复现【机械臂视觉抓取从理论到实战】 此内容为他研究生生涯的阶段性成果展示和技术分享&#xff0c;所有数据和代码均开源。所以鹏鹏我又特此来复现一下&#xff0c;我采用的硬件…

Redis源码篇 - Reactor设计模式 和 Redis Reactor设计模式

Reactor &#xff1a;反应器模式或者应答者模式&#xff0c;它是一种基于事件驱动的设计模式。拥有一个或者多个输入源&#xff0c;通过反应器分发给多个worker线程处理&#xff0c;实现并发场景下事件处理。 此图网上找的&#xff0c;画的很好&#xff1a;

中国新一代载人运载火箭“长征十号”发布,衍生型号积极研发中

我国新一代载人运载火箭“长征十号”已发布&#xff0c;主要用于将月面着陆器和登月飞船送入地月转移轨道。此外&#xff0c;“长征十号”还有一个衍生型号正在积极研发中。根据中国运载火箭技术研究院官方消息&#xff0c;近期&#xff0c;火箭院北京强度环境研究所圆满完成了…

SQlite3数据库相关相关命令

1&#xff09;系统命令 以 ‘.’ 开头 .help 帮助手册 .exit 退出 .table 查看当前数据库的有的表格名 .databases .schema 查看表的结构属性2&#xff09;sql语句 以 ;结尾 1. 创建表格 create table <table-name> (id integer, age integer, name char, score f…

夜深人静学32系列18——DMA+ADC单/多通道采集

夜深人静学32系列18——DMAADC单/多通道采集 DMA & ADC (理论篇)DMADMA框图DMA通道与外设对应表 ADC重要知识不同模式组合的作用 为什么要是用DMA ADC&#xff1f;DMA & ADC (实战篇)任务要求原理图CubeMX配置代码实现实验现象 很久没更新了&#xff0c;这次我们浅浅的…

MVSNet、PatchMatchNet环境配置、运行演示

文章目录 1 环境配置要求2 配置流程2.1 创建新环境mvs环境2.2 配置 PatchMatchNet环境3 程序运行演示1 环境配置要求 Ubuntu 18.04 python 3.7 , CUDA 10.1。 requirements.txt torch==1.4.0 torchvision==0.5.0 opencv-python numpy plyfile pillow tensorboard以上环境MV…

Docker 快速搞定 selenium grid 分布式测试

目录 前言&#xff1a; NO.1 搭环境 NO.2 写代码 NO.3 并发 感想 前言&#xff1a; Docker是一个流行的容器化平台&#xff0c;它可以帮助开发人员快速构建、部署和运行应用程序。Selenium Grid是一个用于分布式测试的工具&#xff0c;它可以并行执行多个测试用例&#xf…

做接口测试需要哪些技能、怎么做?

目录 1、什么是接口测试&#xff1f; 2、接口测试需要会什么&#xff1f; 3、如何学这些技能&#xff1f; 4、如何获取接口相关信息&#xff1f; 5、如何进行进行接口测试&#xff1f; 6、自动化接口测试 7、其他 1、什么是接口测试&#xff1f; 定义&#xff1a;测试系…

【ARM Coresight 系列文章 10 - ARM Coresight STM 介绍及使用】

文章目录 ARM System Trace MacrocellSTM FeaturesSTM 与 ETM/PTM的差异STM Master ARM System Trace Macrocell ARM 对STM 的解释是其支持高带宽的"仪器化输出"&#xff0c;仪器化输出其实也就是像 Cortex-M 系列中的 ITM 一样&#xff0c;通过将数据写入 STM 的 s…