二、滴答定时器、LCD、按键、外部中断

1、systick是内置于stm mcu的一个低级定时器,俗称滴答定时器,使用较简单。

SysTick定时器
SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号: 15)。在以前,大多操
作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。例如,
为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期
的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时
器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问
它的寄存器,以维持操作系统“心跳”的节律。
Cortex‐M3处理器内部包含了一个简单的定时器。因为所有的CM3芯片都带有这个定时
器,软件在不同 CM3器件间的移植工作得以化简。该定时器的时钟源可以是内部时钟(FCLK,
CM3上的自由运行时钟),或者是外部时钟(CM3处理器上的STCLK信号)。不过, STCLK的
具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可能会大不相同,你需要检视
芯片的器件手册来决定选择什么作为时钟源。
SysTick定时器能产生中断, CM3为它专门开出一个异常类型,并且在向量表中有它的一
席之地。它使操作系统和其它系统软件在CM3器件间的移植变得简单多了,因为在所有CM3
产品间对其处理都是相同的。
有4个寄存器控制SysTick定时器,如表8.9至表8.12所示。
133
Cortex‐M3 权威指南 初稿 第 8 章
134
表8.9 SysTick控制及状态寄存器(地址:0xE000_E010)

位段 名称 类型 复位值 描述
16 COUNTFLAG R 0 如果在上次读取本寄存器后, SysTick 已经数到了
0,则该位为 1。如果读取该位,该位将自动清零
2 CLKSOURCE R/W 0 0=外部时钟源(STCLK)
1=内核时钟(FCLK)
1 TICKINT R/W 0 1=SysTick 倒数到 0 时产生 SysTick 异常请求
0=数到 0 时无动作
0 ENABLE R/W 0 SysTick 定时器的使能位


表8.10 SysTick重装载数值寄存器(地址:0xE000_E014)

位段 名称 类型 复位值 描述
23:0 RELOAD R/W 0 当倒数至零时,将被重装载的值


表8.11 SysTick当前数值寄存器(地址:0xE000_E018)

位段 名称 类型 复位值 描述
23:0 CURRENT R/Wc 0 读取时返回当前倒计数的值,写它则使之清零,
同时还会清除在 SysTick 控制及状态寄存器中的
COUNTFLAG 标志


表8.10 SysTick校准数值寄存器(地址:0xE000_E01C)

位段 名称 类型 复位值 描述
31 NOREF R 1=没有外部参考时钟(STCLK 不可用)
0=外部参考时钟可用
30 SKEW R 1=校准值不是准确的 10ms
0=校准值是准确的 10ms
23:0 TENMS R/W 0 10ms 的时间内倒计数的格数。芯片设计者应该通
过 Cortex‐M3 的输入信号提供该数值。若该值读
回零,则表示无法使用校准功能


校准值寄存器提供了这样一个解决方案:它使系统即使在不同的CM3产品上运行,也能
产生恒定的SysTick中断频率。最简单的作法就是:直接把TENMS的值写入重装载寄存器,这
样一来,只要没突破系统极限,就能做到每10ms来一次 SysTick异常。如果需要其它的SysTick
异常周期,则可以根据TENMS的值加以比例计算。只不过,在少数情况下, CM3芯片可能无
法准确地提供TENMS的值(如, CM3的校准输入信号被拉低),所以为保险起见,最好在使
用TENMS前检查器件的参考手册。
SysTick定时器除了能服务于操作系统之外,还能用于其它目的:如作为一个闹铃,用于
测量时间等。要注意的是,当处理器在调试期间被喊停(halt)时,则SysTick定时器亦将暂
停运作。
要想使用该定时器,利用上一个教程建的工程,上一节流水灯的延时用的是软件延时,并不精准,这次改用sysytick。

①、声明一个全局变量

u32 TimeDelay=0;

②、自定义一个延时函数 

void Delay_ms(u32 nTime)
{
   TimeDelay=nTime;
   while(TimeDelay!=0);
}

③、在stm32f10x_it.c文件中写systick处理函数,因为是外部变量(在主函数中定义因而对stm32f10x_it.c相当于外部)所以需要外部引用

extern u32 TimeDelay ;

在最后加上(注:可以写在主函数中,但不建议)

④、最后在主函数中调用systick配置函数 

SysTick_Config(SystemCoreClock/1000); 	  //1ms

因为该处理器为速度为每秒计算72m 次,而SystemCoreClock为系统时钟

