06:(寄存器开发)定时器二

定时器二

1、通用定时器

1.1、输出比较功能

stm32f103c8t6的通用定时器为TIM2,TIM3,TIM4。而通用定时器拥有基本定时器的所有功能,并且增加的如下的功能:

(1)多种时钟源选择

(2)向上计数(加),向下计数(减),向上/向下(先加后减)。当然我们使用的时候更喜欢向上计数

(3)输出比较,用于测量波形的周期/测量脉冲的宽度

(4)输入捕获,用于PWM波形的生成

(5)支持针对定位的增量(正交)编码器和霍尔传感器电路。

下图为通用定时器的结构框图(时钟来源,输入捕获,输出比较,从模式):

实验:使用TIM2的输出比较CH1输出PWM波形实现呼吸灯。实物连接如下图所示:

①TIM2.c文件的代码如下:

c 复制代码
#include "stm32f10x.h"                

/**
 * 通用定时器的输出比较模式输出PWM波形的初始化
 */
void TIM2_Init(void)
{
    /* 1、开启时钟 */
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;//开启GPIOA的时钟
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;//开启TIM2的时钟
    
    /* 2、配置GPIOA0(TIM2_CH1)引脚输出模式:复用推挽输出(MODE0 = 11,CNF0 = 10)*/
    GPIOA->CRL |= GPIO_CRL_MODE0;
    GPIOA->CRL &= ~GPIO_CRL_CNF0_0;
    GPIOA->CRL |= GPIO_CRL_CNF0_1;

    /* 3、定时器TIM2的配置 */
    /* 3.0、选择时钟源,默认的是内部时钟源ABP1*/
    
    /* 3.1、预分频器的设置 */
    TIM2->PSC = 7200 - 1;//每隔0.1ms来一个脉冲,计数一次

    /* 3.2、自动重装载寄存器的设置 */
    TIM2->ARR = 100 - 1;//一个周期的时间为10ms

    /* 3.3、计数器的计数方向:默认向上计数*/
    TIM2->CR1 &= ~TIM_CR1_DIR;//向上计数

    /* 4、配置输出比较 */
    /* 4.1、配置捕获比较寄存器的值 */
    TIM2->CCR1 = 50;

    /* 4.2、配置通道CH1的输出比较模式: TIMx_CCMR1_CC1S = 00(输出模式)
        TIMx_CCMR1_OC1M = 110(PWM1模式)
    */
    TIM2->CCMR1 &= ~TIM_CCMR1_CC1S;//CH1配置为输出模式
    TIM2->CCMR1 &= ~TIM_CCMR1_OC1M_0;
    TIM2->CCMR1 |= TIM_CCMR1_OC1M_1;
    TIM2->CCMR1 |= TIM_CCMR1_OC1M_2;

    /* 4.3、使能通道1:TIMx_CCER_CC1E = 1 */
    TIM2->CCER |= TIM_CCER_CC1E;//使能通道CH1

    /* 5、使能计数器 */
    TIM2->CR1 |= TIM_CR1_CEN;
}

/**
 * 更改占空比函数
 */
void Set_PWMDuty(uint8_t Data)
{
    TIM2->CCR1 = Data;
}

②主函数文件的代码如下:

c 复制代码
#include "stm32f10x.h"                
#include "TIM2.h"
#include "OLED.h"
#include "Delay.h"

int main(void)
{
    uint8_t Data = 0;
    TIM2_Init();
    Set_PWMDuty(Data);
	while(1)
	{
        for(uint8_t i = 0; i<100; i++)
        {
            Set_PWMDuty(++Data);
            Delay_ms(10);
        }
        for(uint8_t i = 0; i<100; i++)
        {
            Set_PWMDuty(--Data);
            Delay_ms(10);
        }
	}
}

实物效果展示如下:

呼吸灯

1.2、输入捕获功能

此功能可以捕获输入通道上输入信号的上升沿或下降沿,多用于测量PWM的周期/频率,也可以测量占空比,只要测量出连续的一个上升沿和一个下降沿的时间间隔,然后除以周期即可。

测量的方法如下:①只要测量出连续的两个上升沿或连续的两个下降沿的时间间隔。②在1s时间内捕获了N个上升沿,那么则1s内有N-1个周期,计算出周期,那么就能计算出频率。

通用定时器能产生中断的部位如下:

1.2.1、测量PWM波形的周期和频率

