WS2812B彩灯 STM32库函数开发:PWM+DMA(stm32f407VET6)

这里写目录标题

  • 1、概述
  • 2、芯片级联方法
  • 3、数据传输特性
  • 4、程序实例
    • 4.1、硬件电路
    • 4.2、定时器初始化
    • 4.3、DMA初始化
    • 4.4、RGB数据驱动
  • 5、完整代码
    • 5.1、WS2812B.c
    • 5.2、WS2812B.h
    • 5.3、main.c

1、概述

WS2812B是一种常见的RGB LED灯带,每个灯珠内部都有一个芯片控制,通过发送特定的时序数据来控制其亮灭。发送数据时,需要按照一定的时序发送24位RGB数据,其中高位在前低位在后,格式为GRB。发送数据时,需要注意不仅仅是发送高电平或低电平,而是要发送占空比不同的PWM波,比如给予一定的高电平和低电平时间。重置码是发送一个持续280us的低电平信号。可以先发送一组24位的数据,然后接一个重置信号表示一组结束。数据采用单总线,归零码的通讯方式, 每个像素点接收24bit数据,溢出的数据传输给下一个像素点。

WS2812B作为一种常见的RGB LED(三色LED)驱动芯片,具有以下优点和缺点:
优点:

  • 集成度高:WS2812B芯片将RGB LED和控制电路集成在一个小型封装中,简化了设计和布线过程。
  • 控制灵活:每个WS2812B芯片都具有独立的控制电路,可以通过单线串联多个LED,并根据需要独立控制每个LED的颜色和亮度。
  • 易于编程:WS2812B芯片与微控制器通信采用简单的串行通信协议,使得编程和控制相对容易。
  • 色彩丰富:每个WS2812B芯片都能够显示256级亮度的红、绿、蓝三个颜色通道,通过调整三个颜色的亮度可以实现丰富多彩的效果。

缺点:

  • 电源需求高:WS2812B芯片对电源的要求较高,供电电源需要稳定而强大,以保证每个芯片的正常工作。
  • 刷新频率限制:由于通信协议的限制,WS2812B的刷新频率相对较低,控制大量LED时可能会出现刷新延迟。
  • 单点故障影响范围大:因为WS2812B芯片串联连接,当某个芯片发生故障时,可能会影响整个串联链路的正常工作。

2、芯片级联方法

典型应用电路:其硬件电路仅需要三根线(5V电源线、GND、DI信号线)。其仅需要一个具有定时器PWM输出功能的GPIO口,即可对多个灯进行控制。
在这里插入图片描述

数据传输示意图:下图中 D1 为 MCU 端发送的数据,D2、D3、D4 为级联电路自动整形转发的数据。
在这里插入图片描述

3、数据传输特性

在这里插入图片描述
如上图所示,当数据线传入灯带后,第一个灯珠截取第一个24位数据自己使用,而后会将其余的数据进行整形后发送给第二颗灯珠,第二颗灯珠会依次截取24位数据并对剩余数据进行整形发送,以此类推。直到最后一组数据被显示为止。每一组24位数根据数据的不同显示不同的颜色和亮度(每个像素点的三基色颜色可实现256级亮度显示, 完成16777216种颜色的全真色彩显示)。
在这里插入图片描述

4、程序实例

根据其电位控制要求,通过软件实现IO控制模拟0码和1码并进行数据传输在理论上是可以实现的,但是在实际过程中,会过于占用CPU资源,所以我们这里采用TIM1+PWM+DMA的控制方式。
通过控制PWM占空比发送0码和1码,额定周期为1.25us,则频率为800Khz
0码PWM占空比:
(0码高电平时间)/(周期)—> 0.4 / 1.25 = 0.32
用占空比乘以定时器重装值加一就是0码的CCR值(代表PWM高电平计数个数)—>
0.32 * (209+1) = 67.2(我实际使用的60,左右相差不太大都可正常使用)
1码PWM占空比:
(1码高电平时间)/(周期)—> 0.8 / 1.25 = 0.64
用占空比乘以定时器重装值加一就是1码的CCR值(代表PWM高电平计数个数)—>
0.64 * (209+1) = 134.4(我实际使用的130,左右相差不太大都可正常使用)

