STM32按键输入、所需要的C语言复习、时钟系统框图
扫描二维码
随时随地手机看文章
第一部分:
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宏定义关键词
nifdef条件编译
n extern变量申明
ntypedef类型别名
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的控制最终都是寄存器的控制。