使用STM32F103的SPI+DMA驱动ws2812 LED

这篇具有很好参考价值的文章主要介绍了使用STM32F103的SPI+DMA驱动ws2812 LED。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

前言

一、WS2812协议

1.1 数据传输编码方式:

 1.2 传输的数据结构

二、驱动方式:SPI+DMA

2.1 原理介绍

2.2 SPI+DMA操作

 2.3 编写代码

2.4 使用

三 总结

参考文章


前言

主要使用的STM32F103C8T6芯片的SPI+DMA方式实现WS2812的驱动协议,总体可以看作是使用SPI来实现一种通信协议来发送信号。

        硬件:STM32F103C8T6

        外设:SPI、DMA


一、WS2812协议

1.1 数据传输编码方式:

T0H 0码,高电平时间 220ns~380ns
T1H 1码,高电平时间 580ns~1us
T0L 0码,低电平时间 580ns~1us
T1L 1码,低电平时间 220ns~420ns
RES 帧单位,低电平时间 280us以上

使用STM32F103的SPI+DMA驱动ws2812 LED

 当使用STM32发送波形高电平(T0H)在220ns~380ns且低电平(TOL)在580ns~1us时表示编码 0,同理 1码和复位码也是如此。总结:一个编码的时间1.25us±300ns之间都能识别到,主要是识别高电平持续的时间;时间段固定,高电平短为0高电平时间长为1,280ns时间无高电平就表示这一个信号结束。

 1.2 传输的数据结构

一颗ws2812的RGB灯里面有三颗灯珠,有红、绿、蓝三个颜色的LED灯。每一个灯使用PWM驱动,发送的数据即为PWM的宽度,一颗LED灯的数据宽度为 8 bits(1 byte)  ,所以一颗 ws2812 RGB灯共需要24 bits(3 bytes)的数据。

一颗RGB灯发送数据的时序如下,高位先行:

G7 G6 G5 G4 G3 G2 G1 G0 R7 ... R0 B7 ... B0

二、驱动方式:SPI+DMA

2.1 原理介绍

驱动ws2812的时候一般采用PWMSPI的方式,这两个速度较快,比直接使用IO口进行电平反转要方便,且控制效果更好。这里采用SPI的方式,因为在点灯是的数据发送间隔时间的约束,如果我们使用SPI发送的数据较多,中途遇到cpu中断可能会打断传输数据,所以我这里使用SPI的DMA控制方式实现。

借助 SPI 来控制 WS2812,我们用 SPI 的 MOSI 接口的一个 Byte(8位)模拟 WS2812 的一个位。比如 SPI 设置的 7M 速率,使用SPI发送一个字节(byte)来模拟WS2812的一个编码(0或1)。比如用SPI发送的 0xF8(1111 1000)表示WS2812编码的1,发送的数据是 0xC0 (1100 0000)时这代表编码 0;这是因为在SPI发送一个字节的时间符合WS2812的一个编码的时间,发送0XF8时高电平持续时间在580ns~1us内,发送0xC0时高电平持续220ns~380ns内。即

        SPI发送 0xF8 = 1 ,SPI发送 0xC0 = 0。

SPI发送24个字节可以控制一颗RGB灯,打成一个包,控制n个灯则需要:n x 包 +RET码。

SPI的速度在5.52——9.41MHz范围内,SPI发送一个字节时间长度等于一个编码的时间长度。

2.2 SPI+DMA操作

1. STM32实际操作

        配置使用芯片的外部晶振,设置为频率为72Hz,配置下载端口,初始化配置如下:

使用STM32F103的SPI+DMA驱动ws2812 LED

配置SPI,主机发送模式,速度为7MHz,Clock Phase: 2Edge。

使用STM32F103的SPI+DMA驱动ws2812 LED

 添加DMA,DMA使用默认配置:普通模式,从Memory取数据,数据宽度为:Byte和Byte。保存生成代码。

使用STM32F103的SPI+DMA驱动ws2812 LED

 

 2.3 编写代码

        创建 .h和.c文件,直接把下面代码块复制进去,或者点击创库地址:gitee仓库

        ws2812.h头文件代码

#ifndef __WS2812_H
#define __WS2812_H

#include "main.h"

typedef struct			//颜色结构体
{
  uint8_t R;
  uint8_t G;
  uint8_t B;
}RGBColor_TypeDef;

#define RGB_NUM    30	// RGB灯的数量,即为缓冲区长度

// 复位函数
void RGB_RST(void);
// 颜色设置函数
void RGB_Set_Color(uint8_t LedId, RGBColor_TypeDef Color);
// RGB 刷新函数
void RGB_Reflash(uint8_t reflash_num);

// 各种颜色测试
void RGB_RED(uint16_t RGB_LEN);			//红
void RGB_GREEN(uint16_t RGB_LEN);		//绿
void RGB_BLUE(uint16_t RGB_LEN);		//蓝
void RGB_YELLOW(uint16_t RGB_LEN);		//黄
void RGB_MAGENTA(uint16_t RGB_LEN);		//紫
void RGB_BLACK(uint16_t RGB_LEN);		//黑
void RGB_WHITE(uint16_t RGB_LEN);		//白

#endif /* __WS2812_H */

ws2812.c源代码

/*
 * ws2812.c
 *
 *  Created on: Mar 27, 2023
 *      Author: mxia2
 */

#include "ws2812.h"
#include "spi.h"
#include "dma.h"

// 常用的颜色,亮度调的比较低
const RGBColor_TypeDef RED      = {30 ,0  ,  0};
const RGBColor_TypeDef GREEN    = {0  , 50,  0};
const RGBColor_TypeDef BLUE     = {0  ,  0, 100};
const RGBColor_TypeDef YELLOW   = { 30, 30,  0};
const RGBColor_TypeDef MAGENTA  = { 30,  0, 30};
const RGBColor_TypeDef BLACK    = {  0,  0,  0};
const RGBColor_TypeDef WHITE    = { 80, 80, 80};

//模拟bit码:0xC0 为 0,0xF8 为 1
const uint8_t code[]={0xC0,0xF8};

//灯颜色缓存区,定义为30颗灯长度缓冲区
RGBColor_TypeDef RGB_DAT[RGB_NUM];

//SPI底层发送接口,一次发24个字节,相当于1个灯
extern DMA_HandleTypeDef hdma_spi1_tx;

static void SPI_Send(uint8_t *SPI_RGB_BUFFER)
{
  /* 判断上次DMA有没有传输完成 */
	while(HAL_DMA_GetState(&hdma_spi1_tx) != HAL_DMA_STATE_READY);
  /* 发送一个(24bit)的 RGB 数据到 2812 */
	HAL_SPI_Transmit_DMA(&hspi1,SPI_RGB_BUFFER,24);
}

//颜色设置函数,传入 ID 和 颜色,进而设置缓存区
void RGB_Set_Color(uint8_t LedId, RGBColor_TypeDef Color)
{
  if(LedId < RGB_NUM)
	{
		RGB_DAT[LedId].G = Color.G;
		RGB_DAT[LedId].R = Color.R;
		RGB_DAT[LedId].B = Color.B;
	}
}

//刷新函数,将颜色缓存区刷新到WS2812,输入参数是指定的刷新长度
void RGB_Reflash(uint8_t reflash_num)
{
	static uint8_t RGB_BUFFER[24]={0};
	uint8_t dat_b,dat_r,dat_g;
	//将数组颜色转化为 24 个要发送的字节数据
	if(reflash_num>0 && reflash_num<=RGB_NUM)
	{
		for(int i=0;i<reflash_num;i++)
		{
			dat_g = RGB_DAT[i].G;
			dat_r = RGB_DAT[i].R;
			dat_b = RGB_DAT[i].B;
			for(int j=0;j<8;j++)
			{
				RGB_BUFFER[7-j] =code[dat_g & 0x01];
				RGB_BUFFER[15-j]=code[dat_r & 0x01];
				RGB_BUFFER[23-j]=code[dat_b & 0x01];
				dat_g >>=1;
				dat_r >>=1;
				dat_b >>=1;
			}
			SPI_Send(RGB_BUFFER);
		}
	}
}

//复位函数
void RGB_RST(void)
{
	uint8_t dat[100] = {0};
  /* 判断上次DMA有没有传输完成 */
	while(HAL_DMA_GetState(&hdma_spi1_tx) != HAL_DMA_STATE_READY);
  /* RGB RESET */
	HAL_SPI_Transmit_DMA(&hspi1,dat,100);
	HAL_Delay(10);
}

//常用颜色的点亮测试函数

void RGB_RED(uint16_t RGB_LEN)
{
  uint8_t i;
  for(i=0;i<RGB_LEN;i++){
	  RGB_Set_Color(i,RED);
  }
  RGB_Reflash(RGB_LEN);
}

void RGB_GREEN(uint16_t RGB_LEN)
{
  uint8_t i;
  for(i=0;i<RGB_LEN;i++){
	  RGB_Set_Color(i,GREEN);
  }
  RGB_Reflash(RGB_LEN);
}

void RGB_BLUE(uint16_t RGB_LEN)
{
  uint8_t i;
  for(i=0;i<RGB_LEN;i++){
	  RGB_Set_Color(i,BLUE);
  }
  RGB_Reflash(RGB_LEN);
}

void RGB_WHITE(uint16_t RGB_LEN)
{
  uint8_t i;
  for(i=0;i<RGB_LEN;i++){
	  RGB_Set_Color(i,WHITE);
  }
  RGB_Reflash(RGB_LEN);
}

2.4 使用

在主函数中使用

#include "main.h"
#include "dma.h"
#include "spi.h"
#include "gpio.h"
#include "ws2812.h"

void SystemClock_Config(void);

int main(void)
{

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_SPI1_Init();

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	RGB_RED(5);
	RGB_RST();
	HAL_Delay(1000);

	RGB_GREEN(4);
	RGB_RST();
	HAL_Delay(1000);

	RGB_BLUE(3);
	RGB_RST();
	HAL_Delay(1000);

	RGB_WHITE(2);
	RGB_RST();
	HAL_Delay(1000);

	RGB_WHITE(5);
	RGB_RST();
	HAL_Delay(1000);

  }
  /* USER CODE END 3 */
}

使用ST-LINK下载到stm32f103芯片里,使用5颗灯查看效果,成功点亮。 

 

使用STM32F103的SPI+DMA驱动ws2812 LED


三 总结

LED的驱动方式,使用PWM驱动

使用SPI的协议来模仿其他单线的协议使用方便快捷,这也是一种不错的选择。

参考文章

STM32CubeMX-SPI+DMA 驱动 2812 灯带

WS2812b幻彩ARGB灯珠的STM32F103的CPU-SPI方式驱动

STM32 SPI+DMA实现WS2812灯的驱动

如何使用STM32F103C8T6驱动WS2812(PWM+DMA)文章来源地址https://www.toymoban.com/news/detail-483309.html

