历史上的今天
今天是:2024年12月28日(星期六)
2018年12月28日 | STM32用PWM +DMA驱动 WS2812
2018-12-28 来源:eefocus
参考的代码:
------------------------------------WS2812B.c------------------------------------
#include "WS2812B.h"
/* Buffer that holds one complete DMA transmission
*
* Ensure that this buffer is big enough to hold
* all data bytes that need to be sent
*
* The buffer size can be calculated as follows:
* number of LEDs * 24 bytes + 42 bytes
*
* This leaves us with a maximum string length of
* (2^16 bytes per DMA stream - 42 bytes)/24 bytes per LED = 2728 LEDs
*/
#define TIM3_CCR3_Address 0x4000043c // physical memory address of Timer 3 CCR1 register
//#define TIM3_CCR1_Address 0x40000434// physical memory address of Timer 3 CCR1 register
//#define TIM2_CCR4_Address 0x40000040
#define TIMING_ONE 61
#define TIMING_ZERO 29
uint16_t LED_BYTE_Buffer[300];
uint16_t testcount = 0;
uint16_t testcount1 = 0;
//---------------------------------------------------------------//
void Timer2_init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
/* GPIOA Configuration: TIM2 Channel 1 as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* Compute the prescaler value */
//PrescalerValue = (uint16_t) (SystemCoreClock / 24000000) - 1;
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 90-1; // 800kHz
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);
// TIM_ARRPreloadConfig(TIM3, ENABLE);
//GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);
/* configure DMA */
/* DMA clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/* DMA1 Channel6 Config */
DMA_DeInit(DMA1_Channel2);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&TIM2->CCR1);// physical address of Timer 3 CCR1
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)LED_BYTE_Buffer;// this is the buffer memory
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;// data shifted from memory to peripheral
DMA_InitStructure.DMA_BufferSize = 42;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;// automatically increase buffer index
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// stop DMA feed after buffer size is reached
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel2, &DMA_InitStructure);
/* TIM3 CC1 DMA Request enable */
TIM_DMACmd(TIM2, TIM_DMA_Update, ENABLE);
}
/* This function sends data bytes out to a string of WS2812s
* The first argument is a pointer to the first RGB triplet to be sent
* The seconds argument is the number of LEDs in the chain
*
* This will result in the RGB triplet passed by argument 1 being sent to
* the LED that is the furthest away from the controller (the point where
* data is injected into the chain)
*/
void WS2812_send(uint8_t (*color)[3], uint16_t len)
{
uint8_t i;
uint16_t memaddr;
uint16_t buffersize;
buffersize = (len*24)+10;// 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
{
LED_BYTE_Buffer[memaddr] = ((color[0][1]<
memaddr++;
}
for(i=0; i<8; i++) // RED
{
LED_BYTE_Buffer[memaddr] = ((color[0][0]<
memaddr++;
}
for(i=0; i<8; i++) // BLUE
{
LED_BYTE_Buffer[memaddr] = ((color[0][2]<
memaddr++;
}
len--;
}
//===================================================================//
//bug:最后一个周期波形不知道为什么全是高电平,故增加一个波形
//LED_BYTE_Buffer[memaddr] = ((color[0][2]<<8) & 0x0080) ? TIMING_ONE:TIMING_ZERO;
//===================================================================//
memaddr++;
while(memaddr < buffersize)
{
LED_BYTE_Buffer[memaddr] = 0;
memaddr++;
}
DMA_SetCurrDataCounter(DMA1_Channel2, memaddr); // load number of bytes to be transferred
DMA_Cmd(DMA1_Channel2, ENABLE); // enable DMA channel 6
TIM_Cmd(TIM2, ENABLE); // enable Timer 3
while(!DMA_GetFlagStatus(DMA1_FLAG_TC2))
{
// testcount1 = DMA_GetCurrDataCounter(DMA1_Channel2);
// if(DMA_GetFlagStatus(DMA1_FLAG_TE2))
// {
// testcount++;
// }
}; // wait until transfer complete
// testcount++;
TIM_Cmd(TIM2, DISABLE); // disable Timer 3
DMA_Cmd(DMA1_Channel2, DISABLE); // disable DMA channel 6
DMA_ClearFlag(DMA1_FLAG_TC2); // clear DMA1 Channel 6 transfer complete flag
}
----------------------------------------Main.c---------------------------------------------
uint8_t r[][3] = {255,0,0};
uint8_t g[][3] = {0,255,0};
uint8_t b[][3] = {0,0,255};
uint8_t cheng[][3] = {255,128,0};
uint8_t huang[][3] = {255,255,0};
uint8_t qing[][3] = {0,255,255};
uint8_t zi[][3] = {128,0,255};
uint32_t testt = (uint32_t)(&TIM3->CCR3);
int main(void)
{
//RCC_Configuration();
delay_init(); //延时函数初始化
//LED_Init(); //初始化与LED连接的硬件接口
Timer2_init();
while(1)
{
WS2812_send(r,8);
delay_ms(1000);
WS2812_send(g,8);
delay_ms(1000);
WS2812_send(b,8);
delay_ms(1000);
WS2812_send(cheng,8);
delay_ms(1000);
WS2812_send(huang,8);
delay_ms(1000);
WS2812_send(qing,8);
delay_ms(1000);
WS2812_send(zi,8);
delay_ms(1000);
}
}
需要注意以下几点:
1)采用的是TIM2->CH1,用的是TIM_DMA_Update触发,如果改用其他的通道需要更改触发方式
2)代码中---bug:最后一个周期波形不知道为什么全是高电平,故增加一个波形
可以注销此句代码,主要是 buffersize = (len*24)+10;不知道为什么需要加上10,加上1就不行,不知道什么原因,那位知道可以探讨下。
下一篇:STM32 获取寄存器的地址
史海拾趣
|
不知道发在什么版合适,看来看去还是发在这个版块了~ 现在我在学习电路板、电路图的知识。以前在学校虽然学习过模电数电但是毕竟没有怎么接触过真东西,只是理论知识。 现在手头有一块电路板,我需要画出它的电路图来。面临的问题是,我不懂电路 ...… 查看全部问答> |
|
dear all: 小弟最近做一个HW的3G卡,WinCE下的USB虚拟串口驱动,在USB中,有8组接口,用了其它的一组有2个端点,8号端点OUT写数据,88号端点IN读取数据,为什么能写成功,IN不到数据呢,望大家指教, 代码如下: dw = IssueBulkTransfer( pDrv-> ...… 查看全部问答> |
|
我通过#pragma 引入了几个lib文件,还需要在项目属性中手动输入那些文件吗? 我生成exe文件后运行的时候显示0x8007007e错误 我又把那些lib文件手工复制到模拟器中,放在exe文件的目录下还是不能执行 请问这是怎么回事? … 查看全部问答> |
|
刚完成了一个CycloneIII fpga开发板,将CycloneIII设计中的问题分享一下,持续更新 我所使用的芯片是Cyclone III EP3C5E144,与ep3c10e144是引脚兼容,没有去兼容ep3c16和25,因为用户IO相差太大, 本来qfp144的封装io就不太多,ep3c16和25就没有考虑。 ep3c5有5136个逻辑资源,跑普通的Verilog代码和niosII 完全 ...… 查看全部问答> |
|
推出市场就绪型NFC“智能”汽车钥匙 中国上海,2011年6月15日 --\" 智能\"汽车钥匙市场的先驱--恩智浦半导体NXP Semiconductors N.V. (NASDAQ:NXPI) 今日宣布推出针对多功能汽车钥匙的生产就绪单芯片解决方案--NCF2970 (KEyLink L ...… 查看全部问答> |
|
g729编解码 感谢cl 教一个从没有学过信号处理相关的计算机白痴 目前在做16位芯片上的g729解码算法。我一个连语音编解码算法最基础的课程都没有学过的计算机白痴,在项目组长CL的帮助下,对g729,有了一个大概的了解。 g729将80bits参数重构成一帧语音,最重要的一个公式是: 80位的比特流分 ...… 查看全部问答> |
|
STM32发送显示数据给串口工业屏的问题,麻烦各位大大来给指导下,万分感谢。。 其实就是用STM32和串口工业屏通信,我写好了数据接收函数,现在是要写发送函数。 但是他给的协议表是这样的: void Uart1_PutStr1(u8 *p,u8 len) { extern UART_TypeDef Uart1_Structure; if(Uart1_Structure.TxStatus) //如果串口正在发 ...… 查看全部问答> |




