Advertisement

WS2812b彩灯(DMA+PWM)

阅读量:

一.WS2812B简介

WS2812B是一种数字可编程的LED灯条,可以使用单个数据线进行通讯控制LED灯的颜色和亮度。每个WS2812B都有一个唯一的地址,可以通过单个数据线进行级联。

二.WS2812B参数简介


三. WS2812B数据通讯简介

1.级联电路

2.数据传输

该芯片是通过数据传输的时间来判断数据是0码还是1码的。

此时就会有PWM的频率计算:

3.级联的数据传输

第一个数据缓存

·第一个24位有第一个模块接收并缓存

·第二个24位会被第一个模块转发到第二个模块上并缓存

·第三个24位会被第一个和第二个转发到第三个模块上并缓存

·第四个24位......

·第N个24位......

复位信号

第二个数据缓存

·第一个24位有第一个模块接收并缓存

·第二个24位会被第一个模块转发到第二个模块上并缓存

·第三个24位会被第一个和第二个转发到第三个模块上并缓存

·第四个24位......

·第N个24位......

复位信号

............

四.WS2812B驱动程序简介

江协科技的程序

这里我们使用PWM+DMA的方式驱动WS2812B。这里我们用的江协科技的程序。(但是本人测试的时候出现错乱的情况不知道怎么回事)

DMA驱动程序:

复制代码
 #include "stm32f10x.h"

    
  
    
  
    
 void (*DMA1_Handler)(void);  //也要开中断   数据转运+DMA  没用ADC
    
  
    
 void DMA1_Init(uint32_t MemoryBaseAddr)//MemoryBaseAddr是WS2812B_Bit数组地址
    
 {
    
  	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    
 	
    
 	DMA_DeInit(DMA1_Channel2);
    
 	
    
 	DMA_InitTypeDef DMA_InitStructure;
    
 	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&TIM2->CCR1);//起始地址
    
 	DMA_InitStructure.DMA_MemoryBaseAddr = MemoryBaseAddr;//存放地址
    
 	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//传输方向:双向   存储点到外设
    
 	DMA_InitStructure.DMA_BufferSize = 0;//缓存区大小,传输计数器大于0,触发源有触发信号,DMA使能
    
 	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设是否自增
    
 	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器是否自增
    
 	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//是否自增 以半字的形式传输16位
    
 	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    
 	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//不使用自动重装
    
 	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
    
 	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//硬件触发
    
 	DMA_Init(DMA1_Channel2, &DMA_InitStructure);
    
 	
    
 	NVIC_InitTypeDef NVIC_InitStructure;
    
 	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn;
    
 	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    
 	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    
 	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    
 	NVIC_Init(&NVIC_InitStructure);
    
 	
    
 	DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);//DMA中断
    
 	
    
 	DMA_Cmd(DMA1_Channel2, ENABLE);
    
 }
    
  
    
 void DMA1_SetIRQHandler(void (*IRQHandler)(void))
    
 {
    
 	DMA1_Handler=IRQHandler;
    
 }
    
  
    
 void DMA1_Start(uint16_t DataNumber)  //调运函数,连续转运
    
 {
    
 	DMA_Cmd(DMA1_Channel2,DISABLE);
    
 	DMA_SetCurrDataCounter(DMA1_Channel2,DataNumber);
    
 	DMA_Cmd(DMA1_Channel2,ENABLE);
    
 }
    
  
    
 void DMA1_Channel2_IRQHandler(void) //DMA开中断12
    
 {
    
 	if(DMA_GetFlagStatus(DMA1_FLAG_TC2))
    
 	{
    
 		DMA1_Handler();
    
 		DMA_ClearFlag(DMA1_FLAG_TC2);
    
 	}
    
 }
    
  
    
    
    
    

这里我们通过定时器中断驱动pwm

PWN TIM2驱动:

