STM32系列课程总结1---固件库---滴答定时器----中断

==========================================================

                                                                《 固件库搭建》

1.开发环境:window+kill5+STM32F407

2.开发准备:(具体下载源码包路径就不提供了,可以下载我已经建好的基本固件库)

(1)连接(已经建好的固件库):链接:https://pan.baidu.com/s/1Ddvcd1LQDZ3V3EOSt4FL3w  提取码:cua6 

       固件库文件结构说明:

        新建一个文件夹叫做 Template ,在 Template 文件夹中新建以下文件夹
        CMSIS        --->存放启动文件以及内核相关文件
        Libraries     --->相关外设的头文件以及源文件
        Output        --->存放编译生成的其他文件
        Project        --->存放工程
        User           --->存放自己日后写的代码,mian.c也在里面(该main.c是官方的,后期把函数体删除加自己的函数实现即可)
        Doc            --->存放 Readme.txt

(2)若想单独建立自己的固件库参考:https://blog.csdn.net/linxiaobo110/article/details/40347689

2.环境搭建:已经弄好的固件库在keill开发平台使用还得需要弄些步骤,直到编译成功才能说明成功。

修改相应的文件以及配置(详细操作另看操作图和视频:)

链接:https://pan.baidu.com/s/1Am9lanrp4IR8Ea0YT2xDqg 
提取码:josk (视频大部分内容是多余的)

    1、 点击魔术棒  ---》C/C++ 
        在 define 位置添加  STM32F40_41xxx, USE_STDPERIPH_DRIVER
        在 Include Paths 中添加工程中所有用到的头文件路径
    2、整理 main.c  main.h 
    3、把 stm32f4xx_it.c 中144行注释掉
             //TimingDelay_Decrement();
    4、设置编译生成的文件输出路径
        点击魔术棒  ---》Output --->Select Folder for Objects     
    5、修改固件库工程时钟  !!!
        看图
    6、 直到编译成功

=================================================================

                                                            《滴答定时器》

1.理论基础:

(1)滴答定时器(内核定时器,SysTick 定时器) ,实现精准延时,是倒计时,用于在每隔一定的时间产生一个中断,即使是系统在睡眠模式下也能工作。

(2)在 STM32F4xx中文参考手册.pdf 文件是找不到,它是属于内核的模块。

(3)相关函数以及宏定义在 跟内核相关(core_开头的那几个头文件)的那几个文件中。

2.使用实例:滴答定时器给流水灯精准定时

                                  

----------------------------------------------------------systick-code-----------------------------------------------

-----------------------------------systick.h----------------------------
#ifndef __SYSTICK_H_
#define __SYSTICK_H_

//头文件
#include "stm32f4xx.h"

//宏定义

//函数声明
void Systick_Init(void);//初始化
void delay_us(u32 nus);//定时微妙
void delay_ms(u32 nms);//定时毫秒
void delay_s(u32 ns);//定时秒


#endif
-----------------------------------systick.c----------------------------
#include "systick.h"

u8 	my_us = 0;
u16 my_ms = 0;

//初始化滴答定时器
void Systick_Init(void)
{
	//得到的Systick时钟 168MHz/8 = 21MHz   -->每隔 1/21us计数一次
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); 
	my_us = 21;        //21
	my_ms = 21*1000;
}

//微秒延时,nus最大值:798915
void delay_us(u32 nus)   //1
{
	u32 temp = 0;
	//往自动重装载除值寄存器写入延时nus  SysTick->LOAD最大值0xFFFFFF
	SysTick->LOAD = nus*my_us;
	SysTick->VAL  = 0x00;
	SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开启计数,开始倒数
    
    //如果还没有数到 0 就卡死在这个循环中,依据控制寄存器的第 16 位
	do
	{
		//读控制寄存器
		temp = SysTick->CTRL;
	}while(!(temp & (1<<16)));
    
	SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数
	SysTick->VAL  = 0x00;
}

//毫秒延时,nms最大值,nms最大值798.915
void delay_ms(u32 nms)
{
	u32 temp = 0;
	//往自动重装载除值寄存器写入延时nms  SysTick->LOAD最大值0xFFFFFF
	SysTick->LOAD = nms*my_ms;
	SysTick->VAL  = 0x00;
    
	SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开启计数
	do
	{
		//读控制寄存器
		temp = SysTick->CTRL;
	}while(!(temp & (1<<16)));
	SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数
	SysTick->VAL  = 0x00;

}