实验:使用TIM3的输入捕获CH1通道测量出TIM2产生的PWM波形的周期与频率
①TIM3.c文件的代码如下;

c 复制代码
#include "stm32f10x.h"                 

/**
 * 通用定时器TIM3的初始化,使用输出捕获通道CH1测量TIM2产生的PWM波形的频率和周期
 */
void TIM3_Init(void)
{
/* 1、开启时钟 */
    /* 1.1、开启定时器TIM3和CH1通道引脚(PA6)的时钟 */
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;//开启GPIOA的时钟
    RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;//开启TIM3的时钟

/* 2、配置CH1通道引脚为浮空输入模式:MODE6 = 00,CNF6 = 01 */
    GPIOA->CRL &= ~GPIO_CRL_MODE6;
    GPIOA->CRL |= GPIO_CRL_CNF6_0;
    GPIOA->CRL &= ~GPIO_CRL_CNF6_1;

/* 3、配置基本定时器TIM3 */
    /* 3.1、选择时钟源 */
    //默认为内部时钟源,所以无需代码配置

    /* 3.2、配置预分频PSC,分频系数为72 */
    TIM3->PSC = 72 - 1;//则一个脉冲的时间为1us

    /* 3.3、配置重装在值,为了防止溢出,配置最大*/
    TIM3->ARR = 65536 - 1;

    /* 3.4、配置计数器为向上计数:TIMx_CR1_DIR = 0 */
    TIM3->CR1 &= ~TIM_CR1_DIR;

/* 4、配置输入捕获相关寄存器 */
    /* 4.1、TIMx_CH1引脚连到TI1输入:TIMx_CR2_TI1S = 0 */
    TIM3->CR2 &= ~TIM_CR2_TI1S;

    /* 4.2、输入滤波器的配置,配置为不滤波:TIMx_CCMR1_IC1F = 0000 */
    TIM3->CCMR1 &= ~TIM_CCMR1_IC1F;
    
    /* 4.3、将CH1通道配置为输入捕获模式,且IC1映射到TI1::TIMx_CCMR1_CC1S = 01 */
    TIM3->CCMR1 |= TIM_CCMR1_CC1S_0;
    TIM3->CCMR1 &= ~TIM_CCMR1_CC1S_1;//IC1映射在TI1上

    /* 4.4、配置为捕获上升沿:TIMx_CCER_CC1P = 0 */
    TIM3->CCER &= ~TIM_CCER_CC1P;

    /* 4.5、输入捕获中的预分频的配置(不分频):TIMx_CCMR1_IC1PSC = 00 */
    TIM3->CCMR1 &= ~TIM_CCMR1_IC1PSC;

    /* 4.6、开启中断请求:TIMx_DIER_CC1IE = 1 */
    TIM3->DIER |= TIM_DIER_CC1IE;

    /* 4.7、使能捕获/比较寄存器:TIMx_CCER_CC1E = 1*/
    TIM3->CCER |= TIM_CCER_CC1E;

/* 5、配置NVIC */
    NVIC_SetPriorityGrouping(4);
    NVIC_SetPriority(TIM3_IRQn,0);
    NVIC_EnableIRQ(TIM3_IRQn);

/* 6、使能计数器:TIMx_CR1_CEN = 1*/
    TIM3->CR1 |= TIM_CR1_CEN;
}

/**
 * 中断服务函数:在捕获到第一个上升沿,让计数器里面的值变为0
 * 当捕获到第二个上升沿时,计数器里面的值拍照到捕获/比较寄存器(CCR)里面(硬件自动完成的)
 */
uint16_t t = 0;
void TIM3_IRQHandler(void)
{
    static uint8_t flag = 0;//第一个一个标志位,用来判断是否为第一个上升沿
    if(TIM3->SR & TIM_SR_CC1IF)
    {
        /* 清除标志位:TIMx_SR_CC1IF*/
        TIM3->SR &= ~TIM_SR_CC1IF;
        flag++;
        /* 判断是否为第一次上升沿,若是那么就清除计数器里面的值*/
        if(flag == 1)
        {
            TIM3->CNT = 0;//将计数器里面的值变为0
            TIM3->CCR1 = 0;//将捕获/比较寄存器(CCR)里面的值也变为0
        }
        else if(flag == 2)
        {
            t = TIM3->CCR1;//将计数器里面的值拍照到捕获/比较寄存器(CCR)里面
            TIM3->CNT = 0;//将计数器里面的值变为0
            TIM3->CCR1 = 0;//将捕获/比较寄存器(CCR)里面的值也变为0
            flag = 0;//让flag = 0;
        }
    }
}