复制代码
 #include "stm32f10x.h" //哪个函数不认识看芯片手册

    
  
    
 void TIM2_Init(void) //TIM2开PWM的发送到DMA  PA0输出
    
 {
    
 	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //开启定时器2时钟
    
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//开启复用引脚时钟
    
  
    
 	GPIO_InitTypeDef GPIO_InitStructure;  //GPIO
    
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出   定时器控制引脚
    
 	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    
 	GPIO_Init(GPIOA,&GPIO_InitStructure);
    
  
    
 	TIM_DeInit(TIM2);    //初始化时基单元
    
 	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    
 	TIM_TimeBaseStructure.TIM_Period = 90-1; //ARR周期            32视频里定时中断讲过,搞懂   90公式试出来的,然后一算
    
 	TIM_TimeBaseStructure.TIM_Prescaler = 0; //PSC预分频器
    
 	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    
 	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    
 	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    
 	
    
 	TIM_OCInitTypeDef TIM_OCInitStructure; //初始化输出比较单元
    
 	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    
 	TIM_OCInitStructure.TIM_Pulse = 0; //CCR捕获比较器  运行中设置
    
 	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    
 	TIM_OC1Init(TIM2, &TIM_OCInitStructure);
    
 	
    
 	TIM_CtrlPWMOutputs(TIM2, ENABLE);
    
 	
    
 	TIM_DMAConfig(TIM2,TIM_DMABase_CCR1,TIM_DMABurstLength_1Transfer); //DMA请求传输
    
 	TIM_DMACmd(TIM2,TIM_DMA_Update,ENABLE); //寄存器位传输对象
    
 	
    
 	TIM_Cmd(TIM2, DISABLE);
    
 }
    
  
    
 void TIM2_Cmd(FunctionalState NewState)
    
 {
    
 	TIM_Cmd(TIM2, NewState);
    
 }
    
  
    
 void TIM2_SetCompare1(uint16_t Value) //主输出使能,TM2为高级定时器,所以这里加上
    
 {
    
 	TIM_SetCompare1(TIM2,Value);
    
 }
    
    
    
    

WS2812B驱动:

复制代码
 #include "stm32f10x.h"

    
 #include "TIM2.h"
    
 #include "DMA1.h"
    
  
    
 //#define WS2812B_LED_QUANTITY	32  //灯珠数量
    
 #define WS2812B_LED_QUANTITY 30 //灯珠数量
    
  
    
 //定义数组 类型符 数组名[常量]
    
 uint32_t WS2812B_Buf[WS2812B_LED_QUANTITY];	//0xGGRRBB    正常的数据口输入,然后配置就行,绿红蓝总共24位,只有32               
    
 uint16_t WS2812B_Bit[24*WS2812B_LED_QUANTITY+1];//灯珠数量*24bit+1 颜色位数+复位信号 根据数据手册可知还要加复位信号0(正常的0),因此需要写入 num24+reset(reset=?自己调) 位。
    
 uint8_t WS2812B_Flag;
    
  
    
 void WS2812B_IRQHandler(void);
    
  
    
 void WS2812B_Init(void)
    
 {
    
 	DMA1_SetIRQHandler(WS2812B_IRQHandler);//把WS2812B_IRQHandler赋给DMA1_Handler
    
 	DMA1_Init((uint32_t) (&WS2812B_Bit));//灯位量的地址存放到DMA  这时DMA就是灯珠的量 强制类型转换 不足的高位补0
    
 	TIM2_Init();//定时器
    
 } //用TIM2开PWM 送给DMA
    
  
    
 void WS2812B_ClearBuf(void)//把LED的RGB数组值清零,全部输出0码,变成黑色,即不发光
    
 {
    
 	uint8_t i;
    
 	for(i=0;i<WS2812B_LED_QUANTITY;i++)  
    
 	{
    
 		WS2812B_Buf[i]=0x000000;//24位的二进制数    6位的16进制数
    
 	}
    
 }
    
  
    
 void WS2812B_SetBuf(uint32_t Color)  //设置显示相同的颜色
    
 {
    
 	uint8_t i;
    
 	for(i=0;i<WS2812B_LED_QUANTITY;i++)  
    
 	{
    
 		WS2812B_Buf[i]=Color;//BUF是颜色,设置成同一个颜色,初始统一设置成不发光
    
 	}
    
 }
    
  
    
 void WS2812B_UpdateBuf(void) //30和60对应不同的高电平时间也对应了时序的0码和1码 占空比控制亮灭   CCR和AAR+1共同决定的
    
 {
    
 	uint8_t i,j;
    
 	for(j=0;j<WS2812B_LED_QUANTITY;j++)  //遍历每个LED
    
 	{
    
 		for(i=0;i<24;i++)    //遍历每个LED的颜色数据的每一位   	10000000 00000000  00000000
    
 		{
    
 			if(WS2812B_Buf[j]&(0x800000>>i)){WS2812B_Bit[j*24+i+1]=60;}//0x800000为二进制的1加23个0,>>:右移  
    
 			else{WS2812B_Bit[j*24+i+1]=30;} //每一位,取值范围是0到23,所以再加1
    
 		}
    
 	}
    
 	DMA1_Start(24*WS2812B_LED_QUANTITY+1);
    
 	TIM2_Cmd(ENABLE);
    
 	while(WS2812B_Flag==0);
    
 	WS2812B_Flag=0;
    
 }
    
  
    
 void WS2812B_IRQHandler(void)    //定时器2 开PWM  直接就是根据时序占空比设置控制灯条
    
 {
    
 	TIM2_SetCompare1(0);//pwm设置
    
 	TIM2_Cmd(DISABLE);//关闭定时器   
    
 	WS2812B_Flag=1;
    
 }
    
    
    
    

