位带灯介绍
传输特性
电平信号
结论:
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);
}
}