STM32学习————从延时函数到中断控制灯500ms闪烁

1.Delay延时函数

//          main              //

#include "stm32f10x.h"                  // Device header
#include "Delay.h"                  // Device header

int main(void)
{

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	
	GPIO_Init(GPIOA, &GPIO_InitStructure);
    
	while(1)
	{
		
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)0);
		Delay_ms(500);
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)1);
		Delay_ms(500);
		
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
		Delay_ms(500);
		GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
		Delay_ms(500);
		
		GPIO_ResetBits(GPIOA, GPIO_Pin_0);
    	Delay_ms(500);
		GPIO_SetBits(GPIOA, GPIO_Pin_0);
		Delay_ms(500);
    }
}

首先是最简单的写法,通过GPIO位操作,delay延时函数直接控制led灯闪灭。 

第一种是通过bitA0引脚直接控制led。

第二种是用向芯片写入数据控制A0引脚。

第三种是用0/1方便查看。

这样写样子太丑了,所以可以把led模块化。

2.模块化led函数

//           main          //

#include "stm32f10x.h"                  // Device header
#include "Delay.h"                  // Device header
#include "led.h"     

int main(void)
{
	led_init();
	while(1)
	{		
		led_on();
		Delay_ms(500);
		led_off();
		Delay_ms(500);
	}
}
//             led            //

#include "stm32f10x.h"                  // Device header

void led_init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	
	GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void led_on(void)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
}

void led_off(void)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
}

用Delay写显然会出现问题,因为delay延时会影响其他函数的正常刷新,导致程序卡死,不能执行其他中断或者函数。

3.中断控制led闪烁

//            main            //

#include "stm32f10x.h"                  // Device header
#include "led.h"     
#include "time.h"

uint16_t f_500ms1;
uint16_t f_500ms2;

uint16_t cnt_500ms1;
uint16_t cnt_500ms2;

void Timer_Init(void);
void led_mainloop(void);

int main(void)
{
	led_init();
	Timer_Init();
	while(1)
	{
		led_mainloop();
	}
}

void led_mainloop(void)
{	
	if(f_500ms1 == 0)
		led_on();
	if(f_500ms2 == 1)
		led_off();
}

void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{		
		if(++cnt_500ms1 >= 5)
		{
			f_500ms1 = 1;cnt_500ms1 = 0;
			if(f_500ms1 == 1)
			{
				f_500ms2 = 1;
				if(++cnt_500ms2 >= 2)
				{
					f_500ms1 = 0;f_500ms2 = 0;cnt_500ms2 = 0;
				}
			}
		}
		
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}
//          timer         //

#include "stm32f10x.h"                  // Device header

void Timer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 1000 - 1;
	TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_Cmd(TIM2, ENABLE);	
}

虽然比第二个麻烦,但是中断是很有必要的。

观察程序发现,用了两个计数器来延时,方法太繁琐了。其实闪烁还有更好的方法,比如说直接把灯500ms取反,这样就能让数据更清晰,不会绕来绕去。

4.中断控制led闪烁取反

//            main           //

#include "stm32f10x.h"                  // Device header
#include "led.h"     
#include "time.h"
#include "OLED.h"

uint8_t f_1ms;
uint16_t f_500ms;

uint16_t cnt_500ms;

void Timer_Init(void);
void time_mainloop(void);
	
int main(void)
{
	led_init();
	Timer_Init();
	OLED_Init();
	while(1)
	{
		time_mainloop();
		OLED_ShowString(1, 1, "cnt_500ms :");
		OLED_ShowNum(1, 14, cnt_500ms, 1);
		OLED_ShowString(3, 1, "f_500ms :");
		OLED_ShowNum(3, 14, f_500ms, 1);
		if(f_500ms==1)
		{
			led_turn();
			f_500ms = 0;
		}
	}
}

void time_mainloop(void)
{
	if(!f_1ms)return;
	f_1ms = 0;
	
	if(++cnt_500ms>=5)
	{
		f_500ms=1;cnt_500ms=0;	
	}
}
//             time              //

#include "stm32f10x.h"                  // Device header

extern uint8_t f_1ms;

void Timer_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	TIM_InternalClockConfig(TIM2);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 1000 - 1;
	TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_ClearFlag(TIM2, TIM_FLAG_Update);
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_Cmd(TIM2, ENABLE);	
}

void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{		
		f_1ms = 1;	
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}
//       led        //
//在原有内容上新增

void led_turn(void)
{
	if(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_0) == 0)
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_0);
	}
	else
	{
		GPIO_ResetBits(GPIOA, GPIO_Pin_0);
	}	
}

程序肉眼可见的少了,而且逻辑更加清晰。此外还加了OLED屏可以方便观察led值的变化,方便调试程序。

一步一步改进和调试程序的过程还是很有意思的,STM32不同于51单片机,中断得自己设置。

能用和51一样的套路来写,毕竟都是单片机嘛。

STM32更多的是对程序深入的理解和分析,底层程序和逻辑都需要自己来写,自由度也很高。

加!油!

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果您的STM32单片机屏幕一直闪烁,可能是因为您的程序中使用了循环延时的方式,导致CPU一直忙碌而无法及时刷新屏幕。为了解决这个问题,可以使用STM32的定时器中断来实现LED的闪烁,从而释放CPU资源,让它能够及时地刷新屏幕。 以下是使用TIM中断方式实现LED闪烁的示例代码: ```c #include "stm32f10x.h" void TIM2_IRQHandler(void) // 定时器2中断服务函数 { if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) // 检查是否发生了更新事件 { static uint8_t led_state = 0; if (led_state == 0) { GPIO_SetBits(GPIOC, GPIO_Pin_13); // PC13输出高电平 led_state = 1; } else { GPIO_ResetBits(GPIOC, GPIO_Pin_13); // PC13输出低电平 led_state = 0; } TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 清除中断标志位 } } int main(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); // 使能GPIOC时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // 使能TIM2时钟 // 配置GPIOC.13为推挽输出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStructure); // 配置TIM2 TIM_TimeBaseStructure.TIM_Period = 999; // 自动重载值 TIM_TimeBaseStructure.TIM_Prescaler = 7199; // 预分频器 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); // 使能更新中断 TIM_Cmd(TIM2, ENABLE); // 启动定时器 // 配置NVIC NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); while (1) { // 空闲循环 } } ``` 在上面的代码中,我们使用了定时器TIM2,并把它配置为1ms的定时器。在定时器中断服务函数中,我们通过改变LED的状态来实现LED的闪烁。由于使用了中断方式,CPU不会一直忙碌,从而可以释放CPU资源,让它能够及时地刷新屏幕。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值