【STM32CubeMX】WS2812彩灯

前言

  有时间我就按照网上的时序推理了WS2812的传输时序。之前就推过时序了,但是当时时序好像没对,因为没用逻辑分析仪查看,就以为通过电片机的运行主频,在控制NOP,就能得到us级的延时控制,但是真实的情况是,调用调用函数,运行循环之类的对于us级来说也需要大量时间了,所以所推时序时,一定要用逻辑分析仪或示波器查看,时序电平的实际反转时间。

  本文要点:1.WS2812的时序基础。2.基于STM32HAL库函数,的引脚电平反转,与WS2812数据传输的代码实现。优点:代码可能简单易懂。缺点:单纯的引脚反转,时序达不到WS2812所指定的要求,但是在控制一盏灯时,只要放在主循环中确能跑出,指定颜色的代码。所以说发出来给大家参考参考。有时间在用DMA写一个看看。
  这里介绍了为啥实现起来有些偏差【杂谈理解】STM32F103引脚反转速度时间

环境

  • STM32F103C6T6系统板,72MHz主频
  • 基于STM32CubeMX生成的HAL库代码
  • keil5中,进行代码的编写修改

WS2812

  • 时序基础

    在这里插入图片描述

  • 数据结构

    在这里插入图片描述

代码实现

以下给出三个关键块的代码 WS2812S.H WS2812S.C main.c

下面中main.c中省略了,WS2812S数据引脚的初始化定义,还有WS2812S.H引脚的宏定义。大家可以自行调整配置。

  • WS2812S.H

    #include "main.h"
    #include <WS2812S.H>
    
    //超低时间总得要些东西来堵塞
    void WS2812S_Delay_300ns()
    {
    	__NOP;__NOP;__NOP;__NOP;__NOP;
    }
    
    void WS2812S_Delay_800ns()
    {
    	for(char i=1;i>0;i--)
    	{
    		__NOP;__NOP;__NOP;__NOP;__NOP;
    	}	
    }
    
    //0.1纳秒延时(没用了可忽视)
    void WS2812S_Delay_us(int Num)
    {
    	for(;Num>0;Num--)
    	{
    		for(char js=7;js>0;js--)
    		{
    			__NOP();
    		}
    	}
    }
    //WS2812S高电平
    void WS2812S_H()
    {
    	HAL_GPIO_WritePin(WS2812S_GPIO_Port, WS2812S_Pin, GPIO_PIN_SET);
    	WS2812S_Delay_800ns();
    	HAL_GPIO_WritePin(WS2812S_GPIO_Port, WS2812S_Pin, GPIO_PIN_RESET);
    	WS2812S_Delay_300ns();
    }
    //WS2812S低电平
    void WS2812S_L()
    {
    	HAL_GPIO_WritePin(WS2812S_GPIO_Port, WS2812S_Pin, GPIO_PIN_SET);
    	WS2812S_Delay_300ns();	
    	HAL_GPIO_WritePin(WS2812S_GPIO_Port, WS2812S_Pin, GPIO_PIN_RESET);
    	WS2812S_Delay_800ns();
    }
    //WS2812S时序复位
    void WS2812S_R()
    {
    	//HAL_GPIO_WritePin(WS2812S_GPIO_Port, WS2812S_Pin, GPIO_PIN_SET);
    	HAL_GPIO_WritePin(WS2812S_GPIO_Port, WS2812S_Pin, GPIO_PIN_RESET);
    	WS2812S_Delay_us(50);
    }
    
    //WS2812S写入字节
    void WS2812S_WR(uint8_t dat)
    {
    	uint8_t i;
    	for(i=0;i<8;i++)
    	{
    		if(dat & (1 << (7-i)))
    		{
    			WS2812S_H();
    		}
    		else
    		{
    			WS2812S_L();
    		}
    	}
    }
    //WS2812S点亮LED
    void WS2812S_WRLED(uint8_t green,uint8_t red,uint8_t blue)
    {
    	HAL_GPIO_WritePin(WS2812S_GPIO_Port, WS2812S_Pin, GPIO_PIN_RESET);
    	WS2812S_WR(green);
    	WS2812S_WR(red);
    	WS2812S_WR(blue);
    	HAL_GPIO_WritePin(WS2812S_GPIO_Port, WS2812S_Pin, GPIO_PIN_SET);
    	WS2812S_R();
    }
    //十次的传输
    void WS2812S_WRLED10(uint8_t green,uint8_t red,uint8_t blue)
    {
    	char i;
    	for(i=0;i<10;i++)
    	{
    		WS2812S_WRLED(green,red,blue);
    	}
    }
    
  • WS2812S.C

    #ifndef __WS2812S_H__
    #define __WS2812S_H__
    
    void WS2812S_H(void);
    void WS2812S_L(void);
    void WS2812S_R(void);
    void WS2812S_WR(uint8_t dat);
    void WS2812S_Delay_us(int Num);
    void WS2812S_WRLED(uint8_t green,uint8_t red,uint8_t blue);
    void WS2812S_WRLED10(uint8_t green,uint8_t red,uint8_t blue);
    #endif
    
  • main.c

    //主函数中导人库后,调用配置即可
    WS2812S_WRLED10(0,0,255);	//WS2812S灯珠
    

时序问题

  1. main.c调用WS2812S.H函数中WS2812S的’0’码和’1’码的函数,就已经完全超过时序要求的了。组成高电平的部分没超,低电平的超了。因为调用的过程中不可避免的有循环,函数之类的调用,增加了时间。

    在这里插入图片描述

    //WS2812S高电平
    void WS2812S_H()
    {
    	HAL_GPIO_WritePin(WS2812S_GPIO_Port, WS2812S_Pin, GPIO_PIN_SET);
    	//WS2812S_Delay_800ns();
    	HAL_GPIO_WritePin(WS2812S_GPIO_Port, WS2812S_Pin, GPIO_PIN_RESET);
    	//WS2812S_Delay_300ns();
    }
    //WS2812S低电平
    void WS2812S_L()
    {
    	HAL_GPIO_WritePin(WS2812S_GPIO_Port, WS2812S_Pin, GPIO_PIN_SET);
    	//WS2812S_Delay_300ns();	
    	HAL_GPIO_WritePin(WS2812S_GPIO_Port, WS2812S_Pin, GPIO_PIN_RESET);
    	//WS2812S_Delay_800ns();
    }
    
  2. 但是我在主函数中,单纯的调用引脚电平反转,就貌似能组成可以用的时序电平时间。从一定程度上就能验证我上面的说法,调用的过程中不可避免的有循环,函数之类的调用,增加了时间。当然一般的模块都是要封装成模块,还有用循环来发送数据位的,所以说在主函数中直接调用肯定是行不通的。

    在这里插入图片描述

    HAL_GPIO_WritePin(WS2812S_GPIO_Port, WS2812S_Pin, GPIO_PIN_SET);
    HAL_GPIO_WritePin(WS2812S_GPIO_Port, WS2812S_Pin, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(WS2812S_GPIO_Port, WS2812S_Pin, GPIO_PIN_SET);
    HAL_GPIO_WritePin(WS2812S_GPIO_Port, WS2812S_Pin, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(WS2812S_GPIO_Port, WS2812S_Pin, GPIO_PIN_SET);
    HAL_GPIO_WritePin(WS2812S_GPIO_Port, WS2812S_Pin, GPIO_PIN_RESET);
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值