STM32F4嵌入式学习总结9
1、STM32F4IO口的复用
STM32F4有很多的内置外设,这些外设的外部引脚都是与GPIO复用的。也就是说,一个GPIO如果可以复用为内置外设的功能引脚,那么当这个GPIO作为内置外设使用的时候,就叫做复用。
这部分知识在《STM32F4中文参考手册》第七章和芯片数据手册有详细的讲解哪些GPIO管脚是可以复用为哪些内置外设。对于本小节知识,STM32F4中文参考手册讲解比较详细,我们同样会从中抽取重要的知识点罗列出来。同时,我们会以串口使用为例给大家讲解具体的引脚复用的配置。
STM32F4系列微控制器IO引脚通过一个复用器连接到内置外设或模块。该复用器一次只允许一个外设的复用功能(AF)连接到对应的IO口。这样可以确保共用同一个IO引脚的外设之间不会发生冲突。每个IO引脚都有一个复用器,该复用器采用16路复用功能输入(AF0到AF15),可通过GPIOxAFRL(针对引脚07)和GPIOxAFRH(针对引脚815)寄存器对这些输入进行配置,每四位控制一路复用:
1)完成复位后,所有IO都会连接到系统的复用功能0(AF0)。
2)外设的复用功能映射到AF1到AF13。
3)CortexM4EVENTOUT映射到AF15。
接下来,我们简单说明一下这个图要如何看,举个例子,探索者STM32F407开发板的原理图上PC11的原理图如图
如上图所示,PC11可以作为SPI3MISOU3RXU4RXSDIOD3DCMID4I2S3extSD等复用功能输出,这么多复用功能,如果这些外设都开启了,那么对STM32F1来说,那就可能乱套了,外设之间可互相干扰,但是STM32F4,由于有复用功能选择功能,可以让PC11仅连接到某个特定的外设,因此不存在互相干扰的情况。
是针对引脚07,对于引脚815,控制寄存器为GPIOxAFRH。从图中可以看出。当需要使用复用功能的时候,我们配置相应的寄存器GPIOxAFRL或者GPIOxAFRH,让对应引脚通过复用器连接到对应的复用功能外设。这里我们列出GPIOxAFRL寄存器的描述,GPIOxAFRH的作用跟GPIOxAFRL类似,只不过GPIOxAFRH控制的是一组IO口的高八位,
从表中可以看出,32位寄存器GPIOxAFRL每四个位控制一个IO口,所以每个寄存器控制3248个IO口。寄存器对应四位的值配置决定这个IO映射到哪个复用功能AF。在微控制器完成复位后,所有IO口都会连接到系统复用功能0(AF0)。这里大家需要注意,对于系统复用功能AF0,我们将IO口连接到AF0之后,还要根据所用功能进行配置
1)JTAGSWD:在器件复位之后,会将这些功能引脚指定为专用引脚。也就是说,这些引脚在复位后默认就是JTAGSWD功能。如果我们要作为GPIO来使用,就需要对对应的IO口复用器进行配置。
2)RTCREFIN:此引脚在系统复位之后要使用的话要配置为浮空输入模式。
3)MCO1和MCO2:这些引脚在系统复位之后要使用的话要配置为复用功能模式。对于外设复用功能的配置,除了ADC和DAC要将IO配置为模拟通道之外其他外设功能一律要配置为复用功能模式,这个配置是在IO口对应的GPIOxMODER寄存器中配置的。同时要配置GPIOxAFRH或者GPIOxAFRL寄存器,将IO口通过复用器连接到所需要的复用功能对应的AFx。不是每个IO口都可以复用为任意复用功能外设。到底哪些IO可以复用为相关外设呢?这在芯片对应的数据手册(请参考光盘目录:)上面会有详细的表格列出来。对于STM32F407,数据手册里面的Table9。Alternatefunctionmapping表格列出了所有的端口AF映射表,因为表格比较大,所以这里只列出PORTA的几个端口为例方便大家理解:
PA9连接AF7可以复用为串口1的发送引脚USART1TX,PA10连接AF7可以复用为串口2的接受引脚USART1RX。接下来我们以串口1为例来讲解怎么配置GPOPA。9,GPIOA。10口为串口1复用功能。
1)首先,我们要使用IO复用功能外设,必须先打开对应的IO时钟和复用功能外设时钟。
使能GPIOA时钟
RCCAHB1PeriphClockCmd(RCCAHB1PeriphGPIOA,ENABLE);
使能USART1时钟
RCCAPB2PeriphClockCmd(RCCAPB2PeriphUSART1,ENABLE);
这里需要说明一下,官方库提供了五个打开GPIO和外设时钟的函数分别为:
voidRCCAHB1PeriphClockCmd(uint32tRCCAHB1Periph,FunctionalStateNewState);
voidRCCAHB2PeriphClockCmd(uint32tRCCAHB2Periph,FunctionalStateNewState);
voidRCCAHB3PeriphClockCmd(uint32tRCCAHB3Periph,FunctionalStateNewState);
voidRCCAPB1PeriphClockCmd(uint32tRCCAPB1Periph,FunctionalStateNewState);
voidRCCAPB2PeriphClockCmd(uint32tRCCAPB2Periph,FunctionalStateNewState);
这五个函数分别用来打开相应的总线下GPIO和外设时钟。比如我们的串口1是挂载在APB2总线之下,所以我们调用对应的APB2总线下外设时钟使能函数RCCAPB2PeriphClockCmd来使能串口1时钟。对于其他外设我们调用相应的函数即可。具体库函数要怎么快速找到对应的外设使能函数,大家可以参考我们接下来的4。7小节快速组织代码技巧,我们有详细的举例说明。
2)其次,我们在GIPOxMODER寄存器中将所需IO(对于串口1是PA9,PA10)配置为复用功能(ADC和DAC设置为模拟通道)。
3)再次,我们还需要对IO口的其他参数,例如类型,上拉下拉以及输出速度。上面两步,在我们库函数中是通过GPIOInit函数来实现的,参考代码如下
GPIOA9与GPIOA10初始化
GPIOInitStructure。GPIOPinGPIOPin9GPIOPin10;
GPIOInitStructure。GPIOModeGPIOModeAF;复用功能
GPIOInitStructure。GPIOSpeedGPIOSpeed50MHz;速度50MHz
GPIOInitStructure。GPIOOTypeGPIOOTypePP;推挽复用输出
GPIOInitStructure。GPIOPuPdGPIOPuPdUP;上拉
GPIOInit(GPIOA,GPIOInitStructure);初始化PA9,PA10
)最后,我们配置GPIOxAFRL或者GPIOxAFRH寄存器,将IO连接到所需的AFx。这些步骤对于我们使用库函数来操作的话,是调用的GPIOPinAFConfig函数来实现的。具体操作代码如下:
PA9连接AF7,复用为USART1TX
GPIOPinAFConfig(GPIOA,GPIOPinSource9,GPIOAFUSART1);
PA10连接AF7,复用为USART1RX
GPIOPinAFConfig(GPIOA,GPIOPinSource10,GPIOAFUSART1);
对于函数GPIOPinAFConfig函数,入口第一个第二个参数很好理解,可以确定是哪个IO,对于第三个参数,实际上我们确定了这个IO到底是复用为哪种功能之后,这个参数也很好选择,因为可选的参数在stm32f4xxgpio。h列出来非常详细,如下
2、重点讲解解析GPIOPinAFConfig
GPIOPinAFConfig(GPIOA,GPIOPinSource9,GPIOAFUSART1)
voidGPIOPinAFConfig(GPIOTypeDefGPIOx,uint16tGPIOPinSource,uint8tGPIOAF)
{
uint32ttemp0x00;
uint32ttemp20x00;
Checktheparameters
assertparam(ISGPIOALLPERIPH(GPIOx));1
assertparam(ISGPIOPINSOURCE(GPIOPinSource));2
assertparam(ISGPIOAF(GPIOAF));3
temp((uint32t)(GPIOAF)((uint32t)((uint32t)GPIOPinSource(uint32t)0x07)4));4
(首先我们先看需要配置的参数为GPIOA,GPIOPinSource9,GPIOAFUSART1,GPIOA是基地址,GPIOPinSource9的(0X09),PIOAFUSART1(0x07),带入到GPIOPinAFConfig,
123assertparam();是预判函数,进入相应的IO口,和功能预判。
4、temp((uint32t)(GPIOAF)((uint32t)((uint32t)GPIOPinSource(uint32t)0x07)4));
我们把第四条语句拆开,GPIOSource这里是GPIOPinSource9(0x09)于(uint32t)0x07)位与,结果是0x01,然后0x014,接下来temp((uint32t)(GPIOAF)0x04)即PIOAFUSART1(0x07)带入temp(0x70);
5、GPIOxAFR〔GPIOPinSource0x03〕((uint32t)0xF((uint32t)((uint32t)GPIOPinSource(uint32t)0x07)4));
化简后GPIOAAFR〔GPIOPin90x03〕((uint32t)0xF(uint32t)0X014);
进一步化简:GPIOAAFR〔1〕((uint32t)0XF0X04)相当于把GPIOAAFR〔1〕0000,复位初始化。
6、temp2GPIOxAFR〔GPIOPinSource0x03〕temp;
化简:temp2GPIOAAFR〔1〕0X70,
第五步是把AF复用功能复位为6的复用功能进行一个清零,第6的结果是:temp20X70;相当于GPIOA和AFR〔1〕建立联系。
7、GPIOxAFR〔GPIOPinSource0x03〕temp2;
是将GPIOA引脚9复用对应的功能。
结构体里AFR是定义为32位的结构数组
GPIOxAFR〔GPIOPinSource0x03〕这里如果GPIOPinSource为07,则在数组的AFR〔0〕里,如果GPIOPinSource为816,则在数组的AFR〔1〕里,对应GPIOxAFRL和GPIOxAFRH。
)
GPIOxAFR〔GPIOPinSource0x03〕((uint32t)0xF((uint32t)((uint32t)GPIOPinSource(uint32t)0x07)4));5
temp2GPIOxAFR〔GPIOPinSource0x03〕temp;6
GPIOxAFR〔GPIOPinSource0x03〕temp2;7
}
3、STM32F4的中断
CM4内核支持256个中断,其中包含了16个内核中断和240个外部中断,并且具有256级的可编程中断设置。但STM32F4并没有使用CM4内核的全部东西,而是只用了它的一部分
STM32F40xxSTM32F41xx总共有92个中断,STM32F42xxSTM32F43xx则总共有96个中断,以下仅以STM32F40xx41xx为例讲解。
STM32F40xxSTM32F41xx的92个中断里面,包括10个内核中断和82个可屏蔽中断,具有16级可编程的中断优先级,而我们常用的就是这82个可屏蔽中断。在MDK内,与NVIC相关的寄存器,MDK为其定义了如下的结构体:
STM32F4的中断在这些寄存器的控制下有序的执行的。只有了解这些中断寄存器,才能方便的使用STM32F4的中断。下面重点介绍这几个寄存器:
ISER〔8〕:ISER全称是:InterruptSetEnableRegisters,这是一个中断使能寄存器组。上面说了CM4内核支持256个中断,这里用8个32位寄存器来控制,每个位控制一个中断。但是STM32F4的可屏蔽中断最多只有82个,所以对我们来说,有用的就是三个(ISER〔02〕),总共可以表示96个中断。而STM32F4只用了其中的前82个。ISER〔0〕的bit031分别对应中断031;ISER〔1〕的bit032对应中断3263;ISER〔2〕的bit017对应中断6481;这样总共82个中断就分别对应上了。你要使能某个中断,必须设置相应的ISER位为1,使该中断被使能(这仅仅是使能,还要配合中断分组、屏蔽、IO口映射等设置才算是一个完整的中断设置)。具体每一位对应哪个中断,请参考stm32f4xx。h里面的第188行处。
ICER〔8〕:全称是:InterruptClearEnableRegisters,是一个中断除能寄存器组。该寄存器组与ISER的作用恰好相反,是用来清除某个中断的使能的。其对应位的功能,也和ICER一样。这里要专门设置一个ICER来清除中断位,而不是向ISER写0来清除,是因为NVIC的这些寄存器都是写1有效的,写0是无效的。
ISPR〔8〕:全称是:InterruptSetPendingRegisters,是一个中断挂起控制寄存器组。每个位对应的中断和ISER是一样的。通过置1,可以将正在进行的中断挂起,而执行同级或更高级别的中断。写0是无效的。
ICPR〔8〕:全称是:InterruptClearPendingRegisters,是一个中断解挂控制寄存器组。其作用与ISPR相反,对应位也和ISER是一样的。通过设置1,可以将挂起的中断接挂。写0无效。
IABR〔8〕:全称是:InterruptActiveBitRegisters,是一个中断激活标志位寄存器组。对应位所代表的中断和ISER一样,如果为1,则表示该位所对应的中断正在被执行。这是一个只读寄存器,通过它可以知道当前在执行的中断是哪一个。在中断执行完了由硬件自动清零。
IP〔240〕:全称是:InterruptPriorityRegisters,是一个中断优先级控制的寄存器组。这个寄存器组相当重要!STM32F4的中断分组与这个寄存器组密切相关。IP寄存器组由240个8bit的寄存器组成,每个可屏蔽中断占用8bit,这样总共可以表示240个可屏蔽中断。而STM32F4只用到了其中的82个。IP〔81〕IP〔0〕分别对应中断810。而每个可屏蔽中断占用的8bit并没有全部使用,而是只用了高4位。这4位,又分为抢占优先级和响应优先级。抢占优先级在前,响应优先级在后。而这两个优先级各占几个位又要根据SCBAIRCR中的中断分组设置来决定。这里简单介绍一下STM32F4的中断分组:STM32F4将中断分为5个组,组04。该分组的设置是由SCBAIRCR寄存器的bit108来定义的。具体的分配关系如表
通过这个表,我们就可以清楚的看到组04对应的配置关系,例如组设置为3,那么此时所有的82个中断,每个中断的中断优先寄存器的高四位中的最高3位是抢占优先级,低1位是响应优先级。每个中断,你可以设置抢占优先级为07,响应优先级为1或0。抢占优先级的级别高于响应优先级。而数值越小所代表的优先级就越高。
这里需要注意两点:第一,如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;第二,高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。而抢占优先级相同的中断,高优先级的响应优先级不可以打断低响应优先级的中断。
结合实例说明一下:假定设置中断优先级组为2,然后设置中断3(RTCWKUP中断)的抢占优先级为2,响应优先级为1。中断6(外部中断0)的抢占优先级为3,响应优先级为0。中断7(外部中断1)的抢占优先级为2,响应优先级为0。那么这3个中断的优先级顺序为:中断7中断3中断6。
上面例子中的中断3和中断7都可以打断中断6的中断。而中断7和中断3却不可以相互打断!
通过以上介绍,我们熟悉了STM32F4中断设置的大致过程。接下来我们介绍如何使用函数实现以上中断设置,使得我们以后的中断设置简单化。
通过以上介绍,我们熟悉了STM32F4中断设置的大致过程。接下来我们介绍如何使用库函数实现以上中断分组设置以及中断优先级管理,使得我们以后的中断设置简单化。NVIC中断管理函数主要在misc。c文件里面。
首先要讲解的是中断优先级分组函数NVICPriorityGroupConfig,其函数申明如下:voidNVICPriorityGroupConfig(uint32tNVICPriorityGroup);这个函数的作用是对中断的优先级进行分组,这个函数在系统中只能被调用一次,一旦分组确定就最好不要更改。这个函数我们可以找到其实现
voidNVICPriorityGroupConfig(uint32tNVICPriorityGroup)
{
assertparam(ISNVICPRIORITYGROUP(NVICPriorityGroup));
SCBAIRCRAIRCRVECTKEYMASKNVICPriorityGroup;
}
从函数体可以看出,这个函数唯一目的就是通过设置SCBAIRCR寄存器来设置中断优先级分组,这在前面寄存器讲解的过程中已经讲到。而其入口参数通过双击选中函数体里面的ISNVICPRIORITYGROUP然后右键Gotodefitionof可以查看到为:
defineISNVICPRIORITYGROUP(GROUP)
(((GROUP)NVICPriorityGroup0)
((GROUP)NVICPriorityGroup1)
((GROUP)NVICPriorityGroup2)
((GROUP)NVICPriorityGroup3)
((GROUP)NVICPriorityGroup4))
这也是我们上表讲解的,分组范围为04。比如我们设置整个系统的中断优先级分组值
为2,那么方法是:
NVICPriorityGroupConfig(NVICPriorityGroup2);
这样就确定了一共为2位抢占优先级,2位响应优先级。
设置好了系统中断分组,那么对于每个中断我们又怎么确定他的抢占优先级和响应优先级呢?下面我们讲解一个重要的函数为中断初始化函数NVICInit,其函数申明为:
voidNVICInit(NVICInitTypeDefNVICInitStruct)
其中NVICInitTypeDef是一个结构体,我们可以看看结构体的成员变量:
typedefstruct
{
uint8tNVICIRQChannel;
uint8tNVICIRQChannelPreemptionPriority;
uint8tNVICIRQChannelSubPriority;
FunctionalStateNVICIRQChannelCmd;
}NVICInitTypeDef;
NVICInitTypeDef结构体中间有四个成员变量,接下来我们一一来看看这些成员变量的含
义。
NVICIRQChannel:定义初始化的是哪个中断,这个我们可以在stm32f10x。h中找到每个中断对应的名字。例如USART1IRQn。NVICIRQChannelPreemptionPriority:定义这个中断的抢占优先级别。NVICIRQChannelSubPriority:定义这个中断的子优先级别,也叫响应优先级。NVICIRQChannelCmd:该中断通道是否使能。
比如我们要使能串口1的中断,同时设置抢占优先级为1,响应优先级位2,初始化的方法
是:
NVICInitTypeDefNVICInitStructure;;
NVICInitStructure。NVICIRQChannelUSART1IRQn;串口1中断
NVICInitStructure。NVICIRQChannelPreemptionPriority1;抢占优先级为1
NVICInitStructure。NVICIRQChannelSubPriority2;响应优先级位2
NVICInitStructure。NVICIRQChannelCmdENABLE;IRQ通道使能
NVICInit(NVICInitStructure);根据上面指定的参数初始化NVIC寄存器
这里我们讲解了中断分组的概念以及设置单个中断优先级的方法。对于每个中断,还有一些类似清除中断,查看中断状态的操作,这在后面我们讲解每个中断的时候会详细讲解怎么使用。最后我们总结一下中断优先级设置的步骤:
1。系统运行开始的时候设置中断分组。确定组号,也就是确定抢占优先级和响应优先级的分配位数。调用函数为NVICPriorityGroupConfig();
2。设置所用到的中断的中断优先级别。对每个中断调用函数为NVICInit();
OPPO开发者大会上线三大板块引领全新数智生活2021OPPO开发者大会将在10月27日在上海举办,而在昨天,大会的官网上线车机互融、智能服务和健康生态三大版块,向开发者和合作伙伴展示了以上领域的技术能力以及生态畅想。……
智能电动牙刷入门首选荣耀亲选小棒冰智能声波电动牙刷刷牙是一件小事,但是我们每天都要去做,早晚各一次,所以牙刷就成了我们生活中的必需品!随着大家对刷牙质量的追求,电动牙刷开始普及开来,发展到今天,电动牙刷已经融入了不少智能功能,……
宝妈心目中的优质进口奶粉这些优点必不可少婴幼儿配方奶粉在宝宝成长的过程中占有重要地位,营养健康、品质优良的奶粉,自然得到宝妈们的喜爱。为了给下一代提供更丰富的营养选择,父母们在挑选奶粉的时候也越来越仔细。现在国……
做空机构的秃鹫式生存瑞幸咖啡这件事,当多数媒体都在夸赞做空机构浑水之际,背后的那份详做空报告才是它最致命的一击。4月3日的报道中,我对瑞幸自燃的原因已有所分析:其一是因为这份做空报告,瑞幸在……
说说我近期对银行版块的看法前言去年四季度开始,民间股神林园开始高调建仓银行;11月份号称中国巴菲特的喜马拉雅资本老总李录,大仓位杀进H股邮储银行;兴全系的董承非、谢志宇将银行板块加成重仓;这几天张……
披荆斩棘的哥哥的男idol,谁会是下一个翻车的哥哥呢?还记得去年那群追光的哥哥吗?那快溢出屏幕的油腻感,让小编恨不得灌下整瓶洗洁精,再自掏腰包拍一部《去油吧!蜀黍!》。但今年这名单一出来,小编确实有点按捺不住心中的悸动,《披……
2B铅笔中的B到底是哪个单词的缩写?你肯定认识从开始学习写字到后来练习画画再到长大后考试填涂答题卡铅笔是从小到大陪伴我们最久的文具记得小时候老师们会对铅笔的型号有各种各样的要求……
企业宽带别人家生意步步领先的秘诀中小企业为什么要一定选择企业宽带而不是用家庭宽带代替?民宿:陈掌柜对中小规模酒店和民宿经营者而言,所需要的企业宽带是具有不高的费用支出和快捷的网速。在如今民宿遍地的……
说句话就能让晾衣架自动升降晾晒衣服,你信吗?前言真是后生可畏啊!随着科技的发达,一些黑科技产品诞生并渗入我们生活的方方面面,我们这些中年人明显感觉跟不上时代的步伐了。当我们还在笨手笨脚用一些土办法生活时,孩子……
丈夫收到陌生女子的自拍,他悄悄地回复却在朋友圈火了丈夫收到陌生女子的自拍,他悄来自一星期一本书00:0017:52点上方绿标即可收听主播善尼朗读音频来源视觉志ID:iiidaily最近一位妹子在为一场活……
咖啡烘焙公司PeaceCoffee视觉形象升级PeaceCoffee成立于1996年,总部设在美国明尼阿波利斯市,是一家小批量、公平贸易的有机咖啡烘焙公司。目前主要在美国中西部地区销售,特别是在明尼阿波利斯市,那里有他们的……
折叠屏手机会是手机未来发展的形态吗?华为刚刚发布了第三代折叠屏手机X2,意味着在折叠屏手机这个形态里,只有华为和三星逐步占领了这块领域的位置。折叠屏作为智能手机中,第一次出现的形态变革,与之前在智能手机的技……