【stm32简单外设篇】- WS2812单线地址式 RGB 灯带

news2026/3/15 3:51:56
一、适用场景适用场景炫彩灯效跑马、流水、渐变、呼吸、状态指示、可穿戴灯光、舞台/装饰灯带、视觉化数值显示温度/音频以及练习精确时序、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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…