/**
 * 对将捕获/比较寄存器(CCR)里面的值进行处理,获取PWM波形的周期(us)
 */
double Get_PWMCycle(void)
{
    return t ;//返回为us
}

/**
 * 对将捕获/比较寄存器(CCR)里面的值进行处理,获取PWM波形的频率(Hz)
 */
double Get_PWMFrequency(void)
{
    return 1000000.0 / t;//返回为Hz
}

TIM2.c文件的代码如下:

c 复制代码
#include "stm32f10x.h"                


/**
 * 通用定时器的输出比较模式输出PWM波形的初始化
 */
void TIM2_Init(void)
{
    /* 1、开启时钟 */
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;//开启GPIOA的时钟
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;//开启TIM2的时钟
    
    /* 2、配置GPIOA0(TIM2_CH1)引脚输出模式:复用推挽输出(MODE0 = 11,CNF0 = 10)*/
    GPIOA->CRL |= GPIO_CRL_MODE0;
    GPIOA->CRL &= ~GPIO_CRL_CNF0_0;
    GPIOA->CRL |= GPIO_CRL_CNF0_1;

    /* 3、定时器TIM2的配置 */
    /* 3.0、选择时钟源,默认的是内部时钟源ABP1*/
    
    /* 3.1、预分频器的设置 */
    TIM2->PSC = 7200 - 1;//每隔0.1ms来一个脉冲,计数一次

    /* 3.2、自动重装载寄存器的设置 */
    TIM2->ARR = 100 - 1;//一个周期的时间为10ms

    /* 3.3、计数器的计数方向:默认向上计数*/
    TIM2->CR1 &= ~TIM_CR1_DIR;//向上计数

    /* 4、配置输出比较 */
    /* 4.1、配置捕获比较寄存器的值 */
    TIM2->CCR1 = 50;

    /* 4.2、配置通道CH1的输出比较模式: TIMx_CCMR1_CC1S = 00(输出模式)
        TIMx_CCMR1_OC1M = 110(PWM1模式)
    */
    TIM2->CCMR1 &= ~TIM_CCMR1_CC1S;//CH1配置为输出模式
    TIM2->CCMR1 &= ~TIM_CCMR1_OC1M_0;
    TIM2->CCMR1 |= TIM_CCMR1_OC1M_1;
    TIM2->CCMR1 |= TIM_CCMR1_OC1M_2;

    /* 4.3、使能通道1:TIMx_CCER_CC1E = 1 */
    TIM2->CCER |= TIM_CCER_CC1E;//使能通道CH1

    /* 5、使能计数器 */
    TIM2->CR1 |= TIM_CR1_CEN;
}

/**
 * 更改占空比函数
 */
void Set_PWMDuty(uint8_t Data)
{
    TIM2->CCR1 = Data;
}

③主函数文件的代码如下:

c 复制代码
#include "stm32f10x.h"                
#include "TIM2.h"
#include "TIM3.h"
#include "OLED.h"

int main(void)
{ 
    uint8_t Data = 0;
    OLED_Init();
    OLED_ShowString(1,1,"Cycle:00000us");
    OLED_ShowString(2,1,"Freq:0000Hz");

    TIM2_Init();//TIM2的初始化,产生了一个周期为10ms的PWM波形
    TIM3_Init();//TIM3的初始化,开启CH1输出捕获
    Set_PWMDuty(Data);
    
	while(1)
	{
       OLED_ShowNum(1,7,Get_PWMCycle(),5);
       OLED_ShowNum(2,6,Get_PWMFrequency(),4);
        
       for(uint8_t i = 0; i<100; i++)
       {
           Set_PWMDuty(++Data);
           Delay_ms(10);
       }
       for(uint8_t i = 0; i<100; i++)
       {
           Set_PWMDuty(--Data);
           Delay_ms(10);
       }
	}
}

实物演示效果如下:

测量PWM周期和频率

1.2.2、定时器的从模式

使用TIM3的输入捕获CH1通道测量出TIM2产生的PWM波形的周期与频率这个实验,捕获到第一个上升沿的时候我们使用中断的方式,在中断函数里面通过CPU执行代码让计数器里面的值变为0。这样的方式测量出来的一个周期的CRR的值是有误差的。