4.1、硬件电路

我在电路设计中,是使用的PE13作为WS2812B的控制引脚,
根据芯片手册可知,PE13是TIM1的CH3通道

在这里插入图片描述

4.2、定时器初始化

下面是定时器1的CH3(PE13)输出PWM的初始化代码
我这里使用的是STM32F407VET6,配置的系统时钟为168MHZ,可根据时钟更改TIM_TimeBaseStructure.TIM_Period的值来修改定时器周期(168MHZ / 210 = 800KHZ)

/*
*函数名称:Timer1_Init
*功能描述:配置TIM1_CH3输出PWM
*传入参数:无
*返回值  :无
*/
void Timer1_Init(void)
{RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);      /*使能GPIOE时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);       /*使能TIM1时钟*/GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_TIM1);   /*将GPIOE13重映射到TIM1的输出通道上*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;               /*将引脚功能配置为复用*/GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;               /*推挽输出*/GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;                 /*上拉*/GPIO_Init(GPIOE, &GPIO_InitStructure);/* 定时器周期 : T =(arr + 1) * (PSC + 1) / Tck.   arr:周期值 PSC:预分频值  Tck: 系统时钟频率 */TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_TimeBaseStructure.TIM_Period = 210 - 1;                     /* T = (TIM_Period + 1)*(0+1)/168M,此时800kHz*/TIM_TimeBaseStructure.TIM_Prescaler = 0;                        /* 0:不预分频 */TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;         /* 0:时钟分频因子设为1,不分频*/TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;     /*向上计数*/TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;                /*重复计数值为0,不使用重复计数*/TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);/* PWM1 Mode configuration: Channel1 */TIM_OCInitTypeDef  TIM_OCInitStructure;TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                /*PWM1模式,计数值小于比较值输出高电平,大于输出低电平*/TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;    /*使能输出通道*/TIM_OCInitStructure.TIM_Pulse = 0;                               /*设置占空比为0, 1 ~ TIM_TimeBaseStructure.TIM_Period */TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;        /*设置输出极性高电平有效*/TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable; /*禁用互补输出通道*/TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;      /*设置互补输出通道极性高电平有效*/TIM_OCInitStructure.TIM_OCIdleState = TIM_OCNIdleState_Set;      /*设置空闲时输出高电平*/TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;   /*设置互补通道空闲时输出低电平*/ TIM_OC3Init(TIM1, &TIM_OCInitStructure);                         /*将上述配置应用到定时器一的通道三上*/TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);                /*使能通道三的输出比较寄存器的预装载功能*/TIM_Cmd(TIM1, ENABLE);                                           /*使能TIM1定时器*/TIM_CtrlPWMOutputs(TIM1,ENABLE);                                 /*使能TIM1的PWM输出*/
}

4.3、DMA初始化

在这里插入图片描述
在这里插入图片描述

下面是DMA初始化代码:

/*
*函数名称:dma2_Init
*功能描述:配置从源地址到TIM1_CCR3的DMA数据传输
*传入参数:无
*返回值  :无
*/
uint16_t g_ledDataBuffer[24];
void dma2_Init(void)
{RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);                        /*使能DMA2时钟*/DMA_DeInit(DMA2_Stream6);                                                   /*对DMA2_Stream6进行默认值初始化*//* DMA2 Stream6 Config for PWM1 by TIM1_CH1*/DMA_InitTypeDef DMA_InitStructure;DMA_InitStructure.DMA_Channel = DMA_Channel_0;                              /*配置DMA通道,通道0*/DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(TIM1->CCR3);         /*配置外设基地址:TIM1的CCR3寄存器*/DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)g_ledDataBuffer;          /*配置源数据的基地址*/DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;                     /*设置搬运方向:存储器到外设*/DMA_InitStructure.DMA_BufferSize = 42;                                      /*设置传输数据的大小*/DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;            /*外设基地址不自增*/DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                     /*源数据基地址自增*/DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; /*设置外设数据大小为半字(16bit)*/DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;         /*设置存储器数据大小为半字(16bit)*/DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                               /*设置DMA为普通模式*/DMA_InitStructure.DMA_Priority = DMA_Priority_High;                         /*DMA优先级为高*/DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;                      /*禁用DMA的FIFO模式*/DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;               /*设置DMA的FIFO阈值为满*/DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;                 /*设置内存突发传输模式为单次传输*/DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;         /*设置外设突发传输模式为单次传输*/DMA_Init(DMA2_Stream6, &DMA_InitStructure);                                 /*将上述配置应用到 DMA2_Stream6*/TIM_DMACmd(TIM1, TIM_DMA_CC3, ENABLE);                                      /*将TIM1的DMA请求映射到通道三并使能*/
}

4.4、RGB数据驱动

#define TIMING_ONE          (130)
#define TIMING_ZERO         (60)
/*
*函数名称:RGB_Show
*功能描述:通过DMA控制器从内存中读取数据,然后将数据传输到TIM1的CC3通道,以驱动RGB灯。
*传入参数:
*返回值  :无
*/
void RGB_Show(uint8_t (*color)[3], uint16_t len)
{uint8_t i = 0;uint16_t memaddr = 0;uint16_t buffersize = 0;buffersize = (len * 24) + 1;       // 缓冲区字节数 = len(RGB灯个数)*24+1while (len){for(i = 0; i < 8; i++)/*  green data */{g_ledDataBuffer[memaddr] = ((color[0][1] << i) & 0x0080) ? TIMING_ONE : TIMING_ZERO;memaddr++;} for(i = 0; i < 8; i++)/*  red data */{   g_ledDataBuffer[memaddr] = ((color[0][0] << i) & 0x0080) ? TIMING_ONE : TIMING_ZERO;memaddr++;}for(i = 0; i < 8; i++)/*  blue data */{g_ledDataBuffer[memaddr] = ((color[0][2] << i) & 0x0080) ? TIMING_ONE : TIMING_ZERO;memaddr++;}len--;}DMA_SetCurrDataCounter(DMA2_Stream6, buffersize);         /*指定要传输的数据量*/TIM_Cmd(TIM1, ENABLE);                                    /*启用TIM1定时器*/TIM_DMACmd(TIM1, TIM_DMA_CC3, ENABLE);                    /*将TIM1的DMA请求映射到通道三并使能*/DMA_Cmd(DMA2_Stream6, ENABLE);                            /*启用DMA2_Stream6,开始数据传输*/while(!DMA_GetFlagStatus(DMA2_Stream6, DMA_FLAG_TCIF6));  /*等待DMA传输完成,使用循环检查DMA传输完成标志*/DMA_Cmd(DMA2_Stream6, DISABLE);                           /*禁用DMA2流6,停止数据传输*/DMA_ClearFlag(DMA2_Stream6, DMA_FLAG_TCIF6);              /*清除DMA传输完成标志*/TIM_Cmd(TIM1, DISABLE);                                   /*禁用TIM1定时器,停止计时*/
}

5、完整代码

5.1、WS2812B.c