幻影的程序

定时器驱动

复制代码
 #include "timer.h"

    
 #include "led.h"
    
  
    
 //通用定时器中断初始化
    
 //这里时钟选择为APB1的2倍,而APB1为36M
    
 //arr:自动重装值。
    
 //psc:时钟预分频数
    
 //这里使用的是定时器3!
    
 void TIM3_Int_Init(u16 arr,u16 psc)
    
 {
    
     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    
 	NVIC_InitTypeDef NVIC_InitStructure;
    
  
    
 	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
    
  
    
 	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 计数到5000为500ms
    
 	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率  
    
 	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
    
 	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    
 	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
    
  
    
 	TIM_ITConfig(  //使能或者失能指定的TIM中断
    
 		TIM3, //TIM2
    
 		TIM_IT_Update ,
    
 		ENABLE  //使能
    
 		);
    
 	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
    
 	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
    
 	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
    
 	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
    
 	NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
    
  
    
 	TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设
    
 							 
    
 }
    
  
    
  
    
    
    
    

DMA驱动程序

复制代码
 #include "dma.h"

    
  
    
 u16 SendBuff[24*16+220]={
    
 	
    
 	10,10,10,10,10,10,10,10,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,		//1
    
     10,10,10,10,10,10,10,10,3,3,10,3,10,3,10,10,3,3,3,3,3,3,3,3,	//2
    
     10,10,10,10,10,10,10,10,3,10,3,10,10,10,3,3,3,3,3,3,3,3,3,3,	//3
    
     10,10,10,10,10,10,10,10,10,3,3,3,3,10,10,3,3,3,3,3,3,3,3,3,		//4
    
     10,10,10,10,10,10,10,10,10,3,10,10,3,10,10,3,3,3,3,3,3,3,3,3,	//5 
    
     10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,3,3,3,3,3,3,3,3,//6
    
     10,10,10,10,10,3,3,10,10,10,10,10,10,10,10,10,3,3,3,3,3,3,3,3,	//7
    
     10,10,3,3,10,3,3,10,10,10,10,10,10,10,10,10,3,3,3,3,3,3,3,3,	//8	
    
     10,3,3,10,10,10,10,3,10,10,10,10,10,10,10,10,3,3,3,3,3,3,3,3,	//9
    
     3,10,10,3,10,10,10,3,10,10,10,10,10,10,10,10,3,3,3,3,3,3,3,3,	//10    
    
     3,10,3,3,3,10,3,3,10,10,10,10,10,10,10,10,3,3,3,3,3,3,3,3,		//11
    
     3,3,3,10,3,3,10,10,10,10,10,10,10,10,10,10,3,3,3,3,3,3,3,3,		//12
    
     3,3,3,3,3,3,3,3,10,10,10,10,10,10,10,10,3,3,3,3,3,3,3,3,		//13
    
     10,10,10,10,10,10,10,10,3,3,3,10,3,3,10,10,3,3,3,3,3,3,3,3,		//14
    
     10,10,10,10,10,10,10,10,3,10,3,3,3,10,3,3,3,3,3,3,3,3,3,3,		//15    
    
     10,10,10,10,10,10,10,10,3,10,10,3,10,10,10,3,3,3,3,3,3,3,3,3,	//16
    
 //    3,3,3,3,3,3,3,3,10,10,10,10,10,10,10,10,3,3,3,3,3,3,3,3,
    
 //    3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,10,10,10,10,10,10,10,10,
    
 //    10,10,10,10,10,10,10,10,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
    
 //    3,3,3,3,3,3,3,3,10,10,10,10,10,10,10,10,3,3,3,3,3,3,3,3,
    
 //    3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,10,10,10,10,10,10,10,10,
    
 //    10,10,10,10,10,10,10,10,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
    
 //    3,3,3,3,3,3,3,3,10,10,10,10,10,10,10,10,3,3,3,3,3,3,3,3,
    
 //    3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,10,10,10,10,10,10,10,10,
    
 //    10,10,10,10,10,10,10,10,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
    
     
    
     
    
     
    
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
    
 };
    
 u16 DMA1_MEM_LEN = 24*16+220;// 保存DMA每次数据传送的长度 
    
  
    
 void DMA_Config(void)
    
 {
    
     DMA_InitTypeDef DMA_InitStructure;
    
     
    
     // 使能DMA时钟
    
  	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);	// 使能DMA传输
    
 	
    
     // 初始化通道参数
    
     DMA_DeInit(DMA1_Channel2); // 将DMA的通道2寄存器重设为缺省值
    
 	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&TIM1->CCR1); // DMA外设TIM1的CCR1基地址
    
 	DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;  // DMA内存基地址
    
 	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;  // 数据传输方向,从内存读取发送到外设
    
 	DMA_InitStructure.DMA_BufferSize = DMA1_MEM_LEN;  //DMA通道的DMA缓存的大小
    
 	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不变
    
 	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增
    
 	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  //数据宽度为16位
    
 	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //数据宽度为16位
    
 	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  // 循环发送
    
 	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级 
    
 	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
    
 	DMA_Init(DMA1_Channel2, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道寄存器
    
     
    
     // 使能TIME的DMA
    
     TIM_DMACmd(TIM1,TIM_DMA_CC1,ENABLE);
    
  
    
     // 开始DMA
    
     DMA_SetCurrDataCounter(DMA1_Channel2,DMA1_MEM_LEN);//DMA通道的DMA缓存的大小
    
     DMA_Cmd(DMA1_Channel2, ENABLE);  //使能USART1 TX DMA1 所指示的通道 
    
 } 
    
  
    
  
    
  
    
 //让LED全灭
    
 void WS2812B_ClearBuf(void)
    
 {
    
 	uint16_t i;
    
 	for(i=0;i<384;i++)  
    
 	{
    
 		SendBuff[i]=3;
    
 	}
    
 }
    
    
    
    
