STM32的定时器
定时器的介绍
介绍:STM32F103C8T6微控制器内部集成了多种类型的定时器,这些定时器在嵌入式系统中扮演着重要角色,用于计时、延时、事件触发以及PWM波形生成、脉冲捕获等应用。
*几种定时器(STM32F103系列):
高级定时器(1) | 通用定时器(3) | 看门口(2) | 滴答定时器(1) |
TIM1:
| TIM2、TIM3和TIM4:
| 2 个看门狗定时器 ( 独立的和窗口型的 ) | 系统时间定时器: 24 位自减型计数器 |
定时器的工作原理
定时器的核心:计数器
每个定时器都由一个16位计数器、预分频器和自动重装寄存器的时基单元组成。预分频器可以对时钟进行分频,计数器则对预分频后的时钟进行计数。当计数器的值达到设定值时,会触发中断,从而执行相应的定时任务。
注意事项:设置预分频器系数(PSC)和自动重装值(ARR)
- 代码PSC写 0,实际:分频系数是1(不分频);PSC写1,分频系数是2(2分频);
- 代码ARR写65536-1,实际是2^16 = 65536。
三种定时器的介绍
类型 | 编号 | 总线 | 功能 |
高级定时器(本章先不介绍) | TIM1、TIM8 | APB2 | 拥有通用定时器全部功能,并额外具有重复计数器、死区生 成、互补输出、刹车输入(三项无刷电机的特供:foc)等功能;-------三种计数模式。 |
通用定时器 | TIM2、TIM3、TIM4、TIM5 | APB1 | 拥有基本定时器全部功能,并额外具有 内外时钟源选择 、 输入捕获、输出比较 、 PWM 或 脉冲计数的通道 、 编码器接口、主从触发模式等功能;------三种计数模式。 |
基本定时器(这个芯没有) | TIM6、TIM7 | APB1 | (时基)拥有定时中断、主模式触发 DAC(绕过CPU) 的功能。------只支持向上计数。 |
- 定时器都是72MHz
定时器的框图
(参考手册中)
- 基本定时器
- 通用定时器
- 简图:
- 高级定时器:
- 通用定时器时钟的来源
简图:
框图:
定时器的计数模式
计数模式 | 计数器溢出值 | 计数器重装值 |
向上计数 | CNT = ARR | CNT = 0 |
向下计数 | CNT = 0 | CNT = ARR |
中心对齐计数 | CNT = ARR - 1 CNT = 1 | CNT = ARR CNT = 0 |
定时器溢出时间
说明:
Tout:定时器溢出时间;Ft:定时器的时钟源频率;
ARR:自动重装载寄存器的值;PSC:预分频器寄存器的值。
举例:要定时500ms,PSC、ARR、Ft的值是多少?
答:PSC = 7199,ARR = 4999,Ft = 72M。
(当频率大时,记一个数的时间短,ARR的值会变大;当频率小时,记一个数的时间短,ARR的值小)。
定时器寄存器
时基单元寄存器
- 预分频寄存器( TIMx_PSC)-16位
- 自动重装载寄存器( TIMx_ARR)-16位
- DMA/中断使能寄存器 (TIMx_DIER)
第 0 位, 该位是更新中断允许位, 当定时器的更新中断,该位要设置为 1,来允许由于更新事件所产生的中断。
- 状态寄存器( TIMx_SR)
该寄存器用来标记当前与定时器相关的各种事件/中断是否发生。
输入捕获/输出比较寄存器
- 捕获/比较寄存器( TIMx_CCR1~4)
该寄存器用来存储捕获发生时, TIMx_CNT的值,我们从 TIMx_CCR1 就可以读出通道 1 捕获发生时刻的 TIMx_CNT 值,通过两次捕获(一次上升沿捕获,一次下降沿捕获)的差值,就可以计算出高电平脉冲的宽度。
捕获/比较模式寄存器( TIMx_CCMRx)
- TIMx_CCMR1(模式寄存器1):控制通道1和通道2
TIMx_CCMR1 是针对 2 个通道的配置,低八位[7:0]用于捕获 / 比较通道 1 的控制,而高八位[15:8]则用于捕获 / 比较通道 2 的控制。
- TIMx_CCMR2(模式寄存器2):控制通道3和通道4
四个通道的模式寄存器一样,重点介绍 TIMx_CMMR1 的[7:0]位:
输入捕获
输出比较
捕获/比较使能寄存器( TIMx_CCER)
- TIMx_CCER(捕获/比较使能寄存器)
定时器中断实验配置步骤
定时器中断的函数
中断服务公共函数
更新中断的回调函数
其他中断回调函数
设置PSC值的函数:
设置/读取 ARR值的函数 :
小实验:定时器中断点灯
实验目的:使用定时器TIM2进行中断点灯,500msLED灯翻转一次。
硬件清单:上官二号、ST-Link。
- timer.c文件代码
#include "timer.h"
#include "led.h"TIM_HandleTypeDef time_hander = {0}; //定义一个全局结构体变量,结构体成员附一个默认值0。//时基单元初始化函数和中断公共回调函数中使用。
//定时器的时基单元初始化函数
void timer_base_init(uint16_t psc ,uint16_t arr){time_hander.Instance = TIM2;time_hander.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; //设置的是影子寄存器,是否自动重装载。time_hander.Init.CounterMode = TIM_COUNTERMODE_UP;time_hander.Init.Prescaler = psc;time_hander.Init.Period = arr;HAL_TIM_Base_Init(&time_hander);HAL_TIM_Base_Start_IT(&time_hander); //打开时钟和使能中断}
//msp函数:初始化MCU相关的硬件,例如:GPIO,NVIC,CLOCK
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim){ //这个函数在HAL_TIM_Base_Init()中调用if(htim->Instance == TIM2){ //先判断这个是不是TIM2定时器占用。__HAL_RCC_TIM2_CLK_ENABLE();HAL_NVIC_SetPriority(TIM2_IRQn,2,2);HAL_NVIC_EnableIRQ(TIM2_IRQn);}
}
//中断服务函数
void TIM2_IRQHandler(void){//中断公共处理的函数HAL_TIM_IRQHandler(&time_hander);
}
//更新中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){ //据饼if(htim->Instance == TIM2){ //判断这个回调函数是否被其他定时器占用。led1_toggle();}
}
- time.h文件代码:
#ifndef __TIMER_H__
#define __TIMER_H__#include "stm32f1xx.h"void timer_base_init(uint16_t psc ,uint16_t arr);#endif
- main.c文件代码
#include "sys.h"
#include "led.h"
#include "delay.h"
#include "timer.h"int main(void)
{HAL_Init(); /* 初始化HAL库 */stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */led_init(); /* LED初始化 */timer_base_init(7200-1,5000-1); //500ms产生一次中断while(1){ }
}
输出比较
简介
输出比较可以通过比较定时计数器的值 CNT 与设定的比较值 CCR,可以控制输出引脚的电平状态(置高或置低),从而实现生成一定频率和占空比的 PWM 波形。
简图:
框图(参考手册) :
PWM模式:
PWM介绍
定义:PWM波形(Pulse Width Modulation,脉冲宽度调制波形)是一种占空比可变的脉冲波形。这种调制方式通过改变脉冲的宽度来控制电路中的信号强度和频率。具体来说,PWM波形中的高电平持续时间和低电平持续时间可以根据需要进行调整,从而实现对模拟信号电平的数字编码。
应用:PWM波形在各种领域都有广泛的应用,包括电源管理、电机控制、LED亮度调节等。此外,生成PWM波形的方法有多种,例如使用波形发生器、单片机或可编程逻辑器件等。
相关参数:
频率:1/Ts(定时器计数溢出的时间);
占空比:Ton / Ts(高电平占整个周期的比例,单位%);
分辨率:占空比变化步距。例:占空比50%,51%;分辨率:1%。分辨率越低对硬件的要求越高。
PWM相关的函数
宏函数: 修改CRR寄存器的值
输出比较的引脚
- TIM1_CHx(x:1、2、3、4)
- TIM2_CHx(x:1、2、3、4)
- TIM3_CHx(x:1、2、3、4)
- TIM4_CHx(x:1、2、3、4)
定时器输出PWM波配置步骤
根据上面简图配置:
小实验:呼吸灯实验
实验目的:使用 定时器4 通道3(看引脚定义表:PB8引脚)生成 PWM 波控制 LED1 ,实现呼吸灯效果。
- 频率:2kHz。根据定时器溢出时间计算:PSC=71,ARR=499。
硬件清单:开发板、ST-Link。
- pwm.c文件代码
#include "pwm.h"TIM_HandleTypeDef pwm_handle = {0};
void pwm_init(uint16_t psc,uint16_t arr){pwm_handle.Instance = TIM4;pwm_handle.Init.CounterMode = TIM_COUNTERMODE_UP;pwm_handle.Init.Period = arr;pwm_handle.Init.Prescaler = psc;pwm_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;HAL_TIM_PWM_Init(&pwm_handle);//pwm模式和crr寄存器设置TIM_OC_InitTypeDef tim_oc_initstruct = {0};tim_oc_initstruct.OCMode = TIM_OCMODE_PWM1; //pwm的模式tim_oc_initstruct.OCPolarity = TIM_OCPOLARITY_LOW; //高电平有效还是低电平;led灯是低电平点亮,故低电平有效tim_oc_initstruct.Pulse = arr/2; //占空比CCR的值,这里随便填,后面crr修改函数HAL_TIM_PWM_ConfigChannel(&pwm_handle,&tim_oc_initstruct,TIM_CHANNEL_3);//使能输出,启动计时器HAL_TIM_PWM_Start(&pwm_handle,TIM_CHANNEL_3);
}
//初始化msp函数
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim){if(htim ->Instance == TIM4){ //判断这个函数是否被定时器4占用__HAL_RCC_TIM4_CLK_ENABLE(); //打开定时器4的时钟__HAL_RCC_GPIOB_CLK_ENABLE(); //打开GPIO口的时钟GPIO_InitTypeDef gpio_initstruct;gpio_initstruct.Mode = GPIO_MODE_AF_PP; //复用推挽输出,看GPIO口定义表gpio_initstruct.Pin = GPIO_PIN_8;gpio_initstruct.Pull = GPIO_PULLUP;gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOB,&gpio_initstruct);}
}
//修改crr的值的函数
void pwm_cmpare_set(uint16_t value){__HAL_TIM_SET_COMPARE(&pwm_handle,TIM_CHANNEL_3,value);
}
- pwm.h文件代码
#ifndef __PWM_H__
#define __PWM_H__
#include "stm32f1xx.h"void pwm_init(uint16_t psc,uint16_t arr);
void pwm_cmpare_set(uint16_t value);#endif
main.c文件代码
#include "sys.h"
#include "led.h"
#include "delay.h"
#include "pwm.h"int main(void)
{HAL_Init(); /* 初始化HAL库 */stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */led_init(); /* LED初始化 */pwm_init(72-1,500-1);//在while函数中不停的修改CRR的值,来实现占空比不断改变while(1){ for(uint16_t i = 0;i<300;i++){pwm_cmpare_set(i);delay_ms(5);}for(uint16_t i = 0;i<300;i++){pwm_cmpare_set(300-i);delay_ms(5);}}
}
写这个代码遇到的问题:
- 调用函数时要注意:DeInit函数和init函数。
- 根据引脚定义表,输出比较口对应哪一个GPIO口。
- 关于外设GPIO口的配置:(参考手册110)
输入捕获
简介
输入捕获模式可以用来 测量脉冲宽度 或者 测量频率。STM32 的定时器,除了 TIM6 和 TIM7,其他定时器都有输入捕获功能。 STM32 的输入捕获,简单的说就是通过检测 TIMx_CHx 上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的通道的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。同时还可以配置捕获时是否触发中断/DMA 等。
框图:(参考手册253)
输入捕获引脚
- 和上面输出比较的引脚相同,参考上面输出比较引脚
输入捕获相关函数
在输入捕获的时基单元里的定时器的使能更新中断的函数:
捕获回调函数:
读取输入捕获中CCR的值:
清除/设置 捕获的通道极性:
关闭定时器:
设置计数器的值 :
获取计数器的值:
定时器输入捕获实验步骤配置
小实验:测量按键按下的时长(测量脉冲宽度)
实验目的:使用定时器 2 通道 2 (PA1)来捕获 按键 2 (PA1)按下时间,并通过串口打印。
- 计一个数的时间:1us,PSC=71,ARR=65535
- 下降沿捕获、输入通道 2 映射在 TI2 上、不分频、不滤波。
硬件清单:开发板、ST-Link、USB转TTL
思路:
输入捕获回调函数中的流程图:
拓展:串口打印功能
- 利用串口调试助手:
- 引脚接线:
USB转TTL | 开发板(型号不同,引脚不同) |
TXD | RX1(PA10) |
RXD | TX1(PA9) |
GND | GND |
- 相关代码和配置:
注意事项:
- 代码中的波特率要和串口助手中的波特率设置的相同,例如:9600 或 115200;
- 上述代码中设置错了!!!
实验1:捕获一次下降沿
- ic.c代码文件
#include "ic.h"
#include "stdio.h"TIM_HandleTypeDef ic_handle = {0};
//初始化时基单元
void ic_init(uint16_t psc,uint16_t arr){ic_handle.Instance = TIM2;ic_handle.Init.Period = arr;ic_handle.Init.Prescaler = psc;ic_handle.Init.CounterMode = TIM_COUNTERMODE_UP;HAL_TIM_IC_Init(&ic_handle);//输入通道的配置TIM_IC_InitTypeDef ic_initstruct = {0};ic_initstruct.ICFilter = 0; //滤波ic_initstruct.ICPolarity = TIM_ICPOLARITY_FALLING; //输入极性的判断ic_initstruct.ICPrescaler = TIM_ICPSC_DIV1; //分频系数:这里不分频ic_initstruct.ICSelection = TIM_ICSELECTION_DIRECTTI; //输入通道选择,还有TRC输入口HAL_TIM_IC_ConfigChannel(&ic_handle,&ic_initstruct,TIM_CHANNEL_2);//打开计数器,是能更新中断,输入捕获中断__HAL_TIM_ENABLE_IT(&ic_handle,TIM_IT_UPDATE);HAL_TIM_IC_Start_IT(&ic_handle,TIM_CHANNEL_2);
}//初始化msp函数
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim){if(htim->Instance == TIM2){//打开时钟__HAL_RCC_TIM2_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();//初始化GPIO口GPIO_InitTypeDef gpio_initstruct;gpio_initstruct.Mode = GPIO_MODE_INPUT;gpio_initstruct.Pin = GPIO_PIN_1;gpio_initstruct.Pull = GPIO_PULLUP;gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA,&gpio_initstruct);//初始化NVICHAL_NVIC_SetPriority(TIM2_IRQn,2,2);HAL_NVIC_EnableIRQ(TIM2_IRQn);}
}//中断服务函数
void TIM2_IRQHandler(void){HAL_TIM_IRQHandler(&ic_handle);
}
//捕获中断的回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){ printf("下降沿触发\n");
}
- ic.h文件代码
#ifndef __IC_H__
#define __IC_H__
#include "stm32f1xx.h"void ic_init(uint16_t psc,uint16_t arr);#endif
- main.c文件代码
#include "sys.h"
#include "led.h"
#include "delay.h"
#include "uart1.h"
#include "ic.h"int main(void)
{HAL_Init(); /* 初始化HAL库 */stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */led_init(); /* LED初始化 */uart1_init(115200); //初始化串口。设置波特率115200printf("hello,world!!!\n"); //打印到串口助手ic_init(72-1,65536-1); //设置中断溢出时长while(1){ led1_on();led2_off();delay_ms(500);led1_off();led2_on();delay_ms(500);}
}
实验2:捕获一次完整的按键,并打印出按键按下的时长
- ic.h文件代码
- 根据上面流程图,写捕获中断的回调函数
#include "ic.h"
#include "stdio.h"
#include "string.h"struct {uint8_t falling_flag;uint8_t success_flag;uint16_t timeout_cnt;
}capture_status = {0};uint16_t time_cnt = 0;TIM_HandleTypeDef ic_handle = {0};
//初始化时基单元
void ic_init(uint16_t psc,uint16_t arr){ic_handle.Instance = TIM2;ic_handle.Init.Period = arr;ic_handle.Init.Prescaler = psc;ic_handle.Init.CounterMode = TIM_COUNTERMODE_UP;HAL_TIM_IC_Init(&ic_handle);//输入通道的配置TIM_IC_InitTypeDef ic_initstruct = {0};ic_initstruct.ICFilter = 0; //滤波ic_initstruct.ICPolarity = TIM_ICPOLARITY_FALLING; //输入极性的判断ic_initstruct.ICPrescaler = TIM_ICPSC_DIV1; //分频系数:这里不分频ic_initstruct.ICSelection = TIM_ICSELECTION_DIRECTTI; //输入通道选择,还有TRC输入口HAL_TIM_IC_ConfigChannel(&ic_handle,&ic_initstruct,TIM_CHANNEL_2);//打开计数器,是能更新中断,输入捕获中断__HAL_TIM_ENABLE_IT(&ic_handle,TIM_IT_UPDATE); //使能更新中断HAL_TIM_IC_Start_IT(&ic_handle,TIM_CHANNEL_2); //打开计时器,并使能捕获中断
}//初始化msp函数
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim){if(htim->Instance == TIM2){//打开时钟__HAL_RCC_TIM2_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();//初始化GPIO口GPIO_InitTypeDef gpio_initstruct;gpio_initstruct.Mode = GPIO_MODE_INPUT;gpio_initstruct.Pin = GPIO_PIN_1;gpio_initstruct.Pull = GPIO_PULLUP;gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA,&gpio_initstruct);//初始化NVICHAL_NVIC_SetPriority(TIM2_IRQn,2,2);HAL_NVIC_EnableIRQ(TIM2_IRQn);}
}//中断服务函数
void TIM2_IRQHandler(void){HAL_TIM_IRQHandler(&ic_handle);
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){
// printf("下降沿触发\n");if(capture_status.success_flag == 0){if(capture_status.falling_flag == 1){printf("上升沿捕获\n");capture_status.success_flag =1;time_cnt = HAL_TIM_ReadCapturedValue(&ic_handle,TIM_CHANNEL_2);//获取计数器的值TIM_RESET_CAPTUREPOLARITY(&ic_handle,TIM_CHANNEL_2); //清除捕获通道TIM_SET_CAPTUREPOLARITY(&ic_handle,TIM_CHANNEL_2,TIM_ICPOLARITY_FALLING); //设置为下降沿捕获}else{printf("下降沿捕获\n");capture_status.falling_flag = 1;capture_status.timeout_cnt = 0;__HAL_TIM_DISABLE(&ic_handle);__HAL_TIM_SetCounter(&ic_handle,0); //计数器的值清零TIM_RESET_CAPTUREPOLARITY(&ic_handle,TIM_CHANNEL_2); //清除通道设置TIM_SET_CAPTUREPOLARITY(&ic_handle,TIM_CHANNEL_2,TIM_ICPOLARITY_RISING); //设置为上升沿捕获__HAL_TIM_ENABLE(&ic_handle);}}
}
//定时器定时中断的回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){if(htim ->Instance == TIM2){//判断是否完成按键if(capture_status.falling_flag == 1) //判断是否捕获到下降沿capture_status.timeout_cnt ++; }
}//定义一个函数,打印按键按下的时间
void pressed_time_get(void){if(capture_status.success_flag == 1){printf("按下时间:%lf s \n",((double)capture_status.timeout_cnt*65536+time_cnt)/1000000);memset(&capture_status,0,sizeof(capture_status));}}
- ic.h文件代码
#ifndef __IC_H__
#define __IC_H__
#include "stm32f1xx.h"void ic_init(uint16_t psc,uint16_t arr);
void pressed_time_get(void);
#endif
- main.c文件代码
#include "sys.h"
#include "led.h"
#include "delay.h"
#include "uart1.h"
#include "ic.h"int main(void)
{HAL_Init(); /* 初始化HAL库 */stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */led_init(); /* LED初始化 */uart1_init(115200);printf("hello,world!!!\n");ic_init(72-1,65536-1);while(1){ pressed_time_get();}
}
要解决的问题:
- 结构体中声明多个标志位。
- 用到的函数。
- 为什么要写到while函数中。
脉冲计数
简介
脉冲计数相关的函数
初始化函数
打开捕获定时器
定时器从模式的配置:通道、滤波、边沿捕获、映射
获取CNT的值
脉冲计数实验步骤配置
根据上面的框图:
小实验:脉冲计数实验 (测量频率)
实验目的:将定时器 2 通道 2 输入(PA1)的低电平脉冲(按下按键2 PA1)作为定时器 2 的时钟,并通过串口打印脉冲数。
- PSC=1-1,ARR=65536-1
- 外部时钟模式1、触发选择:下降沿触发、不分频、不滤波
实验清单:开发板、ST-Link、USB转TTL
实验思路:
- 初始化时基单元;
- 配置输入通道,从模式:时钟模式1;
- msp函数初始化GPIO口、CLOCK、NVIC;
- 打开计数器;
- 获取计数器的值并进行打印。
- counter.c文件代码
#include "counter.h"
#include "stdio.h"TIM_HandleTypeDef counter_handle = {0};void counter_init(uint16_t psc,uint16_t arr){//初始化时基单元counter_handle.Instance = TIM2;counter_handle.Init.Prescaler = psc;counter_handle.Init.Period = arr;counter_handle.Init.CounterMode = TIM_COUNTERMODE_UP;counter_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;HAL_TIM_IC_Init(&counter_handle);//配置输入通道(从模式)TIM_SlaveConfigTypeDef counter_initstruct;counter_initstruct.TriggerFilter = 0; //滤波器counter_initstruct.TriggerPolarity = TIM_TRIGGERPOLARITY_FALLING; //极性的选择:上升沿或下降沿counter_initstruct.SlaveMode = TIM_SLAVEMODE_EXTERNAL1; //从模式的选择counter_initstruct.InputTrigger = TIM_TS_TI2FP2; //输入的通道。counter_initstruct.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1; //分频:这里用不到HAL_TIM_SlaveConfigSynchro(&counter_handle,&counter_initstruct);//使能中断和打开时钟HAL_TIM_IC_Start(&counter_handle,TIM_CHANNEL_2);
}//msp配置mcu外设
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim){ //这是个公用的函数,用的时候要进行判断是否被占用if(htim->Instance == TIM2){//打开时钟__HAL_RCC_TIM2_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();//初始化GPIO口GPIO_InitTypeDef gpio_initstruct;gpio_initstruct.Pin = GPIO_PIN_1;gpio_initstruct.Mode = GPIO_MODE_INPUT;gpio_initstruct.Pull = GPIO_NOPULL;gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA,&gpio_initstruct);}
}//获取计数器的值
uint16_t Ncounter_num = 0;
uint16_t Ocounter_num = 0;
void counter_get(void){Ncounter_num = __HAL_TIM_GetCounter(&counter_handle);
//避免在while循环中一直打印计数器的值,设置打印的条件:计数器的值是否发生变化。if(Ncounter_num != Ocounter_num){printf("计数器的值:%d\n",Ncounter_num);Ocounter_num = Ncounter_num;}
}
- counter.h文件代码
#ifndef __COUNTER_H__
#define __COUNTER_H__#include "stm32f1xx.h"
void counter_init(uint16_t psc,uint16_t arr);
void counter_get(void);
#endif
- main.c文件代码
#include "sys.h"
#include "led.h"
#include "delay.h"
#include "uart1.h"
#include "counter.h"int main(void)
{HAL_Init(); /* 初始化HAL库 */stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */led_init(); /* LED初始化 */uart1_init(115200);printf("hello,world!!!\n");counter_init(1-1,65536-1);while(1){ counter_get();}
}
- 结果:
遇到的问题和注意事项:
- main.c文件中的波特率要和串口助手的波特率相同。
- 在counter.c文件中声明函数获取计数器的值时,要进行条件编译,不然会在主函数while循环中,一直打印。 (给打印函数一个条件)
- 要使能输入和打开计数器。这个函数没有捕获中断。
相关文章:
STM32的定时器
定时器的介绍 介绍:STM32F103C8T6微控制器内部集成了多种类型的定时器,这些定时器在嵌入式系统中扮演着重要角色,用于计时、延时、事件触发以及PWM波形生成、脉冲捕获等应用。 *几种定时器(STM32F103系列)࿱…...
ubuntu-PyQt5安装+PyCharm配置QtDesigner + QtUIC
个人环境 ubuntu22.04 pycharm 2024.3 python 3.10 1)先使用apt命令在线安装 1)sudo apt install pyqt5* 2)sudo apt install qttools5-dev-tools2)Pycharm配置Pycharm External Tool 在设置—工具——外部工具中 配置QtDesigner Name :QtDesigne…...
测试基础笔记第十九天
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、接口的概念二、接口的类型三、接口测试1.概念2.原理:3.特点:4.实现方式:5.什么是自动化接口测试? 二、HTTP协议1.HTTP协议简介2.URL格式…...
Ubuntu 系统上广受好评的浏览器推荐
日常使用与开发者首选 Firefox 特点:开源、隐私保护强大,支持丰富扩展(如开发者工具、广告拦截),默认预装且跨平台兼容368。 适用场景:日常浏览、开发者调试(支持实时 CSS/JS 编辑)、…...
第 13 届蓝桥杯 C++ 青少组省赛中 / 高级组真题解析
一、选择题 第 1 题 题目:下列关于类中声明的变量描述正确的是 ( )。 选项: A. 只属于该类 B. 属于全局变量 C. 任何情况下都可被该类所有实例共享 D. 属于该类,某些情况下也可被该类不同实例所共享 答案:D 解析&…...
Win10下安装Linux-Ubuntu24.04双系统
0 引言 Ubuntu 24.04 LTS(代号“Noble Numbat”)是 Canonical 于 2024 年 4 月 25 日发布的第 10 个长期支持版本,专注于性能优化、企业安全和开发者体验提升 Windows 10 是微软于 2015 年 7 月发布的跨平台操作系统,融合了传统桌…...
express 怎么搭建 WebSocket 服务器
一:使用 express-ws var express require(express); var app express(); var expressWs require(express-ws)(app);app.use(function (req, res, next) {console.log(middleware);req.testing testing;return next(); });app.get(/, function(req, res, next){…...
模型部署——cuda编程入门
CUDA中的线程与线程束 kernel是在device上线程中并行执行的函数,核函数用__global__符号声明,在调用时需要用<<<grid_size, block_size>>>来指定kernel要执行的线程数量。在CUDA中,每一个线程都要执行核函数,并…...
llfc项目TCP服务器笔记
ChatServer 一个TCP服务器必然会有连接的接收,维持,收发数据等逻辑。那我们就要基于asio完成这个服务的搭建。主服务是这个样子的 #include "LogicSystem.h"#include <csignal>#include <thread>#include <mutex>#include "AsioIOServiceP…...
NPP库中libnppi模块介绍
1. libnppi 模块简介 libnppi 是 NPP 库中专门用于 图像处理 的模块,提供高度优化的 GPU 加速函数,支持: 图像滤波(卷积、形态学操作) 几何变换(旋转、缩放、透视变换) 颜色空间转换…...
从头训练小模型: 3 传统RLHF与DPO的区别
这个步骤我其实是忽略了。如果我的目标是建立一个安全领域的模型,我个人理解这步骤并不太必要。关于人类偏好对齐:在前面的训练步骤中,模型已经具备了基本的对话能力。 此时模型还不知道什么是好的回答,什么是不好的回答。我们希…...
Python-Django系列—视图
一、通用显示视图 以下两个基于类的通用视图旨在显示数据。在许多项目中,它们通常是最常用的视图。 1、DetailView class django.views.generic.detail.DetailView 当该视图执行时,self.object 将包含该视图正在操作的对象。 祖先(MRO&a…...
el-input Vue 3 focus聚焦
https://andi.cn/page/622173.html...
动态规划(5)路径问题--剑指offer -珠宝的最大值
题目: 现有一个记作二维矩阵 frame 的珠宝架,其中 frame[i][j] 为该位置珠宝的价值。拿取珠宝的规则为: 只能从架子的左上角开始拿珠宝每次可以移动到右侧或下侧的相邻位置到达珠宝架子的右下角时,停止拿取 注意࿱…...
ZArchiver正版:高效文件管理,完美解压体验
在使用安卓设备的过程中,文件管理和压缩文件的处理是许多用户常见的需求。无论是解压下载的文件、管理手机存储中的文件,还是进行日常的文件操作,一款功能强大且操作简便的文件管理工具都能极大地提升用户体验。今天,我们要介绍的…...
Netlink在SONiC中的应用
Netlink在SONiC中的应用 Netlink介绍 Netlink 是 Linux 内核态程序与用户空间程序之间进行通信的机制之一,原本是用于传递网络协议栈中的各种控制消息。它采用和套接字(socket)编程接口相同的形式,常用于配置内核网络子系统&…...
ReentrantLock实现公平锁和非公平锁
在 Java 里,公平锁和非公平锁是多线程编程中用于同步的两种锁机制,它们的主要差异在于获取锁的顺序规则。下面是对二者的详细介绍: 公平锁 公平锁遵循 “先来先服务” 原则,也就是线程获取锁的顺序和请求锁的顺序一致。先请求锁…...
【C++】 —— 笔试刷题day_25
一、笨小猴 题目解析 这道题,给定一个字符str,让我们找到这个字符串中出现次数最多字母的出现次数maxn和出现次数最少字母的出现次数minn; 然后判断maxn - minn是否是一个质数,如果是就输出Lucky Word和maxn - minn;如…...
terraform resource创建了5台阿里云ecs,如要使用terraform删除其中一台主机,如何删除?
在 Terraform 中删除阿里云 5 台 ECS 实例中的某一台,具体操作取决于你创建资源时使用的 多实例管理方式(count 或 for_each)。以下是详细解决方案: 方法一:使用 for_each(推荐) 如果创建时使…...
Office 三大组件Excel、Word、Access 里 VBA 区别对比
以下是Excel、Word和Access在VBA中的主要区别对比及详细说明: 核心对象模型 Excel Workbook(工作簿)→ Worksheet(工作表)→ Range(单元格区域) 核心围绕单元格数据处理,如 Cells(1,1).Value = "数据" Word Document(文档)→ Range(文本范围)→ Paragrap…...
Linux 进程基础(二):操作系统
目录 一、什么是操作系统:用户和电脑之间的「翻译官」🌐 OS 的层状结构🧩 案例解析:双击鼠标的「跨层之旅」 二、操作系统的必要性探究:缺乏操作系统的环境面临的挑战剖析🔑 OS 的「管理者」属性࿱…...
Java高并发处理核心技术详解:从理论到实战
高并发处理能力是衡量系统性能的重要指标。Java作为企业级开发的主力语言,提供了丰富的并发编程工具和框架。 一、Java并发基础 1.1 Java内存模型(JMM) 主内存与工作内存:每个线程拥有独立的工作内存,通过JMM协议与主…...
单细胞测序数据分析试验设计赏析(二)
单细胞测序数据分析试验设计赏析(二) 这次的单细胞测序数据分析的试验设计是单细胞测序分析机器学习(with SHAP分析),也是常见的试验设计之一,重点是可以用于筛选鉴定基因调控网络,也可以是构建…...
Docker 服务搭建
💢欢迎来到张翊尘的开源技术站 💥开源如江河,汇聚众志成。代码似星辰,照亮行征程。开源精神长,传承永不忘。携手共前行,未来更辉煌💥 文章目录 Docker 服务搭建在 Ubuntu 上安装 Docker更新软件…...
4电池_基于开关电容的均衡
基于开关电容的均衡系统(Switched-Capacitor Equalization System) 开关电容均衡(Switched-Capacitor Equalization, SCE)是一种广泛应用于 电池组(如锂电池、超级电容组) 的主动均衡技术,通过电…...
Matlab/Simulink - BLDC直流无刷电机仿真基础教程(七) - 波形解析专题P2
Matlab/Simulink - BLDC直流无刷电机仿真基础教程(七) - 波形解析专题P2 前言一、缺相与相线错接解析二、电源电压波动三、电机感量及磁链变化四、负载突变及堵转五、换相时机不当及换相错误参考链接 前言 本系列文章分享如何使用Matlab的Simulink功能来…...
如何从GitHub上调研优秀的开源项目,并魔改应用于工作中?
在 Go 语言学习中,我们经常会去学习一些优秀的开源项目。但是学完之后,发现很快就忘记了或者学习效果并不好。学习一个开源项目最好的方式就是围绕这个开源项目进行实战。例如,直接魔改这个开源项目并应用于工作中。本文来介绍下如何调用&…...
【Java学习笔记】构造器
构造器(constructor)(又名构造方法) 作用:可以在创建对象时就初始化属性,注意不是创建 基本结构 [修饰符] 方法名(形参列表){方法体; }代码示例 public class 构造器 {public static void m…...
Redis 数据类型详解(一):String 类型全解析
文章目录 前言一、什么是 Redis 的 String 类型?二、常用命令1.SET2.GET3.MSET4.MGET5.INCR6.INCRBY7.INCRBYFLOAT8.SETNX9.SETEX 三、注意事项总结 前言 提示:这里可以添加本文要记录的大概内容: 在学习 Redis 的过程中,最基础也…...
JAVA---多态
面向对象三大特征:封装、继承、多态 多态 定义:同类型的对象,表现出的不同形态。 它允许不同类的对象通过同一个接口进行调用,并且在运行时根据实际对象类型执行不同的方法。 多态主要通过继承、接口和方法重写来实现。 表现形式…...
K8S的使用(部署pod\service)+安装kubesphere图形化界面使用和操作
master节点中通过命令部署一个tomcat 查看tomcat被部署到哪个节点上 在节点3中进行查看 在节点3中进行停止容器,K8S会重新拉起一个服务 如果直接停用节点3(模拟服务器宕机),则K8S会重新在节点2中拉起一个服务 暴露tomcat访…...
【Linux系统】第二节—基础指令(2)
hello ~ 好久不见 自己想要的快乐要自己好好争取! 云边有个稻草人-个人主页 Linux—本篇文章所属专栏—欢迎订阅—持续更新中 目录 本节课核心指令知识点总结 本节基本指令详解 07.man 指令 08.cp 指令 09.mv 指令 10.cat 指令 11.more 指令 12.less 指令 …...
Java设计模式: 实战案例解析
Java设计模式: 实战案例解析 在软件开发中,设计模式是一种用来解决特定问题的可复用解决方案。它们是经过实践验证的最佳实践,能够帮助开发人员设计出高质量、易于维护的代码。本文将介绍一些常见的Java设计模式,并通过实战案例解析它们在实际…...
ASP.NET MVC 入门与提高指南九
51. 时空数据处理与 MVC 应用拓展 51.1 时空数据概念 时空数据是指与时间和空间相关的数据,如地理信息系统(GIS)数据、交通流量数据、气象数据等,这些数据随时间和空间变化而变化。 51.2 在 MVC 应用中处理时空数据 地理信息系…...
算法学习时段效能分布
算法学习时段效能分布 晨间时段(06:00-09:00)核心优势最佳任务 午后时段(14:00-17:00)核心优势最佳任务 夜间时段(20:00-23:00)核心优势最佳任务 实证数据支持 晨间时段(06:00-09:00)…...
Linux环境部署iview-admin项目
环境:阿里云服务 系统:CentOS7.X系统 1、下载源码安装包 wget https://nodejs.org/dist/v14.17.3/node-v14.17.3-linux-x64.tar.xz2、解压并放入指定目录 tar -xf node-v14.17.3-linux-x64.tar.xz && mv node-v14.17.3-linux-x64 /usr/local/no…...
在 Ubuntu 系统中,查看已安装程序的方法
在 Ubuntu 系统中,查看已安装程序的方法取决于软件的安装方式(如通过 apt、snap、flatpak 或手动安装)。以下是几种常见方法: 通过 apt 包管理器安装的软件 适用于通过 apt 或 dpkg 安装的 .deb 包。 列出所有已安装的软件包&…...
c++26新功能——Pack indexing
一、模板编程 在模板编程中,有一个问题比较突出,就是对变参模板中参数的控制,比较麻烦。因为是变参,所以想把参数单独拿出来处理,就需要借助一些特殊的技巧,而这种特殊的技巧,往往为大多数开发…...
VSCode通过SSH连接VMware虚拟机
以下是关于VSCode通过SSH连接VMware虚拟机的原理、必要条件及注意事项的说明: 一、连接原理 SSH协议通信:SSH(Secure Shell)是一种加密网络协议,VSCode通过Remote-SSH插件将本地开发环境与虚拟机终端绑定&a…...
7 微调 黑盒蒸馏 突破伦理限制
简介 SecGPT-Distill 是我自己做的一个实验模型, 开源地址: 主要功能是进行模型微调和知识蒸馏而来 这次是运用微调技术,来突破现有模型在处理安全相关问题时的各种限制和约束 代码开源: https://github.com/godzeo/SecGPT-distill-boundless 不回答原理 大部…...
基于51单片机的温湿度控制器proteus仿真
地址: https://pan.baidu.com/s/1cENHPmF0XobqKg_7baZX3Q 提取码:1234 仿真图: 芯片/模块的特点: AT89C52/AT89C51简介: AT89C51 是一款常用的 8 位单片机,由 Atmel 公司(现已被 Microchip 收…...
牛客月赛115 C题-命运之弹 题解
原题链接 https://ac.nowcoder.com/acm/contest/107879/C 题目描述 解题思路 记录每个数字出现的次数。枚举使用「转瞬即逝」的位置,统计后边比当前数字更大的数的数量,进而统计、更新答案。 详细细节见代码,代码里有详细的注释解释。 代…...
视频转GIF
视频转GIF 以下是一个使用 Python 将视频转换为 GIF 的脚本,使用了 imageio 和 opencv-python 库: import cv2 import imageio import numpy as np """将视频转换为GIF图参数:video_path -- 输入视频的路径gif_path -- 输出GIF的路径fp…...
day15 python 复习日
作业: 尝试找到一个kaggle或者其他地方的结构化数据集,用之前的内容完成一个全新的项 目,这样你也是独立完成了一个专属于自己的项目。 要求: 1.有数据地址的提供数据地址,没有地址的上传网盘贴出地址即可。 2.尽可能与…...
性能优化实践:渲染性能优化
性能优化实践:渲染性能优化 在Flutter应用开发中,渲染性能直接影响用户体验。本文将从渲染流程分析入手,深入探讨Flutter渲染性能优化的关键技术和最佳实践。 一、Flutter渲染流程解析 1.1 渲染流水线 Flutter的渲染流水线主要包含以下几…...
【SimSession 】3:中继服务 linux和windows实现及MFC集成实现
实现目标 在 echo 测试程序启动时启动中继服务,并在 echo 程序退出时杀死中继进程。我们可以通过以下方式实现这一目标: linux设计 1 Process Management: 流程管理: Added fork() functionality to create a child process for the relay service添加了 fork()功能,…...
表驱动 FSM 在 STM32 上的高效实现与内存压缩优化——源码、性能与实践
目录 一、引言与背景 二、前提环境与依赖 三、表驱动 FSM 核心原理 四、内存压缩方案详解 4.1 稠密二维表(Dense Table) 4.2 稀疏表压缩(Sparse Table) 4.3 行压缩+Offset 4.4 位域打包(Bit‑Packing)...
windows鼠标按键自定义任意设置
因为用惯了Linux的鼠标中键的复制黏贴,发现windows下有完全可以实现类似自定义功能的软件,推荐一下: X Mouse Button Control。 免费版足够好用。 软件简介: X Mouse Button Control是一款专业的重新映射鼠标按钮的软件工具&…...
常用命令集合
安装Miniconda wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-py310_22.11.1-1-Linux-x86_64.shpython 换清华源 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple鱼香ros wget http://fishros.com/install -O fishr…...
【图书管理系统】环境介绍、设计数据库和表、配置文件、引入依赖
0. 环境介绍 (1)JDK版本:JDK_8(JDK_1.8) (2)Java语言版本:8 (3)SpringBoot版本:2.6.13 (4)Maven仓库:阿里云 …...