因为在第一个上升沿来的时候触发中断,在执行中断函数的时候,PWM波形不断的"走",当执行到清零计数器的代码的时候,PWM波形已经走了一会了。所以不是在检测到PWM波形的上升沿的同一时间就立马把计数器里面的数据清零。但是,将计数器中的数据拍照到CRR中是由硬件执行的,在检测到上升沿时,硬件立马会把计数器中的数据拍照到CRR寄存器中。所以,使用上面的实验的方法,测量出来的周期一般比实际周期小。

为了解决这一问题:使用定时器的从模式。从模式的功能都是由硬件自动完成的,无需CPU执行代码。

如上图所示:TRGI为从模式触发信号,其中触发信号的来源如图中蓝色框中的8种,如下图为8中信号来源。
从模式的工作方式:

实验:通过定时器从模式自动测量PWM波的周期和频率和PWM波的占空比。

从模式的触发信号选择TI1FP1,从模式的工作模式为复位模式。将IC1配置为检测上升沿,且IC1映射在TI1FP1。将IC2配置为检测下降沿,且IC2映射在TI1FP2。即来一个上升沿时,通过从模式硬件自动启动复位(计数器清零),来一个下降沿计数器里面的值拍照到捕获/比较寄存器2中CCR2。再来一个上升沿将计数器里面值拍照到CCR1中。则一个周期 = CCR1里面的数值,占空比 = CCR2/CCR1

①TIM3.c文件的代码如下:

c 复制代码
#include "stm32f10x.h"                 

/**
 * 通用定时器TIM3的初始化,使用输出捕获通道CH1测量TIM2产生的PWM波形的频率和周期
 */
void TIM3_Init(void)
{
/* 1、开启时钟 */
    /* 1.1、开启定时器TIM3和CH1通道引脚(PA6)的时钟 */
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;//开启GPIOA的时钟
    RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;//开启TIM3的时钟

/* 2、配置CH1通道引脚为浮空输入模式:MODE6 = 00,CNF6 = 01 */
    GPIOA->CRL &= ~GPIO_CRL_MODE6;
    GPIOA->CRL |= GPIO_CRL_CNF6_0;
    GPIOA->CRL &= ~GPIO_CRL_CNF6_1;

/* 3、配置基本定时器TIM3 */
    /* 3.1、选择时钟源 */
    //默认为内部时钟源,所以无需代码配置

    /* 3.2、配置预分频PSC,分频系数为72 */
    TIM3->PSC = 72 - 1;//则一个脉冲的时间为1us

    /* 3.3、配置重装在值,为了防止溢出,配置最大*/
    TIM3->ARR = 65536 - 1;

    /* 3.4、配置计数器为向上计数:TIMx_CR1_DIR = 0 */
    TIM3->CR1 &= ~TIM_CR1_DIR;

/* 4、配置输入捕获相关寄存器 */
    /* 4.1、TIMx_CH1引脚连到TI1输入:TIMx_CR2_TI1S = 0 */
    TIM3->CR2 &= ~TIM_CR2_TI1S;

    /* 4.2、输入滤波器的配置,配置为不滤波:TIMx_CCMR1_IC1F = 0000 */
    TIM3->CCMR1 &= ~TIM_CCMR1_IC1F;

    /* 4.3、将CH1通道配置为输入捕获模式,且IC1映射到TI1:TIMx_CCMR1_CC1S = 01 
            将CH2通道配置为输入捕获模式,且IC2映射到TI1:TIMx_CCMR1_CC2S = 10*/
    TIM3->CCMR1 |= TIM_CCMR1_CC1S_0;
    TIM3->CCMR1 &= ~TIM_CCMR1_CC1S_1;//IC1映射在TI1FP1上
    TIM3->CCMR1 &= ~TIM_CCMR1_CC2S_0;
    TIM3->CCMR1 |= TIM_CCMR1_CC2S_1;//IC2映射在TI1上

    /* 4.5、配置IC1为捕获上升沿:TIMx_CCER_CC1P = 0 
            配置IC2为捕获下降沿:TIMx_CCER_CC2P = 0*/
    TIM3->CCER &= ~TIM_CCER_CC1P;
    TIM3->CCER |= TIM_CCER_CC2P;

    /* 4.6、输入捕获中IC1的预分频的配置(不分频):TIMx_CCMR1_IC1PSC = 00
            输入捕获中IC2的预分频的配置(不分频):TIMx_CCMR1_IC2PSC = 00 */
    TIM3->CCMR1 &= ~TIM_CCMR1_IC1PSC;
    TIM3->CCMR1 &= ~TIM_CCMR1_IC2PSC;

    /* 4.7、捕获/比较寄存器1使能:TIMx_CCER_CC1E = 1
            捕获/比较寄存器2使能:TIMx_CCER_CC2E = 1*/
    TIM3->CCER |= TIM_CCER_CC1E;
    TIM3->CCER |= TIM_CCER_CC2E;

/* 5、配置从模式 */
    /* 5.1、选择从模式的触发信号为TI1FP1:TIMx_SMCR_TS = 101 */
    TIM3->SMCR |= (TIM_SMCR_TS_0|TIM_SMCR_TS_2);
    TIM3->SMCR &= ~TIM_SMCR_TS_1;

    /* 5.2、配置从模式的工作模式:复位模式 TIMx_SMCR_SMS = 100 */
    TIM3->SMCR |= TIM_SMCR_SMS_2;
    TIM3->SMCR &= ~(TIM_SMCR_SMS_1|TIM_SMCR_SMS_0);

/* 6、使能计数器:TIMx_CR1_CEN = 1*/
    TIM3->CR1 |= TIM_CR1_CEN;
}

