新手入门
- 积分
- 19
- 金钱
- 19
- 注册时间
- 2019-6-10
- 在线时间
- 2 小时
|
发表于 2019-10-21 10:22:45
|
显示全部楼层
#ifndef __WS2812B_H__
#define __WS2812B_H__
#include <stdbool.h>
#include "stm32f4xx.h"
#define WS2812B_TEST 1
#define WS2812B_GPIO_PERIF RCC_AHB1Periph_GPIOA
#define WS2812B_TIM_PERIF RCC_APB1Periph_TIM3
#define WS2812B_TIM TIM3
#define WS2812B_DMA RCC_AHB1Periph_DMA1
#define WS2812B_DMA_CHANNEL DMA1_Stream4
#define WS2812B_DMA_NVIC_IRQChannel DMA1_Stream4_IRQn
#define WS2812B_GPIO_PORT GPIOA
#define WS2812B_GPIO_PIN GPIO_Pin_6
#define WS2812B_PIN_SOURCE GPIO_PinSource6
#define WS2812B_GPIO_AF_TIMER GPIO_AF_TIM3
#define WS2812B_TMI_CLOCK 56000000
#define WS2812B_TIM_PERIOD 29
#define WS2812B_NUM 40
#define WS2812B_PULSE_BIT_SIZE 24
#define WS2812B_BUFF_SIZE (24 * (WS2812B_NUM) + 50) // Buffer size needs to be the number of LEDs times 24 bits plus 43 trailing bit
#define WS2812B_NVIC_PRI 1
#define WS2812B_DMA_PeripheralBaseAddr (uint32_t)&TIM3->CCR1;
#define WS2812B_PWM_HIGH_PULSE_WIDTH 19 // Duty cycle of pwm signal for a logical 1 to be read by the ws2812 chip
#define WS2812B_PWM_LOW_PULSE_WIDTH 9 // Duty cycle of pwm signal for a logical 0 to be read by the ws2812 chip
#define WS2812B_ALL_INDEX -1
#define WS2812B_CREATE_PULSE_BUFF() do { \
clr = color; \
for (j = 0; j < WS2812B_PULSE_BIT_SIZE; j++) { \
ws2812bBuff[k++] = (clr & 0x800000 ) ? WS2812B_PWM_HIGH_PULSE_WIDTH : WS2812B_PWM_LOW_PULSE_WIDTH; \
clr <<= 1; \
} \
} while(0)
void ws2812bInit(void);
bool ws2812bTest(void);
void ws2812bClear(const int index);
void ws2812bClearAll(void);
void ws2812bSet(const int index, const int color);
void ws2812bSetAll(const int32_t color);
void DMA1_Stream5_IRQHandler(void);
#endif
#include "ws2812b.h"
#include <rtthread.h>
#include <string.h>
static bool isInited = false;
static uint16_t ws2812bBuff[WS2812B_BUFF_SIZE]; // Array of data to be sent to leds.
static void ws2812bSend(void);
void ws2812bInit(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
DMA_InitTypeDef DMA_InitStruct;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(WS2812B_GPIO_PERIF, ENABLE);
RCC_APB1PeriphClockCmd(WS2812B_TIM_PERIF, ENABLE);
RCC_AHB1PeriphClockCmd(WS2812B_DMA, ENABLE);
GPIO_InitStruct.GPIO_Pin = WS2812B_GPIO_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_Init(WS2812B_GPIO_PORT, &GPIO_InitStruct);
GPIO_PinAFConfig(WS2812B_GPIO_PORT, WS2812B_PIN_SOURCE, WS2812B_GPIO_AF_TIMER);
TIM_DeInit(WS2812B_TIM);
TIM_TimeBaseStruct.TIM_Period = WS2812B_TIM_PERIOD;
TIM_TimeBaseStruct.TIM_Prescaler = (uint16_t)(SystemCoreClock / WS2812B_TMI_CLOCK) - 1;
TIM_TimeBaseStruct.TIM_ClockDivision = 0;
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStruct.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(WS2812B_TIM, &TIM_TimeBaseStruct);
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_Pulse = 0;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(WS2812B_TIM, &TIM_OCInitStruct);
TIM_OC1PreloadConfig(WS2812B_TIM,TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(WS2812B_TIM, ENABLE);
DMA_DeInit(WS2812B_DMA_CHANNEL);
while (DMA_GetCmdStatus(WS2812B_DMA_CHANNEL) != DISABLE){}
DMA_InitStruct.DMA_BufferSize = WS2812B_BUFF_SIZE; // Specifies the buffer size
DMA_InitStruct.DMA_Channel = DMA_Channel_5; // Deinitialize DAM1 Channel 7 to their default reset values.
DMA_InitStruct.DMA_DIR = DMA_DIR_MemoryToPeripheral; // Data transfered from memory to peripheral
DMA_InitStruct.DMA_FIFOMode= DMA_FIFOMode_Disable; //DMAμÄFIFOÄ£ê½
DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)&ws2812bBuff; // Specifies the buffer memory address
DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // Specifies the memory data width
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; // Incrament the buffer index
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal; // Specifies the operation mode. Normal or Circular
DMA_InitStruct.DMA_PeripheralBaseAddr = WS2812B_DMA_PeripheralBaseAddr; // Specifies Physical address of the peripheral in this case Timer
DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // Specifies the peripheral data width 16bit
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // Do not incrament the peripheral address
DMA_InitStruct.DMA_Priority = DMA_Priority_High; // Specifies the software priority
DMA_Init(WS2812B_DMA_CHANNEL, &DMA_InitStruct); // Initialize DAM1 Channel 2 to values specified in the DMA_InitStruct structure.
TIM_DMACmd(TIM3, TIM_DMA_CC1, ENABLE);
ws2812bClearAll();
isInited = true;
}
bool ws2812bTest(void)
{
#if(WS2812B_TEST == 1)
ws2812bSet(0, 0xff0000);
for(int i = 1000000; i > 0; i--);
ws2812bClear(0);
#endif
return isInited;
}
void ws2812bClear(const int index)
{
ws2812bSet(index, 0);
}
void ws2812bClearAll()
{
int32_t i, j, k = 0;
for (i = 0; i < WS2812B_NUM; i++)
{
for (j = 0; j < WS2812B_PULSE_BIT_SIZE; j++)
{
ws2812bBuff[k++] = WS2812B_PWM_LOW_PULSE_WIDTH;
}
}
memset(&ws2812bBuff[k], 0, WS2812B_BUFF_SIZE - k);
ws2812bSend();
}
void ws2812bSet(const int index, const int32_t color)
{
int32_t i, j;
int32_t k = 0;
int32_t clr = color;
if(index >= WS2812B_NUM || (index < 0 && index != WS2812B_ALL_INDEX))
{
return;
}
k = index * WS2812B_PULSE_BIT_SIZE;
if(index != WS2812B_ALL_INDEX)
{
WS2812B_CREATE_PULSE_BUFF();
}
else
{
for(i = 0; i < WS2812B_NUM; i++)
WS2812B_CREATE_PULSE_BUFF();
}
ws2812bSend();
}
void ws2812bSetAll(const int32_t color)
{
ws2812bSet(WS2812B_ALL_INDEX, color);
}
static void ws2812bSend(void)
{
DMA_SetCurrDataCounter(WS2812B_DMA_CHANNEL, WS2812B_BUFF_SIZE);
DMA_Cmd(WS2812B_DMA_CHANNEL, ENABLE); //ê1ÄüDMA
TIM_SetCounter(TIM3,0x0000);
TIM_Cmd(TIM3, ENABLE); //ê1Äü¶¨ê±Æ÷
while(!DMA_GetFlagStatus(WS2812B_DMA_CHANNEL,DMA_FLAG_TCIF4)); // wait until transfer complete
DMA_Cmd(WS2812B_DMA_CHANNEL, DISABLE); //ê1ÄüDMA
DMA_ClearFlag(WS2812B_DMA_CHANNEL,DMA_FLAG_TCIF4);
TIM_Cmd(TIM3, DISABLE); //ê1Äü¶¨ê±Æ÷
}
/*2aêÔ3ìDò2019.10.18Æá±Î*/
//uint8_t rgb0[1][3] = {0,0,0};
//uint8_t rgb1[1][3] = {0xAA, 0xAA, 0xAA};
//uint8_t r[1][3] = {255,0,0};
//uint8_t g[1][3] = {0,255,0};
//uint8_t b[1][3] = {0,0,255};
//uint8_t y[1][3] = {255,0,255};
//uint8_t cg[1][3] = {153,51,250};
//#define TIMING_ONE 68 // 0.8usμçƽ걼ä
//#define TIMING_ZERO 37 // 0.3usμçƽ걼ä
//void WS2812_send(uint8_t (*color)[3], uint16_t len)
//{
// uint8_t i;
// uint16_t memaddr;
// uint16_t buffersize;
// buffersize = (len*24)+ 50; // number of bytes needed is #LEDs * 24 bytes + 42 trailing bytes
// memaddr = 0; // reset buffer memory index
// while (len)
// {
// for(i=0; i<8; i++) // GREEN data
// {
// ws2812bBuff[memaddr] = ((color[0][1]<<i) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
// memaddr++;
// }
// for(i=0; i<8; i++) // RED
// {
// ws2812bBuff[memaddr] = ((color[0][0]<<i) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
// memaddr++;
// }
// for(i=0; i<8; i++) // BLUE
// {
// ws2812bBuff[memaddr] = ((color[0][2]<<i) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
// memaddr++;
// }
// len--;
// }
////===================================================================//
////bug£o×îoóò»¸öÖüÆú2¨DÎ2»ÖaμàÎaê2Ã′è«êǸßμçƽ£¬1êÔö¼óò»¸ö2¨DÎ
// ws2812bBuff[memaddr] = ((color[0][2]<<8) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
////===================================================================//
// memaddr++;
// while(memaddr < buffersize)
// {
// ws2812bBuff[memaddr] = 0;
// memaddr++;
// }
// DMA_SetCurrDataCounter(WS2812B_DMA_CHANNEL, buffersize);
// DMA_Cmd(WS2812B_DMA_CHANNEL, ENABLE); //ê1ÄüDMA
// TIM_SetCounter(TIM3,0x0000);
// TIM_Cmd(TIM3, ENABLE); //ê1Äü¶¨ê±Æ÷
//
// while(!DMA_GetFlagStatus(WS2812B_DMA_CHANNEL,DMA_FLAG_TCIF4)); // wait until transfer complete
// DMA_Cmd(WS2812B_DMA_CHANNEL, DISABLE); //ê1ÄüDMA
//
//
// DMA_ClearFlag(WS2812B_DMA_CHANNEL,DMA_FLAG_TCIF4);
// TIM_Cmd(TIM3, DISABLE); //ê1Äü¶¨ê±Æ÷
//}
/*2aêÔ3ìDò2019.10.18Æá±Î*/
ALIGN(RT_ALIGN_SIZE)
static char ws2812b_thread_stack[1024];
struct rt_thread ws2812b_thread;
static void ws2812b_thread_entry(void *param)
{
rt_time_t next_delay;
ws2812bInit();
if(!ws2812bTest()) while(1);
next_delay = 50; //100ms
rt_thread_delay(next_delay);
while(1)
{
// for(int i = 0;i < 31;i++)
// {
// ws2812bSet(i, 0xff0000);
// rt_thread_delay(next_delay);
// }
// rt_thread_delay(next_delay);
// ws2812bClearAll();
// for(int i = 0;i < 31;i++)
// {
// ws2812bSet(i, 0x00ff00);
// rt_thread_delay(next_delay);
// }
// rt_thread_delay(next_delay);
// ws2812bClearAll();
// for(int i = 0;i < 31;i++)
// {
// ws2812bSet(i, 0x0000ff);
// rt_thread_delay(next_delay);
// }
ws2812bSet(5, 0xff0000);
rt_thread_delay(next_delay);
ws2812bClearAll();
rt_thread_delay(next_delay);
}
}
void ws2812b_thread_init(uint8_t prio)
{
//pulse pump thread init
rt_thread_init(&ws2812b_thread, "ws2812b",
ws2812b_thread_entry, RT_NULL,
&ws2812b_thread_stack[0],
sizeof(ws2812b_thread_stack), prio, 5);
rt_thread_startup(&ws2812b_thread);
} |
|