STM32CubeMX WS2812B灯驱动

2024-06-21 21:52
文章标签 驱动 stm32cubemx ws2812b

本文主要是介绍STM32CubeMX WS2812B灯驱动,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、WS2812B

数据发送速度可达800Kbps。

数据协议采用单线归零码的通讯方式,像素点在上电复位以后,DIN端接受从控制器传输过来的数据,首先送过来的24bit数据被第一个像素点提取后,送到像素点内部的数据锁存器,剩余的数据经过内部整形处理电路整形放大后通过DO端口开始转发输出给下一个级联的像素点,每经过一个像素点的传输,信号减少24bit。像素点采用自动整形转发技术,使得该像素点的级联个数不受信号传送的限制,仅受限信号传输速度要求。

280μs以上的RESET时间,出现中断也不会引起误复位,可以支持更低频率、价格便宜的MCU。LED具有低电压驱动、环保节能、亮度高、散射角度大、一致性好超、低功率及超长寿命等优点。将控制电路集成于LED上面,电路变得更加简单,体积小,安装更加简便

 二、CubeMX配置

我这里使用的是stm32f030f4p6,留了一个485接口

1.打开调试 选择滴答时钟

2.RCC配置

 3.时钟树配置

4.配置PWW输出

设置周期为60个时钟周期(48MHz / 60 = 800kHz, 1.25us周期)

dma配置

5.串口配置

 生成工程

三、KEIL代码

目标PWM信号

WS2812 LED的时序要求非常严格。一般来说,WS2812的高电平和低电平的持续时间如下:

  • 高电平时间约为0.7µs(亮位)
  • 低电平时间约为0.35µs(暗位)

总信号周期约为1.25µs。

设置

  • 系统时钟频率:48 MHz
  • 目标PWM周期:1.25µs

计算

  1. 计算计数器周期值(ARR)

    我们需要让一个PWM周期为1.25µs,即:

    给定系统时钟频率为48 MHz,时钟周期为:

    因此,计数器周期值为:

  2. 设置高电平和低电平持续时间

    • 高电平时间约为0.7µs
    • 低电平时间约为0.35µs

    对应的计数器值:

WS2812B.c

