×
单片机 > 单片机程序设计 > 详情

STM32按键输入、所需要的C语言复习、时钟系统框图

发布时间:2020-09-01 发布时间:
|

第一部分:

STM32按键输入是我的第二个在STM32 平台上有输入的小实例。思路为,先查询硬件图看清按键是低电平有效还是高电平有效,根据我的开发环境得知四个按键有三个按键是低电平有效,有一个按键是高电平有效。然后设计代码,设计代码之前得分析清楚,按键有两种情况,可持续按键和不可持续按键。可持续按键的意思是,按一下放开后,继续按还会有用,而不可持续按键就不行。

分清按键类型就可以照一般运用外设的三步走战略前进,第一步初始化按键输入时钟,第二步初始化所运用的IO时钟,第三步扫描键盘

初始化时钟选择时钟系统中的高速总线挂载的时钟,APB2所包含的时钟函数RCC_APB2PeriphClockCmd()。具体下面的时钟系统分析会清晰的讲述。

接下来调用IO初始化函数GPIO_Init();

最后一步用于扫描键盘,扫描键盘设置了扫描参数,为两种模式,模式0是不持续按键,模式1是持续按键,具体扫描参数如下代码:

u8 key_scan(u8 mode)
{
static u8 key_up=1;//mode0是不持续按键,mode1是持续按键
  if(mode==1) key_up=1;
if(key_up&&(key0==0||key1==0||key2==0||wk_up==1))
{
delay_ms(30);
key_up=0;
if(key0==0)return key0_pres;//
else if(key1==0) return key1_pres;
else if(key2==0) return key2_pres;
else if(wk_up==1) return wkup_pres;
}
else if(key0==1&&key1==1&&key2==1&&wk_up==0)key_up=1;
return 0;
}

所写的头文件主要是函数申明和一些所需要的预编译如下:

#ifndef __Key_Init
#define __Key_Init
#include "sys.h"//包含位带操作
//采用位带操作
//#define key0  PEin(4)
//#define key1  PEin(3)
//#define key2  PEin(2)
//#define wk_up PAin(0)
//采用库函数
#define key0  GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)
#define key1  GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)
#define key2  GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2)
#define wk_up GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)
#define key0_pres 1//控制led0
#define key1_pres 2//控制led0
#define key2_pres 3//控制跑马灯
#define wkup_pres 4//控制蜂鸣器
//采用寄存器

void __key_init(void);
u8 key_scan(u8);
#endif
采用寄存器进行操作,主要是操作CRL和ODR寄存器,由于采用的是上拉下拉输入,而上拉下拉的控制是由ODR寄存器控制

第二部分:

接下来的内容是对STM32 中经常用到的C语言知识的复习回顾,按键输入中用到的不持续按键就用到了static变量,让变量存储于静态区,以利于键值的保持。

对于STM32中用到比较多的C语言是下述


n位操作

n  define宏定义关键词

n  ifdef条件编译

n  extern变量申明

n  typedef类型别名

n  结构体

n  static关键字

位操作主要有六种,按位与,或,取反,异或左移右移

按位或主要运用在如上面对GPIO口的初始化中GPIO_InitKEY.GPIO_Pin= GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;

可以节省代码量。

后面的ifdef等属于预编译,主要有的代码块可以执行也可以不执行,一般用到ifdef预编译。

extern申明这个变量或者函数可以在别的文件中引用

typedef主要就是给数据类型取一个别名如u8等,和#define类型,但差别又很大,#define可以定义任何别名,而typedef一般用于数据类型

static主要就是把全局或局部变量存储于静态存储区,运用其所谓的记忆功能

结构体则具有很强的作用,很重要的作用,尤其对于代码的扩展性来说,如一个函数有很多的参数,若想添加参数则,整个文件所有运用到这个函数的地方都得改动,而用结构体只需在引用时引用在结构体中添加即可。

增加一个内容,STM32中的寄存器地址映射:

以地址是如何计算到GPIOA为例,首先地址找到的是外设的基地址,然后加上偏移找到APB2总线的地址,再加上GPIOA的地址偏移量,计算出GPIOA的基地址,其他的七个寄存器地址依次加入偏移量即可,原理图如图一。

第三部分:


我认为第三部分是整个STM32中最重要的地方,很多地方把时钟系统比喻为系统的心脏,我觉得更贴切的是比喻为血液,一个器官有血液流过,才带来氧用于提供器官所需能量。
时钟系统原理图在最下面给出。首先给出时钟系统的总结如下:


1.STM32 有5个时钟源:HSI、HSE、LSI、LSE、PLL。

     ①、HSI是高速内部时钟,RC振荡器,频率为8MHz,精度不高。
   ②、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时

                钟源,频率范围为4MHz~16MHz。
   ③、LSI是低速内部时钟,RC振荡器,频率为40kHz,提供低功耗时钟。WDG
   ④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体。RTC
   ⑤、PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。

              倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。
2. 系统时钟SYSCLK可来源于三个时钟源:
        ①、HSI振荡器时钟

        ②、HSE振荡器时钟

        ③、PLL时钟

3.STM32可以选择一个时钟信号输出到MCO脚(PA8)上,可以选择为PLL

  输出的2分频、HSI、HSE、或者系统时钟。

4.任何一个外设在使用之前,必须首先使能其相应的时钟。

下面给出系统比较重要的时钟:

1SYSCLK(系统时钟) :

2AHB总线时钟:总共有六种分频因子,用来提供APB1和APB2

3APB1总线时钟(低速): 速度最高36MHz,主要用来提供低速外设的

4APB2总线时钟(高速): 速度最高72MHz,主要用来提供高速外设

5PLL时钟,锁相环所提供的时钟主要用来倍频。

typedefstruct

{

  __IO uint32_tCR;                //HSI,HSE,CSS,PLL等的使能和就绪标志位

  __IO uint32_tCFGR;           //PLL等的时钟源选择,分频系数设定

 __IO uint32_t CIR;              //清除/使能 时钟就绪中断

 __IO uint32_t APB2RSTR;  //APB2线上外设复位寄存器

 __IO uint32_t APB1RSTR;   //APB1线上外设复位寄存器

  __IO uint32_tAHBENR;    //DMA,SDIO等时钟使能

  __IO uint32_tAPB2ENR;   //APB2线上外设时钟使能

  __IO uint32_tAPB1ENR;   //APB1线上外设时钟使能

 __IO uint32_t BDCR;        //备份域控制寄存器

 __IO uint32_t CSR;           //控制状态寄存器

} RCC_TypeDef;

控制上述时钟的各个状态就靠寄存器,任何MCU的控制最终都是寄存器的控制。




『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
8051单片机的函数发生器的设计