原理了解
使用通用定时器进行脉冲计数实验需要用到图中红色框框出来的时基单元,通过选用外部时钟模式1中的通道一或通道二,这里以通道一为例,选择TI1FP1为触发信号(这里不选用TI1F_ED为触发信号的原因为其是双边沿捕获,而实验是一个脉冲数计数+1),配置从模式控制器为计数然后就可以实现脉冲计数。
STM32CubeMx配置
定时器及通道选择
脉冲计数实验前提是产生一个脉冲,所以这里需要用到一个按键,查看硬件原理图结合数据手册
我们选用定时器2通道1作为我们的外部时钟模式一,同时作为按键使用,这里在增加一个按键PE4,作为等会清空脉冲计数使用,配置如下:
从模式选择外部时钟模式1,触发源选择TI1FP1,然后配置不分频,因为一个脉冲数计数器+1,接着是自动重装载值选择65335,因为这样能计的最大脉冲数则为65536个,接着就是触发极性配置为上升沿触发,接着就可以生成工程了。
工程生成及代码编写
工程文件
生成工程后我们可以看到左边已经有了相关代码:
来看一下脉冲计数实验中几个比较重要的函数:
void MX_TIM2_Init(void); //定时器2初始化函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle);//相关时钟,IO口配置
HAL_StatusTypeDef HAL_TIM_IC_Start(TIM_HandleTypeDef *htim, uint32_t Channel); //使能输入捕获并启动计数器
__HAL_TIM_GET_COUNTER(__HANDLE__); //这是一个宏定义,用于获取计数器的值
__HAL_TIM_SET_COUNTER(__HANDLE__); //这是一个宏定义,用于设置计数器的值
代码编写
首先打开tim.c文件:
可以看到在void MX_TIM2_Init(void)函数中已经生成了我们刚刚STM32CubeMx配置的定时器设置,以及在void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)中开启了相对应的时钟及IO口配置,我们需要做的就是在用户代码区添加使能输入捕获并启动计数器函数,即:
HAL_TIM_IC_Start(&htim2, TIM_CHANNEL_1);
key.c编写
由于添加了一个按键用于清空当前的脉冲计数值,所以独立写了一个按键函数:
#include "key.h"
uint8_t key_scan()
{
static uint8_t key_sta = 1;
uint8_t key_value = 0;
if(key_sta && (KEY0 == 0))
{
HAL_Delay(10);
key_sta = 0;
if(KEY0 == 0)
key_value = KEY0_PRESS;
}
else if(KEY0)
{
key_sta = 1;
}
return key_value;
}
key.h文件
#ifndef __KEY_H
#define __KEY_H
#include "main.h"
#define KEY0_PRESS 1 //PE4按下状态
#define KEY0 HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4) //读取当前PE4状态
uint8_t key_scan(void);
#endif
main.c编写
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
uint16_t oldcnt = 0; //记录旧脉冲计数
uint16_t curcnt = 0; //更新脉冲计数
uint8_t key = 0; //记录键值
uint8_t t =0;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
key = key_scan();
if(key == KEY0_PRESS)
{
__HAL_TIM_SET_COUNTER(&htim2, 0);
}
curcnt = __HAL_TIM_GET_COUNTER(&htim2);
if(oldcnt != curcnt)
{
oldcnt = curcnt;
printf("CNT = %d\r\n", oldcnt);
}
/*LED翻转证明程序正常工作*/
t++;
if(t > 20)
{
t = 0;
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_5);
}
HAL_Delay(10);
}
/* USER CODE END 3 */
}
这样脉冲计数实验就完成了,如果想试一下双边沿触发,则可将触发极性修改为双边沿触发,即在tim.c中修改如下两个设置即可:
sSlaveConfig.InputTrigger = TIM_TS_TI1F_ED;
sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_BOTHEDGE;
若想使脉冲计数的值可以达到更大,则打开更新中断,并定义多一个变量记录溢出次数即可。