定时器及其简单使用

定时器及其简单使用


文章目录

  • 定时器及其简单使用
  • ARM32单片机定时器
  • 定时器原理
    • 系统主频与定时时间的关系
    • 定时器计时上限
    • 预分频器
  • 基于定时器应用配置
    • Timer.c
    • PSC、CAR减1原因
  • PWM
    • 什么是PWM?
    • 如何生成PWM?
    • PWM输出使用
    • PWM模式有效电平
    • 定时器可以输出几个通道的PWM?
  • 输入捕获
    • 输入捕获应用
  • 红外NEC
    • 红外NEC通信协议
    • 红外遥控软件实现


ARM32单片机定时器

在这里插入图片描述

根据功能和用途的不同,GD32F303芯片的定时器可以分为以下几类:

  • 内核定时器:用于提供系统tick计数,是系统延时和任务调度的基础。
  • SysTick定时器:SysTick定时器是Cortex-M内核自带的定时器,用于提供系统tick计数,是系统延时和任务调度的基础。
  • 基本定时器:功能相对简单,主要用于产生PWM波形、捕获外部信号等。
  • 常规定时器:功能与基本定时器类似,但具有更丰富的配置选项,如支持多路PWM输出、输入捕获等。
  • 通用定时器:功能更加强大,支持多种工作模式,如PWM输出、输入捕获、脉冲计数、DMA传输等。
  • 高级定时器:具有更强的定时精度和控制能力,支持多路PWM输出、输入捕获、脉冲计数、DMA传输等。
  • 独立看门狗:用于检测系统是否正常运行,如果系统发生故障,看门狗会复位芯片。
  • 专用定时器:用于特定功能,如I2C、SPI、USART等通信接口的定时。
  • 窗口看门狗:与独立看门狗类似,但具有更灵活的配置选项,如可以设置看门狗窗口范围等。
  • RTC实时时钟:用于提供精确的时间信息,即使芯片掉电后也能保持时间准确。

定时器应用场景
在这里插入图片描述

GD32F303定时器资源概述
在这里插入图片描述

定时器原理

定时器本质上是一个电子计数器,当输入端输入3个周期的数字脉冲信号后,计数值将增加3,如果我们知道这个信号的周期T=1s,那么也就表示时间t已经过去了3s。
在这里插入图片描述

系统主频与定时时间的关系

如果输入的信号就是系统主频120Mhz信号,周期T=(1/120)us,从0开始计数,假如记录到120时,对应过去了时间t为:
在这里插入图片描述

定时器计时上限