//秒延时
void delay_s(u32 ns)
{
	for(; ns>0; ns--)
	{
		delay_ms(500);
		delay_ms(500);
	}
}
------------------------------led.h-------------------
#ifndef __LED_H
#define __LED_H

//头文件
#include "stm32f4xx.h"   //这个头文件一定要留

//宏定义
#define  LED_ON         0
#define  LED_OFF        1

#define  LED0(a);      if(a) \
                            GPIO_SetBits(GPIOF,GPIO_Pin_9); \
                       else \
                            GPIO_ResetBits(GPIOF,GPIO_Pin_9);

#define  LED1(a);      if(a) \
                            GPIO_SetBits(GPIOF,GPIO_Pin_10); \
                       else \
                            GPIO_ResetBits(GPIOF,GPIO_Pin_10);
                       
#define  LED2(a);      if(a) \
                            GPIO_SetBits(GPIOE,GPIO_Pin_13); \
                       else \
                            GPIO_ResetBits(GPIOE,GPIO_Pin_13);

#define  LED3(a);      if(a) \
                            GPIO_SetBits(GPIOE,GPIO_Pin_14); \
                       else \
                            GPIO_ResetBits(GPIOE,GPIO_Pin_14);                      
//函数声明
void GPIO_LED_Init(void);

#endif 
---------------------------------led.c-------------------------

#include "led.h"

/*
 *  PF9         --->LED0
 *  PF10        --->LED1
 *  PE13        --->LED2
 *  PE14        --->LED3
 *  0           --->LED_ON
 *  1           --->LED_OFF
 */

/*
 * 功  能:初始化 LED 的 GPIO 口
 * 参  数:无
 * 返回值:无
 */
void GPIO_LED_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructrue;
    
    //1、开启 GPIOE GPIOF 时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);

    //配置为 输出 推挽 上拉 25MHz
    GPIO_InitStructrue.GPIO_Mode  = GPIO_Mode_OUT;
    GPIO_InitStructrue.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructrue.GPIO_PuPd  = GPIO_PuPd_UP;
    GPIO_InitStructrue.GPIO_Speed = GPIO_Speed_25MHz;

    //2、初始化 PF9 PF10
    GPIO_InitStructrue.GPIO_Pin   = GPIO_Pin_9|GPIO_Pin_10;
    GPIO_Init(GPIOF, &GPIO_InitStructrue);
    //2、初始化 PE13 PE14
    GPIO_InitStructrue.GPIO_Pin   = GPIO_Pin_13|GPIO_Pin_14;
    GPIO_Init(GPIOE, &GPIO_InitStructrue);
    
    //初始灯灭
    GPIO_SetBits(GPIOF, GPIO_Pin_9|GPIO_Pin_10);
    GPIO_SetBits(GPIOE, GPIO_Pin_13|GPIO_Pin_14);
    
}    
 
 
 
 
----------------------------------main.h--------------------------
#ifndef __MAIN_H
#define __MAIN_H

#include "stm32f4xx.h"   //这个头文件一定要留

#endif 





---------------------------------main.c----------------------------

/**
  ******************************************************************************
  * @author  LLH
  * @version V1.0
  * @date    05-12-2018
  * @brief   Main program body
  ******************************************************************************
  */
#include "stm32f4xx.h"   //类似于51单片机  #include <reg52.h>
#include "led.h" 
#include "systick.h"

int main(void)
{
    //1、硬件初始化
    Systick_Init();
    GPIO_LED_Init();
    
    while(1)
    {
       LED0(LED_ON); 
       delay_s(1);
        
       LED0(LED_OFF);
       delay_s(1);   
    }  
}

=====================================================================

                                                                    《前后台系统及中断》

一 、理论知识点--程序运行方式:

----------------------
	方式一:轮询
	int main()
	{
		while(1)
		{
		
		}
	}
---------------------
	方式二:前后台系统  (轮询(后台) + 中断(前台))
	int main()
	{
		while(1)
		{
			//中断产生
		}
	}
	//中断函数
	void IRQ_Handler()
	{
	
	}
---------------------		
	方式三:多任务	--->类似于进程和线程,采用操作系统

