STM32_HAL:简单定时器的使用

0x00.章索引

STM32_HAL:点亮第一个LED

STM32_HAL:按键输入检测

STM32_HAL:简单定时器的使用

0x01.目录

0x02.背景/声明

得益于STM32系列MCU的外设功能丰富、软件驱动库规范与参考资料多等特性,该系列MCU被广泛运用于各种电子/电气设备中,本文所使用的软件驱动库以官方的HAL(硬件抽象层)库为基础,以结构体指针的方式将各种外设功能进行进一步的封装,让程序具有面对对象编程的部分特性。
本文所使用的驱动库均为自行编写,受限于自身的水平,代码中难免会有不规范的地方,各位多指正~

0x03.开始前…

0X04.定时器类和它的成员们

定时器无疑是单片机的所有外设功能中最为重要的几个功能之一,STM32F1的中容量版本单片机具有4个定时器(1个高级定时器+3个通用定时器),定时器的基本原理可以参考STM32之定时器详解,定时器类主要实现了开启/关闭定时器、设置/读取定时器相关寄存器的值与添加PWM或IC通道等功能,详细的结构体定义如下所示:

typedef struct TIMER_COMMON {
	TIM_HandleTypeDef tim_handle;
	PWM_COMMON pwm_out[4];
	IC_CAP_COMMON ic_cap[4];
	u32 (*GetCNT)(struct TIMER_COMMON *this);
	void (*SetCNT)(struct TIMER_COMMON *this, u32 cnt);
	void (*SetPSC)(struct TIMER_COMMON *this, u32 psc);
	void (*SetARR)(struct TIMER_COMMON *this, u32 arr);
	void (*StartIT)(struct TIMER_COMMON *this);
	void (*StopIT)(struct TIMER_COMMON *this);
	void (*Start)(struct TIMER_COMMON *this);
	void (*Stop)(struct TIMER_COMMON *this);

	void (*AddPWMCh)(struct TIMER_COMMON *this, uint32_t Channel,
			GPIO_TypeDef *port, uint32_t pin);
	void (*AddICAPCh)(struct TIMER_COMMON *this, uint32_t Channel,
			GPIO_TypeDef *port, uint32_t pin);
} TIMER_COMMON;

定义了结构体之后,还需要实现该“类”的“构造函数”(也就是对该结构体进行初始化):

TIMER_COMMON* new_TIMER(struct TIMER_COMMON *this, TIM_TypeDef *tim, u8 mode,
		u32 psc, u32 arr) {
	TIM_ClockConfigTypeDef sClockSourceConfig = { 0 };
	TIM_MasterConfigTypeDef sMasterConfig = { 0 };
	this = (struct TIMER_COMMON*) calloc(1, sizeof(struct TIMER_COMMON));
	this->tim_handle.Instance = tim;
	this->tim_handle.Init.Prescaler = psc;
	this->tim_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
	this->tim_handle.Init.Period = arr;
	this->tim_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
	this->tim_handle.Init.RepetitionCounter = 0;
	this->tim_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

	if (HAL_TIM_Base_Init(&this->tim_handle) != HAL_OK) {
		Error_Handler();
	}
	sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
	if (HAL_TIM_ConfigClockSource(&this->tim_handle, &sClockSourceConfig)
			!= HAL_OK) {
		Error_Handler();
	}
	if (mode == PWM_MODE) {
		if (HAL_TIM_PWM_Init(&this->tim_handle) != HAL_OK) {
			Error_Handler();
		}
	} else if (mode == IC_CAPTURE_MODE) {
		if (HAL_TIM_IC_Init(&this->tim_handle) != HAL_OK) {
			Error_Handler();
		}
	}
	sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
	sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
	if (HAL_TIMEx_MasterConfigSynchronization(&this->tim_handle, &sMasterConfig)
			!= HAL_OK) {
		Error_Handler();
	}
	this->StopIT = TIM_StopIT;
	this->StartIT = TIM_StartIT;
	this->Stop = TIM_Stop;
	this->Start = TIM_Start;
	this->GetCNT = TIM_Get_CNT;
	this->SetCNT = TIM_Set_CNT;
	this->SetARR = TIM_Set_ARR;
	this->SetPSC = TIM_Set_PSC;
	this->AddPWMCh = new_TIM_PWM_Channel;
	this->AddICAPCh = new_TIM_IC_CAPTURE_Channel;
	return this;
}

本文所描述的例程使用定时器的定时功能,实现频率为2Hz的LED翻转与串口输出,编程的逻辑与使用传统的STD/HAL库类似,首先计算出输出2Hz频率的psc 分频值与arr 自动重装载值的参数,并使用相应的new函数进行初始化:

    tim1_up = new_TIMER(tim1_up, TIM1,BASE_MODE, 7199, 4999);						//定时器初始化
	tim1_up->StartIT(tim1_up);

在配置好定时器后,定时器以2Hz的频率进入定时器溢出回调函数,在定时器中断函数中立起标志位:

void TIM1_UP_IRQHandler(void) {
	HAL_TIM_IRQHandler(&tim1_up->tim_handle);
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
	if (htim->Instance == TIM1) {
		time_up = 1;
	}
}

在main函数中,实例化LED与UART对象,并根据定时器的标志位进行LED的闪烁与UART串口发送:

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    GPIO_COMMON *led=NULL;
    led=new_Gpio(led, GPIOB, GPIO_PIN_5, GPIO_MODE_OUTPUT_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_HIGH);

    while (1)
    {
        led->TogglePin(led);
        HAL_Delay(500);
    }
}

0x05.小结

TIMER_COMMON是一个实现内容比较多的类,因为定时器本身比较复杂,且后续的PWM输出与INPUT CAPTURE输入捕获都继承于该类,或许有一些定时器的功能是我没有用过的,所以定时器类的接口难免还是会有一些遗漏,可能需要开发者在使用的时候手动修改或添加功能(反正又不是静态库!

附录

Gitee:https://gitee.com/hyjjjjjjjj/STM32_HAL_MODULES
Github:https://github.com/HYJJJJJJJJ/STM32_HAL_MODULES(不怎么更新

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值