STM32中断实验,在debug模式下led可以交叉亮灭,但在正常情况下全暗
#include "stm32f10x.h"
#include "stm32f10x_it.h"
#include <stdio.h>
void GPIO_init(void) // GPIO 的初始化配置
{
GPIO_InitTypeDef GPIO_InitStructure; // 定义一个 GPIO_InitTypeDef 类型的结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO , ENABLE);
// 开启 AFIO 时钟和 GPIOB 的外设时钟
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); // 禁用 JTAG 功能
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 |GPIO_Pin_5 |GPIO_Pin_6|GPIO_Pin_7;
// 选择要控制的 GPIOB 引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 设置引脚速率为 50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 设置引脚模式为通用推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure); // 调用库函数,初始化 GPIOB
}
void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; // 定义一个定时器初始化参数结构体
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE); // 开启 APB1 的 TIM2 外设时钟
TIM_DeInit(TIM2); // 复位TIM2定时器,使之进入初始状态
TIM_TimeBaseStructure.TIM_Prescaler= (7200 - 1); // 设置预分频系数为(7200-1)
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 向上计数模式
TIM_TimeBaseStructure.TIM_Period=10000; // 自动加载值设置,累计 10000 个时钟周期(1s)后溢出
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
// 根据 TIM_TimeBaseStructure 中指定的参数初始化 TIM2 里的相关寄存器
TIM_ClearFlag(TIM2, TIM_FLAG_Update); // 清除溢出中断标志
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); // 使能 TIM2 中断,允许更新中断
TIM_Cmd(TIM2, ENABLE); // 使能 TIM2 外设
}
void TIM2_NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure; // 定义 NVIC 初始化结构体
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 选择中断优先级分组 0
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; // 选择配置 TIM2 全局中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 占先优先级为 0
NVIC_InitStructure.NVIC_IRQChannelSubPriority =1; // 响应优先级为 1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能 TIM2 中断通道
NVIC_Init(&NVIC_InitStructure); // 根据以上配置初始化 NVIC
}
int main()
{
int led_state=0;
GPIO_init();
GPIO_WriteBit(GPIOB,GPIO_Pin_4,(BitAction)0x01); //status
GPIO_WriteBit(GPIOB,GPIO_Pin_5,(BitAction)0x01); //R
GPIO_WriteBit(GPIOB,GPIO_Pin_6,(BitAction)0x01); //T
GPIO_WriteBit(GPIOB,GPIO_Pin_7,(BitAction)0x01); //User
TIM2_NVIC_Configuration();
TIM2_Configuration();
while(1)
{
if ( TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET ) // 1S 时间到,检测到 TIM2 中断
{
led_state++; // 状态加 1
switch (led_state)
{
case 1: // 状态 1:灭掉 User1,点亮 Status
GPIO_WriteBit(GPIOB,GPIO_Pin_7,(BitAction)0x01);
GPIO_WriteBit(GPIOB,GPIO_Pin_4,(BitAction)0x00);
break;
case 2: // 状态 2:灭掉 Status,点亮 RS485-R
GPIO_WriteBit(GPIOB,GPIO_Pin_4,(BitAction)0x01);
GPIO_WriteBit(GPIOB,GPIO_Pin_5,(BitAction)0x00);
break;
case 3: // 状态 3:灭掉 RS485-R,点亮 RS485-T
GPIO_WriteBit(GPIOB,GPIO_Pin_5,(BitAction)0x01);
GPIO_WriteBit(GPIOB,GPIO_Pin_6,(BitAction)0x00);
break;
case 4: // 状态 4:灭掉 RS485-T,点亮 User1
GPIO_WriteBit(GPIOB,GPIO_Pin_6,(BitAction)0x01);
GPIO_WriteBit(GPIOB,GPIO_Pin_7,(BitAction)0x00);
led_state=0; // led_state 置 0,下个 1s 时间到后可再次进入状态 1
break;
default:
break;
}
TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update); // 清除中断标志位
}
}
}
你这个定时器中断服务函数的内容怎么放在main函数的while循环里咯!这是有问题的哦!
既然使能了定时器中断,就该在中断函数里做main函数里那个循环里的功能,否则默认的中断服务函数清空了标志,导致main里读不到状态,自然无法计数,也就无法实现状态切换
那么我们的时钟是多少呢?如果你是调试模式,这个时钟是通过目标选项(Options For Target)来进行配置,开心就好:
如果是直接烧录到STM32的板子里面,默认使用的是HSI(High Speed Internal,内部高速时钟),即8MHz;所以为了Debug的效果和烧录之后的效果保持一致,最好是设置为一致的时钟频率。
答案:
该问题可能是由时钟频率不一致导致的。在调试模式下,时钟频率由目标选项进行配置,与烧录之后的频率不一致可能会导致LED在调试模式下能够交叉亮灭,但在正常模式下却全暗。
解决方法如下:
在代码中确认时钟频率设置是否与烧录之后的配置一致。具体方法如下:
RCC_DeInit(); // 复位时钟
RCC_HSEConfig(RCC_HSE_ON); // 开启外部高速时钟
while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET); // 等待外部高速时钟启动
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); // 设置PLL时钟
RCC_PLLCmd(ENABLE); // 开启PLL时钟
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); // 等待PLL时钟启动
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // 将SYSCLK设置为PLL时钟
while (RCC_GetSYSCLKSource() != 0x08); // 等待SYSCLK稳定
RCC_HCLKConfig(RCC_SYSCLK_Div1); // AHB时钟 = 系统时钟
RCC_PCLK2Config(RCC_HCLK_Div1); // APB2时钟 = AHB时钟
RCC_PCLK1Config(RCC_HCLK_Div2); // APB1时钟 = AHB时钟/2
在检查时钟设置无误之后,还需要确认中断设置是否正确。具体方法如下:
if (GPIOx == GPIOA) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
else if (GPIOx == GPIOB) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
else if (GPIOx == GPIOC) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 配置引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 设置为浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化GPIO
EXTI_InitStructure.EXTI_Line = EXTI_Line0; // 中断线0
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; // 中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; // 触发方式
EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 开启中断线0
EXTI_Init(&EXTI_InitStructure); // 初始化中断
void EXTI0_IRQHandler(void) {
if (EXTI_GetFlagStatus(EXTI_Line0) != RESET) { // 判断中断标志是否置位
EXTI_ClearFlag(EXTI_Line0); // 清除中断标志位
// 在此添加中断处理代码
}
}
参考资料: