001 蓝桥杯嵌入式赛道备赛——基础

个人笔记,不扭扭捏捏,一口气到位。方便自己也方便大家

00 时钟线

cubeMX已经完成了大多数工作

01 LED(GPIO输出)

在使用LED的时候先把SN74HC573锁存器PD2置高电平,然后写入LED所要的高低电平,然后置PD2低电平,将数据所存在里面。

void LED_Control(u8 led_ctrl)
{//先熄灭所有LED灯HAL_GPIO_WritePin(GPIOC,0xff00,GPIO_PIN_SET);		//让PC8~PC15输出高电平,熄灭LEDHAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);	//打开锁存器HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);	//关闭锁存器//根据led_ctrl来点亮对应的LEDHAL_GPIO_WritePin(GPIOC,led_ctrl<<8,GPIO_PIN_RESET);//根据led_ctrl输出低电平,点亮LED,<<8的原因是LED对应PC15-8,即数据高位HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);	//打开锁存器HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);	//关闭锁存器
}

输出模式有:

推挽输出(GPIO_MODE_OUTPUT_PP):既可以输出高电平,也可以输出低电平。
开漏输出(GPIO_MODE_OUTPUT_OD):如果没有上拉电阻,只能输出低电平,此种模式更多用在IIC协议下。
复用推挽输出(GPIO_MODE_AF_PP):将gpio用作第二功能,使用片内外设时候的IIC。
复用开漏输出(GPIO_MODE_AF_OD):将gpio用作第二功能,使用片内外设时候的SPI。

02 独立KEY(GPIO输入)

蓝桥杯嵌入式:KEY的使用(二)_嵌入式stm32的key代码-CSDN博客

#define KB1  HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)
#define KB2  HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)
#define KB3  HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)
#define KB4  HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)
#define KEYPORT  KB1 | (KB2<<1) | (KB3<<2) | (KB4<<3) | 0xf0u8 Trg;	 	 // 全局变量,单次触发
u8 Cont; 	 // 全局变量,长按
void Key_Read(void)
{u8 ReadData = (KEYPORT)^0xff;   		   // 1Trg = ReadData & (ReadData ^ Cont);        // 2 Cont = ReadData;                           // 3
}
/*			按键不触发的时候都是高电平,相当于就是0xff,当如果按下KB1的时候KB1就是低电平,此时的表达式就是1111 1110--->0xfe,s将0xfe与0xff异或,得出来的结果就是0x01,0x01&(0x01^0x00)-->先异或得出结果是0x01在与自己做&运算(都为1才为1)得出结果0x01返回给单机变量trg,在main函数里面进行就是if(trg&0x01)时进行触发如果这次按键事件是一个长按,则继续走下面cont变量,cont=ReadData,也就是第一次ReadData的结果如果持续是ReadData,则第二行的trg表达式的异或会一直都是0(在进行第二次判断的时候),trg就为0了在执行长按的情况下
*/

输入模式有:

模拟输入(GPIO_MODE_ANALOG):在比赛中采集ADC的时候常用。
浮空输入(GPIO_MODE_INPUT):在比赛中通常会拿来写键盘程序。
上拉输入(GPIO_Mode_IPU):将输入口上拉到VCC。
下拉输入(GPIO_Mode_IPD):将输入口上拉到GND。

.Pull = GPIO_NOPULL;

03 串口收发

UART1是直接与C8T6(模拟的DAPlink)连接的,且C8T6还支持了USB串口。

int fputc(int ch, FILE *f)
{HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);return ch;
}

初始化接收中断:

HAL_UART_Receive_IT(&huart1,rx_buf,1);

回调函数:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart -> Instance == USART1){//接收到的串口一发来的东西就可以在这里进行逻辑操作}HAL_UART_Receive_IT(&huart1,rx_buff,1);//这个不要忘记了,如果没有中断就只能发生一次
}

DMA

【STM32】HAL库 STM32CubeMX教程十一---DMA (串口DMA发送接收)_stm32 串口dma接收-CSDN博客

04 LCD

一、硬件框架

