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输出高电平,熄灭LED
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);	//打开锁存器
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);	//关闭锁存器
	
	//根据led_ctrl来点亮对应的LED
	HAL_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) | 0xf0

u8 Trg;	 	 // 全局变量,单次触发
u8 Cont; 	 // 全局变量,长按
void Key_Read(void)
{
    u8 ReadData = (KEYPORT)^0xff;   		   // 1
    Trg = 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;  // 通道5
        volt_r38 = adc_values[1] / 4096.0f * 3.3f;  // 通道11
    
    DMA模式(连续触发)​:
        // 全局变量
        uint16_t adc1_dma_buffer[2];  // 存储ADC1两个通道的数据
        // 初始化中启动DMA
        HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc1_dma_buffer, 2);
    
        // DMA自动更新adc1_dma_buffer数组
        volt_mcp = adc1_dma_buffer[0] / 4096.0f * 3.3f;  // 通道5
        volt_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 --> 1365
      	HAL_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 --> 2730
      	HAL_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);//A7
        TIM17->ARR = 499;	// 周期是500us,对应频率2kHz
        TIM17->CCR1 = 400; // 80%占空比
        
        MX_TIM16_Init();
        HAL_TIM_PWM_Start(&htim16,TIM_CHANNEL_1);//A6
        TIM16->ARR = 49;	// 周期是50us,对应频率20kHz
        TIM16->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置为1
        			tim2_state = 1;							
        		}
        		else if(tim2_state == 1)					//获取T1,并改成上升沿中断
        		{
        			tim2_cnt1 = __HAL_TIM_GetCounter(&htim2);//获取T1(us)
        			TIM2->CCER &= ~0x02;					//上升沿中断,CC1P置为0
        			tim2_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置为1
        			tim3_state = 1;							
        		}
        		else if(tim3_state == 1)					//获取T1,并改成上升沿中断
        		{
        			tim3_cnt1 = __HAL_TIM_GetCounter(&htim3);//获取T1(us)
        			TIM3->CCER &= ~0x02;					//上升沿中断,CC1P置为0
        			tim3_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();
        	  }

        评论
        添加红包

        请填写红包祝福语或标题

        红包个数最小为10个

        红包金额最低5元

        当前余额3.43前往充值 >
        需支付:10.00
        成就一亿技术人!
        领取后你会自动成为博主和红包主的粉丝 规则
        hope_wisdom
        发出的红包
        实付
        使用余额支付
        点击重新获取
        扫码支付
        钱包余额 0

        抵扣说明:

        1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
        2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

        余额充值