STM32F030F4P6控制WS2811灯带
1、STM32F030使用的是内部晶振,频率48MHZ。刚开始根据网上资料想用IO模拟时序发现没有预期显示效果。后期又用定时器PWM模式加DMA模式实现WS2811芯片的控制。STM32是3.3V供电,WS2811是5V脉冲。所以采用一个SN74LVC2T45DCUR(SN74LVC2T45 具有可配置电压转换的 双位双电源总线收发器)转换频率可达到420Mbps(3.3V 至 5V 转换)。STM32F030F4P6可以直接用定时器3的CH1(PA6)口,我当时没考虑这块随便弄了PA4和PA3,这就导致我在程序里配置DMA的时候又重新映射了一下,定时器没有配置成外部输出,改成内部事件了(TIM_OCMode_Timing)。原理图如下:
2、了解下WS2811的性质,基础知识资料很多可以对应搜索,他需要1.25us时钟,根据占空比来确定0 1,比如高电平占350ns时表示0,高电平占700ns时表示1。如图所示:
那就要求STM32F030先配个定时器实现PWM可调,那就程序配置预分频TIM_Prescaler为0,TIM_Period 计数59。这样就是T=(TIM_Period+1)*(TIM_Prescaler+1)/TIMxCLK,1*60/48000000=1.25us。用逻辑分析仪检测脉冲TIM_Pulse计数是17时高电平是350ns,脉冲TIM_Pulse计数是34时高电平是700ns,用逻辑分析仪监控了一段WS2811的数据RGB分别8位总共是24位。这是显示绿色的脉冲如图所示:
3、复制相关代码:
48M内部时钟开启:
void SystemClock_Config(void)
{
RCC_DeInit();
FLASH_SetLatency(FLASH_Latency_1);
RCC_HSICmd(ENABLE);
while (RCC_GetFlagStatus(RCC_FLAG_HSIRDY) != SET);
RCC_AdjustHSICalibrationValue(16);
RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_12);
RCC_PLLCmd(ENABLE);
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) != SET);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLKConfig(RCC_HCLK_Div1);
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while (RCC_GetSYSCLKSource() != 0x08)
{
}
RCC_USARTCLKConfig(RCC_USART1CLK_PCLK);
}
extern __O uint8_t WS2811_IO_High; //PA3 PA4
extern __O uint8_t WS2811_IO_Low ; //PA3 PA4
extern uint8_t WS2811_IO_FrameData[264]; //11节RGB
void OUT_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);//
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6; //PA6控制485通信 接收发送
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHz
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_DOWN;
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO
GPIO_ResetBits(GPIOA,GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6); //设置0
}
void WS2811_Init_Timer(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_Period = 59;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_ARRPreloadConfig(TIM3, DISABLE);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
TIM_OCInitStructure.TIM_Pulse = 17;
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Disable); //立即生效
TIM_OCInitStructure.TIM_Pulse = 34;
TIM_OC3Init(TIM3, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Disable); //立即生效
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void WS2811_Init_DMA(void)
{
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
// TIM3 update event, DMA1 Channel 3
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&GPIOA->ODR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&WS2811_IO_High;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //外设作为数据传输的目的地
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_BufferSize = 0; //
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; //DMA存储地址不递增
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel3, &DMA_InitStructure);
// TIM3 CC1 event, DMA1 Channel 4
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)WS2811_IO_FrameData; //WS2812B_IO_FrameData[0];
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //DMA存储地址递增
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
// TIM3 CC3 event, DMA1 Channel 2
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&WS2811_IO_Low;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; //DMA存储地址不递增
DMA_Init(DMA1_Channel2, &DMA_InitStructure);
// DMA1 Channel 2 interrupt
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);
}
void WS2811::WS2811_Send_Buffer(void)
{
WS2811_TC = 0;
DMA_ClearFlag(DMA1_FLAG_TC2 | DMA1_FLAG_HT2 | DMA1_FLAG_GL2 | DMA1_FLAG_TE2);
DMA_ClearFlag(DMA1_FLAG_TC3 | DMA1_FLAG_HT3 | DMA1_FLAG_GL3 | DMA1_FLAG_TE3);
DMA_ClearFlag(DMA1_FLAG_TC4 | DMA1_FLAG_HT4 | DMA1_FLAG_GL4 | DMA1_FLAG_TE4);
DMA_SetCurrDataCounter(DMA1_Channel2, WS2811_BUFFER_SIZE);
DMA_SetCurrDataCounter(DMA1_Channel3, WS2811_BUFFER_SIZE);
DMA_SetCurrDataCounter(DMA1_Channel4, WS2811_BUFFER_SIZE);
TIM3->SR = 0;
DMA_Cmd(DMA1_Channel2, ENABLE);
DMA_Cmd(DMA1_Channel3, ENABLE);
DMA_Cmd(DMA1_Channel4, ENABLE);
TIM_DMACmd(TIM3, TIM_DMA_CC1, ENABLE);
TIM_DMACmd(TIM3, TIM_DMA_CC3, ENABLE);
TIM_DMACmd(TIM3, TIM_DMA_Update, ENABLE);
TIM_SetCounter(TIM3, 60);
TIM_Cmd(TIM3, ENABLE);
}
uint8_t WS2811::WS2811_Get_TC(void)
{
return WS2811_TC;
}
主函数:
__O uint8_t WS2811_IO_High = 0x18; //PA3 PA4
__O uint8_t WS2811_IO_Low = 0xE7; //PA3 PA4
uint8_t WS2811_IO_FrameData[264]; //11节RGB
__IO uint8_t WS2811_TC = 1; //WS2811发送完毕
uint16_t WS2811_BUFFER_SIZE = 264; //11节RGB
//11段RGB灯带控制
__IO uint8_t WS2811_IO_FrameDataR[264]=
{
17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,
};
__IO uint8_t WS2811_IO_FrameDataG[264]=
{
34,34,34,34,34,34,34,34,17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,
34,34,34,34,34,34,34,34,17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,
34,34,34,34,34,34,34,34,17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,
34,34,34,34,34,34,34,34,17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,
34,34,34,34,34,34,34,34,17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,
34,34,34,34,34,34,34,34,17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,
34,34,34,34,34,34,34,34,17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,
34,34,34,34,34,34,34,34,17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,
34,34,34,34,34,34,34,34,17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,
34,34,34,34,34,34,34,34,17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,
34,34,34,34,34,34,34,34,17,17,17,17,17,17,17,17,34,34,34,34,34,34,34,34,
};
__IO uint8_t WS2811_IO_FrameDataB[264]=
{
34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,17,17,17,17,17,17,17,17,
34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,17,17,17,17,17,17,17,17,
34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,17,17,17,17,17,17,17,17,
34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,17,17,17,17,17,17,17,17,
34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,17,17,17,17,17,17,17,17,
34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,17,17,17,17,17,17,17,17,
34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,17,17,17,17,17,17,17,17,
34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,17,17,17,17,17,17,17,17,
34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,17,17,17,17,17,17,17,17,
34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,17,17,17,17,17,17,17,17,
34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,17,17,17,17,17,17,17,17,
};
int main(void)
{
uint8_t i;
SystemClock_Config();
OUT_GPIO_Init();
My_Uart1.Begin(1,9600);
WS2811_Init_Timer();
WS2811_Init_DMA();
TIM17_Config();
CTRL=0; //模块处于接收模式
delay_ms(200);
strcpy((char*) WS2811_IO_FrameData,(char*) WS2811_IO_FrameDataB); //开机发送蓝色
RGB_WS2811.WS2811_Send_Buffer();
delay_ms(200);
while(1)
{
MyU1CmdProcess();
}
}
对应的中断处理
void DMA1_Channel2_3_IRQHandler(void)
{
DMA_ClearITPendingBit(DMA1_IT_TC2);
GPIO_ResetBits(GPIOA,GPIO_Pin_3|GPIO_Pin_4);//设置0
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
DMA_Cmd(DMA1_Channel2, DISABLE);
DMA_Cmd(DMA1_Channel3, DISABLE);
DMA_Cmd(DMA1_Channel4, DISABLE);
TIM_DMACmd(TIM3, TIM_DMA_CC1, DISABLE);
TIM_DMACmd(TIM3, TIM_DMA_CC3, DISABLE);
TIM_DMACmd(TIM3, TIM_DMA_Update, DISABLE);
}
void TIM3_IRQHandler(void)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
TIM_Cmd(TIM3, DISABLE);
TIM_ITConfig(TIM3, TIM_IT_Update, DISABLE);
WS2811_TC = 1;
}
作者:你我同行LN