二、理论知识点--中断向量:

	1、
       STM32F407ZE 这个型号有 82 + 10 = 92 个中断
       这 92 个中断组成了一个中断向量表,和启动文件中的向量表是一样
	
	2、
       NVIC	--->嵌套向量中断控制器  ---》用于管理所有的中断(类似于电源总闸)
	   这个 NVIC 属于内核外设,所有跟 NVIC 相关的函数都在 misc.c 中
    3、	
       优先级分为两种
	   抢占优先级(主优先级)	---》抢占优先级高的可以打断抢占优先级低的中断
	   响应优先级(子优先级)	---》当多个中断同时到达时,谁的响应优先级高就先执行谁
   4、
       中断有哪些:
	   定时器中断
	   串口中断
	   外部中断(本次程序案列使用这个)

三、程序案列:中断+按键+滴答定时器+led灯

案列思路:(1)滴答定时器起到延时作用。(2)按键产生中断源。(3)led灯亮灭是中断执行的功能。(4)中断类似第三方,站在管理者角度,绑定按键作为中断输入来源,制定中断执行函数体中执行点灯延时点灯.....等操作,中断执行函数时间不易过久。关键点在于中断初始化部分。

------------------------按键--key.h----------------------
#ifndef __KEY_H
#define __KEY_H

//头文件
#include "stm32f4xx.h"   //这个头文件一定要留

//宏定义
#define  KEY_ON         0
#define  KEY_OFF        1

#define  KEY0     GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)
#define  KEY1     GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_2)
#define  KEY2     GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_3)
#define  KEY3     GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4)

//函数声明
void GPIO_KEY_Init(void);

#endif 

------------------------按键--key.c----------------------
#include "key.h"

/*
 *  PA0         --->KEY0
 *  PE2         --->KEY1
 *  PE3         --->KEY2
 *  PE4         --->KEY3
 *  0           --->按下
 *  1           --->松开
 */

/*
 * 功  能:初始化 KEY 的 GPIO 口
 * 参  数:无
 * 返回值:无
 */
void GPIO_KEY_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructrue;
    
    //1、开启 GPIOE GPIOA 时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

    //配置为 输入 上拉
    GPIO_InitStructrue.GPIO_Mode  = GPIO_Mode_IN;
    GPIO_InitStructrue.GPIO_PuPd  = GPIO_PuPd_UP;

    //2、初始化 PA0
    GPIO_InitStructrue.GPIO_Pin   = GPIO_Pin_0;
    GPIO_Init(GPIOA, &GPIO_InitStructrue);
    //2、初始化 PE2 PE3 PE4
    GPIO_InitStructrue.GPIO_Pin   = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;
    GPIO_Init(GPIOE, &GPIO_InitStructrue);
}    
 
 
-------------------led灯-led.h------------
#ifndef __LED_H
#define __LED_H

//头文件
#include "stm32f4xx.h"   //这个头文件一定要留

//宏定义
#define  LED_ON         0
#define  LED_OFF        1

#define  LED0(a);      if(a) \
                            GPIO_SetBits(GPIOF,GPIO_Pin_9); \
                       else \
                            GPIO_ResetBits(GPIOF,GPIO_Pin_9);

#define  LED1(a);      if(a) \
                            GPIO_SetBits(GPIOF,GPIO_Pin_10); \
                       else \
                            GPIO_ResetBits(GPIOF,GPIO_Pin_10);
                       
#define  LED2(a);      if(a) \
                            GPIO_SetBits(GPIOE,GPIO_Pin_13); \
                       else \
                            GPIO_ResetBits(GPIOE,GPIO_Pin_13);

#define  LED3(a);      if(a) \
                            GPIO_SetBits(GPIOE,GPIO_Pin_14); \
                       else \
                            GPIO_ResetBits(GPIOE,GPIO_Pin_14);                      
//函数声明
void GPIO_LED_Init(void);

#endif 

-------------------led灯-led.c------------

#include "led.h"

/*
 *  PF9         --->LED0
 *  PF10        --->LED1
 *  PE13        --->LED2
 *  PE14        --->LED3
 *  0           --->LED_ON
 *  1           --->LED_OFF
 */

/*
 * 功  能:初始化 LED 的 GPIO 口
 * 参  数:无
 * 返回值:无
 */
