欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【嵌入式】STM32硬件系统复习

程序员文章站 2022-07-03 17:38:16
...

前言

硬件方面有很多东西长时间不接触容易忘记,复习的时候记录一下自己的想法,这样便于快速恢复

时钟系统

SPI的初始化中需要配置波特率分频系数,需要了解stm32的时钟和总线等基础结构知识才能搞清楚SPI的实际可配置的工作频率。此外,在网上查找有关SPI的峰值工作频率出现了很多超频会跑飞的情况,大部分的说法是虽然STM32的SPI支持很多不同的工作频率,但最终的选择会受到硬件等诸多因素的影响。
STM32之所以会有相比51单片机复杂很多的时钟系统,是因为stm32f4的结构和外设非常的丰富和复杂,不同的外设所需要的时钟频率是不一样的,为了降低功耗需要因地制宜……STM32的时钟系统有很多功能如果不是使用到的话很难记忆,所以暂时先只熟悉一下默认情况下的STMf4的时钟配置信息。
【嵌入式】STM32硬件系统复习
这张图应该是学习STM32必定会看到一张图,其实里面很多东西不需要记忆,就算记住了长时间不接触也会忘掉。。所以只能能大概看懂我觉得就可以了。。
虽然STM32提供了很多不同的时钟源选择,但是最常见的是 采用HSE外部高速时钟,外接一个8Mhz的晶振->经过PLL后产生168Mhz提供给系统时钟 。SYSCLK:系统时钟,总线、外设等所有的时钟均是以它为基础的,它是整个芯片系统的脉搏。在STM32执行main函数之前会先执行SysTickInit:选择HSE并等待它稳定->设定AHB、APB1/2分频系数->设定PLL的参数(PLL的时钟源以及分频系数等)并且等待它稳定->选择PLL倍频为系统的时钟源。这些步骤结束后,整个系统的时钟就完全确定了。
PLL=SYSCLK(系统时钟)=HCLK(AHB总线时钟)=168Mhz;
PCLK1(APB1总线时钟)=HCLK/4=42Mhz;
PCLK2(APB2总线时钟)=HCLK/2=84Mhz;
以上是对默认情况下STM32的时钟系统的简单回顾,其实是学习STM32时的一个很基础的内容。

SPI时钟频率问题

stm32f4系列的SPI1外设挂载在SPB2总线上,所以SPI1的基础时钟频率是84Mhz。在对SPI1的初始化中,需要设置SPI波特率发生器的预分频系数,如下图:SPI1的波特率理论上最高可达PCLK2/2即42Mhz。
【嵌入式】STM32硬件系统复习
http://www.openedv.com/posts/list/28715.htm 该楼主发现在STM32F4的datasheet上SPI的器件特性写明最高支持到37.5Mhz:
【嵌入式】STM32硬件系统复习
所以对于主频仍采用168Mhz的情况下,采用4分频即21Mhz会比较稳妥。如果仍采用2分频即42Mhz就相当于是计算机的超频使用,偶尔一两次没问题,但不适合作为产品设计或者是长时间高稳定性的使用场景。所以采用21Mhz相当于是为了稳定和安全的一种妥协吧。
顺便搜索了一下为什么大部分串口的波特率都采用115200或者9600:串口的波特率越高,有效传输距离就越短,对于115200大概只有5M左右,而且波特率越大越容易出错,所以和SPI是同一个道理。串口通信的种种限制是导致它们带宽有限的主要原因吧……

SYSTICK滴答定时器

systick是一个非常简单的定时器,arm官方要求芯片中必须有这样一个定时器。它占用资源很少,一旦使能后就会一直工作,即使在睡眠模式下也正常运转。

  • 本质上就是一个递减计数器,当递减到0时从重装载寄存器中读取新的数值继续递减;
  • 如果使能了中断就会在每次递减到0时触发systick中断;
  • 时钟源可以是HCLK/8或者HCLK,对于F4芯片,HCLK=168Mhz;

正点原子的延时函数没有使用systick中断,它的原理是:

  1. 初始化systick的时钟源为HCLK/8;
  2. 获取到用户想要延时的时长并根据systick的时钟源确定一个装载值;
  3. 将val当前值寄存器清空,使能systick定时器;
  4. systick定时器加载一个值后进行递减;
  5. 程序始终监视CTRL寄存器中的countflag标志位是否为1;
  6. 如果为1就立即关闭systick定时器

外部中断

STM32F405ZGT6有7组GPIO(A-G),每组有16个GPIO口(0-15),一共144个GPIO口。外部中断先EXTI有16个(0-15)
GPIOX.0映射到EXTI0以此类推。其实用多了以后很好理解,外部可以是板上外设例如按键,也可以是网络模块,它们在某一时刻会触发电平的变化,而外部中断就可以捕获它们并执行相应的中断函数。
比较重要的一个概念是,对于EXTI0,GPIOA0-GPIOG0中同时只能有一个映射到EXTI0。
中断服务函数和中断向量表有关,我的理解是,当触发中断时,会到中断向量表中找到指定的函数地址,进而去执行相应的处理函数。因为中断向量表中只分配了7个,所以只有7个中断服务函数,如下:
EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
EXTI9_5_IRQHandler
EXTI15_10_IRQHandler

void EXTIX_Init(void)
{
	NVIC_InitTypeDef   NVIC_InitStructure;
	EXTI_InitTypeDef   EXTI_InitStructure;
 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//ʹÄÜSYSCFGʱÖÓ
	
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource4);//PE4 Á¬½Óµ½ÖжÏÏß4

	/* ÅäÖÃEXTI_Line2,3,4 */
	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);//ÅäÖÃ
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;//ÍⲿÖжÏ4
 	 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;//ÇÀÕ¼ÓÅÏȼ¶1
 	 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//×ÓÓÅÏȼ¶2
 	 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//ʹÄÜÍⲿÖжÏͨµÀ
 	 NVIC_Init(&NVIC_InitStructure);//ÅäÖÃ
}

通用定时器

【嵌入式】STM32硬件系统复习
通用定时器的时钟来源有很多,支持定时器级联等,但是最基础的就是直接使用外设总线的时钟,以TIM5为例,时钟来源是PCLK1(APB1总线时钟)=HCLK/4=42Mhz;然后,通过psc预分频器处理后得到定时器最终的计数频率。

采用APB1作为时钟来源时,有一句非常绕人的话:如果APB1的分频系数是1,也就是说APB1等于AHB时,通用定时器的时钟来源就是APB1,如果不是,比如说最常见的是APB1=AHB/4=42Mhz,分频系数是4,所以此时通用定时器的时钟来源是42*2=84Mhz。注意!!!!!!!这里并不是通用定时器最终的频率,还需经过psc预分频器处理才能得到。

实现定时器指定的周期触发中断,背景是向上/向下计数模式。需要参考如下的计算方法:
假设需要实现xms中断一次:首先可以知道的是,定时器的时钟源频率是APB1*2=84Mhz,然后经过psc的分频得到的定时器计数频率是:APB1*2/(PSC+1)。所以(PSC+1)/APB1*2就是指定时器计数跳动一次的耗时,所以溢出事件发生的总间隔是
(ARR+1)*(PSC+1)/APB1*2。这里最重要的是分频系数和重装载值在计算的时候都需要加1。我的理解是:重装载的时候本身也需要消耗一次,所以是ARR+1.