1.原理学习
1.1ws2821的手册内容
注:VDD接5V
DIN接单片机PWM输出引脚(本文中接PA8引脚,即TIM1_PWM输出通道1)
若不使用PWM驱动,则将DIN与PA9引脚连接,PA9设置如下
DOUT接下一个LED的DIN引脚
1.2.1通过NOP延时函数
选择72MHZ,然后一个NOP=(1/72MhZ)=0.0138us
T0L: 0.0138*50=0.69us 50代表nop的个数
T0H: 0.0138*20=0.276us 20代表nop的个数
T1L: 0.0138*20=0.276us 20代表nop的个数
T1H: 0.0138*50=0.69us 50代表nop的个数
1.2.2通过pwm+dma的方式
通过控制PWM占空比发送0码和1码,额定周期为1.25us,则频率为800Khz
0码PWM占空比:
(0码高电平时间)/(周期)---> 0.4 / 1.25 = 0.32
用占空比乘以定时器重装值加一就是0码的CCR值(代表PWM高电平计数个数)--->
0.32 * (89+1) = 28.8(取28)
1码PWM占空比:
同理计算:(1码高电平时间)/ (周期)---> 0.8 / 1.25 = 0.64
(占空比)*(重置值+1)= CCR ---> 0.64 * (89+1) = 57.6(取58)
2.Cube配置
配置时钟
定时器配置
配置DMA
3.驱动代码编写
ws2821.h
#ifndef __RGB_H__
#define __RGB_H__
#include "main.h"
/*这里是上文计算所得CCR的宏定义*/
#define CODE_1 (58) //1码定时器计数次数
#define CODE_0 (28) //0码定时器计数次数
#define Pixel_NUM 24 //LED数量宏定义
void Reset_Load(void); //该函数用于将数组最后24个数据变为0,代表RESET_code
void RGB_SendArray(void); //发送最终数组
void RGB_RED_while(uint16_t Pixel_Len);
void RGB_Change(uint16_t Pixel_Len);
void RGB_Set(uint8_t LedId,uint32_t color_temp);
void RGB_test(uint16_t Pixel_Len);
void RGB_Bit1(void);
void RGB_Bit0(void);
void RGB_RESET(void);
#endif
ws2821.c
#include "RGB.h"
#include "tim.h"
#include "stdio.h"
uint32_t Pixel_Buf[Pixel_NUM+1][24];
/*
功能:设定单个RGB LED的颜色,把结构体中RGB的24BIT转换为0码和1码
参数:LedId为LED序号,Color:定义的颜色结构体
*/
void RGB_Bit0(void)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_9,GPIO_PIN_SET);
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_9,GPIO_PIN_RESET);
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
}
void RGB_Bit1(void)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_9,GPIO_PIN_SET);
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_9,GPIO_PIN_RESET);
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
}
void RGB_RESET(void)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_9,GPIO_PIN_RESET);
for(int i=0;i<10;i++)
{
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
}
}
void Reset_Load(void)
{
uint8_t i;
for(i=0;i<24;i++)
{
Pixel_Buf[Pixel_NUM][i]=0;
}
}
/*
功能:发送数组
参数:(&htim1)定时器1,(TIM_CHANNEL_1)通道1,((uint32_t *)Pixel_Buf)待发送数组,
(Pixel_NUM+1)*24)发送个数,数组行列相乘
*/
void RGB_SendArray(void)
{
HAL_TIM_PWM_Start_DMA(&htim1, TIM_CHANNEL_1, (uint32_t *)Pixel_Buf,(Pixel_NUM+1)*24);
}
void RGB_RED_while(uint16_t Pixel_Len)
{
uint16_t i;
for(i=0;i<Pixel_Len;i++)//给对应个数LED写入白色
{
RGB_SetColor(i,GREEN);
//Reset_Load();
RGB_SendArray();
}
}
void RGB_Change(uint16_t Pixel_Len)
{
int i;
for(i=Pixel_Len;i>=0;i--)//给对应个数LED写入白色
{
//RGB_SetColor(i,RED);
RGB_Set(i,0xff0000);
Reset_Load();
RGB_SendArray();
HAL_Delay(100);
}
}
void RGB_Set(uint8_t LedId,uint32_t color_temp)
{
uint16_t i;
if(LedId > Pixel_NUM)return; //avoid overflow 防止写入ID大于LED总数
for(i=0;i<8;i++)
{
//Pixel_Buf[LedId][i] = (((color_temp>>8)&(1<<i))?(CODE_1):(CODE_0));
Pixel_Buf[LedId][i] = (((color_temp>>8)&(1<<i)));
if((Pixel_Buf[LedId][i]&(1<<i))==0)
{
RGB_Bit0();
}
else
{
RGB_Bit1();
}
}
for(i=8;i<16;i++)
{
//Pixel_Buf[LedId][i] = (((color_temp>>16)&(1<<(i-8)))?(CODE_1):(CODE_0));
Pixel_Buf[LedId][i] = (((color_temp>>16)&(1<<(i-8))));
if((Pixel_Buf[LedId][i]&(1<<(i-8)))==0)
{
RGB_Bit0();
}
else
{
RGB_Bit1();
}
}
for(i=16;i<24;i++)
{
//Pixel_Buf[LedId][i] = (((color_temp)&(1<<(i-16)))?(CODE_1):(CODE_0));
Pixel_Buf[LedId][i] = (((color_temp)&(1<<(i-16))));
if((Pixel_Buf[LedId][i]&(1<<(i-16)))==0)
{
RGB_Bit0();
}
else
{
RGB_Bit1();
}
}
}
void RGB_test(uint16_t Pixel_Len)
{
uint16_t i;
for(i=0;i<24;i++)
{
RGB_Set(i,0x00ff00);
//Reset_Load();
//RGB_SendArray();
}
}
3.1通过NOP延时函数
void RGB_Bit0(void)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_9,GPIO_PIN_SET);
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_9,GPIO_PIN_RESET);
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
}
void RGB_Bit1(void)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_9,GPIO_PIN_SET);
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_9,GPIO_PIN_RESET);
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
}
设置颜色
void RGB_Set(uint8_t LedId,uint32_t color_temp)
{
uint16_t i;
if(LedId > Pixel_NUM)return; //avoid overflow 防止写入ID大于LED总数
for(i=0;i<8;i++)
{
Pixel_Buf[LedId][i] = (((color_temp>>8)&(1<<i)));
if((Pixel_Buf[LedId][i]&(1<<i))==0)
{
RGB_Bit0();
}
else
{
RGB_Bit1();
}
}
for(i=8;i<16;i++)
{
Pixel_Buf[LedId][i] = (((color_temp>>16)&(1<<(i-8))));
if((Pixel_Buf[LedId][i]&(1<<(i-8)))==0)
{
RGB_Bit0();
}
else
{
RGB_Bit1();
}
}
for(i=16;i<24;i++)
{
Pixel_Buf[LedId][i] = (((color_temp)&(1<<(i-16))));
if((Pixel_Buf[LedId][i]&(1<<(i-16)))==0)
{
RGB_Bit0();
}
else
{
RGB_Bit1();
}
}
}
测试函数
void RGB_test(uint16_t Pixel_Len)
{
uint16_t i;
for(i=0;i<24;i++)
{
RGB_Set(i,0x00ff00);
//Reset_Load();
//RGB_SendArray();
}
}
直接在main 调用
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_TIM1_Init();
MX_RTC_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
RGB_test(24);
}
/* USER CODE END 3 */
}
3.2通过pwm+dma的方式
通过先前提到的,取0码高电平数28,取1码高电平数58,这种方法与上面的区别在于驱动和设置颜色
/*这里是上文计算所得CCR的宏定义*/
#define CODE_1 (58) //1码定时器计数次数
#define CODE_0 (28) //0码定时器计数次数
设置颜色
void RGB_Set(uint8_t LedId,uint32_t color_temp)
{
uint16_t i;
if(LedId > Pixel_NUM)return; //avoid overflow 防止写入ID大于LED总数
for(i=0;i<8;i++)
{
Pixel_Buf[LedId][i] = (((color_temp>>8)&(1<<i))?(CODE_1):(CODE_0));
}
for(i=8;i<16;i++)
{
Pixel_Buf[LedId][i] = (((color_temp>>16)&(1<<(i-8)))?(CODE_1):(CODE_0));
}
for(i=16;i<24;i++)
{
Pixel_Buf[LedId][i] = (((color_temp)&(1<<(i-16)))?(CODE_1):(CODE_0));
}
}
发送数组
void RGB_SendArray(void)
{
HAL_TIM_PWM_Start_DMA(&htim1, TIM_CHANNEL_1, (uint32_t *)Pixel_Buf,(Pixel_NUM+1)*24);
}
测试函数
void RGB_test(uint16_t Pixel_Len)
{
uint16_t i;
for(i=0;i<24;i++)
{
RGB_Set(i,0xff0000);
Reset_Load();
RGB_SendArray();
}
}
在main中直接调用
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_TIM1_Init();
MX_RTC_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
RGB_test(24);
}
/* USER CODE END 3 */
}