所以用该时钟后间隔1ms,最后在用到延时的地方直接使用

Delay_ms(1000);  //延时1s

即可;

2、LCD

比赛一般提供驱动函数,把图中三个文件加到自己建的工程中即可使用

 

在图示四个位置更改延时函数使用上面的systick,同样外部引用

 

最后主函数中便可以调用

#include "stm32f10x.h"
#include "lcd.h"

u32 TimingDelay = 0;

void Delay_Ms(u32 nTime);

//Main Body
int main(void)
{

	STM3210B_LCD_Init();
	LCD_Clear(Blue);
	LCD_SetBackColor(Blue);
	LCD_SetTextColor(White);
	
	SysTick_Config(SystemCoreClock/1000);

	LCD_DrawLine(120,0,320,Horizontal);
	LCD_DrawLine(0,160,240,Vertical);
	Delay_Ms(1000);
	LCD_Clear(Blue);

	LCD_DrawRect(70,210,100,100);
	Delay_Ms(1000);
	LCD_Clear(Blue);

	LCD_DrawCircle(120,160,50);
	Delay_Ms(1000);

	LCD_Clear(Blue);
	LCD_DisplayStringLine(Line4 ,"    Hello,world.   ");
	Delay_Ms(1000);

	LCD_SetBackColor(White);
	LCD_DisplayStringLine(Line0,"                    ");	
	LCD_SetBackColor(Black);
	LCD_DisplayStringLine(Line1,"                    ");	
	LCD_SetBackColor(Grey);
	LCD_DisplayStringLine(Line2,"                    ");
	LCD_SetBackColor(Blue);
	LCD_DisplayStringLine(Line3,"                    ");
	LCD_SetBackColor(Blue2);
	LCD_DisplayStringLine(Line4,"                    ");
	LCD_SetBackColor(Red);						
	LCD_DisplayStringLine(Line5,"                    ");
	LCD_SetBackColor(Magenta);	
	LCD_DisplayStringLine(Line6,"                    ");
	LCD_SetBackColor(Green);	
	LCD_DisplayStringLine(Line7,"                    ");	
	LCD_SetBackColor(Cyan);	
	LCD_DisplayStringLine(Line8,"                    ");
	LCD_SetBackColor(Yellow);		
	LCD_DisplayStringLine(Line9,"                    ");	
	
	while(1);
}

//
void Delay_Ms(u32 nTime)
{
	TimingDelay = nTime;
	while(TimingDelay != 0);	
}

3、外部中断

①、若想用到外部中断首先把相应的exti和misc文件包含进去

②、 这次程序的主要功能是实现按键中断,因此先看按键,由CT117E的电路图可知KEY1-KEY4分别对应PA0、PA8、PB1、PB2,本次实验用到key1和key2。首先是引脚的初始化,和led的类似不过mode为GPIO_Mode_IN_FLOATING;(也可以是GPIO_Mode_IPU),注意要开启引脚的复用功能。

③、接着是exti的初始化:

STM32 的每个 IO 都可以作为外部中断
的中断输入口,这点也是 STM32 的强大之处。 STM32F103 的中断控制器支持 19 个外部中断/
事件请求。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。 STM32F103 的
19 个外部中断为:
线 0~15:对应外部 IO 口的输入中断。
线 16:连接到 PVD 输出。
线 17:连接到 RTC 闹钟事件。
线 18:连接到 USB 唤醒事件
在库函数中,配置 GPIO 与中断线的映射关系的函数 GPIO_EXTILineConfig()来实现的:
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
该函数将 GPIO 端口与中断线映射起来,使用范例是:
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);
将中断线 2 与 GPIOE 映射起来,那么很显然是 GPIOE.2 与 EXTI2 中断线连接了。 设置好中断
线映射之后, 那么到底来自这个 IO 口的中断是通过什么方式触发的呢? 接下来我们就要设置
该中断线上中断的初始化参数了。
中断线上中断的初始化是通过函数 EXTI_Init()实现的。 EXTI_Init()函数的定义是:
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
下面我们用一个使用范例来说明这个函数的使用:
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line=EXTI_Line4;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure); //根据 EXTI_InitStruct 中指定的
//参数初始化外设 EXTI 寄存器
上面的例子设置中断线 4 上的中断为下降沿触发。 STM32 的外设的初始化都是通过结构体来设
置初始值的,这里就不罗嗦结构体初始化的过程了。
④、NVIC