CAR寄存器是用于设置(NT计时上限的,比如将(AR设置成12000,(NT从0开始向上计数,当(NT=12000时,(NT将被系统清零。同时,系统可以产生一个定时中断:
在这里插入图片描述

预分频器

PSC是预分频器,可以灵活调整进入计数器的时钟频率,比如PS(设置为120后,那么实际进入CNT的信号周期也变成了1us,然后再把CAR设置成100,此时定时中断的周期依然是100us,所以PS(可以从硬件层面,节定时周期的长短,非常灵活·
在这里插入图片描述

高级定时器硬件结构
在这里插入图片描述

  1. 时钟源
  • CK_INT:内部时钟,频率为系统时钟的2倍
  • ETR:外部触发输入,可以是外部脉冲信号或定时器1的输出
  • ITRx:内部触发输入,可以是其他定时器的输出
  1. 预分频器
  • PSC:预分频系数,可以为1-65536
  1. 计数器
  • CNT:16位计数器,可以向上计数或向下计数
  1. 自动重载寄存器
  • ARR:自动重载寄存器,当计数器值等于ARR时,计数器会自动重载
  1. 比较寄存器
  • CCR1-CCR4:4个比较寄存器,当计数器值等于CCR1-CCR4时,会产生一个比较事件
  1. 输出控制寄存器
  • CCER:输出控制寄存器,用于控制输出模式、输出极性等
  1. DMA请求寄存器
  • DMAR:DMA请求寄存器,用于请求DMA传输
  1. 中断寄存器
  • SR:状态寄存器,用于指示中断标志
  • IER:中断使能寄存器,用于使能中断
  • CCR1-CCR4:比较寄存器,当计数器值等于CCR1-CCR4时,会产生一个中断
    工作模式
    高级定时器支持多种工作模式,如:
  • PWM模式:产生PWM波形
  • 输入捕获模式:捕获外部信号
  • 脉冲计数模式:计数脉冲信号
  • DMA传输模式:通过DMA传输数据
    配置步骤
    要配置高级定时器,需要按照以下步骤进行:
    1.选择定时器
    2.选择工作模式
    3.配置时钟源
    4.配置预分频系数
    5.配置计数器
    6.配置比较寄存器
    7.配置输出控制寄存器
    8.配置中断

基于定时器应用配置

设计一个1ms的定时中断,基于定时器0,如何配置?

Timer.c

#if 0
static void TimerInit(uint32_t periodUs)
{
    /* 使能定时器时钟;*/
    rcu_periph_clock_enable(RCU_TIMER0);
    /* 复位定时器;*/
    timer_deinit(TIMER0);
    
    timer_parameter_struct timerInitPara;
    timer_struct_para_init(&timerInitPara);
    /* 设置预分频器值;*/
    timerInitPara.prescaler = 120 - 1;     // 输入给计数器的时钟频率为1Mhz,周期1us
    /* 设置自动重装载值;*/ 
    timerInitPara.period = periodUs - 1;
    timer_init(TIMER0, &timerInitPara);
    
    /* 使能定时器的计数更新中断;*/
    timer_interrupt_enable(TIMER0, TIMER_INT_UP);
    /* 使能定时器中断和优先级;*/
    nvic_irq_enable(TIMER0_UP_IRQn, 0, 0);
    /* 使能定时器;*/ 
    timer_enable(TIMER0);
}

void TIMER0_UP_IRQHandler(void)
{
    if (timer_interrupt_flag_get(TIMER0, TIMER_INT_FLAG_UP) == SET)
    {
        timer_interrupt_flag_clear(TIMER0, TIMER_INT_FLAG_UP);
        ToggleLed(LED1);
    }
}
#else
static void TimerInit(uint32_t periodUs)
{
    /* 使能定时器时钟;*/
    rcu_periph_clock_enable(RCU_TIMER4);
    /* 复位定时器;*/
    timer_deinit(TIMER4);
    
    timer_parameter_struct timerInitPara;
    timer_struct_para_init(&timerInitPara);
    /* 设置预分频器值;*/
    timerInitPara.prescaler = 120 - 1;     // 输入给计数器的时钟频率为1Mhz,周期1us
    /* 设置自动重装载值;*/ 
    timerInitPara.period = periodUs - 1;
    timer_init(TIMER4, &timerInitPara);
    
    /* 使能定时器的计数更新中断;*/
    timer_interrupt_enable(TIMER4, TIMER_INT_UP);
    /* 使能定时器中断和优先级;*/
    nvic_irq_enable(TIMER4_IRQn, 0, 0);
    /* 使能定时器;*/ 
    timer_enable(TIMER4);
}

void TIMER4_IRQHandler(void)
{
    if (timer_interrupt_flag_get(TIMER4, TIMER_INT_FLAG_UP) == SET)
    {
        timer_interrupt_flag_clear(TIMER4, TIMER_INT_FLAG_UP);
        ToggleLed(LED1);
    }
}
#endif

1.TimerInit 函数:

  • 首先,通过 rcu_periph_clock_enable(RCU_TIMER4) 使能了定时器4的时钟,确保定时器可以正常工作。
  • 然后,通过 timer_deinit(TIMER4) 将定时器4进行了复位,以确保其处于初始状态。
  • 之后,定义了一个结构体 timer_parameter_struct timerInitPara 用于配置定时器的参数,并通过 timer_struct_para_init(&timerInitPara) 将该结构体初始化为默认值。
  • 接着,设置了预分频器的值为 120 - 1,这表示定时器的时钟频率为输入给计数器的时钟频率为1MHz,即周期为1微秒。
  • 设置了自动重载值为 periodUs - 1,其中 periodUs 是作为参数传入的定时器的周期值(单位为微秒)。
  • 最后,通过 timer_init(TIMER4, &timerInitPara) 对定时器进行初始化配置,使其按照指定的参数进行工作。
  • 使能了定时器的计数更新中断和相应的中断向量 TIMER4_IRQn,并设置了中断的优先级。
  • 最后,通过 timer_enable(TIMER4) 使能了定时器,使其开始计数。
    2.TIMER4_IRQHandler函数:
  • 这是定时器4的中断处理函数,当定时器4的计数更新中断触发时,该函数将被调用。
  • 在函数内部,首先通过 timer_interrupt_flag_get(TIMER4, TIMER_INT_FLAG_UP) 判断是否是计数更新中断触发,如果是则执行下一步。
  • 使用 timer_interrupt_flag_clear(TIMER4, TIMER_INT_FLAG_UP) 清除定时器4的计数更新中断标志位。
  • 调用 ToggleLed(LED1) 函数,这个函数可能是用来控制 LED1 灯的状态,可能是将其切换为开或关状态。

PSC、CAR减1原因

在实际编程时,并不是把PSC设置成120,CAR设置成1000,而是把PSC设置成(120-1),得到1us的时钟周期,再把CAR设置成(1000-1)才行,为什么都需要-1呢?
先看CAR的设置,因为计数器需要实现0-1000循环计数,而当计数来到999后,再来一个机器周期CNT会变成0,也就是说第1000个周期实际是999变0,而不是999变1000,所以当我们需要1000个计数周期循环计数时,需要设置到999。
在这里插入图片描述
计数模式
在这里插入图片描述

PWM

什么是PWM?

PWM, Pulse width modulation,脉冲宽度调制,通过调节PWM的脉冲宽度进而调节功率。PWM的周期T,脉宽W,占空比D=W/T,假设W是负载的有效工作时间,在一个工作周期T内, W越长也就相当于对负载输出的功率越大,也就是说D越大,输出功率越大。
在这里插入图片描述
定时器输入捕获和输出比较资源概述

在这里插入图片描述

如何生成PWM?

相较于计时功能,除了CAR自动重装载寄存器,输出比较模式还要用到CHxCV寄存器。它是输入捕获和输出比较寄存器,是一个可以复用的寄存器。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

PWM输出使用

设计输出一个周期500us(频率2Khz)占空比50%的PWM,基于定时器0通道0,如何配置?

static void GpioInit(void)
{
    rcu_periph_clock_enable(RCU_GPIOA);
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_8);
}

static void TimerInit(void)
{
    /* 使能定时器时钟;*/
    rcu_periph_clock_enable(RCU_TIMER0);
    /* 复位定时器;*/
    timer_deinit(TIMER0);

    timer_parameter_struct timerInitPara;
    timer_struct_para_init(&timerInitPara);
    /* 设置预分频器值;*/
    timerInitPara.prescaler = 120 - 1;     // 输入给计数器的时钟频率为1Mhz,周期1us
    /* 设置自动重装载值;*/ 
    timerInitPara.period = 500 - 1;
    timer_init(TIMER0, &timerInitPara);

    timer_oc_parameter_struct ocInitPara;
    timer_channel_output_struct_para_init(&ocInitPara);
    /* 设置通道为输出功能;*/
    ocInitPara.outputstate = TIMER_CCX_ENABLE;
    /* 设置通道输出极性;*/
    ocInitPara.ocpolarity = TIMER_OC_POLARITY_HIGH;
    timer_channel_output_config(TIMER0, TIMER_CH_0, &ocInitPara);
    
    /* 设置占空比;*/
    timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_0, 250 - 1); 
    /* 设置通道输出PWM模式;*/
    timer_channel_output_mode_config(TIMER0, TIMER_CH_0, TIMER_OC_MODE_PWM0);
    timer_primary_output_config(TIMER0, ENABLE);
    /* 使能定时器;*/ 
    timer_enable(TIMER0);
}

void PwmDrvInit(void)
{
    GpioInit();
    TimerInit();
}

void PwmDrvTest(void)
{
    for (uint32_t i = 0; i < 500; i += 10)
    {
        timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_0, i); 
        DelayNms(50);
    }
    
    for (uint32_t i = 500; i > 0; i -= 10)
    {
        timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_0, i); 
        DelayNms(50);
    }
}

PWM模式有效电平

PMW模式分PWMO和PWM1两种模式:
PWMO模式下,当CNT(计数值)<CHxCV的设置值时,输出为有效电平,否则为无效电平;
PWM1模式下,当CNT(计数值)<CHxCV的设置值时,输出为无效电平,否则为有效电平。
有效电平可以简单理解为,能使开关打开的电平:比如,我们控制NPN三极管导通,需要配置有效电平为高;而PNP三极管是低电平导通,因此需要配置有效电平为低。
两者区别在于,脉宽(有效电平)在一个周期中的位置。PWMO模式脉宽靠左;PWM1模式脉宽靠右。
有效电平是可以配置的,如果把有效电平定义为高电平,那么我们重新整理上面一段话得到:
PWMO模式下,当CNT(计数值)<CHxCV的设置值时,输出为高电平,否则为低电平;
PWM1模式下,当CNT(计数值) <CHxCV的设置值时,输出为低电平,否则为高电平。

在这里插入图片描述

定时器可以输出几个通道的PWM?

一个定时器只有一个CAR寄存器,但是可以有多个(Hx(V寄存器,定时器0和7有4个通道,所以也有4个CHxCV0也是说每个定时器是可以输出4路频率相同占空比不同的PWM。

在这里插入图片描述

输入捕获

输入捕获模式可以用来测量信号周期频率或脉冲宽度。
在这里插入图片描述

输入捕获模式可以用来测量信号周期频率或脉冲宽度。
在这里插入图片描述

在中断处理中,定时器不会停止,会一直运行。

输入捕获应用

测量一个周期为500us(频率2Khz)的PWM信号的周期,基于定时器1通道0,如何配置?

static void GpioInit(void)
{
    rcu_periph_clock_enable(RCU_GPIOA);
    gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_10MHZ, GPIO_PIN_0);
}

static void TimerInit(void)
{
    /* 使能定时器时钟;*/
    rcu_periph_clock_enable(RCU_TIMER1);
    /* 复位定时器;*/
    timer_deinit(TIMER1);

    timer_parameter_struct timerInitPara;
    timer_struct_para_init(&timerInitPara);
    /* 设置预分频器值;*/
    timerInitPara.prescaler = 120 - 1;     // 输入给计数器的时钟频率为1Mhz,周期1us
    /* 设置自动重装载值;*/ 
    timerInitPara.period = 65535;
    timer_init(TIMER1, &timerInitPara);

    timer_ic_parameter_struct icInitPara;
    timer_channel_input_struct_para_init(&icInitPara);
    /* 设置上升沿/下降沿捕获;*/
    icInitPara.icpolarity = TIMER_IC_POLARITY_RISING;
    /* 设置输入通道;*/
    icInitPara.icselection = TIMER_IC_SELECTION_DIRECTTI;
    timer_input_capture_config(TIMER1, TIMER_CH_0, &icInitPara);
    
    /* 使能定时器的捕获中断;*/
    timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_CH0);
    timer_interrupt_enable(TIMER1, TIMER_INT_CH0);
    /* 使能定时器中断和优先级;*/
    nvic_irq_enable(TIMER1_IRQn, 0, 0);

    /* 使能定时器;*/ 
    timer_enable(TIMER1);
}

static uint32_t g_icValue;

void TIMER1_IRQHandler(void)
{
    if (timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_CH0) == SET)
    {
        timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_CH0);
        g_icValue = timer_channel_capture_value_register_read(TIMER1, TIMER_CH_0) + 1;
        timer_counter_value_config(TIMER1, 0);
    }
}
void CaptureDrvInit(void)
{
    GpioInit();
    TimerInit();
}

void CaptureDrvTest(void)
{
    printf("period is %d us.\n", g_icValue);
    DelayNms(500);
}

红外NEC

红外NEC通信协议

在这里插入图片描述

红外接收头内部的三极管电路具有信号反向的功能,也是将1变为0,0变为1,所以数据0是0.56ms的低电平和0·56ms的高电平,数据1是0.56ms的低电平和1.69ms的高电平,引导码的9ms是高电平变为低电平。
在这里插入图片描述

接收0x55数据,二进制01010101:
在这里插入图片描述

红外遥控软件实现

ir.h

#ifndef _IR_H_
#define _IR_H_

#include <stdint.h>
#include <stdbool.h>

#define KEY1_CODE   0X45
#define KEY2_CODE   0X46

/**
***********************************************************
* @brief 红外接收硬件初始化函数
* @param 
* @return 
***********************************************************
*/
void IrDrvInit(void);
    
/**
***********************************************************
* @brief 获取遥控按键码值
* @param code,输出,按键码值
* @return 返回是否成功获取到按键码值
***********************************************************
*/
bool GetIrCode(uint8_t *code);

#endif

ir.c

#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include "gd32f30x.h"

static void GpioInit(void)
{
    rcu_periph_clock_enable(RCU_GPIOC);
    gpio_init(GPIOC, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_10MHZ, GPIO_PIN_6);
}

static void TimerInit(void)
{
    /* 使能定时器时钟;*/
    rcu_periph_clock_enable(RCU_TIMER7);
    /* 复位定时器;*/
    timer_deinit(TIMER7);

    timer_parameter_struct timerInitPara;
    timer_struct_para_init(&timerInitPara);
    /* 设置预分频器值;*/
    timerInitPara.prescaler = 120 - 1;     // 输入给计数器的时钟频率为1Mhz,周期1us
    /* 设置自动重装载值;*/ 
    timerInitPara.period = 65535;
    timer_init(TIMER7, &timerInitPara);

    timer_ic_parameter_struct icInitPara;
    timer_channel_input_struct_para_init(&icInitPara);
    /* 设置上升沿/下降沿捕获;*/
    icInitPara.icpolarity = TIMER_IC_POLARITY_FALLING;
    /* 设置输入通道;*/
    icInitPara.icselection = TIMER_IC_SELECTION_DIRECTTI;
    timer_input_capture_config(TIMER7, TIMER_CH_0, &icInitPara);
    
    /* 使能定时器的捕获中断;*/
    timer_interrupt_flag_clear(TIMER7, TIMER_INT_FLAG_CH0);
    timer_interrupt_enable(TIMER7, TIMER_INT_CH0);
    /* 使能定时器中断和优先级;*/
    nvic_irq_enable(TIMER7_Channel_IRQn, 0, 0);

    /* 使能定时器;*/ 
    timer_enable(TIMER7);
}

#define TICK_HEAD_MAX     20000    // 表示引导码周期最大值20000us
#define TICK_HEAD_MIN     10000    // 表示引导码周期最小值10000us
#define TICK_0_MAX        1800     // 表示二进制0周期最大值1800us
#define TICK_0_MIN        500      // 表示二进制0周期最小值500us
#define TICK_1_MAX        3000     // 表示二进制1周期最大值3000us
#define TICK_1_MIN        1800     // 表示二进制1周期最小值1800us

static uint8_t g_irCode[4];
static bool g_irCodeFlag = false;

/**
***********************************************************
* @brief 解析按键码值
* @param tickNum,捕获计数值,单位us
* @return
***********************************************************
*/
static void ParseIrFrame(uint32_t tickNum)
{
    static bool s_headFlag = false;//静态局部变量,标识是否正确获取到引导码
    static uint8_t s_index = 0;//静态局部变量,保存解析了多少位的0和1
    
    if (tickNum > TICK_HEAD_MIN && tickNum < TICK_HEAD_MAX)
    {
        s_headFlag = true;
        return;
    }
    
    if (!s_headFlag)
    {
        return;
    }
    if (tickNum > TICK_1_MIN && tickNum < TICK_1_MAX)
    {
        g_irCode[s_index / 8] >>= 1;
        g_irCode[s_index / 8] |= 0x80;
        s_index++;
    }
    if (tickNum > TICK_0_MIN && tickNum < TICK_0_MAX)
    {
        g_irCode[s_index / 8] >>= 1;
        s_index++;
    }
    
    if (s_index == 32)
    {
        if ((g_irCode[2] & g_irCode[3]) == 0)   //(g_irCode[2] == (uint8_t)~g_irCode[3])
        {
            g_irCodeFlag = true;
        }
        else
        {
            g_irCodeFlag = false;
        }
        s_headFlag = false;
        s_index = 0;
    }
}

/**
***********************************************************
* @brief 获取遥控按键码值
* @param code,输出,按键码值
* @return 返回是否成功获取到按键码值
***********************************************************
*/
bool GetIrCode(uint8_t *code)
{
    if (!g_irCodeFlag)
    {
        return false;
    }
    *code = g_irCode[2];
    g_irCodeFlag = false;
    return true;
}

void TIMER7_Channel_IRQHandler(void)
{
    uint32_t icValue;
    if (timer_interrupt_flag_get(TIMER7, TIMER_INT_FLAG_CH0) == SET)
    {
        timer_interrupt_flag_clear(TIMER7, TIMER_INT_FLAG_CH0);
        icValue = timer_channel_capture_value_register_read(TIMER7, TIMER_CH_0) + 1;
        timer_counter_value_config(TIMER7, 0);
        ParseIrFrame(icValue);
    }
}

/**
***********************************************************
* @brief 红外接收硬件初始化函数
* @param 
* @return 
***********************************************************
*/
void IrDrvInit(void)
{
    GpioInit();
    TimerInit();
}

1.GpioInit函数:

  • 该函数初始化了一个 GPIO 端口,用于连接红外接收器。具体地,使用 rcu_periph_clock_enable(RCU_GPIOC) 使能了 GPIOC 端口的时钟。
  • 使用 gpio_init(GPIOC, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_10MHZ, GPIO_PIN_6) 初始化了 GPIOC 的第6个引脚,设置为浮空输入模式。
    2.TimerInit 函数:
  • 该函数初始化了定时器7(TIMER7)用于捕获红外接收器接收到的信号。
  • 首先,通过 rcu_periph_clock_enable(RCU_TIMER7) 使能了定时器7的时钟,并通过 timer_deinit(TIMER7) 对定时器7进行了复位。
  • 然后,设置了定时器的预分频器值为120 - 1,使定时器的输入时钟频率为1MHz,周期为1微秒,并设置了自动重载值为65535。
  • 使用 timer_init(TIMER7, &timerInitPara) 对定时器进行了初始化配置。
  • 初始化了定时器7的通道0用于输入捕获,设置了捕获的触发边沿为下降沿,并通过 timer_input_capture_config(TIMER7, TIMER_CH_0, &icInitPara) 进行了配置。
  • 使能了定时器7的通道0的捕获中断,并通过 nvic_irq_enable(TIMER7_Channel_IRQn, 0, 0) 使能了定时器7的中断。
    3.ParseIrFrame 函数:
  • 该函数用于解析红外信号的帧,根据红外信号的脉冲宽度判断数据位的值。
  • 首先判断是否获取到引导码,若未获取到则直接返回。
  • 若获取到引导码,则根据不同的脉冲宽度判断数据位是0还是1,并逐步解析出完整的按键码值。
  • 当解析完成32位的按键码值后,判断按键码值的有效性,并将解析状态置为未获取引导码的状态。
    4.GetIrCode 函数:
  • 该函数用于获取解析到的红外按键码值。
  • 若成功获取到按键码值,则将按键码值保存到参数 code 中,并将解析状态置为未获取的状态。
    5.TIMER7_Channel_IRQHandler 函数:
  • 该函数为定时器7的中断处理函数,当捕获中断触发时被调用。
  • 首先判断是否是通道0的捕获中断触发,若是则清除中断标志,并读取捕获寄存器的值,并进行解析。
    6.IrDrvInit 函数:
  • 该函数用于初始化红外接收硬件,包括初始化 GPIO 端口和定时器。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JUC(二)

1、wait notify Owner 线程发现条件不满足&#xff0c;调用 wait 方法&#xff0c;即可进入 WaitSet 变为 WAITING 状态 BLOCKED 和 WAITING 的线程都处于阻塞状态&#xff0c;不占用 CPU 时间片 BLOCKED 线程会在 Owner 线程释放锁时唤醒 WAITING 线程会在 Owner 线程调用 …

什么是Linux?它与其他操作系统有何区别?

什么是Linux&#xff1f;它与其他操作系统有何区别&#xff1f; 什么是Linux&#xff1f;它与其他操作系统有何区别&#xff1f;摘要引言正文内容了解LinuxLinux与其他操作系统的区别开放性多样性安全性 &#x1f914; QA环节小结 参考资料表格总结总结未来展望 博主 默语带您 …

超高并发下Redis热点数据风险破解

1 介绍 作者是互联网一线研发负责人,所在业务也是业内核心流量来源,经常参与 业务预定、积分竞拍、商品秒杀等工作。 近期参与多场新员工的面试工作,经常就 『超高并发场景下热点数据』 可用性保障与候选人进行讨论。 本文聚焦一些关键点技术进行讨论,并总结一些热点场景…

Apache HTTP服务器(Linux离线编译安装)

Apache HTTP服务器&#xff08;Linux离线编译安装&#xff09; Apache是普通服务器&#xff0c;本身只支持html即普通网页。可以通过插件支持PHP,还可以与Tomcat连通(单向Apache连接Tomcat,就是说通过Apache可以访问Tomcat资源。反之不然)。 Apache和Tomcat都可以做为独立的w…

12 Games101 - 笔记 - 几何(网格处理)、阴影图

12 几何&#xff08;网格处理&#xff09;、阴影图 曲面细分 曲面细分是指将一个模型的面合理的分成更多小的面&#xff0c;从而提升模型精度&#xff0c;使模型越来越光滑&#xff0c;提高渲染效果。 Loop细分 Loop细分是指Loop提出来的细分规则&#xff0c;只能针对于三角…

【Canvas与艺术】暗蓝网格汽车速度仪表盘

【关键点】 采用线性渐变色&#xff0c;使上深下浅的圆有凹下效果&#xff0c;使上浅下深的圆有凸起效果&#xff0c;两者结合就有立体圆钮的感觉。 【图例】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type&quo…

计算联合体union的大小

一&#xff1a;联合类型的定义 联合也是一种特殊的自定义类型&#xff0c;这种类型定义的变量也包含一系列的成员&#xff0c;特征是这些成员公用同一块空间&#xff08;所以联合也叫共用体&#xff09; 比如&#xff1a;共用了 i 这个较大的空间 二&#xff1a; 联合的特点 …

matlab实现神经网络检测手写数字

一、要求 1.计算sigmoid函数的梯度&#xff1b; 2&#xff0e;随机初始化网络权重&#xff1b; 3.编写网络的代价函数。 二、算法介绍 神经网络结构&#xff1a; 不正则化的神经网络的代价函数&#xff1a; 正则化&#xff1a; S型函数求导&#xff1a; 反向传播算法&…

阿里云服务器价格表2024,最新报价2核2G/2核4G/4核8G/8核16G/16核32G

2024年腾讯云服务器优惠价格表&#xff0c;一张表整理阿里云服务器最新报价&#xff0c;阿里云服务器网整理云服务器ECS和轻量应用服务器详细CPU内存、公网带宽和系统盘详细配置报价单&#xff0c;大家也可以直接移步到阿里云CLUB中心查看 aliyun.club 当前最新的云服务器优惠券…

项目管理证书有何用?这些PMP考试机会一定要抓住

项目管理证书有何用&#xff1f;这些PMP考试机会一定要抓住&#xff01; PMP认证的中文全称是“项目管理专业人士资格认证”&#xff0c;是目前国际上声誉较高并且含金量比较高的项目管理证书之一&#xff0c;本人有幸考过&#xff0c;也通过PMP认证成功转岗&#xff0c;应该也…

力扣刷题之21.合并两个有序链表

仅做学习笔记之用。 题目&#xff1a; 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4]示例 2&#xff1a; 输入&#xf…

进程和线程,线程实现的几种基本方法

什么是进程&#xff1f; 我们这里学习进程是为了后面的线程做铺垫的。 一个程序运行起来&#xff0c;在操作系统中&#xff0c;就会出现对应的进程。简单的来说&#xff0c;一个进程就是跑起来的应用程序。 在电脑上我们可以通过任务管理器可以看到&#xff0c;跑起来的应用程…

几个简单的参数,实现计算特征向量的余弦相似度(java实现,纯手撸)

几个简单的参数&#xff0c;实现计算特征向量的余弦相似度&#xff08;java实现&#xff0c;纯手撸&#xff09; 太狂喽&#xff01;突然高级起来&#x1f9e0;&#x1f9e0;&#x1f9e0;&#x1f9e0;&#x1f9e0;&#x1f9e0;&#x1f9e0;&#x1f9e0;&#x1f9e0;&am…

基于图的在线社区假新闻检测建模

论文原文&#xff1a;Graph-based Modeling of Online Communities for Fake News Detection 论文代码&#xff1a;GitHub - shaanchandra/SAFER: Repository containing the official code for the paper Graph-based Modeling of Online Communities for Fake News Detectio…

这个国产原型设计工具,建议PM新人一定要用!

Hello小伙伴们&#xff01;我是榛妮&#xff0c;原BAT大厂女产品经理一枚&#xff0c;目前在香港创业。 一转眼&#xff0c;做产品经理已经8年&#xff0c;想想入行时的种种往事&#xff08;尴尬情况&#xff09;&#xff0c;至今仍然历历在目。 说起刚入行时遇到的那些问题&a…

判断链表是否为环形链表

目录 一、题目 二、代码 三、疑点代码解析 1.初始化 2.循环 3.if判断 4. 需要注意的是 一、题目 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为…

Python综合实战案例-数据清洗分析

写在前面&#xff1a; 本次是根据前文讲解的爬虫、数据清洗、分析进行的一个纵隔讲解案例&#xff0c;也是对自己这段时间python爬虫、数据分析方向的一个总结。 本例设计一个豆瓣读书数据⽂件&#xff0c;book.xlsx⽂件保存的是爬取豆瓣⽹站得到的图书数据&#xff0c;共 6067…

python—接口编写部分

最近准备整理一下之前学过的前端小程序知识笔记&#xff0c;形成合集。顺便准备学一学接口部分&#xff0c;希望自己能成为一个全栈嘿嘿。建议关注收藏&#xff0c;持续更新技术文档。 目录 前端知识技能树http请求浏览器缓存 后端知识技能树python_api&#xff1a;flaskflask…

WebClient 同步、异步调用实现对比

文章目录 一、概述二、pom依赖三、代码结构四、源码传送1、异步代码2、同步代码3、完整代码 一、概述 WebClient是Spring WebFlux模块提供的一个非阻塞的基于响应式编程的进行Http请求的客户端工具&#xff0c;从Spring5.0开始WebClient作为RestTemplete的替代品&#xff0c;有…

Programming Abstractions in C阅读笔记:p331-p337

《Programming Abstractions in C》学习第79天&#xff0c;p331-p337&#xff0c;总计7页。 一、技术总结 /** File: stack.h* -------------* This interface defines an abstraction for stacks. In any* single application that uses this interface, the values in* the…