到了这里,关于使用STM32F103的SPI+DMA驱动ws2812 LED的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32F103硬件SPI驱动ADS1256

    最近实验室有几个项目都需要用到高分辨率AD转换,于是就开始了ADS1256的开发。 新手,焊得丑,见谅(能用就行) 二: 本以为很容易就能做完,结果被采样速率的问题困扰了很久。 代码如下,使用2.5V基准源进行测试,结果在读ADS时经常出现读出0xFFFFFF的情况,只能忍住悲伤

    2024年02月12日
    浏览(71)
  • 普冉PY32系列(十三) SPI驱动WS2812全彩LED

    普冉PY32系列(一) PY32F0系列32位Cortex M0+ MCU简介 普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode开发环境 普冉PY32系列(三) PY32F002A资源实测 - 这个型号不简单 普冉PY32系列(四) PY32F002A/003/030的时钟设置 普冉PY32系列(五) 使用JLink RTT代替串口输出日志 普冉PY32系列(六) 通过I2C接口驱动PCF8574扩

    2024年02月05日
    浏览(48)
  • 软件STM32cubeIDE下STM32F1xx使用定时器(TIM8)+DMA+PWM点亮灯带WS2812-基础样例

    好长时间不调试灯带ws2812了,最近项目上,要在STM32F1上进行点灯带ws2812,虽然自己之前做了很多了,但是人有个性质,一旦某个事情做完了,你不在去惦记它了,基本会完全抛在脑后。所以才体现记录的重要性,本次在做STM32F1上验证时,即使之前有经验的情况下,还是掉坑

    2024年02月01日
    浏览(58)
  • STM32驱动全彩LED灯模块WS2812

    WS2812全彩LED灯模块系列,可以进行级联实现灯带的效果,MCU端通过一个管脚可以控制所有级联的LED灯的不同发光颜色显示。 WS2811(未集成LED)的级联电路如下所示: WS2812(集成LED)的级联电路如下所示: STM32是3.3V供电芯片,输出Push-Pull模式只有3.3V,WS2812采用5V供电,输入Vi

    2024年01月17日
    浏览(38)
  • STM32+PWM+DMA驱动WS2812彩灯模块(附源码)

    WS2812是一颗数字LED灯珠,采用单总线通讯,每颗灯珠支持24bit的颜色控制,也即RGB888,信号线通过DIN输入,经过一颗灯珠之后,信号线上前24bit数据会被该灯珠锁存,之后将剩下的数据信号整形之后通过DOUT输出 C1为VDD的滤波电容,一般大小为100NF。 WS2812.c pwm.c DMA.c main.c 需要源

    2024年02月15日
    浏览(43)
  • 【STM32F4系列】【HAL库】【自制库】WS2812(软件部分)(PWM+DMA)

    硬件介绍(PCB设计方案) 模拟时序发送 WS2812是一种异步串行通信,它每一位数据时间是ns级别的 默认是高电平状态 0码:220-380ns高电平+580-1600ns低电平 1码:580-1600ns高电平+220-380ns低电平 复位码:280us低电平 24Bit数据来代表GRB的亮度值 从高位到低位发送,分别按照G-R-B的顺序发送

    2024年02月15日
    浏览(81)
  • 【STM32CubeIDE】STM32F103硬件SPI驱动1.8寸TFT LCD128X160 ST7735S屏幕

    ✨虽然STM32CubeIDE也是基于HAL库,但是还是不能直接转Keil MDK工程,本驱动案例从GitHub下载来的,原始工程使用的是较老版本的STM32CubeIDE配置的,没法在继续在新版本上程序配置,工程只是做了初始化配置。程序并不能直接被点亮,重新配置了lcd初始化函数以及复位函数后,才

    2024年02月12日
    浏览(37)
  • STM32C0开发(1)----SPI 驱动WS2812灯珠

    本文介绍了如何使用STM32微控制器,结合STM32CubeMX配置工具和SPI通讯接口,来驱动和控制WS2812 LED灯带。这是一个集硬件连接、软件配置和编程开发于一体的综合性项目,目标是实现对LED灯带颜色和亮度的精确控制。 最近在弄ST的课程,需要样片的可以加群申请:615061293 。 ht

    2024年02月04日
    浏览(42)
  • STM32F103C8T6—库函数应用I2C/SPI驱动OLED显示中文、字符串

    I2C(Inter-Integrated Circuit) SPI(Serial Peripheral Interface) 传输方式 半双工 全双工 传输速度 低速,100Kbps----4Mbps 高速,30Mbps以上 几线制 4线制:VCC,GND,SCL,SDA 6/7线制:VCC,GND,SCLK(D0),MOSI(D1/SDA),DC,CS/SS 主从模式 多主机总线,通过SDA上的地址信息锁定从机 只有一个主机,主

    2024年02月02日
    浏览(56)
  • 基于STM32F103ZET6单片机驱动SM16306SJ控制8个LED灯的系统设计

    1.设计要求:使用stm32f103zet6精英开发板  采用SM16306SJ驱动8个LED灯。 2.原理图 3.代码 4.实物效果图 备注:1 硬件上有一个LED灯坏了,所以才亮了7个LED灯            2 一个SM16306SJ最多可以驱动16个LED灯            3 SM16306SJ跟MBI5020程序通用

    2024年04月17日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包