/**
 * 对将捕获/比较寄存器(CCR1)里面的值进行处理,获取PWM波形的周期(us)
 */
double Get_PWMCycle(void)
{
    return TIM3->CCR1;//返回为us
}

/**
 * 对将捕获/比较寄存器(CCR)里面的值进行处理,获取PWM波形的频率(Hz)
 */
 
double Get_PWMFrequency(void)
{
    return 1000000.0 / TIM3->CCR1;//返回为Hz
}

/**
 * 对将捕获/比较寄存器(CCR1)和(CCR2)里面的值进行处理,获取PWM波形占空比(%)
 */
double Get_PWMDutycycle(void)
{
    return ((TIM3->CCR2) * 100) / TIM3->CCR1;//返回为%
}

②TIM2.c文件的代码如下:

c 复制代码
#include "stm32f10x.h"                

/**
 * 通用定时器的输出比较模式输出PWM波形的初始化
 */
void TIM2_Init(void)
{
    /* 1、开启时钟 */
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;//开启GPIOA的时钟
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;//开启TIM2的时钟
    
    /* 2、配置GPIOA0(TIM2_CH1)引脚输出模式:复用推挽输出(MODE0 = 11,CNF0 = 10)*/
    GPIOA->CRL |= GPIO_CRL_MODE0;
    GPIOA->CRL &= ~GPIO_CRL_CNF0_0;
    GPIOA->CRL |= GPIO_CRL_CNF0_1;

    /* 3、定时器TIM2的配置 */
    /* 3.0、选择时钟源,默认的是内部时钟源ABP1*/
    
    /* 3.1、预分频器的设置 */
    TIM2->PSC = 7200 - 1;//每隔0.1ms来一个脉冲,计数一次

    /* 3.2、自动重装载寄存器的设置 */
    TIM2->ARR = 100 - 1;//一个周期的时间为10ms

    /* 3.3、计数器的计数方向:默认向上计数*/
    TIM2->CR1 &= ~TIM_CR1_DIR;//向上计数

    /* 4、配置输出比较 */
    /* 4.1、配置捕获比较寄存器的值 */
    TIM2->CCR1 = 50;

    /* 4.2、配置通道CH1的输出比较模式: TIMx_CCMR1_CC1S = 00(输出模式)
        TIMx_CCMR1_OC1M = 110(PWM1模式)
    */
    TIM2->CCMR1 &= ~TIM_CCMR1_CC1S;//CH1配置为输出模式
    TIM2->CCMR1 &= ~TIM_CCMR1_OC1M_0;
    TIM2->CCMR1 |= TIM_CCMR1_OC1M_1;
    TIM2->CCMR1 |= TIM_CCMR1_OC1M_2;

    /* 4.3、使能通道1:TIMx_CCER_CC1E = 1 */
    TIM2->CCER |= TIM_CCER_CC1E;//使能通道CH1

    /* 5、使能计数器 */
    TIM2->CR1 |= TIM_CR1_CEN;
}

/**
 * 更改占空比函数
 */