NVIC,中文名嵌套中断向量控制器,是 Cortex-M3 系列控制器内部独有集成单元,
与 CPU 结合紧密,降低中断延迟时间并且能更加高效处理后续中断。举个例子,比如火车站买票,
那些火车站的规章制度就是 NVIC,规定学生和军人有比一般人更高优先级,它们则给你单独安排
个窗口,同学与同学之间也有区别,那就是你也得排队,也就是你的组别(抢断优先级)和你的排
队序号(响应优先级)决定你何时能买到票。
抢断优先级,顾名思义,能再别人中断是抢占别人中断,实现中断嵌套。响应优先
级则只能排队,不能抢在前面插别人的对,即不能嵌套。
STM32 中指定优先级的寄存器为 4 位,其定义如下:
第 0 组:所有 4 位用于指定响应优先级
第 1 组:最高 1 位用于指定抢占式优先级,最低 3 位用于指定响应优先级
第 2 组:最高 2 位用于指定抢占式优先级,最低 2 位用于指定响应优先级
第 3 组:最高 3 位用于指定抢占式优先级,最低 1 位用于指定响应优先级
第 4 组:所有 4 位用于指定抢占式优先级
以上定义也称作中断优先级分组,相关内容在 STM32 固件库的 misc.h 文件中有详细定义。

初始化:

NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; //使能按键外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //子优先级 2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //中断优先级分组初始化
 

STM32 的 IO 口外部中断函数只有 6 个,
分别为:
EXPORT EXTI0_IRQHandler
EXPORT EXTI1_IRQHandler
EXPORT EXTI2_IRQHandler
EXPORT EXTI3_IRQHandler
EXPORT EXTI4_IRQHandler
EXPORT EXTI9_5_IRQHandler
EXPORT EXTI15_10_IRQHandler
中断线 0-4 每个中断线对应一个中断函数, 中断线 5-9 共用中断函数 EXTI9_5_IRQHandler,中
断线 10-15 共用中断函数 EXTI15_10_IRQHandler。 在编写中断服务函数的时候会经常使用到两
个函数, 第一个函数是判断某个中断线上的中断是否发生(标志位是否置位):
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
这个函数一般使用在中断服务函数的开头判断中断是否发生。 另一个函数是清除某个中断线上
的中断标志位:
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
这个函数一般应用在中断服务函数结束之前, 清除中断标志位。
常用的中断服务函数格式为:
void EXTI3_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line3)!=RESET)//判断某个线上的中断是否发生
{
中断逻辑…
EXTI_ClearITPendingBit(EXTI_Line3); //清除 LINE 上的中断标志位
}
}
在这里需要说明一下,固件库还提供了两个函数用来判断外部中断状态以及清除外部状态
标志位的函数 EXTI_GetFlagStatus 和 EXTI_ClearFlag,他们的作用和前面两个函数的作用类似。
只是在 EXTI_GetITStatus 函数中会先判断这种中断是否使能,使能了才去判断中断标志位,而
EXTI_GetFlagStatus 直接用来判断状态标志位。

然后在stm32f10x_it.c中写相应的中断服务函数(注意,函数名必须是上文中提到的不可自定义)


 

这里我们主要想实现按键功能,因此主函数自定义了一个 变量u8 EXTI_Status=0;之后通过判断EXTI_Status的值来判断按下的按键。

附上主函数的完整代码

#include "stm32f10x.h"
#include "lcd.h"

u32 TimingDelay = 0;
u8 EXTI_Status=0;


void Delay_Ms(u32 nTime);
void EXTI_Config(void);

//Main Body
int main(void)
{

	STM3210B_LCD_Init();

	EXTI_Config();

	LCD_Clear(Blue);
	LCD_SetBackColor(Blue);
	LCD_SetTextColor(White);
	
	SysTick_Config(SystemCoreClock/1000);

	

	LCD_DisplayStringLine(Line1," KEY_EXTI  TEST     ");	
	LCD_DisplayStringLine(Line3," PRESS THE BUTTON   ");	
	
	LCD_SetBackColor(White);
	LCD_SetTextColor(Blue);
	
	while(1)
	{
	 switch(EXTI_Status)
	 {
	 case 1:
	 LCD_DisplayStringLine(Line5," BUTTON1 PRESSED    ");
	 break;

	 case 2:
	 LCD_DisplayStringLine(Line5," BUTTON2 PRESSED    ");
	 break;

	 
	 }
	
	}
}

