个人笔记,不扭扭捏捏,一口气到位。方便自己也方便大家
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型号兼容性处理
支持两种控制器:uC8230
和ILI932X
系列(通过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-D15 | PC0-PC15 | 数据总线 |
CS | PB9 | 片选信号 |
WR | PB8 | 写使能 |
RD | PB5 | 读使能 |
RS | PA8 | 命令/数据选择 |
LCD_Init();//初始化
LCD_SetBackColor(Black);//设置背景颜色
LCD_SetTextColor(White);//设置文字颜色
LCD_Clear(Black);//刷新屏幕
05 ADC与DAC
1.ADC
ADC通道分配表(外部通道)
GPIO引脚 | 对应ADC模块及通道 | 复用功能备注 |
---|---|---|
PB15 | ADC2_IN15 | …… |
PB12 | ADC1_IN11 | …… |
PB14 | ADC1_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_CCx , ContinuousConvMode=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博客
-
核心功能:
- MCP4017是一个数字控制的可变电阻,通过I2C接口调节电阻值(0-10kΩ,128级可调0-127)。
N值(十进制) 阻值(Ω) 电压分压值(VDD=3.3V) 0 0 0V 64 50.4k 2.45V 127(0x7F) 100k 3.0V(实际约2.9V) - 相当于一个“电子滑动变阻器”,程序可以动态改变其阻值,无需手动调节。
- 阻值计算公式
- MCP4017是一个数字控制的可变电阻,通过I2C接口调节电阻值(0-10kΩ,128级可调0-127)。
- 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();}