#include "WS2812B.h"
#include "DWT_Delay.h"
#include "string.h"#define TIMING_ONE          (130)
#define TIMING_ZERO         (60)/*
*函数名称:Timer1_Init
*功能描述:配置TIM1_CH3输出PWM
*传入参数:无
*返回值  :无
*/
void Timer1_Init(void)
{RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);      /*使能GPIOE时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);       /*使能TIM1时钟*/GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_TIM1);   /*将GPIOE13重映射到TIM1的输出通道上*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;               /*将引脚功能配置为复用*/GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;               /*推挽输出*/GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;                 /*上拉*/GPIO_Init(GPIOE, &GPIO_InitStructure);/* 定时器周期 : T =(arr + 1) * (PSC + 1) / Tck.   arr:周期值 PSC:预分频值  Tck: 系统时钟频率 */TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_TimeBaseStructure.TIM_Period = 210 - 1;                     /* T = (TIM_Period + 1)*(0+1)/168M  = 800kHz*/TIM_TimeBaseStructure.TIM_Prescaler = 0;                        /* 0:不预分频 */TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;         /* 0:时钟分频因子设为1,不分频*/TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;     /*向上计数*/TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;                /*重复计数值为0,不使用重复计数*/TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);/* PWM1 Mode configuration: Channel1 */TIM_OCInitTypeDef  TIM_OCInitStructure;TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                /*PWM1模式,计数值小于比较值输出高电平,大于输出低电平*/TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;    /*使能输出通道*/TIM_OCInitStructure.TIM_Pulse = 0;                               /*设置占空比为0, 1 ~ TIM_TimeBaseStructure.TIM_Period */TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;        /*设置输出极性高电平有效*/TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable; /*禁用互补输出通道*/TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;      /*设置互补输出通道极性高电平有效*/TIM_OCInitStructure.TIM_OCIdleState = TIM_OCNIdleState_Set;      /*设置空闲时输出高电平*/TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;   /*设置互补通道空闲时输出低电平*/ TIM_OC3Init(TIM1, &TIM_OCInitStructure);                         /*将上述配置应用到定时器一的通道三上*/TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);                /*使能通道三的输出比较寄存器的预装载功能*/TIM_Cmd(TIM1, ENABLE);                                           /*使能TIM1定时器*/TIM_CtrlPWMOutputs(TIM1,ENABLE);                                 /*使能TIM1的PWM输出*/
}uint16_t g_ledDataBuffer[24];
/*
*函数名称:dma2_Init
*功能描述:配置从源地址到TIM1_CCR3的DMA数据传输
*传入参数:无
*返回值  :无
*/
void dma2_Init(void)
{RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);                        /*使能DMA2时钟*/DMA_DeInit(DMA2_Stream6);                                                   /*对DMA2_Stream6进行默认值初始化*//* DMA2 Stream6 Config for PWM1 by TIM1_CH1*/DMA_InitTypeDef DMA_InitStructure;DMA_InitStructure.DMA_Channel = DMA_Channel_0;                              /*配置DMA通道,通道0*/DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(TIM1->CCR3);         /*配置外设基地址:TIM1的CCR3寄存器*/DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)g_ledDataBuffer;          /*配置源数据的基地址*/DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;                     /*设置搬运方向:存储器到外设*/DMA_InitStructure.DMA_BufferSize = 42;                                      /*设置传输数据的大小*/DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;            /*外设基地址不自增*/DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                     /*源数据基地址自增*/DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; /*设置外设数据大小为半字(16bit)*/DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;         /*设置存储器数据大小为半字(16bit)*/DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                               /*设置DMA为普通模式*/DMA_InitStructure.DMA_Priority = DMA_Priority_High;                         /*DMA优先级为高*/DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;                      /*禁用DMA的FIFO模式*/DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;               /*设置DMA的FIFO阈值为满*/DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;                 /*设置内存突发传输模式为单次传输*/DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;         /*设置外设突发传输模式为单次传输*/DMA_Init(DMA2_Stream6, &DMA_InitStructure);                                 /*将上述配置应用到 DMA2_Stream6*/TIM_DMACmd(TIM1, TIM_DMA_CC3, ENABLE);                                      /*将TIM1的DMA请求映射到通道三并使能*/
}/*
*函数名称:RGB_Show
*功能描述:通过DMA控制器从内存中读取数据,然后将数据传输到TIM1的CC3通道,以驱动RGB灯。
*传入参数:
*返回值  :无
*/
void RGB_Show(uint8_t (*color)[3], uint16_t len)
{uint8_t i = 0;uint16_t memaddr = 0;uint16_t buffersize = 0;buffersize = (len * 24) + 1;       // 缓冲区字节数 = len(RGB灯个数)*24+1while (len){for(i = 0; i < 8; i++)/*  green data */{g_ledDataBuffer[memaddr] = ((color[0][1] << i) & 0x0080) ? TIMING_ONE : TIMING_ZERO;memaddr++;} for(i = 0; i < 8; i++)/*  red data */{   g_ledDataBuffer[memaddr] = ((color[0][0] << i) & 0x0080) ? TIMING_ONE : TIMING_ZERO;memaddr++;}for(i = 0; i < 8; i++)/*  blue data */{g_ledDataBuffer[memaddr] = ((color[0][2] << i) & 0x0080) ? TIMING_ONE : TIMING_ZERO;memaddr++;}len--;}DMA_SetCurrDataCounter(DMA2_Stream6, buffersize);         /*指定要传输的数据量*/TIM_Cmd(TIM1, ENABLE);                                    /*启用TIM1定时器*/TIM_DMACmd(TIM1, TIM_DMA_CC3, ENABLE);                    /*将TIM1的DMA请求映射到通道三并使能*/DMA_Cmd(DMA2_Stream6, ENABLE);                            /*启用DMA2_Stream6,开始数据传输*/while(!DMA_GetFlagStatus(DMA2_Stream6, DMA_FLAG_TCIF6));  /*等待DMA传输完成,使用循环检查DMA传输完成标志*/DMA_Cmd(DMA2_Stream6, DISABLE);                           /*禁用DMA2流6,停止数据传输*/DMA_ClearFlag(DMA2_Stream6, DMA_FLAG_TCIF6);              /*清除DMA传输完成标志*/TIM_Cmd(TIM1, DISABLE);                                   /*禁用TIM1定时器,停止计时*/
}