void GPIO_LED_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructrue;
    
    //1、开启 GPIOE GPIOF 时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);

    //配置为 输出 推挽 上拉 25MHz
    GPIO_InitStructrue.GPIO_Mode  = GPIO_Mode_OUT;
    GPIO_InitStructrue.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructrue.GPIO_PuPd  = GPIO_PuPd_UP;
    GPIO_InitStructrue.GPIO_Speed = GPIO_Speed_25MHz;

    //2、初始化 PF9 PF10
    GPIO_InitStructrue.GPIO_Pin   = GPIO_Pin_9|GPIO_Pin_10;
    GPIO_Init(GPIOF, &GPIO_InitStructrue);
    //2、初始化 PE13 PE14
    GPIO_InitStructrue.GPIO_Pin   = GPIO_Pin_13|GPIO_Pin_14;
    GPIO_Init(GPIOE, &GPIO_InitStructrue);
    
    //初始灯灭
    GPIO_SetBits(GPIOF, GPIO_Pin_9|GPIO_Pin_10);
    GPIO_SetBits(GPIOE, GPIO_Pin_13|GPIO_Pin_14);
    
}    
 
 
--------------------滴答定时器---systick.h--------------------
#ifndef __SYSTICK_H_
#define __SYSTICK_H_

//头文件
#include "stm32f4xx.h"

//宏定义

//函数声明
void Systick_Init(void);
void delay_us(u32 nus);
void delay_ms(u32 nms);
void delay_s(u32 ns);


#endif

--------------------滴答定时器---systick.c--------------------

#include "systick.h"

u8 	my_us = 0;
u16 my_ms = 0;

//初始化滴答定时器
void Systick_Init(void)
{
	//得到的Systick时钟 168MHz/8 = 21MHz   -->每隔 1/21us计数一次
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); 
	my_us = 21;        //21
	my_ms = 21*1000;
}

//微秒延时,nus最大值:798915
void delay_us(u32 nus)   //1
{
	u32 temp = 0;
	//往自动重装载除值寄存器写入延时nus  SysTick->LOAD最大值0xFFFFFF
	SysTick->LOAD = nus*my_us;
	SysTick->VAL  = 0x00;
	SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开启计数,开始倒数
    
    //如果还没有数到 0 就卡死在这个循环中,依据控制寄存器的第 16 位
	do
	{
		//读控制寄存器
		temp = SysTick->CTRL;
	}while(!(temp & (1<<16)));
    
	SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数
	SysTick->VAL  = 0x00;
}

//毫秒延时,nms最大值,nms最大值798.915
void delay_ms(u32 nms)
{
	u32 temp = 0;
	//往自动重装载除值寄存器写入延时nms  SysTick->LOAD最大值0xFFFFFF
	SysTick->LOAD = nms*my_ms;
	SysTick->VAL  = 0x00;
    
	SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开启计数
	do
	{
		//读控制寄存器
		temp = SysTick->CTRL;
	}while(!(temp & (1<<16)));
	SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数
	SysTick->VAL  = 0x00;

}

//秒延时
void delay_s(u32 ns)
{
	for(; ns>0; ns--)
	{
		delay_ms(500);
		delay_ms(500);
	}
}


----------------------中断----exti.h-------------
#ifndef __EXTI_H
#define __EXTI_H

//头文件
#include "stm32f4xx.h"   //这个头文件一定要留
#include "key.h"
#include "led.h"
#include "systick.h"

//宏定义


//函数声明
void EXTI_0234_Init(void);

#endif 


----------------------中断----exti.c-------------
#include "exti.h"

/*
 *  EXTI0   --->PA0     --->KEY0
 *
 */