复制代码
 #ifndef __DMA_H

    
 #define __DMA_H	 
    
 #include "sys.h"
    
  
    
 void DMA_Config(void);
    
  
    
 void WS2812B_ClearBuf(void);
    
  
    
  
    
  
    
 #endif
    
    
    
    

PWM驱动程序

复制代码
 #include "pwm.h"

    
 #include "led.h"
    
 //	 
    
 //本程序只供学习使用,未经作者许可,不得用于其它任何用途
    
 //ALIENTEK Mini STM32开发板
    
 //PWM  驱动代码			   
    
 //正点原子@ALIENTEK
    
 //技术论坛:www.openedv.com
    
 //修改日期:2010/12/03
    
 //版本:V1.0
    
 //版权所有,盗版必究。
    
 //Copyright(C) 正点原子 2009-2019
    
 //All rights reserved
    
 // 	  
    
  
    
  
    
 //PWM输出初始化
    
 //arr:自动重装值
    
 //psc:时钟预分频数
    
 void delay_ms(u16 nms);
    
 void TIM1_PWM_Init(u16 arr,u16 psc)
    
 {  
    
 	GPIO_InitTypeDef GPIO_InitStructure;
    
 	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    
 	TIM_OCInitTypeDef  TIM_OCInitStructure;
    
  
    
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);// 定时器1
    
  	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);  //使能GPIO外设时钟使能         
    
  
    
     //设置该引脚为复用输出功能,输出TIM1 CH1的PWM脉冲波形
    
 	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //TIM_CH1
    
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
    
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    
 	GPIO_Init(GPIOA, &GPIO_InitStructure);  
    
  
    
 	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 80K
    
 	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  不分频
    
 	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
    
 	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    
 	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
    
  
    
  
    
 	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
    
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
    
 	TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
    
 	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
    
 	TIM_OC1Init(TIM1, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
    
  
    
     TIM_CtrlPWMOutputs(TIM1,ENABLE);	//MOE 主输出使能	
    
  
    
 	TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);  //CH1预装载使能	 
    
 	
    
 	TIM_ARRPreloadConfig(TIM1, ENABLE); //使能TIMx在ARR上的预装载寄存器
    
 	
    
 	TIM_Cmd(TIM1, ENABLE);  //使能TIM1
    
  
    
    
    
 }
    
    
    
    