void EXTI_Config(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	EXTI_InitTypeDef  EXTI_InitStructure;
	NVIC_InitTypeDef  NVIC_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);

   EXTI_InitStructure.EXTI_Line = EXTI_Line0;
   EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
   EXTI_InitStructure.EXTI_LineCmd = ENABLE;
   EXTI_Init(&EXTI_InitStructure);


   NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

   NVIC_Init(&NVIC_InitStructure);



	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource8);

   EXTI_InitStructure.EXTI_Line = EXTI_Line8;
   EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
   EXTI_InitStructure.EXTI_LineCmd = ENABLE;
   EXTI_Init(&EXTI_InitStructure);


   NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

   NVIC_Init(&NVIC_InitStructure);




}



void Delay_Ms(u32 nTime)
{
	TimingDelay = nTime;
	while(TimingDelay != 0);	
}

stm32f10x_it.c代码

/**
  ******************************************************************************
  * @file    Project/STM32F10x_StdPeriph_Template/stm32f10x_it.c 
  * @author  MCD Application Team
  * @version V3.5.0
  * @date    08-April-2011
  * @brief   Main Interrupt Service Routines.
  *          This file provides template for all exceptions handler and 
  *          peripherals interrupt service routine.
  ******************************************************************************
  * @attention
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x_it.h"
extern u32 TimingDelay;
extern u8 EXTI_Status;

/** @addtogroup STM32F10x_StdPeriph_Template
  * @{
  */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/******************************************************************************/
/*            Cortex-M3 Processor Exceptions Handlers                         */
/******************************************************************************/

/**
  * @brief  This function handles NMI exception.
  * @param  None
  * @retval None
  */
void NMI_Handler(void)
{
}

/**
  * @brief  This function handles Hard Fault exception.
  * @param  None
  * @retval None
  */
void HardFault_Handler(void)
{
  /* Go to infinite loop when Hard Fault exception occurs */
  while (1)
  {
  }
}

/**
  * @brief  This function handles Memory Manage exception.
  * @param  None
  * @retval None
  */
void MemManage_Handler(void)
{
  /* Go to infinite loop when Memory Manage exception occurs */
  while (1)
  {
  }
}

/**
  * @brief  This function handles Bus Fault exception.
  * @param  None
  * @retval None
  */
void BusFault_Handler(void)
{
  /* Go to infinite loop when Bus Fault exception occurs */
  while (1)
  {
  }
}

/**
  * @brief  This function handles Usage Fault exception.
  * @param  None
  * @retval None
  */
void UsageFault_Handler(void)
{
  /* Go to infinite loop when Usage Fault exception occurs */
  while (1)
  {
  }
}

/**
  * @brief  This function handles SVCall exception.
  * @param  None
  * @retval None
  */
void SVC_Handler(void)
{
}

/**
  * @brief  This function handles Debug Monitor exception.
  * @param  None
  * @retval None
  */
void DebugMon_Handler(void)
{
}

/**
  * @brief  This function handles PendSVC exception.
  * @param  None
  * @retval None
  */
void PendSV_Handler(void)
{
}

/**
  * @brief  This function handles SysTick Handler.
  * @param  None
  * @retval None
  */
void SysTick_Handler(void)
{
	TimingDelay--;
}

void EXTI0_IRQHandler(void)
{
  if(EXTI_GetITStatus(EXTI_Line0) != RESET)
  {
   	EXTI_Status=1;

   
    EXTI_ClearITPendingBit(EXTI_Line0);
  }

}

void EXTI9_5_IRQHandler(void)
{
  if(EXTI_GetITStatus(EXTI_Line8) != RESET)
  {
   	EXTI_Status=2;

   
    EXTI_ClearITPendingBit(EXTI_Line8);
  }

}

/******************************************************************************/
/*                 STM32F10x Peripherals Interrupt Handlers                   */
/*  Add here the Interrupt Handler for the used peripheral(s) (PPP), for the  */
/*  available peripheral interrupt handler's name please refer to the startup */
/*  file (startup_stm32f10x_xx.s).                                            */
/******************************************************************************/

/**
  * @brief  This function handles PPP interrupt request.
  * @param  None
  * @retval None
  */
/*void PPP_IRQHandler(void)
{
}*/

/**
  * @}
  */ 


/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
发布了48 篇原创文章 · 获赞 129 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/qqGHJ/article/details/86565786
今日推荐