1.​LCD型号兼容性处理

支持两种控制器:uC8230ILI932X系列(通过REG_8230_Init()REG_932X_Init()区分)

  • 初始化时通过读取寄存器0的值(dummy = LCD_ReadReg(0))判断控制器型号
	dummy = LCD_ReadReg(0);	if(dummy == 0x8230){REG_8230_Init();}else{REG_932X_Init();	}

2.GPIO配置

  • 控制信号线
    • PB5: RD(读使能)
    • PB8: WR(写使能)
    • PB9: CS(片选)
    • PA8: RS(寄存器/数据选择)
  • 数据总线
    • PC0-PC15作为16位并行数据总线(通过LCD_BusIn()/LCD_BusOut()切换方向)
信号线GPIO功能描述
D0-D15PC0-PC15数据总线
CSPB9片选信号
WRPB8写使能
RDPB5读使能
RSPA8命令/数据选择

    LCD_Init();//初始化
    LCD_SetBackColor(Black);//设置背景颜色
    LCD_SetTextColor(White);//设置文字颜色
    LCD_Clear(Black);//刷新屏幕
 

05 ADC与DAC

1.ADC

ADC通道分配表(外部通道)

GPIO引脚对应ADC模块及通道复用功能备注
PB15ADC2_IN15……
PB12ADC1_IN11……
PB14ADC1_IN5……

VREF+引脚(ADC参考电压)

基本定义
  • VREF+:ADC/DAC的参考电压正极输入引脚,决定模拟信号转换的基准电压上限。
  • VDDA:​模拟电源引脚​(通常与VDD同电压,但独立滤波),为模拟模块(ADC/DAC、运算放大器等)供电。

VDDA=3.3V,则ADC输入信号范围:0~3.3V

误差处理:

    HAL_ADC_Start(&hadc1);
    adc1_val = HAL_ADC_GetValue(&hadc1);
    volt_r38 = adc1_val/4095.0f*3.3f;还是偏大

考虑volt_r38 = adc1_val/4094.0f*3.3f;

ADC多通道调用规则

ADC的规则组转换结果会按Rank顺序存储在数据寄存器中。每次调用HAL_ADC_GetValue()会读取当前结果并指向下一个被开启的通道

Rank顺序配置:

// 通道5配置为Rank1
sConfig.Channel = ADC_CHANNEL_5;               
sConfig.Rank = ADC_REGULAR_RANK_1;              
sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5; // 长采样时间提高精度[7](@ref)
//640.5周期≈47.2μs(假设ADCCLK=14MHz)
// 通道11配置为Rank2
sConfig.Channel = ADC_CHANNEL_11;
sConfig.Rank = ADC_REGULAR_RANK_2;               // 转换顺序第二[1](@ref)

    如何优化代码效率?​

    • 使用DMA+连续模式可减少CPU占用(推荐)。
    • 避免在循环中频繁启动/停止ADC,可设置定时器触发采样
    轮询模式(单次触发)​:uint32_t adc_values[2];  // 存储两个通道的结果// 启动ADC1转换HAL_ADC_Start(&hadc1);HAL_ADC_PollForConversion(&hadc1, 100);  // 等待转换完成// 读取所有通道数据adc_values[0] = HAL_ADC_GetValue(&hadc1);  // Rank1(通道5)adc_values[1] = HAL_ADC_GetValue(&hadc1);  // Rank2(通道11)这种连续转换需要配置:ContinuousConvMode = ENABLE
    /*否则,hadc1.Init.ContinuousConvMode = DISABLE; 需如下手动调用HAL_ADC_Start()启动后再读取
    HAL_ADC_Start(&hadc1);
    adc_values[0] = HAL_ADC_GetValue(&hadc1);  // Rank1(通道5)
    HAL_ADC_Start(&hadc1);
    adc_values[1] = HAL_ADC_GetValue(&hadc1); */// 计算电压volt_mcp = adc_values[0] / 4096.0f * 3.3f;  // 通道5volt_r38 = adc_values[1] / 4096.0f * 3.3f;  // 通道11DMA模式(连续触发)​:// 全局变量uint16_t adc1_dma_buffer[2];  // 存储ADC1两个通道的数据// 初始化中启动DMAHAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc1_dma_buffer, 2);// DMA自动更新adc1_dma_buffer数组volt_mcp = adc1_dma_buffer[0] / 4096.0f * 3.3f;  // 通道5volt_r38 = adc1_dma_buffer[1] / 4096.0f * 3.3f;  // 通道11
    
    其他关键参数​配置:
    hadc1.Init.Resolution = ADC_RESOLUTION_12B;      // 12位分辨率[2](@ref)
    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;      // 数据右对齐[3](@ref)
    //右对齐时数据寄存器直接存储0-4095的原始值
    hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;  // 每通道转换完成触发EOC[1](@ref)误差处理​​:
    若电压偏差超过1%,检查参考电压是否稳定(测量VDDA引脚)
    高频干扰时可启用过采样:
    hadc1.Init.OversamplingMode = ENABLE;
    hadc1.Init.Oversample.Ratio = ADC_OVERSAMPLING_RATIO_16;
    校准操作​​:
    HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED); // 上电后执行一次[8](@ref)
    通道5采样时间可优化为:
    sConfig.SamplingTime = ADC_SAMPLETIME_24CYCLES_5; // 短时间适合低阻抗信号[6](@ref)

      四、模式扩展建议

      若要实现更复杂的转换模式,可参考以下配置组合:

      应用场景配置参数组合
      定时器触发连续转换ExternalTrigConv=TIMx_CCxContinuousConvMode=ENABLE
      注入通道中断采集配置注入通道组,启用HAL_ADC_Start_IT()
      双ADC同步采集Mode=ADC_MODE_RegSimult, 配置ADC1和ADC2的同步规则组
      温度传感器采集启用内部温度传感器通道(ADC_CHANNEL_TEMPSENSOR),设置采样时间≥17.1μs

      2.DAC

      STM32G431RBT6学习笔记---DAC入门模块及ADC和DAC结合_stm32g431rbt6 dac-CSDN博客

      u16 dac_ch1_val,dac_ch2_val;
      void DAC_Process()
      {dac_ch1_val = (1.1f/3.3f*4095);dac_ch2_val = (2.5f/3.3f*4095);HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R, dac_ch1_val);	//0-->0v  4095--> 3.3V    1.1v --> 1365HAL_DAC_Start(&hdac1, DAC_CHANNEL_1);HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_2, DAC_ALIGN_12B_R, dac_ch2_val);	//0-->0v  4095--> 3.3V    2.5v --> 2730HAL_DAC_Start(&hdac1, DAC_CHANNEL_2);
      }
      

      06 IIC通信

      一、24c02

      蓝桥杯嵌入式:EEPROM(AT89C02)(九)_蓝桥杯驱动文件只给.c文件-CSDN博客

      实现掉电不丢失

      设备地址:

      IIC流程:

      代码(比赛时看着手册写会简单很多)

      //写24C02
      void EEPROM_Write(u8 add,u8 dat)
      {I2CStart(); I2CSendByte(0xa0); I2CWaitAck(); I2CSendByte(add);	I2CWaitAck(); I2CSendByte(dat); I2CWaitAck(); I2CStop();HAL_Delay(5);
      }
      //读24C02
      u8 EEPROM_Read(u8 add)
      {u8 dat;I2CStart(); I2CSendByte(0xa0);I2CWaitAck(); 	I2CSendByte(add);I2CWaitAck(); I2CStart();I2CSendByte(0xa1); I2CWaitAck();dat = I2CReceiveByte(); I2CSendNotAck();I2CStop();return(dat);
      }

      二、MCP4017

      蓝桥杯嵌入式:MCP4017的使用(四)_蓝桥杯嵌入式mcp4017-CSDN博客

      1. 核心功能

        • MCP4017是一个数字控制的可变电阻,通过I2C接口调节电阻值(0-10kΩ,128级可调0-127)。
          ​N值(十进制)​​阻值(Ω)​​电压分压值(VDD=3.3V)​
          000V
          6450.4k2.45V
          127(0x7F)100k3.0V(实际约2.9V)
        • 相当于一个“电子滑动变阻器”,程序可以动态改变其阻值,无需手动调节。
        • 阻值计算公式

      2. MCP4017的作用:生成一个已知电压供ADC采样,验证ADC模块是否正常工作。

      注意ADC测量MCP4017时需要上拉对应的ADC引脚,如下图:

      07 TIM

      蓝桥杯嵌入式:PWM输出的使用(六)_蓝桥杯方波输出可以用pwm吗-CSDN博客

      1.PWM

      初始化:

      MX_TIM17_Init();HAL_TIM_PWM_Start(&htim17,TIM_CHANNEL_1);//A7TIM17->ARR = 499;	// 周期是500us,对应频率2kHzTIM17->CCR1 = 400; // 80%占空比MX_TIM16_Init();HAL_TIM_PWM_Start(&htim16,TIM_CHANNEL_1);//A6TIM16->ARR = 49;	// 周期是50us,对应频率20kHzTIM16->CCR1 = 10; // 20%占空比
      /*
      ->ARR对应.Period;
      ->CCR1对应.Pulse
      */
      法二:
      // 动态修改ARR
      __HAL_TIM_SET_AUTORELOAD(&htim16, 49);  // 立即生效(需禁用预装载)
      // 动态修改CCR1
      __HAL_TIM_SET_COMPARE(&htim16, TIM_CHANNEL_1, 10);


       

      2.输入捕获

      蓝桥杯嵌入式:输入捕获(频率捕获,占空比计算)的使用(八)_蓝桥杯15届嵌入式pa15捕获功能-CSDN博客

      测量原理:捕获相邻上升沿之间的计数器差值

      htim2.Init.Prescaler = 80;       // 预分频系数
      htim2.Init.Period = 0xFFFF;      // 自动重装载值
      sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING; // 上升沿捕获
      • 定时器时钟 = 80MHz / 80(预分频) = ​1MHz
      • 最大测量周期:65535μs(对应最小频率≈15.26Hz
      • 最小测量周期:1μs(对应最大频率≈1MHz
        f40 = 1000000 / cc1_value_2; // 周期(μs)转频率(Hz)

         频率测量

        u32 tim2_cnt1 = 0;
        u32 f40 = 0;
        u32 tim3_cnt1 = 0;
        u32 f39 = 0;
        void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
        {if(htim == &htim2){tim2_cnt1 = __HAL_TIM_GetCounter(&htim2);//获取CNT,对应CNT(us)__HAL_TIM_SetCounter(&htim2,0);			// 设置CNT为0,重新开始计时		f40 = 1000000/tim2_cnt1;				//R40的调整的555频率	HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);//开启TIM2_CH1的输入捕获中断}if(htim == &htim3){tim3_cnt1 = __HAL_TIM_GetCounter(&htim3);//获取TIM3的CNT,对应CNT(us)__HAL_TIM_SetCounter(&htim3,0);			// 设置CNT为0,重新开始计时		f39 = 1000000/tim3_cnt1;				//R39的调整的555频率	HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);//开启TIM3_CH1的输入捕获中断}
        }

        频率+占空比测量

        
        uint32_t tim2ch1_cnt1 = 0;
        uint32_t tim2ch1_cnt2 = 0;
        uint32_t tim2ch1_cnt3 = 0;
        uint32_t tim3ch1_cnt1 = 0;
        uint32_t tim3ch1_cnt2 = 0;
        uint32_t tim3ch1_cnt3 = 0;
        uint32_t tim2ch1_HighCnt = 0;
        uint32_t tim2ch1_LowCnt = 0;
        uint32_t tim3ch1_HighCnt = 0;
        uint32_t tim3ch1_LowCnt = 0;
        float tim2ch1_duty = 0.0;
        float tim3ch1_duty = 0.0;
        uint32_t tim2ch1_fre = 0;
        uint32_t tim3ch1_fre = 0;
        int tim2ch1_step = 0;
        int tim3ch1_step = 0;void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
        {if(htim -> Instance == TIM2)//判断是什么定时器{if(htim -> Channel == HAL_TIM_ACTIVE_CHANNEL_1){if(tim2ch1_step == 0){tim2ch1_cnt1 = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);__HAL_TIM_SET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_FALLING);tim2ch1_step = 1;}else if(tim2ch1_step == 1){tim2ch1_cnt2 = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);if(tim2ch1_cnt2 > tim2ch1_cnt1){tim2ch1_HighCnt = tim2ch1_cnt2 - tim2ch1_cnt1;}else if(tim2ch1_cnt2 < tim2ch1_cnt1){tim2ch1_HighCnt = ((0xffff - tim2ch1_cnt1) +tim2ch1_cnt2) + 1; }tim2ch1_step = 2;__HAL_TIM_SET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING);}else if(tim2ch1_step == 2){tim2ch1_cnt3 = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);if(tim2ch1_cnt3 > tim2ch1_cnt2){tim2ch1_LowCnt = tim2ch1_cnt3 - tim2ch1_cnt2;}else if(tim2ch1_cnt3 < tim2ch1_cnt2){tim2ch1_LowCnt = ((0xffff - tim2ch1_cnt2) +tim2ch1_cnt3) + 1; }tim2ch1_step = 0;tim2ch1_fre = (80000000/80)/(tim2ch1_cnt3 - tim2ch1_cnt1);//(tim2ch1_LowCnt+tim2ch1_HighCnt);tim2ch1_duty = 100.0f * tim2ch1_HighCnt / (tim2ch1_LowCnt+tim2ch1_HighCnt);}}}if(htim -> Instance == TIM3)//判断是什么定时器{if(htim -> Channel == HAL_TIM_ACTIVE_CHANNEL_1){if(tim3ch1_step == 0){tim3ch1_cnt1 = HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_1);__HAL_TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_FALLING);tim3ch1_step = 1;}else if(tim3ch1_step == 1){tim3ch1_cnt2 = HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_1);if(tim3ch1_cnt2 > tim3ch1_cnt1){tim3ch1_HighCnt = tim3ch1_cnt2 - tim3ch1_cnt1;}else if(tim3ch1_cnt2 < tim3ch1_cnt1){tim3ch1_HighCnt = ((0xffff - tim3ch1_cnt1) +tim3ch1_cnt2) + 1; }tim3ch1_step = 2;__HAL_TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING);}else if(tim3ch1_step == 2){tim3ch1_cnt3 = HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_1);if(tim3ch1_cnt3 > tim3ch1_cnt2){tim3ch1_LowCnt = tim3ch1_cnt3 - tim3ch1_cnt2;}else if(tim3ch1_cnt3 < tim3ch1_cnt2){tim2ch1_LowCnt = ((0xffff - tim3ch1_cnt2) +tim3ch1_cnt3) + 1; }tim3ch1_step = 0;tim3ch1_fre = (80000000/80)/(tim3ch1_cnt3 - tim3ch1_cnt1);//(tim2ch1_LowCnt+tim2ch1_HighCnt);tim3ch1_duty = 100.0f * tim3ch1_HighCnt / (tim3ch1_LowCnt+tim3ch1_HighCnt);}}}
        }

        法三:

        u32 tim2_cnt1 = 0, tim2_cnt2 = 0;
        u32 f40 = 0;
        float d40 = 0;u32 tim3_cnt1 = 0, tim3_cnt2 = 0;
        u32 f39 = 0;
        float d39 = 0;
        u8 tim2_state = 0;	//0:开始计时,1:获取T1,2:获取T2
        u8 tim3_state = 0;	//0:开始计时,1:获取T1,2:获取T2
        void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
        {if(htim == &htim2){if(tim2_state == 0)							//第一个上升沿产生,开始计时{__HAL_TIM_SetCounter(&htim2,0);			// 设置CNT为0,重新开始计时TIM2->CCER |= 0x02;						//下降沿中断,CC1P置为1tim2_state = 1;							}else if(tim2_state == 1)					//获取T1,并改成上升沿中断{tim2_cnt1 = __HAL_TIM_GetCounter(&htim2);//获取T1(us)TIM2->CCER &= ~0x02;					//上升沿中断,CC1P置为0tim2_state = 2;}else if(tim2_state == 2)					//第二个上升沿中断,获取T2(周期){tim2_cnt2 = __HAL_TIM_GetCounter(&htim2);//获取T2(us)f40 = 1000000/tim2_cnt2;				//R40的调整的555频率	d40 = tim2_cnt1*100.0f/tim2_cnt2;tim2_state = 0;}HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);//开启TIM2_CH1的输入捕获中断}if(htim == &htim3){if(tim3_state == 0)							//第一个上升沿产生,开始计时{__HAL_TIM_SetCounter(&htim3,0);			//设置CNT为0,重新开始计时TIM3->CCER |= 0x02;						//下降沿中断,CC1P置为1tim3_state = 1;							}else if(tim3_state == 1)					//获取T1,并改成上升沿中断{tim3_cnt1 = __HAL_TIM_GetCounter(&htim3);//获取T1(us)TIM3->CCER &= ~0x02;					//上升沿中断,CC1P置为0tim3_state = 2;}else if(tim3_state == 2)					//第二个上升沿中断,获取T2(周期){tim3_cnt2 = __HAL_TIM_GetCounter(&htim3);//获取T2(us)f39 = 1000000/tim3_cnt2;				//R39的调整的555频率	d39 = tim3_cnt1*100.0f/tim3_cnt2;tim3_state = 0;}HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);//开启TIM3_CH1的输入捕获中断}
        }

        其中:
        防止超过cnt缓存区导致计算错误的一段源码:
        if(tim2ch1_cnt2 > tim2ch1_cnt1)
        {
            tim2ch1_HighCnt = tim2ch1_cnt2 - tim2ch1_cnt1;
        }
        else if(tim2ch1_cnt2 < tim2ch1_cnt1)
        {
            tim2ch1_HighCnt = ((0xffff - tim2ch1_cnt1) +tim2ch1_cnt2) + 1; 
        }

        特性​HAL_TIM_ReadCapturedValue()__HAL_TIM_GetCounter()
        ​数据来源​捕获事件锁存的快照值(TIMx_CCRy实时计数器值(TIMx_CNT
        ​是否需要中断​通常在输入捕获中断中使用无需中断,随时读取
        ​硬件依赖​需配置输入捕获通道仅需定时器启动
        ​典型误差场景​未启用捕获通道时返回0计数器溢出时需处理溢出逻辑

        3.定时器

        HAL_TIM_Base_Start_IT(&htim1);
        HAL_TIM_Base_Start(&htim1);
        HAL_TIM_Base_Stop(&htim1);__HAL_TIM_SET_COUNTER(&htim3, 0);  // 重置计数器
        void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
        {if(htim -> Instance == TIM3){}
        }
        

        08 RTC实时时钟

        //RTC
        RTC_TimeTypeDef rtc_time;
        RTC_DateTypeDef rtc_date;
        void RTC_Process()
        {HAL_RTC_GetTime(&hrtc, &rtc_time, RTC_FORMAT_BIN);HAL_RTC_GetDate(&hrtc, &rtc_date, RTC_FORMAT_BIN);
        }

        09 延时函数

        STM32CubeMX | STM32 HAL库方式的微秒延时函数_hal库微秒延时-CSDN博客

        HAL_DELAY():

        10 滴答定时器

        (蓝桥杯)STM32G431RBT6(SysTick timer)_stm32g431rbt6数据手册-CSDN博客

        HAL_SYSTICK_Config(170000000/10000);if(HAL_GetTick()-temCnt>1000){HAL_GPIO_TogglePin (LED1_GPIO_Port,LED1_Pin);temCnt=HAL_GetTick();}

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

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

        相关文章

        案例-索引对于并发Insert性能优化测试

        前言 最近因业务并发量上升,开发反馈对订单表Insert性能降低。应开发要求对涉及Insert的表进行分析并提供优化方案。   一般对Insert 影响基本都在索引,涉及表已按创建日期做了分区表,索引全部为普通索引未做分区索引。 优化建议: 1、将UNIQUE改为HASH(64) GLOBAL IND…

        【技术文章的标准结构与内容指南】

        技术文章的标准结构与内容指南 技术文章是传递专业知识、分享实践经验的重要媒介。一篇高质量的技术文章不仅能够帮助读者解决问题&#xff0c;还能促进技术交流与创新。以下是技术文章通常包含的核心内容与结构指南。 1. 标题 一个好的技术文章标题应当&#xff1a; 简洁明…

        豪越消防一体化安全管控平台:构建消防“一张图”新生态

        在城市化进程加速、建筑规模与功能日益复杂的当下&#xff0c;消防救援工作面临着诸多严峻挑战。火灾隐患如同隐藏在暗处的“定时炸弹”&#xff0c;广泛分布于城市的各个角落&#xff0c;想要快速、精准定位绝非易事。信息传递的不顺畅更是雪上加霜&#xff0c;导致救援效率大…

        重学Redis:Redis常用数据类型+存储结构(源码篇)

        一、SDS 1&#xff0c;SDS源码解读 sds (Simple Dynamic String)&#xff0c;Simple的意思是简单&#xff0c;Dynamic即动态&#xff0c;意味着其具有动态增加空间的能力&#xff0c;扩容不需要使用者关心。String是字符串的意思。说白了就是用C语言自己封装了一个字符串类型&a…

        抖音IP属地可以随便选择地址吗?深度解析

        在当今社交媒体盛行的时代&#xff0c;抖音作为受欢迎的短视频平台之一&#xff0c;其IP属地显示功能引发了广泛关注。许多用户好奇&#xff1a;抖音的IP属地是否可以随意更改&#xff1f;是否存在方法可以“伪装”自己的位置&#xff1f;‌本文将深入探讨这一话题。 一、抖音I…

        SOLID原则详解:提升软件设计质量的关键

        前言 关于设计原则SOLID具体指的是什么&#xff0c;怎么理解这些设计原则&#xff0c;我觉得有必要记录一笔&#xff0c;毕竟这个设计原则确实经常在关键技术文档中提及&#xff0c;在编程思想中提及&#xff0c;在日常的开发中使用&#xff0c;但是对我来说&#xff0c;似乎知…

        如何使用 ONLYOFFICE 恢复之前的文件版本?

        如何使用 ONLYOFFICE 恢复之前的文件版本&#xff1f; https://www.onlyoffice.com/blog/zh-hans/2023/04/how-to-use-version-history

        简简单单实现一个Python+Selenium的自动化测试框架

        什么是Selenium&#xff1f; Selenium是一个基于浏览器的自动化测试工具&#xff0c;它提供了一种跨平台、跨浏览器的端到端的web自动化解决方案。Selenium主要包括三部分&#xff1a;Selenium IDE、Selenium WebDriver 和Selenium Grid。 Selenium IDE&#xff1a;Firefox的…

        Java设计模式之中介者模式:从入门到架构级实践

        一、什么是中介者模式&#xff1f; 中介者模式&#xff08;Mediator Pattern&#xff09;是一种行为型设计模式&#xff0c;其核心思想是通过引入一个中介对象来封装多个对象之间的交互关系。这种模式将原本复杂的网状通信结构转换为星型结构&#xff0c;类似于现实生活中的机…

        Trinity三位一体开源程序是可解释的 AI 分析工具和 3D 可视化

        一、软件介绍 文末提供源码和程序下载学习 Trinity三位一体开源程序是可解释的 AI 分析工具和 3D 可视化。Trinity 提供性能分析和 XAI 工具&#xff0c;非常适合深度学习系统或其他执行复杂分类或解码的模型。 二、软件作用和特征 Trinity 通过结合具有超维感知能力的不同交…

        LeetCode 热题 100_单词拆分(86_139_中等_C++)(动态规划)

        LeetCode 热题 100_单词拆分&#xff08;86_139&#xff09; 题目描述&#xff1a;输入输出样例&#xff1a;题解&#xff1a;解题思路&#xff1a;思路一&#xff08;动态规划&#xff09;&#xff1a; 代码实现代码实现&#xff08;思路一&#xff08;动态规划&#xff09;&a…

        VM虚拟机安装及Ubuntu安装配置

        VM虚拟机安装及Ubuntu安装配置 1、VM虚拟机安装2、创建虚拟机3、Ubuntu系统安装4、编译环境配置4.1 、Ubuntu和 Windows文件互传 文件互传4.1.1、 开启Ubunt下的FTP服务 4.2、 Ubuntu下NFS和SSH服务开启4.2.1、 NFS服务开启4.2.2、 SSH服务开启 4.3、 交叉编译器安装4.3.1 安装…

        【KWDB 创作者计划】_产品技术解读_1

        【KWDB 创作者计划】_产品技术解读_1 一、存储引擎:高性能混合存储架构1. 存储模型设计2. 存储压缩与编码3. 持久化策略二、KWDB 组件源码解析1. 核心模块分层架构2. 关键组件源码剖析三、KWDB 特性代码通读1. 实时分析能力(Real-Time OLAP)2. 混合负载隔离(HTAP)3. 智能索…

        高速电路中的电阻、电容的选型及应用

        2.1 电阻的应用 2.1.1 与电阻相关的经典案例 如果说芯片是电路的骨架&#xff0c;那么电阻就是在芯片之间起连接作用的关节。电阻的阻值、布放位置等&#xff0c;对设计的成功起着至关重要的作用。 【案例2.1】串联电阻过大&#xff0c;导致板间告警失败 某产品由业务板和主…

        springBoot接入文心一言

        文章目录 效果接入步骤项目接入配置类&#xff1a;WenXinYiYan前端vue代码js代码 后端mapper层service层controller层 测试代码 效果 先来看一下最后实现的效果 &#xff08;1&#xff09;未点击前的功能页面 &#xff08;2&#xff09;点击后的页面 &#xff08;3&#xff…

        css解决边框四个角有颜色

        效果 html <div class"gradient-corner">2021年</div>css background:/* 左上角横线 */linear-gradient(90deg, rgb(5, 150, 247) 9px, transparent 0) 0 0,/* 左上角竖线 */linear-gradient(0deg, rgb(5, 150, 247) 9px, transparent 0) 0 0,/* 右上…

        自动化三维扫描:CASAIM外观尺寸智能检测

        制造业向智能化、数字化加速转型&#xff0c;传统检测方式因效率低、精度差、数据断层等问题&#xff0c;已难以满足现代工业对精密测量与实时质控的需求。CASAIM依托前沿技术实力&#xff0c;以自动化三维扫描为核心&#xff0c;为工业检测提供了从数据采集到智能分析的全流程…

        突破亚马逊壁垒,Web Unlocker API 助您轻松获取数据

        目录 一、Web Unlocker API简介二、开始使用Web Unlocker API1、首先进入控制台页面&#xff0c;点击左侧第一个tab键“代理 & 抓取基础设施”&#xff0c;找到“网页解锁器”&#xff0c;开始使用。2、进入网页解锁器页面后&#xff0c;填写通道名称&#xff0c;添加简短描…

        【力扣05】最长回文子串

        0. 引言 ●子串(substring&#xff09;&#xff1a;原始字符串的一个连续子集; ●子序列&#xff08;subsequence&#xff09;&#xff1a;原始字符串的一个子集。 1. 什么叫回文串&#xff1f; 如果一个字符串正着读和反着读是一样的&#xff0c;那它就是回文串。[1] 例如&…

        统计销量前十的订单

        传入参数&#xff1a; 传入begin和end两个时间 返回参数 返回nameList和numberList两个String类型的列表 controller层 GetMapping("/top10")public Result<SalesTop10ReportVO> top10(DateTimeFormat(pattern "yyyy-MM-dd") LocalDate begin,Dat…