void EXTI_0234_Init(void)
{
    EXTI_InitTypeDef  EXTI_InitStructrue;
    NVIC_InitTypeDef  NVIC_InitStructrue;
    
    //一定要开启这个时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
    
    //1、设置 PA0(KEY0) PE2(KEY1) PE3(KEY2) PE4(KEY3) 引脚设置为上拉输入模式
    GPIO_KEY_Init(); 
    
    //2、选择 PA0 PE2 PE3 PE4 引脚作为外部中断的输入来源
    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);
    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource2);
    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource3);
    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource4);
    
    //3、初始化 外部中断
    EXTI_InitStructrue.EXTI_Line    = EXTI_Line0 | EXTI_Line2 | EXTI_Line3 | EXTI_Line4;   //外部中断0 2 3 4 
    EXTI_InitStructrue.EXTI_LineCmd = ENABLE;       //打开
    EXTI_InitStructrue.EXTI_Mode    = EXTI_Mode_Interrupt;//中断
    EXTI_InitStructrue.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿(按键默认高电平,按下去的那一瞬间就会由高变低)
    EXTI_Init(&EXTI_InitStructrue);
    
    //4、初始化 NVIC
    NVIC_InitStructrue.NVIC_IRQChannel = EXTI0_IRQn;   //选择外部中断0
    NVIC_InitStructrue.NVIC_IRQChannelCmd = ENABLE;       //打开
    NVIC_InitStructrue.NVIC_IRQChannelPreemptionPriority = 0;   //抢占优先级
    NVIC_InitStructrue.NVIC_IRQChannelSubPriority        = 1;   //响应优先级
    NVIC_Init(&NVIC_InitStructrue);
    
    NVIC_InitStructrue.NVIC_IRQChannel = EXTI2_IRQn;   //选择外部中断2
    NVIC_InitStructrue.NVIC_IRQChannelCmd = ENABLE;       //打开
    NVIC_InitStructrue.NVIC_IRQChannelPreemptionPriority = 1;   //抢占优先级
    NVIC_InitStructrue.NVIC_IRQChannelSubPriority        = 1;   //响应优先级
    NVIC_Init(&NVIC_InitStructrue);
    
    NVIC_InitStructrue.NVIC_IRQChannel = EXTI3_IRQn;   //选择外部中断3
    NVIC_InitStructrue.NVIC_IRQChannelCmd = ENABLE;       //打开
    NVIC_InitStructrue.NVIC_IRQChannelPreemptionPriority = 1;   //抢占优先级
    NVIC_InitStructrue.NVIC_IRQChannelSubPriority        = 0;   //响应优先级
    NVIC_Init(&NVIC_InitStructrue);
    
    NVIC_InitStructrue.NVIC_IRQChannel = EXTI4_IRQn;   //选择外部中断4
    NVIC_InitStructrue.NVIC_IRQChannelCmd = ENABLE;       //打开
    NVIC_InitStructrue.NVIC_IRQChannelPreemptionPriority = 0;   //抢占优先级
    NVIC_InitStructrue.NVIC_IRQChannelSubPriority        = 0;   //响应优先级
    NVIC_Init(&NVIC_InitStructrue);
}

//编写外部中断0执行函数
void EXTI0_IRQHandler(void)
{
    //判断中断是否产生
    if(EXTI_GetFlagStatus(EXTI_Line0) != RESET)
    {
        //清除中断标志位
        EXTI_ClearITPendingBit(EXTI_Line0);
        
        LED0(LED_ON);
        delay_s(3);
        
        LED0(LED_OFF);  
    }  
}

//编写外部中断2执行函数
void EXTI2_IRQHandler(void)
{
      //判断中断是否产生
    if(EXTI_GetFlagStatus(EXTI_Line2) != RESET)
    {
        //清除中断标志位
        EXTI_ClearITPendingBit(EXTI_Line2);
        
        LED1(LED_ON);
        delay_s(1);
        
        LED1(LED_OFF);  
    } 
}

//编写外部中断3执行函数
void EXTI3_IRQHandler(void)
{
      //判断中断是否产生
    if(EXTI_GetFlagStatus(EXTI_Line3) != RESET)
    {
        //清除中断标志位
        EXTI_ClearITPendingBit(EXTI_Line3);
        
        LED2(LED_ON);
        delay_s(1);
        
        LED2(LED_OFF);  
    } 
}

//编写外部中断2执行函数
void EXTI4_IRQHandler(void)
{
      //判断中断是否产生
    if(EXTI_GetFlagStatus(EXTI_Line4) != RESET)
    {
        //清除中断标志位
        EXTI_ClearITPendingBit(EXTI_Line4);
        
        LED3(LED_ON);
        delay_s(1);
        
        LED3(LED_OFF);  
    } 
}
-------------------------main.h---------------
#ifndef __MAIN_H
#define __MAIN_H

#include "stm32f4xx.h"   //这个头文件一定要留

#endif 


-----------------------main.c-----------------
/**
  ******************************************************************************
  * @author  LLH
  * @version V1.0
  * @date    05-12-2018
  * @brief   Main program body
  ******************************************************************************
  */
#include "stm32f4xx.h"   //类似于51单片机  #include <reg52.h>
#include "led.h" 
#include "systick.h"
#include "key.h"
#include "exti.h"

int main(void)
{
    //一般优先级分组写在整个程序的开始,后面尽量不要修改分组
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //第 2 组是最常用的一组
    
    //1、硬件初始化
    Systick_Init();
    GPIO_LED_Init();
    EXTI_0234_Init();
    
    while(1);
}

猜你喜欢

转载自blog.csdn.net/wghkemo123/article/details/85120373