#include "WS2812B.h"
#include "tim.h"#define MAX_LED 6    // 灯的数量
#define USE_BRIGHTNESS 1    // 启用亮度控制uint8_t LED_Data[MAX_LED][4];
uint8_t LED_Mod[MAX_LED][4];  // 用于亮度控制void Set_LED(int LEDnum, int Red, int Green, int Blue) {LED_Data[LEDnum][0] = LEDnum;LED_Data[LEDnum][1] = Green;LED_Data[LEDnum][2] = Red;LED_Data[LEDnum][3] = Blue;
}void Set_LED_HEX(int LEDnum, uint32_t colorValue) {LED_Data[LEDnum][0] = LEDnum;LED_Data[LEDnum][2] = (colorValue >> 16) & 0xFF;  // RLED_Data[LEDnum][1] = (colorValue >> 8) & 0xFF;   // GLED_Data[LEDnum][3] = colorValue & 0xFF;          // B
}void Set_Brightness(int brightness) {if (brightness > 90) brightness = 90;  // 最大亮度值为100if (brightness < 10) brightness = 10;      // 最小亮度值为0for (int i = 0; i < MAX_LED; i++) {LED_Mod[i][0] = LED_Data[i][0];for (int j = 1; j < 4; j++) {LED_Mod[i][j] = (LED_Data[i][j] * brightness) / 100;}}
}uint16_t pwmData[(24 * MAX_LED) + 50];void WS2812_Send(void) {uint32_t indx = 0;uint32_t color;for (int i = 0; i < MAX_LED; i++) {
#if USE_BRIGHTNESScolor = ((LED_Mod[i][1] << 16) | (LED_Mod[i][2] << 8) | (LED_Mod[i][3]));
#elsecolor = ((LED_Data[i][1] << 16) | (LED_Data[i][2] << 8) | (LED_Data[i][3]));
#endiffor (int j = 23; j >= 0; j--) {if (color & (1 << j)) {pwmData[indx] = 34;  // 高电平持续时间} else {pwmData[indx] = 17;  // 低电平持续时间}indx++;}}for (int i = 0; i < 50; i++) {pwmData[indx] = 0;indx++;}HAL_TIM_PWM_Start_DMA(&htim3, TIM_CHANNEL_1, (uint32_t *)pwmData, indx);
}

WS2812B.h

#ifndef __WS2812B_H#define __WS2812B_H
#include "main.h"void Set_LED (int LEDnum, int Red, int Green, int Blue);//RGBvoid Set_LED_HEX(int LEDnum, uint32_t colorValue);//十六进制void Set_Brightness (int brightness);  // 0-100
void WS2812_Send (void);#endif

 主函数

导入头文件和定义接收数组

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "WS2812B.h"
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
//接收数据解析 FD 亮度 小灯1 2 3 4 5 6 FF
uint8_t rx1data[15]={0};
uint8_t data[15];
uint8_t rx1flag=0;
/* USER CODE END PTD */

 空闲中断接收数据

/* USER CODE BEGIN 0 */
//空闲中断回调函数,参数Size为串口实际接收到数据字节数
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{if(huart->Instance==USART1){for(int i=0;i<15;i++){data[i]=rx1data[i];}rx1flag=1;//再次开启空闲中断接收,不然只会接收一次数据HAL_UARTEx_ReceiveToIdle_IT(&huart1,rx1data,Size);}
}
/* USER CODE END 0 */

 main函数 接收一帧数据并且控制小灯RGB

int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_DMA_Init();MX_USART1_UART_Init();MX_TIM3_Init();HAL_UARTEx_ReceiveToIdle_IT(&huart1,rx1data,sizeof(rx1data));while (1){if(rx1flag==1){if(data[0]==0xFD){Set_LED(0,data[2],data[3]>>4,data[3]&0x0f);Set_LED(1,data[4],data[5]>>4,data[5]&0x0f);Set_LED(2,data[6],data[7]>>4,data[7]&0x0f);Set_LED(3,data[8],data[9]>>4,data[9]&0x0f);Set_LED(4,data[10],data[11]>>4,data[11]&0x0f);Set_LED(5,data[12],data[13]>>4,data[13]&0x0f);Set_Brightness(data[1]);WS2812_Send();rx1flag=0;}}}}

 帧解析

FD F0 0F 00 0F F0 00 F0 00 0F 00 FF 0F 0F FF

帧头帧尾    FD- FF

第一个字节数据 是调节RGB亮度       F0

第二第三个字节 控制第一个RGB 显示红色   0F 00

第四第五个字节 控制第二个RGB 显示黄色   0F F0

第六第七个字节 控制第三个RGB 显示绿色   00 F0

第八第九个字节 控制第四个RGB 显示蓝色   00 0F

第十第十一个字节 控制第五个RGB 显示靛蓝 00 FF

第十二第十三个字节 控制第6个RGB显示紫色  0F 0F

效果

 

 

 https://oshwhub.com/chem4111/ledboad 

链接:https://pan.baidu.com/s/1WSJNQzQiiU7Vc3ed04pNPw?pwd=1cjy 
提取码:1cjy

这篇关于STM32CubeMX WS2812B灯驱动的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1082433

相关文章

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

驱动(RK3588S)第七课时:单节点设备树

目录 需求一、设备树的概念1、设备树的后缀名:2、设备树的语法格式3、设备树的属性(重要)4、设备树格式举例 二、设备树所用函数1、如何在内核层种获取设备树节点:2、从设备树上获取 gpio 口的属性3、获取节点上的属性只针对于字符串属性的4、函数读取 np 结点中的 propname 属性的值,并将读取到的 u32 类型的值保存在 out_value 指向的内存中,函数的返回值表示读取到的

STM32CubeMX和HAL库-新建项目

目录 新建项目 选择开发板  MCU图形化配置界面总览 MCU配置 新建项目 新建项目包含选择MCU创建项目、选择开发板新建项目和交叉选择MCU新建项目三部分。 1. 选择MCU创建项目 单击主菜单项File→New Project,或Home视图上的ACCESS TO MCU SELECTOR 按钮,都可以打开的New Project from a MCU/MPU对话框。

驱动安装注册表指令

HKCR: HKEY_CLASSES_ROOT HKCU: HKEY_CURRENT_USER HKLM: HKEY_LOCAL_MACHINE HKU: HEKY_USER HER: 相对根键

UMDF驱动安装

VS2013 + WDF8.1,UMDF驱动选择User Mode Driver,不要选User Mode Driver 2.0,否则Win7安装有问题,如图 另外,在驱动安装时不要忘记WUDFUpdate_<主版本号><次版本号>.dll文件,具体文件名在INF中查找。此文件可在WDF的安装目录中找到。注意:在WDF的安装目录中会有3个WUDFUpdate_xxx.dll文件,x86,x6

电脑驱动分类

电脑驱动程序(驱动程序)是操作系统与硬件设备之间的桥梁,用于使操作系统能够识别并与硬件设备进行通信。以下是常见的驱动分类: 1. 设备驱动程序 显示驱动程序:控制显卡和显示器的显示功能,负责图形渲染和屏幕显示。 示例:NVIDIA、AMD 显示驱动程序。打印机驱动程序:允许操作系统与打印机通信,控制打印任务。 示例:HP、Canon 打印机驱动程序。声卡驱动程序:管理音频输入和输出,与声卡硬件

麒麟系统安装GPU驱动

1.nvidia 1.1显卡驱动 本机显卡型号:nvidia rtx 3090 1.1.1下载驱动 打开 https://www.nvidia.cn/geforce/drivers/ 也可以直接使用下面这个地址下载 https://www.nvidia.com/download/driverResults.aspx/205464/en-us/ 1.1.3安装驱动 右击,

windows10 卸载网络驱动以及重新安装

右键桌面此电脑的图标,点击管理,设备管理器—网络适配器,找到下图中的驱动(不同的系统或者显卡会导致网卡驱动名称与下图不一样,多为Realtek开头),右键选择卸载设备,然后重启电脑,系统会自动重新安装驱动 新电脑首次安装驱动: 根据主板厂家,比如华硕,进入华硕官网,点击服务支持,点击下载中心,选择型号,点击右侧驱动程序和工具软件,选择windows版本,下载相应的驱动,下载完之后在对应文件中找

笔记整理—内核!启动!—kernel部分(1)驱动与内核的关系

首先,恭喜完成了uboot部分的内容整理,其次补充一点,uboot第一部分和第二部分的工作不是一定的,在不同的版本中,可能这个初始化早一点,那个的又放在了第二部分,版本不同,造成的工作顺序不同,但终归是要完成基本内容初始化并传参给kernel的。         那么至于驱动与内核的关系,用一张图来说明最适合不过:         驱动位于OS层的中下层与硬件相接。驱动是内

读源码笔记--文件过滤驱动FileSpy第1篇 -- DriverEntry

今天只读FileSpy的DriverEntry,位于源文件:filespy.c。 // // 全局变量. // ULONG gFileSpyDebugLevel = DEFAULT_FILESPY_DEBUG_LEVEL; #if WINVER >= 0x0501 ULONG gFileSpyAttachMode = FILESPY_ATTACH_ALL_VOLUMES; #else ULON