5.2、WS2812B.h

#ifndef __WS2818B_H
#define __WS2812B_H
#include "stm32f4xx.h"                  // Device header
void Timer1_Init(void);
void dma2_Init(void);
void RGB_Show(uint8_t (*color)[3], uint16_t len);
#endif

5.3、main.c

#include "stm32f4xx.h"                  // Device header
#include "DWT_Delay.h"
#include "WS2812B.h"uint8_t rgbRed[][3] = {{0xff, 0xff, 0x99}};
uint8_t rgbRed1[][3] = {{0x20, 0x20, 0x20}};
uint8_t rgbRed2[][3] = {{0x33, 0x00, 0x33}};
uint8_t rgbRed3[][3] = {{0xFF, 0x33, 0xff}};
int main(void)
{DWT_Init();Timer1_Init();dma2_Init();while(1){RGB_Show(rgbRed,1);DWT_DelayMS(1000);RGB_Show(rgbRed1,1);DWT_DelayMS(1000);RGB_Show(rgbRed2,1);DWT_DelayMS(1000);RGB_Show(rgbRed3,1);DWT_DelayMS(1000);RGB_Show(rgbRed,1);DWT_DelayMS(1000);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/473515.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【第二十四课】二分图:acwing-860染色法判定二分图 / acwing-861二分图的最大匹配 ( c++代码 )

目录 二分图是什么 acwing-860染色法判定二分图 染色法 代码 acwing-861二分图的最大匹配 思路 代码 二分图是什么 学习二分图的目的就是一些题目可以简化成二分图的模型来求解。 二分图也就是&#xff1a;一个无向图顶点集&#xff0c;分成了两堆顶点(可以理解为两…

【数据结构】18 二叉搜索树(查找,插入,删除)

定义 二叉搜索树也叫二叉排序树或者二叉查找树。它是一种对排序和查找都很有用的特殊二叉树。 一个二叉搜索树可以为空&#xff0c;如果它不为空&#xff0c;它将满足以下性质&#xff1a; 非空左子树的所有键值小于其根节点的键值非空右子树的所有键值都大于其根结点的键值左…

【Redis实战】有MQ为啥不用?用Redis作消息队列!?Redis作消息队列使用方法及底层原理高级进阶

&#x1f389;&#x1f389;欢迎光临&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《Redis实战与进阶》 本专栏纯属为爱发电永久免费&#xff01;&a…

初始Git及Linux Centos下安装Git

文章目录 前言版本控制器注意Git安装 前言 不知道你⼯作或学习时&#xff0c;有没有遇到这样的情况&#xff1a;我们在编写各种⽂档时&#xff0c;为了防⽌⽂档丢失&#xff0c;更改失误&#xff0c;失误后能恢复到原来的版本&#xff0c;不得不复制出⼀个副本&#xff0c;⽐如…

算法练习-赎金信(思路+流程图+代码)

难度参考 难度&#xff1a;中等 分类&#xff1a;哈希表 难度与分类由我所参与的培训课程提供&#xff0c;但需要注意的是&#xff0c;难度与分类仅供参考。且所在课程未提供测试平台&#xff0c;故实现代码主要为自行测试的那种&#xff0c;以下内容均为个人笔记&#xff0c;旨…

【mysql】数据约束

一、数据约束&#xff1a; 什么是约束&#xff1f; 为了确保表中的数据的完整性(准确性、正确性)&#xff0c;为表添加一些限制。是数据库中表设计的一个最基本规则。使用约束可以使数据更加准确&#xff0c;从而减少冗余数据&#xff08;脏数据&#xff09;。 数据库完整性约…

HarmonyOS—@State装饰器:组件内状态

State装饰的变量&#xff0c;或称为状态变量&#xff0c;一旦变量拥有了状态属性&#xff0c;就和自定义组件的渲染绑定起来。当状态改变时&#xff0c;UI会发生对应的渲染改变。 在状态变量相关装饰器中&#xff0c;State是最基础的&#xff0c;使变量拥有状态属性的装饰器&a…

CSS 不同颜色的小圆角方块组成的旋转加载动画

<template><!-- 创建一个装载自定义旋转加载动画的容器 --><view class="spinner"><!-- 定义外部包裹容器,用于实现整体旋转动画 --><view class="outer"><!-- 定义四个内部小方块以形成十字形结构 --><view clas…

如何让Obsidian实现电脑端和安卓端同步

Obsidian是一款知名的笔记软件&#xff0c;支持Markdown语法&#xff0c;它允许用户在多个设备之间同步文件。要在安卓设备上实现同步&#xff0c;可以使用remote save插件&#xff0c;以下是具体操作步骤&#xff1a; 首先是安装电脑端的obsidian&#xff0c;然后依次下载obs…

MOSFET栅极应用电路分析汇总(驱动、加速、保护、自举等等)

概述 MOSFET是一种常见的电压型控制器件&#xff0c;具有开关速度快、高频性能、输入阻抗高、噪声小、驱动功率小、动态范围大、安全工作区域(SOA)宽等一系列的优点&#xff0c;因此被广泛的应用于开关电源、电机控制、电动工具等各行各业。栅极做为MOSFET本身较薄弱的环节&am…

Python如何实现定时发送qq消息

因为生活中老是忘记各种事情&#xff0c;刚好又在学python&#xff0c;便突发奇想通过python实现提醒任务的功能&#xff08;尽管TIM有定时功能&#xff09;&#xff0c;也可定时给好友、群、讨论组发送qq消息。其工作流程是&#xff1a;访问数据库提取最近计划——>根据数据…

Java - SPI机制

本文参考&#xff1a;SPI机制 SPI&#xff08;Service Provider Interface&#xff09;&#xff0c;是JDK内置的一种服务提供发现机制&#xff0c;可以用来启动框架扩展和替换组件&#xff0c;主要是被框架的开发人员使用&#xff0c;比如 java.sql.Driver接口&#xff0c;其他…