复制代码
 #ifndef __PWM_H

    
 #define __PWM_H
    
 #include "sys.h"
    
  
    
 void TIM1_PWM_Init(u16 arr,u16 psc);
    
  
    
 #endif
    
    
    
    

要初始化io口不初始化会出现错误

复制代码
 #include "led.h"

    
  
    
 //初始化PB5和PE5为输出口.并使能这两个口的时钟		    
    
 //LED IO初始化
    
 void LED_Init(void)
    
 {
    
  
    
 	GPIO_InitTypeDef  GPIO_InitStructure;
    
  
    
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	 // 使能PA端口时钟
    
  
    
 	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;				 // LED0-->PA.8 端口配置
    
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 // 推挽输出
    
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 // IO口速度为50MHz
    
 	GPIO_Init(GPIOA, &GPIO_InitStructure);					 // 根据设定参数初始化GPIOA.8
    
 	GPIO_SetBits(GPIOA,GPIO_Pin_8);						 	 // PA.8 输出高
    
 }
    
  
    
    
    
    
复制代码
 #ifndef __LED_H

    
 #define __LED_H	 
    
 #include "sys.h"
    
  
    
 #define LED0 PAout(8)	// PA8
    
 #define LED1 PDout(2)	// PD2	
    
  
    
 void LED_Init(void);//初始化
    
  
    
 		 				    
    
 #endif
    
    
    
    

主程序

复制代码
 #include "led.h"

    
 #include "delay.h"
    
 #include "sys.h"
    
 #include "timer.h"
    
 #include "pwm.h"
    
 #include "dma.h"
    
  
    
 extern u16 SendBuff[20]; // 
    
 extern u16 DMA1_MEM_LEN; // 保存DMA每次数据传送的长度 
    
  
    
 void TIM3_IRQHandler(void)   //TIM3中断
    
 {
    
 	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 
    
     {
    
     TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx的中断待处理位:TIM 中断源 
    
     
    
     // 用户逻辑
    
     }
    
 }
    
  
    
  int main(void)
    
  {	
    
     // 延时函数初始化
    
 	delay_init();	   
    
  	 
    
     // IO初始化
    
     LED_Init();
    
      
    
     // DMA控制PWM输出
    
     TIM1_PWM_Init(13-1,7-1); // 72/7=10.285MHz  1.26us
    
     DMA_Config();
    
      
    
     // 定时器任务
    
     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
    
     TIM3_Int_Init(10-1,72-1); // 72分频,10us
    
      
    
     
    
    	while(1)
    
     {
    
 //        TIM1->CCR1 = 3; // 0
    
 //        TIM1->CCR1 = 10; // 1      
    
     }
    
 }
    
  
    
    
    
    

五.江协科技程序文件

程序代码 链接:https://pan.baidu.com/s/12t9pRkyJYpP5MXVNhYFELg 提取码:5gkc

原来视频 链接[WS2812B] 七彩流水灯/呼吸灯/三级调光照明 附赠程序_哔哩哔哩_bilibili

视频讲解 链接:2ws2812b外设配置_哔哩哔哩_bilibili

全部评论 (0)

还没有任何评论哟~