【stm32简单外设篇】- WS2812单线地址式 RGB 灯带
一、适用场景适用场景炫彩灯效跑马、流水、渐变、呼吸、状态指示、可穿戴灯光、舞台/装饰灯带、视觉化数值显示温度/音频以及练习精确时序、DMA定时器应用与实时动画算法。二、器材清单WS2812NeopixelLED 灯带stm32f103或其它 STM32开发板 ×1若干杜邦线母对母/公对母×1组稳定电源3.3V 或 5V按模块标注×1三、工作原理要点WS2812 使用单线串行协议时序严格常见 800kHz每个 LED 接收 24 位数据按 GRB 顺序每个位占用 约 1.25µsTbit。逻辑 0T_H ≈ 0.35µsT_L ≈ 0.9µs逻辑 1T_H ≈ 0.7µsT_L ≈ 0.6µs复位latch脉冲拉低 ≥ 50µsLED 把接收的 24×N 位数据写入并显示。因时序严格常用两种驱动方式软件 bit-bang阻塞屏蔽中断、严格微秒延时逐位输出 —— 实现简单但会阻塞 CPU适合少量 LED / 教学。硬件 PWM DMA用定时器 PWM 输出固定周期例如 1.25µs 分 30 个计数把“0/1”映射为不同的 CCR 值通过 DMA 把整个比特流送入 CCR 寄存器精度高且 CPU 空闲适合中大量灯带我使用的也是这种方法。母头是输入信号公头是输出注意这里的公母头看的是接口的公母不是外壳上的公母四、接线示意白色线→GND红色线→5V/3.3V电源另外还有两根补压线一根5V一根GND当LED灯带超过300个LED灯或灯带长5米时最后进行一个补压操作实际补压时最好大于5V暂时不使用标准库绿色线→PB6HAL库绿色线→PA8五、示例代码标准库#include stm32f10x.h #include stdio.h #include bsp_SysTick.h #include bsp_usart.h #include oled.h #define led_num 10 uint32_t ws2812b_buf[led_num]; uint16_t ws2812b_bit[24*led_num1]; uint16_t showflag0,showtime0; int z; char show[20]; int flag; void WS2812B_IRQHandler(void)//自定义的中断是当DMA搬运完一次数据后才会触发的 { TIM_SetCompare1(TIM4,0);//设置pwm的比较值为0 TIM_Cmd(TIM4,DISABLE);//关闭定时器 flag1; // for(z0;z100000;z); } void WS2812B_ClearBuf(void) { uint8_t i; for(i0;iled_num;i) { ws2812b_buf[i]0x000000;//给每个led写入24位的0即清除颜色 } } void WS2812B_Init(void) { Dma1_SetIRQHandler(WS2812B_IRQHandler);//指定DMA中断后执行的中断函数并不是用系统的函数 Dma1_Configuare((uint32_t)(ws2812b_bit));//指定DMA帮运的数组 Remote_Init();//进行TIM的初始化 } void WS2812B_SetBuf(uint32_t color) { uint8_t i; for(i0;iled_num;i) { ws2812b_buf[i]color;//循环给每个led赋值24位的颜色数据 } } void WS2812B_UpdateBuf(void)//将所有灯的颜色数据进行全部更新 { uint8_t i,j; for(j0;jled_num;j)//遍历每个灯 { for(i0;i24;i)//遍历每个灯的颜色位 { if(ws2812b_buf[j](0x800000i))//判断每个灯的24位颜色数据如果为0则定义其对应的PWM数据为30反之为60 ws2812b_bit[j*24i]60; else ws2812b_bit[j*24i]30; } Dma1_Configuare((uint32_t)(ws2812b_bit));//将更新好的数组重新赋值到DMA初始化中 Dma1_start(24*led_num);//启动DMA并将一次要搬运的数据个数指明 Time4_run(ENABLE);//开启定时器 while(flag0);//等待数据搬运完成 flag0; } } void init_ALL(void) { WS2812B_Init(); WS2812B_ClearBuf(); tim2_Init(); } void showbreath() { static uint8_t i,color; showtime6;//设置运行时间 if(i0)WS2812B_SetBuf((color)); if(i1)WS2812B_SetBuf((255-color)); if(i2)WS2812B_SetBuf((color)8); if(i3)WS2812B_SetBuf((255-color)8); if(i4)WS2812B_SetBuf((color)16); if(i5)WS2812B_SetBuf((255-color)16); if(i6)WS2812B_SetBuf((color)|(color)8); if(i7)WS2812B_SetBuf((255-color)|(255-color)8); if(i8)WS2812B_SetBuf((color)|(color)16); if(i9)WS2812B_SetBuf((255-color)|(255-color)16); if(i10)WS2812B_SetBuf(((color)8)|((color)16)); if(i11)WS2812B_SetBuf(((255-color)8)|((255-color)16)); if(i12)WS2812B_SetBuf(((color))|((color)8)|((color)16)); if(i13)WS2812B_SetBuf(((255-color))|((255-color)8)|((255-color)16)); color; if(color0) { i; i%14; } } void startshow() { uint8_t i,num; uint32_t R,G,B; static uint8_t j; showtime20; for(iled_num;i0;i--) { ws2812b_buf[i]ws2812b_buf[i-1]; } if(j0) { numrand()%7; if(num0)ws2812b_buf[0]0x0000ff; if(num1)ws2812b_buf[0]0x00ff00; if(num2)ws2812b_buf[0]0xff0000; if(num3)ws2812b_buf[0]0x00ffff; if(num4)ws2812b_buf[0]0xff00ff; if(num5)ws2812b_buf[0]0xffff00; if(num6)ws2812b_buf[0]0xffffff; }else if(j15) { Rws2812b_buf[1]/0X100%0x100; Gws2812b_buf[1]/0X10000%0x100; Bws2812b_buf[1]%0x100; if(G20) G-20; if(R20) R-20; if(B20) B-20; ws2812b_buf[0](G16)|(R8)|B; }else{ ws2812b_buf[0]0; } j; j%50; } int main(void) { init_ALL(); USART_Config(); while(1) { if(showflag 1)//定时一段时间后会自动开启颜色设置 { showflag0; startshow();//将颜色数据写入数组中 // showbreath();//将颜色数据写入数组中 WS2812B_UpdateBuf();//将数组数据更新到DMA中有DMA自行去将数据写入到LED灯带中 } } } #include bsp_SysTick.h extern uint16_t showflag,showtime; void Remote_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE); //使能PORTB时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); //TIM4 时钟使能 GPIO_InitStructure.GPIO_Pin GPIO_Pin_6; //PB9 输入 GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; //上拉输入 GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOB, GPIO_InitStructure); // GPIO_SetBits(GPIOB,GPIO_Pin_9); //初始化GPIOB.9 TIM_TimeBaseStructure.TIM_Period 90-1; //设定计数器自动重装值 最大10ms溢出 TIM_TimeBaseStructure.TIM_Prescaler 1-1; //配置输入分频,不分频,即72MHz约等于1/72MHz0.00000001s10ns TIM_TimeBaseStructure.TIM_ClockDivision TIM_CKD_DIV1; //设置时钟分割:TDTS Tck_tim TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseInit(TIM4, TIM_TimeBaseStructure); //根据指定的参数初始化TIMx TIM_OCInitStruct.TIM_OCMode TIM_OCMode_PWM1; // 选择输入端 IC4映射到TI4上 TIM_OCInitStruct.TIM_OCPolarity TIM_OCPolarity_High; //上升沿捕获 TIM_OCInitStruct.TIM_OutputState TIM_OutputState_Enable; TIM_OCInitStruct.TIM_Pulse 0; //配置输入分频,不分频 TIM_OC1Init(TIM4, TIM_OCInitStruct);//初始化定时器输入捕获通道 TIM_DMAConfig(TIM4,TIM_DMABase_CCR1,TIM_DMABurstLength_1Transfer); TIM_DMACmd(TIM4,TIM_DMA_Update,ENABLE); TIM_Cmd(TIM4,DISABLE); } void tim2_Init(void) { NVIC_InitTypeDef NVIC_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //TIM2 时钟使能 TIM_TimeBaseStructure.TIM_Period 1000; //设定计数器自动重装值 最大1ms溢出 TIM_TimeBaseStructure.TIM_Prescaler (72-1); //预分频器,1M的计数频率,1us加1. TIM_TimeBaseStructure.TIM_ClockDivision TIM_CKD_DIV1; //设置时钟分割:TDTS Tck_tim TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseStructure.TIM_RepetitionCounter 0 ; TIM_TimeBaseInit(TIM2, TIM_TimeBaseStructure); //根据指定的参数初始化TIMx TIM_ClearFlag(TIM2,TIM_FLAG_Update);//手动把更新中断标志位清除一下解决刚初始化完就进入中断计数从1开始的问题 TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); NVIC_InitStructure.NVIC_IRQChannel TIM2_IRQn; //TIM2中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority 3; //从优先级3级 NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; //IRQ通道被使能 NVIC_Init(NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 TIM_Cmd(TIM2,ENABLE ); //使能定时器2 } void Time4_run(FunctionalState NewState)//控制TIM的运行 { TIM_Cmd(TIM4,NewState); } void Time4_SetCompare(uint16_t Compare1)//控制TIM的比较值 { TIM_SetCompare1(TIM4,Compare1); } void TIM2_IRQHandler(void) { static uint16_t rupttime; if(TIM_GetITStatus(TIM2,TIM_IT_Update)!RESET)//计时器更新中断 { rupttime; if(rupttime showtime)//超时打开标志位去设置led的数据并打开灯 { showflag1; rupttime0; } } TIM_ClearITPendingBit(TIM2,TIM_IT_Update); }HAL库/* USER CODE BEGIN Header */ /** ****************************************************************************** * file : main.c * brief : Main program body ****************************************************************************** * attention * * Copyright (c) 2025 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include main.h /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include more-led.h /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ TIM_HandleTypeDef htim1; TIM_HandleTypeDef htim2; DMA_HandleTypeDef hdma_tim1_ch1; UART_HandleTypeDef huart2; /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_DMA_Init(void); static void MX_TIM1_Init(void); static void MX_TIM2_Init(void); static void MX_USART2_UART_Init(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ extern uint16_t showflag; /* USER CODE END 0 */ /** * brief The application entry point. * retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); MX_TIM1_Init(); MX_TIM2_Init(); MX_USART2_UART_Init(); /* USER CODE BEGIN 2 */ init_ALL(); HAL_TIM_Base_Start_IT(htim2); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { if(showflag 1)//定时一段时间后会自动开启颜色设置 { showflag0; // startshow();//将颜色数据写入数组中 showbreath();//将颜色数据写入数组中 WS2812B_UpdateBuf();//将数组数据更新到DMA中有DMA自行去将数据写入到LED灯带中 } /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * brief System Clock Configuration * retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct {0}; /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSIState RCC_HSI_ON; RCC_OscInitStruct.PLL.PLLState RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL RCC_PLL_MUL9; if (HAL_RCC_OscConfig(RCC_OscInitStruct) ! HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(RCC_ClkInitStruct, FLASH_LATENCY_2) ! HAL_OK) { Error_Handler(); } } /** * brief TIM1 Initialization Function * param None * retval None */ static void MX_TIM1_Init(void) { /* USER CODE BEGIN TIM1_Init 0 */ /* USER CODE END TIM1_Init 0 */ TIM_MasterConfigTypeDef sMasterConfig {0}; TIM_OC_InitTypeDef sConfigOC {0}; TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig {0}; /* USER CODE BEGIN TIM1_Init 1 */ /* USER CODE END TIM1_Init 1 */ htim1.Instance TIM1; htim1.Init.Prescaler 0; htim1.Init.CounterMode TIM_COUNTERMODE_UP; htim1.Init.Period 89; htim1.Init.ClockDivision TIM_CLOCKDIVISION_DIV1; htim1.Init.RepetitionCounter 0; htim1.Init.AutoReloadPreload TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_PWM_Init(htim1) ! HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(htim1, sMasterConfig) ! HAL_OK) { Error_Handler(); } sConfigOC.OCMode TIM_OCMODE_PWM1; sConfigOC.Pulse 0; sConfigOC.OCPolarity TIM_OCPOLARITY_HIGH; sConfigOC.OCNPolarity TIM_OCNPOLARITY_HIGH; sConfigOC.OCFastMode TIM_OCFAST_DISABLE; sConfigOC.OCIdleState TIM_OCIDLESTATE_RESET; sConfigOC.OCNIdleState TIM_OCNIDLESTATE_RESET; if (HAL_TIM_PWM_ConfigChannel(htim1, sConfigOC, TIM_CHANNEL_1) ! HAL_OK) { Error_Handler(); } sBreakDeadTimeConfig.OffStateRunMode TIM_OSSR_DISABLE; sBreakDeadTimeConfig.OffStateIDLEMode TIM_OSSI_DISABLE; sBreakDeadTimeConfig.LockLevel TIM_LOCKLEVEL_OFF; sBreakDeadTimeConfig.DeadTime 0; sBreakDeadTimeConfig.BreakState TIM_BREAK_DISABLE; sBreakDeadTimeConfig.BreakPolarity TIM_BREAKPOLARITY_HIGH; sBreakDeadTimeConfig.AutomaticOutput TIM_AUTOMATICOUTPUT_DISABLE; if (HAL_TIMEx_ConfigBreakDeadTime(htim1, sBreakDeadTimeConfig) ! HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM1_Init 2 */ /* USER CODE END TIM1_Init 2 */ HAL_TIM_MspPostInit(htim1); } /** * brief TIM2 Initialization Function * param None * retval None */ static void MX_TIM2_Init(void) { /* USER CODE BEGIN TIM2_Init 0 */ /* USER CODE END TIM2_Init 0 */ TIM_ClockConfigTypeDef sClockSourceConfig {0}; TIM_MasterConfigTypeDef sMasterConfig {0}; /* USER CODE BEGIN TIM2_Init 1 */ /* USER CODE END TIM2_Init 1 */ htim2.Instance TIM2; htim2.Init.Prescaler 71; htim2.Init.CounterMode TIM_COUNTERMODE_UP; htim2.Init.Period 999; htim2.Init.ClockDivision TIM_CLOCKDIVISION_DIV1; htim2.Init.AutoReloadPreload TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(htim2) ! HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(htim2, sClockSourceConfig) ! HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(htim2, sMasterConfig) ! HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM2_Init 2 */ /* USER CODE END TIM2_Init 2 */ } /** * brief USART2 Initialization Function * param None * retval None */ static void MX_USART2_UART_Init(void) { /* USER CODE BEGIN USART2_Init 0 */ /* USER CODE END USART2_Init 0 */ /* USER CODE BEGIN USART2_Init 1 */ /* USER CODE END USART2_Init 1 */ huart2.Instance USART2; huart2.Init.BaudRate 115200; huart2.Init.WordLength UART_WORDLENGTH_8B; huart2.Init.StopBits UART_STOPBITS_1; huart2.Init.Parity UART_PARITY_NONE; huart2.Init.Mode UART_MODE_TX_RX; huart2.Init.HwFlowCtl UART_HWCONTROL_NONE; huart2.Init.OverSampling UART_OVERSAMPLING_16; if (HAL_UART_Init(huart2) ! HAL_OK) { Error_Handler(); } /* USER CODE BEGIN USART2_Init 2 */ /* USER CODE END USART2_Init 2 */ } /** * Enable DMA controller clock */ static void MX_DMA_Init(void) { /* DMA controller clock enable */ __HAL_RCC_DMA1_CLK_ENABLE(); /* DMA interrupt init */ /* DMA1_Channel2_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn); } /** * brief GPIO Initialization Function * param None * retval None */ static void MX_GPIO_Init(void) { /* USER CODE BEGIN MX_GPIO_Init_1 */ /* USER CODE END MX_GPIO_Init_1 */ /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /* USER CODE BEGIN MX_GPIO_Init_2 */ /* USER CODE END MX_GPIO_Init_2 */ } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * brief This function is executed in case of error occurrence. * retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * param file: pointer to the source file name * param line: assert_param error line source number * retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf(Wrong parameters value: file %s on line %d\r\n, file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ #include more-led.h DMA_HandleTypeDef hdma_tim4_ch1; extern TIM_HandleTypeDef htim1; extern TIM_HandleTypeDef htim2; extern DMA_HandleTypeDef hdma_tim4_up; volatile uint32_t ADC_ConvertedValue[2]{0}; /* 颜色位缓冲区和实际 LED 数据缓冲 */ uint32_t ws2812b_buf[LED_NUM]; uint16_t ws2812b_bit[LED_NUM * 24]; /* 传输完成标志与回调指针 */ volatile uint8_t flag 0; uint16_t showtime; uint8_t showflag; /* 存放用户回调 */ static DMA_CallbackTypeDef user_dma_cb NULL; //static void WS2812B_IRQHandler(void) //{ // /* 关闭 PWM 输出——恢复为零电平 */ // __HAL_TIM_SET_COMPARE(htim4, TIM_CHANNEL_1, 0); // /* 停止 TIM4 PWM */ // HAL_TIM_PWM_Stop(htim4, TIM_CHANNEL_1); // // /* 通知上层数据已全部发送完 */ // flag 1; //} /*------------------------------------------------------------------------------*/ /* 2. 清空 LED 数据缓冲所有颜色置黑 */ void WS2812B_ClearBuf(void) { for (uint8_t i 0; i LED_NUM; i) { ws2812b_buf[i] 0x000000; } } /*------------------------------------------------------------------------------*/ /* 4. 设置所有 LED 同一个颜色 */ void WS2812B_SetBuf(uint32_t color) { for (uint8_t i 0; i LED_NUM; i) { ws2812b_buf[i] color; } } /*------------------------------------------------------------------------------*/ /* 5. 更新并发送整个 LED 缓冲区 */ void WS2812B_UpdateBuf(void) { for (uint8_t j 0; j LED_NUM; j) { uint32_t c ws2812b_buf[j]; /* 逐 LED 展开为 24bit PWM 数据流 */ for (uint8_t i 0; i 24; i) { ws2812b_bit[j*24 i] (c (1UL (23 - i))) ? 60 : 30; // if (ws2812b_buf[j] (0x800000 i)) // ws2812b_bit[j * 24 i] 60; /* “1” 对应高电平时长 */ // else // ws2812b_bit[j * 24 i] 30; /* “0” 对应高电平时长 */ } } Time4_run(ENABLE); // 启动 TIM4 DMA while (flag 0) { } flag 0; } /*------------------------------------------------------------------------------*/ /* 6. 系统初始化入口清缓冲并启动周期中断TIM2 */ void init_ALL(void) { WS2812B_ClearBuf(); /* TIM2 中断由 CubeMX 的 HAL_TIM_Base_Start_IT(htim2) 在 main() 中启动 */ } /*------------------------------------------------------------------------------*/ /* 7. 呼吸灯效果驱动每次调用更新一次显示缓冲和定时参数 */ void showbreath(void) { static uint8_t idx 0, color 0; showtime 4; /* 由 TIM2 中断控制刷新周期 */ switch (idx) { case 0: WS2812B_SetBuf( color); break; case 1: WS2812B_SetBuf((255 - color)); break; case 2: WS2812B_SetBuf( color 8); break; case 3: WS2812B_SetBuf((255 - color) 8); break; case 4: WS2812B_SetBuf( color 16); break; case 5: WS2812B_SetBuf((255 - color) 16); break; case 6: WS2812B_SetBuf(( color) | ( color 8)); break; case 7: WS2812B_SetBuf(((255 - color)) | ((255 - color) 8)); break; case 8: WS2812B_SetBuf(( color) | ( color 16)); break; case 9: WS2812B_SetBuf(((255 - color)) | ((255 - color) 16)); break; case 10: WS2812B_SetBuf(( color 8) | ( color 16)); break; case 11: WS2812B_SetBuf(((255 - color) 8) | ((255 - color) 16)); break; case 12: WS2812B_SetBuf(( color) | ( color 8) | ( color 16)); break; case 13: WS2812B_SetBuf(((255 - color)) | ((255 - color) 8) | ((255 - color) 16)); break; } color; if (color 0) { idx (idx 1) % 14; } } /*------------------------------------------------------------------------------*/ /* 8. 滚动色带/随机色效果 */ void startshow(void) { static uint8_t j 0; uint8_t num; uint32_t R, G, B; showtime 20; /* 数据右移一位为最新色腾出位置 */ for (uint8_t i LED_NUM - 1; i 0; i--) { ws2812b_buf[i] ws2812b_buf[i - 1]; } if (j 0) { num rand() % 7; const uint32_t colors[7] { 0x0000FF, 0x00FF00, 0xFF0000, 0x00FFFF, 0xFF00FF, 0xFFFF00, 0xFFFFFF }; ws2812b_buf[0] colors[num]; } else if (j 15) { Rws2812b_buf[1]/0X100%0x100; Gws2812b_buf[1]/0X10000%0x100; Bws2812b_buf[1]%0x100; if (G 20) G - 20; if (R 20) R - 20; if (B 20) B - 20; ws2812b_buf[0] (G 16) | (R 8) | B; } else { ws2812b_buf[0] 0; } j (j 1) % 50; } void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) { __HAL_TIM_SET_COMPARE(htim1, TIM_CHANNEL_1, 0); HAL_TIM_PWM_Stop_DMA(htim1,TIM_CHANNEL_1); flag 1; } /** * brief 启停 TIM4 PWM / DMA * param NewState: ENABLE 或 DISABLE */ void Time4_run(FunctionalState NewState) { if (NewState) { HAL_TIM_PWM_Start_DMA(htim1,TIM_CHANNEL_1,(uint32_t *)ws2812b_bit,LED_NUM * 24); } else { HAL_TIM_PWM_Stop_DMA(htim1, TIM_CHANNEL_1); } } /** * brief 更新 TIM4 的比较寄存器 CCR1 值用于输出PWM控制LED * param Compare1: 新的比较值 */ void Time4_SetCompare(uint16_t Compare1) { __HAL_TIM_SET_COMPARE(htim1, TIM_CHANNEL_1, Compare1); } /** * brief TIM 中断定时到达回调弱定义可被重载 * param htim: 产生中断的定时器句柄 */ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { static uint16_t rupttime 0; if (htim-Instance TIM2) { rupttime; if (rupttime showtime) { showflag 1; rupttime 0; } } } #ifndef _ADC_TIME_H #define _ADC_TIME_H #include main.h #define LED_NUM 10 /* 用户用来接收 DMA 完成回调的函数指针类型 */ typedef void (*DMA_CallbackTypeDef)(void); static void WS2812B_IRQHandler(void); void WS2812B_ClearBuf(void); void WS2812B_Init(void); void WS2812B_SetBuf(uint32_t color); void WS2812B_UpdateBuf(void); void init_ALL(void); void showbreath(void); void startshow(void); void Dma1_SetIRQHandler(DMA_CallbackTypeDef cb); void Dma1_start(uint16_t DataNumber); void Time4_run(FunctionalState NewState); void Time4_SetCompare(uint16_t Compare1); void Dma1_Configuare(uint32_t MemoryBaseAddr); #endif六、讲解视频https://www.bilibili.com/video/BV1hvNNzaE3d/?spm_id_from333.1387.homepage.video_card.clickvd_sourceb035825fef3be39bc47a9c50b324d086https://www.bilibili.com/video/BV1wiNKzQE8v/?spm_id_from333.1387.homepage.video_card.clickvd_sourceb035825fef3be39bc47a9c50b324d086https://www.bilibili.com/video/BV1ZtNuzXEod/?spm_id_from333.1387.homepage.video_card.clickvd_sourceb035825fef3be39bc47a9c50b324d086
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2413168.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!