1. 实验目的
写一个1s的定时器,来控制LED灯的亮灭。这里LED1的端口是GPIOF,引脚是PIN10。定时器是通用定时器TIM3。
2. 实验流程
初始化LED;
初始化定时器;
编写时钟中断函数;
编写LED.h函数;
编写main.c函数;
2.1 初始化LED
//初始化GPIO端口
void LED_GPIO_Config(void)
{
//初始化结构体 GPIO_InitStruct(取的一个随机的名字)
//里面是GPIO的速度,上下拉,输出类型
GPIO_InitTypeDef GPIO_InitStruct;
//打开时钟(一般开时钟要放到前面的位置,然后再是设置上拉,输出这些)
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE); //使能时钟必须放到前面,不然后面的操作不会使灯点亮
//驱动是哪个引脚 PF10
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
//推挽输出
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
//上拉
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP ;
//输出的速度
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
//变量获取它的指针,取地址就行(&)
GPIO_Init(GPIOF,&GPIO_InitStruct);
GPIO_SetBits(GPIOF,GPIO_Pin_10);//GPIOF10设置高,灯灭
}
2.2 初始化定时器
这里定时器的计算公式是:
Tout= ((arr+1)*(psc+1))/Tclk;
arr:自动重装载值;
psc:时钟预分频系数;
Tclk:TIM3 的输入时钟频率(单位为 Mhz),这里TIM3的时钟频率为是84Mhz;
Tout:TIM3 溢出时间。
按照下面的设置:计数一次的时间是 (1000 * 84) / 84000000 = 1ms (后面计数1000次就是1s,所以就是LED经过1s亮灭一次)
//这里使用了中断,就要配置中断的初始化
void BASIC_TIM_NVIC_Config(void){
//NVIC初始化结构体
NVIC_InitTypeDef NVIC_InitStruct;
//设置中断优先级的分组
//就是设置主抢占优先级和子抢占优先级各是几,这里是分组为1,代表主优先级可以是0和1(就是1个位来设置主优先级),子优先级是0-7,是2的3次方
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
//配置TIM6_IRQn为中断源
NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn; //配置时钟
//配置抢占优先级
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
//配置子优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
//使能中断
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
//定时器初始化
void BASIC_TIM_Config(void){
//时钟基结构体
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
//开启定时器时钟,即内部时钟CK_INT = 84M
//BASIC_TIM_APB1Clock_FUN(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); ///使能 TIM3 时钟
//自动重装载寄存器的值,累计TIM_Period+1个评率后产生一个更新或者中断
TIM_TimeBaseStructure.TIM_Period = 1000-1; //自动重装载值arr 这就是500ms
//时钟预分频系数为
TIM_TimeBaseStructure.TIM_Prescaler = 84-1; //定时器分频
//时钟分频因子,基本定时器没有,不用管
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
//计数器计数模式,基本定时器只能向上计数,没有计数模式的设置
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
//重复计数器的值,基本定时器没有,不用管
//TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; //扩大定时器的周期的
//初始化定时器
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //哪一个定时器初始化
//清除计数器中断标志
TIM_ClearFlag(TIM3, TIM_FLAG_Update);
//开启计数器中断
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //允许定时器3更新中断
//使能计数器
TIM_Cmd(TIM3,ENABLE);
}
//初始化上面两个函数,在main函数只调用这一个就可以了
void BASIC_TIM_Init(void){
//初始化中断优先级
BASIC_TIM_NVIC_Config();
//初始化定时器配置
BASIC_TIM_Config();
}
2.3 编写时钟中断函数
extern uint16_t time; //计数用的
//编写时钟中断函数
//void BASIC_TIM_IRQHandler(){
void TIM3_IRQHandler(void){
if(TIM_GetITStatus(TIM3,TIM_IT_Update) != RESET){ //判断更新中断状态位
time++; //全局变量,在main.c里面的
TIM_ClearITPendingBit(TIM3,TIM_FLAG_Update); //清除中断标志位
}
}
2.4 编写LED.h函数
里面主要是翻转的宏定义。
^异或相同为0,不同为1。
#define LED_G_TOGGLE {LED_G_GPIO_PORT->ODR ^= LED_G_GPIO_PIN;}
LED_G_GPIO_PORT->ODR就是GPIOF->ODR,GPIOF->ODR ^= GPIO_Pin_10;
其中 #define GPIO_Pin_10 ((uint16_t)0x0400), 0000 0100 0000 0000就是第10位为1,GPIOF的ODR寄存器的初始值都是0,所以异或GPIO_Pin_10 就是把ODR寄存器的第10位置1,再置0这样进行反转。文章来源:https://www.toymoban.com/news/detail-434455.html
#ifndef LED.h
#define LED.h
//包含GPIO的头文件
#include "stm32f4xx.h"
#define LED_G_GPIO_PIN GPIO_Pin_10
#define LED_G_GPIO_PORT GPIOF
// \c语言里面的续行符,后面不能有任何的东西
//带参宏的主体
#define LED_G(a) if(a) \
GPIO_SetBits(GPIOF,GPIO_Pin_10);\
else GPIO_ResetBits(GPIOF,GPIO_Pin_10);
#define LED_G_TOGGLE {LED_G_GPIO_PORT->ODR ^= LED_G_GPIO_PIN;} //异或相同为0,不同为1
void LED_GPIO_Config(void); //初始化LED
#endif /*__LED.h */
2.5 编写main.c函数
int main(void){
LED_GPIO_Config();
BASIC_TIM_Init();
while(1){
if(time == 1000){ //1000ms就是1s
LED_G_TOGGLE; //反转小灯
time = 0; //清除这个计数的值
}
}
3. 实验结果
每隔1s闪烁一次文章来源地址https://www.toymoban.com/news/detail-434455.html
到了这里,关于定时器控制LED灯的亮灭(每隔1s翻转一次灯的状态)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!