STM32学习
- 定时器(TIM)
- 定时器工作原理
- 定时器相关参数
- 相关函数和配置参数
- 通用输入/输出(GPIO)
- GPIO原理
- GPIO相关函数
- 实现定时扫描按键
- 总结
在STM32F103系列的单片机应用中,定时器(TIM)和通用输入/输出(GPIO)是常用的模块之一。这两个模块结合起来,可以实现非常多的实际应用,其中,定时器可以用来实现定时扫描按键,而GPIO可以用来控制LED等设备。
本文将介绍,在STM32F103系列的单片机中如何通过定时器和GPIO模块,实现定时扫描按键功能。
本文将从定时器、GPIO原理入手,讲解使用到的函数以及配置参数,最后做总结。
定时器(TIM)
使用定时器,需要先了解定时器的原理及其相关参数。
定时器工作原理
定时器是一种计算时间的模块,可以用来触发一些事件、完成一些操作或者调度系统任务。定时器的核心部分为计数器和控制寄存器。
定时器开始计数后,计数值会每次增加1,当计数值达到设定的上限值时,会触发一个中断或者其他的事件。同时,可以通过调整定时器的各个参数来控制计数器的计数速率、计数上限以及触发中断的条件。
定时器相关参数
在使用定时器前,需要对其相关参数进行配置,常用的定时器参数包括:
- 周期(ARR):定时器计数器的上限值,当计数器增加到该值时,会触发定时器的中断或其他操作。
- 预分频器(PSC):用于降低计数器输入时钟的频率,从而达到降低定时器计数速率的目的。
- 计数模式(Counter Mode):定时器可以分为向上计数模式和向下计数模式,可以根据具体需求进行配置。
- 输出比较通道(Output Compare Channel):可以通过定时器的输出比较通道来产生PWM波形等复杂的定时信号。
相关函数和配置参数
常用的配置定时器的函数包括:
void TIM_DeInit(TIM_TypeDef* TIMx); //TIMx 定时器的初始化
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct); //定时器基本配置
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState); //开启或关闭定时器
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1); //设置定时器输出比较通道 1 的占空比
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState); //允许或禁止定时器中断
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG); //清除定时器的中断标志位
其中,TIM_TimeBaseInitTypeDef 结构体用于初始化定时器的基本配置参数,常用的配置参数包括:
//定时器基本配置结构体
typedef struct
{
uint16_t TIM_Prescaler; //定时器计数器的预分频值
uint16_t TIM_CounterMode; //定时器的计数模式(向上或向下)
uint32_t TIM_Period; //定时器计数器的上限值
uint16_t TIM_ClockDivision; //采样分频
uint8_t TIM_RepetitionCounter; //自动重载计数器值
} TIM_TimeBaseInitTypeDef;
在使用定时器时,需要对其进行初始化并配置相关参数。以下代码段为一个示例初始化函数:
void Timer_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseInitStruct.TIM_Prescaler = 7200;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period = 1000-1;
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
TIM_Cmd(TIM3, ENABLE);
}
该函数使用的是 TIM3 定时器,采用向上计数模式。定时器预分频器值为7200,计数到1000后(即从0计数到999),会触发定时器中断。TIM_Cmd() 函数用于启用定时器。
推荐查看之前文章:https://blog.csdn.net/hongyun1221/article/details/130973099
通用输入/输出(GPIO)
通用输入/输出(GPIO)是单片机上最为基础,也是最常用的模块之一。GPIO模块包含多个引脚,每个引脚具有输入和输出两种模式,可以用来控制各种外设,例如LED、按键等。
GPIO原理
GPIO模块的输入输出控制是通过寄存器进行的,每个IO口都与一个寄存器相关联,我们可以通过修改该寄存器的值来控制IO口的状态,从而实现相应的输入/输出功能。常见的GPIO寄存器包括:GPIOx_CRL、GPIOx_CRH、GPIOx_ODR、GPIOx_IDR、GPIOx_BSRR、GPIOx_BRR、GPIOx_LCKR等。
GPIO相关函数
在STM32F103系列单片机中,使用GPIO模块时,常用的函数包括:
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct); //初始化GPIO引脚
void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); //GPIO引脚锁定
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal); //设置或清除GPIO引脚的输出状态
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); //读取GPIO引脚的输入状态
其中,GPIO_InitTypeDef 结构体用于配置GPIO引脚的具体参数,常用的配置参数包括:
//GPIO 配置结构体
typedef struct
{
uint16_t GPIO_Pin; //需要初始化的GPIO引脚
GPIOMode_TypeDef GPIO_Mode; //GPIO引脚工作模式
GPIOSpeed_TypeDef GPIO_Speed; //GPIO引脚速度
GPIOOType_TypeDef GPIO_OType; //GPIO引脚输出类型
GPIOPuPd_TypeDef GPIO_PuPd; //GPIO引脚上下拉模式
} GPIO_InitTypeDef;
使用GPIO模块,需要对相关引脚进行初始化并配置其相应的工作模式、输出类型、上下拉模式等参数。以下为一个示例初始化函数:
void GPIO_InitExample(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能GPIOB的时钟
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; //初始化GPIOB的0号引脚
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; //输入上拉模式
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //50MHz速度
GPIO_Init(GPIOB, &GPIO_InitStruct); //初始化GPIOB
}
该函数使用的是GPIOB模块的0号引脚,初始化为输入上拉模式。
实现定时扫描按键
下面我们结合以上的知识,来实现简单的定时扫描按键功能。该功能的基本实现思路为:
- 初始化GPIO引脚,设置为输入上拉模式
- 初始化TIM定时器,启用定时中断
- 在定时器中断处理函数中检测按键状态
为了便于演示,我们使用开发板上的资源做一个示例:定时器每20ms扫描一次按键,按键配置LED亮灭。
主程序代码
int main(void){
LED_GPIO_Init();
KEY_GPIO_Init();
TIM_EXIT_Init(20000-1, 72-1);
while(1){
}
}
定时器头文件
#ifndef __TIMER_H
#define __TIMER_H
#include "stm32f10x.h"
#define TIM TIM3
#define TIM_CLK RCC_APB1Periph_TIM3
#define TIM_IRQ TIM3_IRQn
#define TIM_IRQHandler TIM3_IRQHandler
void TIM_EXIT_Init(uint16_t arr, uint16_t psc);
#endif /* __TIMER_H */
定时器源代码
#include "bsp_timer.h"
void TIM_NVIC_Init(void){
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStruct.NVIC_IRQChannel = TIM_IRQ;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
void TIM_EXIT_Init(uint16_t arr, uint16_t psc){
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_NVIC_Init();
RCC_APB1PeriphClockCmd(TIM_CLK, ENABLE);
TIM_TimeBaseInitStruct.TIM_Prescaler = psc;
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period = arr;
TIM_TimeBaseInit(TIM, &TIM_TimeBaseInitStruct);
TIM_ITConfig(TIM, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM, ENABLE);
}
按键源文件
#ifndef __KEY_H
#define __KEY_H
#include "stm32f10x.h"
typedef enum {
key_button = 0,
key_release = 1
} KeyStatus;
#define KEY_GPIO_PORT GPIOB
#define KEY_GPIO_CLK RCC_APB2Periph_GPIOB
#define KEY_GPIO_PIN GPIO_Pin_1
void KEY_GPIO_Init(void);
void KEY_GPIO_Scan(void);
#endif /* __KEY_H */
总结
本文介绍了在STM32F103单片机中,如何使用定时器和GPIO模块实现定时扫描按键功能。通过学习定时器和GPIO的相关原理和函数,我们可以更加深入地了解STM32F103单片机的工作原理,从而更好地完成各类实际应用。
总的来说,定时器和GPIO模块是STM32F103单片机非常常用和重要的模块,掌握其相关知识和应用技巧,对于提高单片机的应用水平和开发效率具有重要的作用。
程序代码资源下载:https://download.csdn.net/download/hongyun1221/87852606