一、学习参考资料
(1)正点原子的寄存器源码。
(2)STM32F103最小系统板开发指南-寄存器版本_V1.1(正点)
(3)STM32F103最小系统板开发指南-库函数版本_V1.1(正点)
(4)Cortex-M3权威指南(中文)
(5)STM32中文参考手册_V10
(6)stm32cubemx可视化时钟树配置
(7)其他博主文章
本文主要以stm32f1系列单片机为研究对象,从寄存器层面对时钟树的配置、中断优先级的配置进行阐述。
本文主要介绍GPIO口的寄存器配置,以及GPIO的外部中断的配置。
二、普通GPIO模式的配置
2.1、GPIO的基本知识点
由图可以所有普通GPIO口的外设都挂载在APB2总线上,GPIO的普通模式配置是比较简单的。
(1)使能APB2上对应GPIO的外设时钟。
(2)对应GPIO的寄存器设置其模式,并且设置高低电平。
输入模式:
- 浮空输入(GPIO_Mode_IN_FLOATING)
浮空即逻辑器件既不接高电平也不接低电平,电压处于确定的情况,多用于外部按键ADC输入,减少上下拉电阻对结果的影响。
2.上拉输入(GPIO_Mode_IPU)
上拉就是把点位拉高,比如拉到Vcc。上拉就是将不确定的信号通过一个电阻嵌位在高电平。电阻同时起到限流的作用。弱强只是上拉电阻的阻值不同,没有什么严格区分。
3.下拉输入(GPIO_Mode_IPD)
就是把电压拉低,拉到GND。与上拉原理相似。
4.模拟输入(GPIO_Mode_AIN)
模拟输入是指传统方式的输入,数字输入是输入PCM数字信号,即0、1的二进制数字信号,通过数模转换,转换成模拟信号,经前级放大进入功率放大器,功率放大器还是模拟的。
输出模式:
- 开漏输出(GPIO_Mode_Out_OD)
输出端相当于三极管的集电极,要得到高电平状态需要上拉电阻才行,适合于做电流型的驱动,其吸收电流的能力相对强(一般20mA以内)。开漏形式的电路有以下几个特点:
利用外部电路的驱动能力,减少IC内部的驱动。当IC内部MOSFET导通时,驱动电流是从外部的VCC流经R pull-up ,MOSFET到GND,IC内部仅需很小的栅极驱动电流。
一般来说,开漏是用来连接不同电平的器件,匹配电平用的,因为开漏引脚不连接外部的上拉电阻时,只能输出低电平,如果需要同时具备输出高电平的功能,则需要接上拉电阻,很好的一个优点是通过改变上拉电源的电压,便可以改变传输电平。比如加上上拉电阻就可以提供TTL/CMOS电平输出等。(上拉电阻的阻值决定了逻辑电平转换的沿的速度 ,阻值越大,速度越低功耗越小,所以负载电阻的选择要兼顾功耗和速度。)
OPEN-DRAIN提供了灵活的输出方式,但是也有其弱点,就是带来上升沿的延时。因为上升沿是通过外接上拉无源电阻对负载充电,所以当电阻选择小时延时就小,但功耗大;反之延时大功耗小。所以如果对延时有要求,则建议用下降沿输出。
可以将多个开漏输出的Pin连接到一条线上,通过一只上拉电阻,在不增加任何器件的情况下,形成"与逻辑"关系。这也是I2C,SMBus等总线判断总线占用状态的原理。可以简单的理解为:在所有引脚连在一起时,外接一上拉电阻,如果有一个引脚输出为逻辑0,相当于接地,与之并联的回路"相当于被一根导线短路",所以外电路逻辑电平便为0,只有都为高电平时,与的结果才为逻辑1。
2.开漏复用功能(GPIO_Mode_AF_OD)
可以理解为GPIO口被用作第二功能时的配置情况(即并非作为通用IO口使用)。端口必须配置成复用功能输出模式(推挽或开漏)。
3.推挽输出(GPIO_Mode_Out_PP)
可以输出高、低电平,连接数字器件;推挽结构一般是指两个三级管分别受到互补信号的控制,总是在一个三极管导通的时候另一个截止。高低电平由IC的电源低定。
推挽电路是两个参数相同的三极管或MOSFET,以推挽方式存在于电路中,各负责正负半周的波形方法任务,电路工作时,两只对称的功率开关管每次只有一个导通,所以导通损耗小,效率高。输出即可以向负载灌电流。推拉式输出级即提高电路的负载能力,又提高开关速度。
4.推挽复用功能(GPIO_Mode_AF_PP)
可以理解为GPIO口被用作第二功能时的配置情况(并非作为通用IO口使用)。
GPIO与外设连接时的配置模式:STM32中文手册110页(外设的 GPIO 配置 ),配置不同的功能的时候可以参考。
2.2、普通GPIO模式的配置
使能APB2上对应的GPIO的时钟。
设置对应的GPIO模式。
下面是GPIO的普通模式的配置代码(正点):
cpp
//初始化PB5和PE5为输出口.并使能这两个口的时钟
//LED IO初始化
void LED_Init(void)
{
RCC->APB2ENR|=1<<3; //使能PORTB时钟
RCC->APB2ENR|=1<<6; //使能PORTE时钟
GPIOB->CRL&=0XFF0FFFFF;
GPIOB->CRL|=0X00300000;//PB.5 推挽输出
GPIOB->ODR|=1<<5; //PB.5 输出高
GPIOE->CRL&=0XFF0FFFFF;
GPIOE->CRL|=0X00300000;//PE.5推挽输出
GPIOE->ODR|=1<<5; //PE.5输出高
}
三、GPIO的外部中断模式
3.1、GPIO外部中断的基础知识
STM32 的每个 IO 都可以作为外部中断 的中断输入口,这点也是 STM32 的强大之处。STM32F103 的中断控制器支持 19 个外部中断/ 事件请求。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。
STM32F103 的 19 个外部中断为:
线 0~15 :对应外部 IO 口的输入中断。
线 16 :连接到 PVD 输出。
线 17 :连接到 RTC 闹钟事件。
线 18 :连接到 USB 唤醒事件。
GPIO外部中断的配置的基本流程如下所示:
(1) 辅助功能 IO 时钟使能。
(2)设置GPIO映射到对应的外部中断EXTI。
(3)开启line BITx上的中断。
(4)外部中断的触发方式的选择(上升沿或者下降沿)。
3.2、GPIO外部中断的寄存器配置
(1)辅助功能IO时钟使能。
注意,辅助功能IO时钟的使能是在APB2ENR使能寄存器的首位。其他外设的辅助功能IO时钟使能是在AFIO寄存器中。
(2) 设置GPIO映射到对应的外部中断EXTI。
这里就了到了上面讲的,将外部中断划分成16组的形式,对应16个引脚。
(3)开启line BITx上的中断。
中断的配置寄存器中和时间配置寄存器是在一起的,这里说明一下中断寄存器和事件寄存器之间的区别。
事件机制提供了一个完全有硬件自动完成的触发到产生结果的通道,不要软件的参与,降低了CPU的负荷,节省了中断资源,提高了响应速度(硬件总快于软件),是利用硬件来提升CPU芯片处理事件能力的一个有效方法。
(4)外部中断的触发方式的选择(上升沿或者下降沿)。
3.3、GPIO的中断配置代码
下面是正点的GPIO中断配置代码:
其中外部中断的映射寄存器是四个bit位对应设置,这里函数入口只会给对那个引脚进行设置,这时候设置对应位时,就需要进行处理一下。
如上图所示,通过需要配置的引脚数PIN_NUM计算出来需要对那组寄存器进行配置(例如需要配置pin_5这个寄存器,5/4=1,所以需要配饰EXI5[3:0]),并且需要计算出来配置的寄存器的起始偏移地址位置(例如需要配置pin_5这个寄存器,(5%4)*4=4,所以配置寄存器位就是AFIO_EXTICR2的第五位,即数组下表为4)。
cpp
//外部中断配置函数
//只针对GPIOA~G;不包括PVD,RTC和USB唤醒这三个
//参数:
//GPIOx:0~6,代表GPIOA~G
//BITx:需要使能的位;
//TRIM:触发模式,1,下升沿;2,上降沿;3,任意电平触发
//该函数一次只能配置1个IO口,多个IO口,需多次调用
//该函数会自动开启对应中断,以及屏蔽线
void Ex_NVIC_Config(u8 GPIOx,u8 BITx,u8 TRIM)
{
u8 EXTADDR;
u8 EXTOFFSET;
EXTADDR=BITx/4; //得到中断寄存器组的编号
EXTOFFSET=(BITx%4)*4; //获得中断寄存器组的首偏移地址
RCC->APB2ENR|=0x01; //使能io复用时钟
AFIO->EXTICR[EXTADDR]&=~(0x000F<<EXTOFFSET); //清除原来设置!!!
AFIO->EXTICR[EXTADDR]|=GPIOx<<EXTOFFSET; //EXTI.BITx映射到GPIOx.BITx
//自动设置
EXTI->IMR|=1<<BITx; // 开启line BITx上的中断
//EXTI->EMR|=1<<BITx; //不屏蔽line BITx上的事件 (如果不屏蔽这句,在硬件上是可以的,但是在软件仿真的时候无法进入中断!)
if(TRIM&0x01)EXTI->FTSR|=1<<BITx; //line BITx上事件下降沿触发
if(TRIM&0x02)EXTI->RTSR|=1<<BITx; //line BITx上事件上升降沿触发
}
下面是AFIO结构体寄存器的封装代码:
cpp
typedef struct
{
__IO uint32_t IMR;
__IO uint32_t EMR;
__IO uint32_t RTSR;
__IO uint32_t FTSR;
__IO uint32_t SWIER;
__IO uint32_t PR;
} EXTI_TypeDef;
cpp
#define EXTI ((EXTI_TypeDef *) EXTI_BASE)
四、串口配置
4.1串口的基础知识
串口的主要配置参数有:波特率 、数据位 、奇偶校验位 、停止位 、数据流控制。
数据流控制(介绍):
通过串口传输数据时,由于计算机之间处理速度或其他因素的影响,会造成丢失数据的现象。例如,台式机与单片机之间的通信,接收端数据缓冲区已满的情况下,继续收到数据,新发送来的数据就会由于无法处理造成丢失。数据流控制用于解决这个问题。通过控制发送数据的速度,确保数据不会出现丢失。
数据流控制可以分为软件流控制(Xon/Xoff)和硬件流控制,如图6.17所示,也可以选择不使用数据流控制。软件流控制使用特殊的字符作为启动或停止的标志。而硬件流控制通过使用硬件信号(CTR/RTS)来实现 。使用硬件流控制时,在接收端准备好接收数据后,设定CTS为1,否则CTS为0。同样,如果发送端准备好要发送数据,则设定RTS为1;如果还未准备好,设置CTS为0。
下面是usart配置的一些知识:
● 总线在发送或接收前应处于空闲状态
● 一个起始位
● 一个数据字 (8 或 9 位 ) ,最低有效位在前
● 0.5 , 1.5 , 2 个的停止位,由此表明数据帧的结束
● 使用分数波特率发生器 ------ 12 位整数和 4 位小数的表示方法。
● 一个状态寄存器 (USART_SR)
● 数据寄存器 (USART_DR)
● 一个波特率寄存器 (USART_BRR) , 12 位的整数和 4 位小数
● 一个智能卡模式下的保护时间寄存器 (USART_GTPR)
可配置的停止位
随每个字符发送的停止位的位数可以通过控制寄存器 2 的位 13 、 12 进行编程。
**1.**1个停止位:停止位位数的默认值。
2. 2个停止位:可用于常规 USART 模式、单线模式以及调制解调器模式。
3. 0.5个停止位:在智能卡模式下接收数据时使用。
**4.**1.5个停止位:在智能卡模式下发送和接收数据时使用。
空闲帧包括了停止位。
单字节通信
清零TXE 位总是通过对数据寄存器的写操作来完成的。 TXE 位由硬件来设置,它表明:
● 数据已经从TDR 移送到移位寄存器,数据发送已经开始
● TDR 寄存器被清空
● 下一个数据可以被写进USART_DR 寄存器而不会覆盖先前的数据
如果TXEIE 位被设置,此标志将产生一个中断。
下面是串口的波特率的设置:
CPU的时钟频率越低,则某一特定波特率的误差也越低
根据上面的公式,知道波特率和PCLK1时钟就可以计算出来串口设置对应波特率时候,寄存器位USARTDIV的值应设置为多少。不同的串口挂载的的总线位置是不一样的,所以计算的时候fclk的值是不一样的。串口有挂载在PCLK1或者PCLK2上的。
下面是DMA的收和发的配置的形式:
下面是硬件控制流的知识点。
4.2、串口的收发寄存器配置
串口寄存器的配置,从普通的串口寄存器的基础参数的配置、串口的中断的寄存器配置、串口的DMA寄存器的配置。
4.2.1、串口的寄存器配置
串口的配置之前首先需要对GPIO进行配置。GPIO的引脚要设置成对应的形式(因为要与其它的外设联系,所以这里需要将GPIO于其他的外设复用起来)。
注意:配置串口等外设的时候,需要将GPIO的引脚与对应的外设(例如串口)联系起来,如果GPIO与外设的复用为"没有复用"(部分复用、完全复用)的时候,这时候只需要将GPIO口为输入模式的时候,配置成"复用推挽或者复用开漏输出",GPIO口为输入的时候,就普通配置就可以了。
两者的共同点都是引脚可以通过给出正反向电压来控制MOS管导通从而让引脚输出高低电平,而两者区别就在于推挽复用输出不经过输出数据寄存器(ODR) 。
拿usart1为例:若要实现usart1的通信功能,我们就要同时使能GPIOA和外设USART1。如果采用推挽输出,则该引脚电平直接由ODR控制而不受usart外设的控制。因此采用推挽复用输出从而绕过ODR的限制,由相应的外设模块控制。
输入的时候和输出不一样,是没有"输出控制器",所以输入会同时以两路传输到芯片的内部,"A"、"B"、"C"三路都是有信号输入的。
上面知识的链接:STM32中推挽输出和推挽复用输出的区别 - 案板上的三文鱼 - 博客园 (cnblogs.com)
下面将针对"USART1"的串口的配置,中断,DMA进行阐述。
(1)使能USART1的GPIO口的时钟,USART1串口的时钟(PA9、PA10)
cpp
RCC->APB2ENR|=1<<2; //使能PORTA口时钟
RCC->APB2ENR|=1<<14; //使能串口时钟
(2)IO状态的配置
cpp
GPIOA->CRH&=0XFFFFF00F; //IO状态设置,引脚状态的清零
GPIOA->CRH|=0X000008B0; //IO状态设置 ,引脚状态的配置
(3)对串口时钟复位之后,停止复位后进行配置
cpp
RCC->APB2RSTR|=1<<14; //复位串口1
RCC->APB2RSTR&=~(1<<14); //停止复位
(4)波特率,数据位,校验位,硬件流控制
前面GPIO的配置都已经讲过了,这里串口的配置还没有讲,这里进行详细的介绍。USART的控制寄存器,有下面的比较常用的7个寄存器。
状态寄存器(USART_SR)是串口的"发送完成"等标志。
数据寄存器(USART_DR),是串口数据寄存去,它由两个寄存器组成"TDR"和"RDR",
波特比率寄存器(USART_BRR),是串口的波特率设置的寄存器,分为整数部分寄存器和小数部分寄存器。
控制寄存器1(USART_CR1),串口的使能,以及发送接收等寄存器的使能的设置。
控制寄存器2(USART_CR2)
控制寄存器3(USART_CR3)
保护时间和预分频寄存器(USART_GTPR),该寄存器一般都是在低功耗的时候使用,使用比较少。
对串口进行配置的时候,可以根据实际的需求进行配置。
cpp
USART1->BRR=mantissa; //波特率设置
USART1->CR1|=0X200C; //1位停止,无校验位.
(5)使能中断,并对中断优先级配置
串口中断的配置,需要根据串口的控制寄存器,使能串口的接收缓冲区非空中断使能,然后根据中断的通道对中断进行配置。中断的配置下面讲
cpp
USART1->CR1|=1<<5; //接收缓冲区非空中断使能
4.2.2、串口的中断的寄存器配置
串口中断的配置,就是抢占优先级和响应优先级的配置,这两个参数进行配置的时候需要根据设置的中断优先级进行配置。配置的时候需要根据中断的通道进行配置。这部分知识是在内核手册的文档中的,"Cortex-M3权威指南(中文)"。
下面是中断的使能寄存器,Cortex-M3