PWM+DMA控制WS2812位带灯

位带灯介绍

传输特性

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

电平信号

在这里插入图片描述

结论:
0信号:高电平占比3/10
1信号:高电平占比7/10
复位信号:高电平占比0

数据传输特性

在这里插入图片描述

总结:
数据传输随着传送的次数,数据逐次存入灯的锁存寄存器,逐次减少24位。
灯的颜色,//白色为0xffffff 熄灭为0x000000 红色为0x00ff00 绿色为0xff0000 蓝色为0x0000ff

代码讲解

运用模块

使用定时器输出PWM+DMA存储

注意事项

1、在配置 TIM_OCInitTypeDef TIM_OCInitStructure;结构体时,需要将其设置为全局变量,因为在配置结构体时,们没有对全部的结构体成员进行初始化,可能会带有原有配置,导致结果出不来。
2、主函数的延时初始化,放在灯带初始化下面

重点知识

1、PWM和DMA配置流程
2、对占空比的理解
3、DMA使用原理
4、发送函数中对代码语句的理解
LED_Buffer[addr] = ((color[0]<<i) & 0x80) ? ONE:ZERO;

代码

.c文件

#include<stdio.h>
#include "stm32f10x.h"
#include "delay.h"
#include "tim2.h"
#include "pin.h"
#include "uart.h"
#include "string.h"
#include "ws2812.h"


//PC8--TIM8_CH3--DMA2_CH1
//白色为0xffffff 熄灭为0x000000 红色为0x00ff00 绿色为0xff0000 蓝色为0x0000ff
/*-----------------------------------------  time8 输出pwm --------------------------------------------------------*/
u16 LED_Buffer[2400];  //存放CCR值得数组


u8  color_green[3] = {0xff,0x00,0x00};//定义颜色GRB
u8  color_red[3] = {0x00,0xff,0x00};//定义颜色GRB
u8  color_blue[3] = {0x00,0x00,0xff};//定义颜色GRB
u8  color_rest[3] = {0x00,0x00,0x00};//定义颜色GRB
u8  color_write[3] = {0x00,0x00,0x00};//定义颜色GRB

#define    ONE     63    
#define    ZERO    27   
	    TIM_OCInitTypeDef                TIM_OCInitStructure;
void ws2812_init(void)
{
	    TIM_TimeBaseInitTypeDef          TIM_TimeBaseStructure;

	    GPIO_InitTypeDef                 GPIO_InitStructure;
	    DMA_InitTypeDef                  DMA_InitStructure;
		
		//clock
	    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
	    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
			RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
		
		//GPIO
	    GPIO_InitStructure.GPIO_Pin    = GPIO_Pin_8;
	    GPIO_InitStructure.GPIO_Mode   = GPIO_Mode_AF_PP;
	    GPIO_InitStructure.GPIO_Speed  = GPIO_Speed_50MHz;
	    GPIO_Init(GPIOC, &GPIO_InitStructure);	
	    
	    //TIME
	    TIM_TimeBaseStructure.TIM_Period = 90-1; // 800kHZ   时钟是72MHZ  72000/90=n
	    TIM_TimeBaseStructure.TIM_Prescaler = 0;
//	    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
	    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	    TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);
	    
		//PWM
	    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
			TIM_OCInitStructure.TIM_OutputNState=TIM_OutputNState_Disable;//高级定时器这句一定要配
	    TIM_OCInitStructure.TIM_Pulse = 0; //CCRX寄存器值
	    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	    TIM_OC3Init(TIM8, &TIM_OCInitStructure);
			
			TIM_CtrlPWMOutputs(TIM8,ENABLE);
			TIM_OC3PreloadConfig(TIM8,TIM_OCPreload_Enable);//使能预加载值,这句一定要配,不然时序会乱
	
	    //DMA
	    DMA_DeInit(DMA2_Channel1);
	    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&(TIM8->CCR3);//设置CCR值,外设基地址
	    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)LED_Buffer;	//存放CCR值的数组
	    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;				//从数组读					
	    DMA_InitStructure.DMA_BufferSize = 240;
	    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;					
	    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//这里传输的是多少位,根据你定义的存放CCR值得数据类型,我是u16
	    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//这里传输的是多少位,根据你定义的存放CCR值得数据类型,我是u16
	    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;							
	    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
	    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	    DMA_Init(DMA2_Channel1, &DMA_InitStructure);
	   
	    TIM_DMACmd(TIM8, TIM_DMA_Update, ENABLE);
			TIM_Cmd(TIM8, DISABLE);
}


/*---------- 组包 将颜色位 转变成CCR值  发送颜色顺序GRB高位先发   我这里所有的灯都一样的颜色要不一样的自己改下面的-----------*/
void WS2812_led_send(uint8_t *color, uint16_t len)
{
    uint8_t i;
    uint16_t addr;
    uint16_t buffersize;
		memset(LED_Buffer,0,2400);
    buffersize = (len*24)+400;	//颜色位数+复位信号
    addr = 0;				
    while(len)
    {
        for(i=0; i<8; i++) // GREEN 
        {
					//(color[0]<<i) & 0x80)表示让数据左移,与最高位1想与,判断当前位是0还是1
            LED_Buffer[addr] = ((color[0]<<i) & 0x80) ? ONE:ZERO;
            addr++;
        }

        for(i=0; i<8; i++) // RED
        {
            LED_Buffer[addr] = ((color[1]<<i) & 0x80) ? ONE:ZERO;
            addr++;
        }

        for(i=0; i<8; i++) // BLUE
        {
            LED_Buffer[addr] = ((color[2]<<i) & 0x80) ? ONE:ZERO;
            addr++;
        }

        len--;
    }

    DMA_SetCurrDataCounter(DMA2_Channel1, buffersize); 	//设置DMA传输的数量
    DMA_Cmd(DMA2_Channel1, ENABLE); 			
    TIM_Cmd(TIM8, ENABLE); 					
    while(!DMA_GetFlagStatus(DMA2_FLAG_TC1)) ; 	
    TIM_Cmd(TIM8, DISABLE); 	
    DMA_Cmd(DMA2_Channel1, DISABLE); 			
    DMA_ClearFlag(DMA2_FLAG_TC1); 			
}

.h文件

#ifndef WS2812_H
#define WS2812_H

#include <stdio.h>
#include "stdint.h"
#include "stm32f10x.h"


//extern u16 LED_Buffer[2400];  //存放CCR值得数组
extern u8  color_green[3];//定义颜色GRB
extern u8  color_red[3];//定义颜色GRB
extern u8  color_blue[3];//定义颜色GRB
extern u8  color_rest[3];//定义颜色GRB
extern u8  color_write[3];


void ws2812_init(void);
void WS2812_led_send(uint8_t *color, uint16_t len);

#endif

main文件

int main(void)
{
	ws2812_init();
	delay_init();		//延时函数初始化
	
	while(1)
	{	
//		WS2812_led_send(color_red,8);

		WS2812_led_send(color_red,4);
		delay_ms(1000);
		WS2812_led_send(color_rest,4);
		
		WS2812_led_send(color_blue,4);
		delay_ms(1000);
		WS2812_led_send(color_rest,4);

		WS2812_led_send(color_green,4);
		delay_ms(1000);
		WS2812_led_send(color_rest,4);
		
	}
}

未使用DMA方法

在这里插入图片描述

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

好好睡觉好好吃饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值