void Set_PWMDuty(uint8_t Data)
{
    TIM2->CCR1 = Data;
}

③主函数文件的代码如下:

c 复制代码
#include "stm32f10x.h"                
#include "TIM2.h"
#include "TIM3.h"
#include "OLED.h"
#include "Delay.h"

int main(void)
{ 
    uint8_t Data = 0;
    OLED_Init();
    OLED_ShowString(1,1,"Cycle:00000us");
    OLED_ShowString(2,1,"Freq:0000Hz");
    OLED_ShowString(3,1,"Duty:000%");

    TIM2_Init();//TIM2的初始化,产生了一个周期为10ms的PWM波形
    TIM3_Init();//TIM3的初始化,开启CH1输出捕获
    Set_PWMDuty(Data);
    
	while(1)
	{
       OLED_ShowNum(1,7,Get_PWMCycle(),5);
       OLED_ShowNum(2,6,Get_PWMFrequency(),4);
       OLED_ShowNum(3,6,Get_PWMDutycycle(),3);
        
       for(uint8_t i = 0; i<100; i++)
       {
           Set_PWMDuty(++Data);
           OLED_ShowNum(3,6,Get_PWMDutycycle(),3);//显示一下占空比
           Delay_ms(20);
       }
       for(uint8_t i = 0; i<100; i++)
       {
           Set_PWMDuty(--Data);
           OLED_ShowNum(3,6,Get_PWMDutycycle(),3);
           Delay_ms(20);
       }
	}
}

实物演示效果如下:

占空比

2、高级定时器

高级定时器有2个分别为TIM1和TIM8,而stm32f103c8t6只有一个高级定时器(TIM1)。高级定时器有通用定时器的所有功能外,还具备了以下的功能:
(1)重复计数器
(2)死区时间可编程的互补输出
(3)刹车输入信号

高级定时器的结构图如下:

如上图所示:①计数器CNT溢出1次时,重复计数器减1,当重复计数器溢出时(从0减到重复计数器的重装值),才会产生UI和U信号,若开启中断,才会执行中断。
重复计数器值为N,则CNT计数器溢出N+1次才会产生一次更新事件。

②死区时间可编程的互补输出:而互补输出一般情况下用于电机驱动,互补信号:频率周期相等,相位相差180°

③刹车输入信号:通过BKIN引脚输入/事件来控制定时器的比较输出。

高级定时器能产生中断的部位:

❄【注】①使用高级定时器的捕获/比较寄存器的通道输出波形,则要使能TIMx_BDTR_MOE位
②计数器使用的是向下计数+开启UP中断(计数器溢出中断),则在使能计数器前,将状态寄存器TIMx_SR_UIF位置0。否则一上电就会进入一次中断。(因为向下计数,初始前计数器里面的值为0,定时器初始化后,重装载寄存器里面的值会转载到计数器里面,计数器里面的值有0变为N,相当于一次溢出,产生一个更新事件,若开启了中断,则会立马进入中断复位函数)

相关推荐
TESmart碲视1 小时前
HKS201-M24 大师版 8K60Hz USB 3.0 适用于 2 台 PC 1台显示器 无缝切换 KVM 切换器
单片机·嵌入式硬件·物联网·游戏·计算机外设·电脑·智能硬件
small_wh1te_coder2 小时前
硬件嵌入式学习路线大总结(一):C语言与linux。内功心法——从入门到精通,彻底打通你的任督二脉!
linux·c语言·汇编·嵌入式硬件·算法·c
花落已飘2 小时前
STM32中实现shell控制台(shell窗口输入实现)
stm32·单片机·嵌入式硬件
花落已飘3 小时前
STM32中实现shell控制台(命令解析实现)
stm32·shell
没有钱的钱仔3 小时前
STM32低功耗模式全面指南
css·stm32·css3
牵牛老人5 小时前
Qt处理USB摄像头开发说明与QtMultimedia与V4L2融合应用
stm32·单片机·qt
宇钶宇夕6 小时前
针对工业触摸屏维修的系统指南和资源获取途径
单片机·嵌入式硬件·自动化
黑听人6 小时前
【力扣 简单 C】70. 爬楼梯
c语言·leetcode
杜子不疼.6 小时前
二分查找,乘法口诀表,判断闰年,判断素数,使用函数实现数组操作
c语言
和风化雨6 小时前
stm32的三种开发方式
stm32·单片机·嵌入式硬件