【物联网】stm32芯片结构组成,固件库、启动过程、时钟系统、GPIO、NVIC、DMA

在系统初始化前期:使能了内部高速时钟HSI

 

RCC->CR |= (uint32_t)0x00000001;

RCC->CFGR &= (uint32_t)0xF8FF0000;

  • [26:24] = 000(b) MCO:没有时钟输出
  • [10:8] = 000(b) HCLK不分频
  • [7:4] = 0000(b) SYSCLK不分频
  • [3:2] = 00(b) SWS(SW状态标志位)
  • [1:0] = 00(b) HSI作为系统时钟

设置系统时钟sysclk:

    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    
    /* PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;


    /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
                                        RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);

由上代码可知系统时钟源:

PLL 选择外部高速晶振:8MHz

经过PLL倍频器9倍频后提供给sysclk = 8*9 = 72MHz

HCLK没有对sysclk进行分频,所以HCLK = 72MHz

PCLK1对HCLK进行2分频,所以PCLK1 = 36MHz

PCLK2对HCLK没有进行分频,所以PCLK2 = 72MHz

TIM2——7:72MHz

TIM1和TIM8:72MHz

六、通用输入输出

1、GPIO功能介绍

根据数据手册中列出的每个IO端口的特定硬件特征,GPIO端口的每个位可以由软件分别配置成多种模式。

功能:

输入(Input):

浮空:

模拟:

上拉:

下拉:

输出(Output):

推挽:推挽输出有一定的驱动能力,可以真正的输出高低电平

开漏:实际是没有驱动能力的,想要驱动设备,需要外部有驱动电路支持

2、GPIO固件库相关函数介绍

开启GPIO时钟函数声明:

/**
  * @brief  Enables or disables the High Speed APB (APB2) peripheral clock.
  * @param  RCC_APB2Periph: specifies the APB2 peripheral to gates its clock.
  *   This parameter can be any combination of the following values:
  *     @arg RCC_APB2Periph_AFIO, RCC_APB2Periph_GPIOA, RCC_APB2Periph_GPIOB,
  *          RCC_APB2Periph_GPIOC, RCC_APB2Periph_GPIOD, RCC_APB2Periph_GPIOE,
  *          RCC_APB2Periph_GPIOF, RCC_APB2Periph_GPIOG, RCC_APB2Periph_ADC1,
  *          RCC_APB2Periph_ADC2, RCC_APB2Periph_TIM1, RCC_APB2Periph_SPI1,
  *          RCC_APB2Periph_TIM8, RCC_APB2Periph_USART1, RCC_APB2Periph_ADC3,
  *          RCC_APB2Periph_TIM15, RCC_APB2Periph_TIM16, RCC_APB2Periph_TIM17,
  *          RCC_APB2Periph_TIM9, RCC_APB2Periph_TIM10, RCC_APB2Periph_TIM11     
  * @param  NewState: new state of the specified peripheral clock.
  *   This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)

初始化GPIO函数声明:

/**
  * @brief  Initializes the GPIOx peripheral according to the specified
  *         parameters in the GPIO_InitStruct.
  * @param  GPIOx: where x can be (A…G) to select the GPIO peripheral.
  * @param  GPIO_InitStruct: pointer to a GPIO_InitTypeDef structure that
  *         contains the configuration information for the specified GPIO peripheral.
  * @retval None
  */
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)

结构体GPIO_InitTypeDef:

typedef struct
{
  uint16_t GPIO_Pin;             /*!< Specifies the GPIO pins to be configured.
                                      This parameter can be any value of @ref GPIO_pins_define */

GPIOSpeed_TypeDef GPIO_Speed;  /*!< Specifies the speed for the selected pins.
                                      This parameter can be a value of @ref GPIOSpeed_TypeDef */

GPIOMode_TypeDef GPIO_Mode;    /*!< Specifies the operating mode for the selected pins.
                                      This parameter can be a value of @ref GPIOMode_TypeDef */
}GPIO_InitTypeDef;

GPIOSpeed_TypeDef:

typedef enum

  GPIO_Speed_10MHz = 1,
  GPIO_Speed_2MHz, 
  GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;

GPIOMode_TypeDef:

typedef enum
{ GPIO_Mode_AIN = 0x0,模拟输入
  GPIO_Mode_IN_FLOATING = 0x04,浮空输入
  GPIO_Mode_IPD = 0x28,下拉
  GPIO_Mode_IPU = 0x48,上拉

GPIO_Mode_Out_OD = 0x14,开漏
  GPIO_Mode_Out_PP = 0x10,推挽
  GPIO_Mode_AF_OD = 0x1C,
  GPIO_Mode_AF_PP = 0x18,复用功能的推挽输出
}GPIOMode_TypeDef;

引脚定义:

#define GPIO_Pin_0                 ((uint16_t)0x0001)  /*!< Pin 0 selected */
#define GPIO_Pin_1                 ((uint16_t)0x0002)  /*!< Pin 1 selected */
#define GPIO_Pin_2                 ((uint16_t)0x0004)  /*!< Pin 2 selected */
#define GPIO_Pin_3                 ((uint16_t)0x0008)  /*!< Pin 3 selected */
#define GPIO_Pin_4                 ((uint16_t)0x0010)  /*!< Pin 4 selected */
#define GPIO_Pin_5                 ((uint16_t)0x0020)  /*!< Pin 5 selected */
#define GPIO_Pin_6                 ((uint16_t)0x0040)  /*!< Pin 6 selected */
#define GPIO_Pin_7                 ((uint16_t)0x0080)  /*!< Pin 7 selected */
#define GPIO_Pin_8                 ((uint16_t)0x0100)  /*!< Pin 8 selected */
#define GPIO_Pin_9                 ((uint16_t)0x0200)  /*!< Pin 9 selected */
#define GPIO_Pin_10                ((uint16_t)0x0400)  /*!< Pin 10 selected */
#define GPIO_Pin_11                ((uint16_t)0x0800)  /*!< Pin 11 selected */
#define GPIO_Pin_12                ((uint16_t)0x1000)  /*!< Pin 12 selected */
#define GPIO_Pin_13                ((uint16_t)0x2000)  /*!< Pin 13 selected */
#define GPIO_Pin_14                ((uint16_t)0x4000)  /*!< Pin 14 selected */
#define GPIO_Pin_15                ((uint16_t)0x8000)  /*!< Pin 15 selected */
#define GPIO_Pin_All               ((uint16_t)0xFFFF)  /*!< All pins selected */

置位函数声明:

/**
  * @brief  Sets the selected data port bits.
  * @param  GPIOx: where x can be (A…G) to select the GPIO peripheral.
  * @param  GPIO_Pin: specifies the port bits to be written.
  *   This parameter can be any combination of GPIO_Pin_x where x can be (0…15).
  * @retval None
  */
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)

复位函数声明:

/**
  * @brief  Clears the selected data port bits.
  * @param  GPIOx: where x can be (A…G) to select the GPIO peripheral.
  * @param  GPIO_Pin: specifies the port bits to be written.
  *   This parameter can be any combination of GPIO_Pin_x where x can be (0…15).
  * @retval None
  */
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)

3、GPIO输出实例

4、GPIO软件调试

 

先复位,点击运行到断点位置,多次点击往下执行查看寄存器电平变化:

 2000=0010 0000 0000 0000,第十三位置1,即引脚13输出高电平:

七、stm32定时器

1、概述

共有8个定时器:高级定时器(TIM1和TIM8)、通用定时器(TIM2——TIM5)、基本定 时器(TIM6和TIM7),具体功能特点参考stm32数据手册。

高级控制定时器(TIM1和TIM8):

高级控制定时器(TIM1和TIM8)由一个16位的自动装载计数器组成,它由一个可编程的预分频器 驱动。

它适合多种用途,包含测量输入信号的脉冲宽度(输入捕获),或者产生输出波形(输出比较、 PWM、嵌入死区时间的互补PWM等)。

使用定时器预分频器和RCC时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个 毫秒间调整。

每个定时器都是完全独立的,没有互相共享任何资源。它们可以一起同步操作

TIM1和TIM8定时器的功能包括:

● 16位向上、向下、向上/下自动装载计数器

● 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65535之间的任意 数值

● 多达4个独立通道:

─ 输入捕获

─ 输出比较

─ PWM生成(边缘或中间对齐模式)

─ 单脉冲模式输出

● 死区时间可编程的互补输出

● 使用外部信号控制定时器和定时器互联的同步电路

● 允许在指定数目的计数器周期之后更新定时器寄存器的重复计数器

● 刹车输入信号可以将定时器输出信号置于复位状态或者一个已知状态

● 如下事件发生时产生中断/DMA:

─ 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)                 ─ 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)

─ 输入捕获

─ 输出比较

─ 刹车信号输入

● 支持针对定位的增量(正交)编码器和霍尔传感器电路

● 触发输入作为外部时钟或者按周期的电流管理

通用定时器(TIM2——TIM5):

通用定时器是一个通过可编程预分频器驱动的16位自动装载计数器构成。

它适合多种用途,包含测量输入信号的脉冲宽度(输入捕获),或者产生输出波形(输出比较、 PWM)。

使用定时器预分频器和RCC时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个 毫秒间调整。

每个定时器都是完全独立的,没有互相共享任何资源。它们可以一起同步操作

通用TIMx (TIM2、TIM3、TIM4和TIM5)定时器功能包括:

● 16位向上、向下、向上/下自动装载计数器

● 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65535之间的任意 数值

● 多达4个独立通道:

─ 输入捕获

─ 输出比较

─ PWM生成(边缘或中间对齐模式)

─ 单脉冲模式输出

● 使用外部信号控制定时器和定时器互连的同步电路

● 如下事件发生时产生中断/DMA:

─ 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)

─ 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)

─ 输入捕获

─ 输出比较

● 支持针对定位的增量(正交)编码器和霍尔传感器电路

● 触发输入作为外部时钟或者按周期的电流管理

基本定时器(TIM6和TIM7)

基本定时器TIM6和TIM7各包含一个16位自动装载计数器,由各自的可编程预分频器驱动。 它们可以作为通用定时器提供时间基准,特别地可以为数模转换器(DAC)提供时钟。实际上,它 们在芯片内部直接连接到DAC并通过触发输出直接驱动DAC。 这2个定时器是互相独立的,不共享任何资源。

TIM6和TIM7定时器的主要功能包括:

● 16位自动重装载累加计数器

● 16位可编程(可实时修改)预分频器,用于对输入的时钟按系数为1~65536之间的任意数值分频

● 触发DAC的同步电路

● 在更新事件(计数器溢出)时产生中断/DMA请求

2、 定时器PWM输出

PWM:脉冲宽度调制(频率可以设定,占空比可动态调节)

(1)原理说明

每个定时器有4路输出通道:OC1——OC4 有RCC给到TIM2——TIM7的时钟频率是72MHz

3、固件库相关函数说明

结构体: TIM_TimeBaseInitTypeDef:

typedef struct
{
  uint16_t TIM_Prescaler;         //预分频值 f_cnt= f_tim/(TIM_Prescaler+1)

uint16_t TIM_CounterMode;     //计数模式

uint16_t TIM_Period;           //周期(计数值)

uint16_t TIM_ClockDivision;

uint8_t TIM_RepetitionCounter;  
} TIM_TimeBaseInitTypeDef;

定时器的初始化函数 :

/**
  * @brief  Initializes the TIMx Time Base Unit peripheral according to 
  *         the specified parameters in the TIM_TimeBaseInitStruct.
  * @param  TIMx: where x can be 1 to 17 to select the TIM peripheral.
  * @param  TIM_TimeBaseInitStruct: pointer to a TIM_TimeBaseInitTypeDef
  *         structure that contains the configuration information for the 
  *         specified TIM peripheral.
  * @retval None
  */
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)

结构体: TIM_OCInitTypeDef:

//pwm相关的输出模式

//PWM1模式:CNT < CRRx , 输出为有效电平

//PWM2模式:相反

//有效电平由极性决定:TIM_OCPolarity_High TIM_OCPolarity_Low

#define TIM_OCMode_PWM1 ((uint16_t)0x0060)

#define TIM_OCMode_PWM2 ((uint16_t)0x0070)

//输出状态

#define TIM_OutputState_Disable ((uint16_t)0x0000)

#define TIM_OutputState_Enable ((uint16_t)0x0001)

//输出极性

#define TIM_OCPolarity_High ((uint16_t)0x0000)

#define TIM_OCPolarity_Low ((uint16_t)0x0002)

typedef struct
{
  uint16_t TIM_OCMode;       //输出模式

uint16_t TIM_OutputState;      //输出状态

uint16_t TIM_Pulse;        //比较寄存器值  0x0000-0xFFFF

uint16_t TIM_OCPolarity;    //输出极性
} TIM_OCInitTypeDef;

输出通道初始化:

void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);

设置OCx的比较寄存器预装载功能:

/**
  * @brief  Enables or disables the TIMx peripheral Preload register on CCR1.
  * @param  TIMx: where x can be  1 to 17 except 6 and 7 to select the TIM peripheral.
  * @param  TIM_OCPreload: new state of the TIMx peripheral Preload register
  *   This parameter can be one of the following values:
*     @arg TIM_OCPreload_Enable
  *     @arg TIM_OCPreload_Disable

  * @retval None
  */

void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC3PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC4PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);

设置自动重装载使能 :

/**
  * @brief  Enables or disables TIMx peripheral Preload register on ARR.
  * @param  TIMx: where x can be  1 to 17 to select the TIM peripheral.
  * @param  NewState: new state of the TIMx peripheral Preload register
  *   This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState)

使能定时器的计数功能:

/**
  * @brief  Enables or disables the specified TIM peripheral.
  * @param  TIMx: where x can be 1 to 17 to select the TIMx peripheral.
  * @param  NewState: new state of the TIMx peripheral.
  *   This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)

4、实例

tim4定时器引脚为PB6-PB9

5、调试

示波器看对应引脚的输出波形

八、嵌套中断向量控制器NVIC

1、NVIC介绍

NVIC(Nest Vector Interrupt Controller),嵌套中断向量控制器,作用是管理中断嵌套,核心任务是管理中断优先级

特点:

  • 68个可屏蔽中断通道(不包含16个Cortex-M3的中断线)
  • 16个可编程的优先等级(使用4位中断优先级)
  • 低延迟的异常和中断处理
  • 电源管理控制
  • 系统控制寄存器的实现

嵌套向量中断控制器(NVIC)和处理器核的接口紧密相连,可以实现中断的低延迟处理和高效地处理晚到的中断。

NVIC给每个中断赋予抢占优先级和响应优先级。关系如下:

  • 拥有较高抢占优先级的中断可以打断抢占优先级较低的中断
  • 若两个抢占优先级的中断同时挂起,则优先执行响应优先级较高的中断
  • 若两个挂起的中断优先级都一致,则优先执行位于中断向量表中位置较高的中断
  • 响应优先级不会造成中断嵌套,也就是说中断嵌套是由抢占优先级决定的

2、优先级

每个中断源都需要被指定这两种优先级,Cortex-M3核定义了8个bit用于设置中断源的优先 级,这8个bit可以有以下8种分配方式:

  • 所有8位全部用于指定响应优先级
  • 第7位用于指定抢占式优先级,0-6位用于指定响应优先级
  • 6-7位用于指定抢占式优先级,0-5位用于指定响应优先级
  • 5-7位用于指定抢占式优先级,0-4位用于指定响应优先级
  • 4-7位用于指定抢占式优先级,0-3位用于指定响应优先级
  • 3-7位用于指定抢占式优先级,0-2位用于指定响应优先级
  • 2-7位用于指定抢占式优先级,0-1位用于指定响应优先级
  • 1-8位用于指定抢占式优先级,0位用于指定响应优先级

Cortex-M3允许具有较少中断源时使用较少的寄存器位指定中断源的优先级,因此STM32 中断优先级的寄存器位只用到AIRCR高四位,共有以下几种组合:

  • 第0组:所有4位用于指定响应优先级
  • 第1组:第7位用于指定抢占式优先级,4-6位用于指定响应优先级
  • 第2组:第6-7位用于指定抢占式优先级,4-5位用于指定响应优先级
  • 第3组:第5-7位用于指定抢占式优先级,第4位用于指定响应优先级
  • 第4组:所有4位用于指定抢占式优先级

使用固件库函数配置中断优先级(misc.c中定义):(优先级组确定后,可以根据优先级组来配置对应IRQ的抢占优先级和响应优先级)

/**
  * @brief  Configures the priority grouping: pre-emption priority and subpriority.
  * @param  NVIC_PriorityGroup: specifies the priority grouping bits length. 
  *   This parameter can be one of the following values:
  *     @arg NVIC_PriorityGroup_0: 0 bits for pre-emption priority
  *                                                     4 bits for subpriority
  *     @arg NVIC_PriorityGroup_1: 1 bits for pre-emption priority
  *                                                     3 bits for subpriority
  *     @arg NVIC_PriorityGroup_2: 2 bits for pre-emption priority
  *                                                     2 bits for subpriority
  *     @arg NVIC_PriorityGroup_3: 3 bits for pre-emption priority
  *                                                     1 bits for subpriority
  *     @arg NVIC_PriorityGroup_4: 4 bits for pre-emption priority
  *                                                     0 bits for subpriority
  * @retval None
  */
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)

3、NVIC初始化

每个外部中断都由NVIC统一进行管理,所以NVIC包含了中断功能的使能和失能,优先级的 配置等功能。

固件库中关于NVIC的初始化函数:

/**
  * @brief  Initializes the NVIC peripheral according to the specified
  *         parameters in the NVIC_InitStruct.
  * @param  NVIC_InitStruct: pointer to a NVIC_InitTypeDef structure that contains
  *         the configuration information for the specified NVIC peripheral.
  * @retval None
  */
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)

结构体形参变量说明:

typedef struct
{
  uint8_t NVIC_IRQChannel;

uint8_t NVIC_IRQChannelPreemptionPriority;  抢占优先级0-15

uint8_t NVIC_IRQChannelSubPriority;        响应优先级0-15

FunctionalState NVIC_IRQChannelCmd;            
} NVIC_InitTypeDef;

结构体内变量说明:

1、NVIC_IRQChannel:外部中断通道(在stm32f10x.h中定义)

typedef enum IRQn
{
/******  Cortex-M3 Processor Exceptions Numbers *********************************/
  NonMaskableInt_IRQn         = -14,    /*!< 2 Non Maskable Interrupt                             */
  MemoryManagement_IRQn       = -12,    /*!< 4 Cortex-M3 Memory Management Interrupt  
  BusFault_IRQn               = -11,    /*!< 5 Cortex-M3 Bus Fault Interrupt                      */
  UsageFault_IRQn             = -10,    /*!< 6 Cortex-M3 Usage Fault Interrupt                    */
  SVCall_IRQn                 = -5,     /*!< 11 Cortex-M3 SV Call Interrupt                       */
  DebugMonitor_IRQn           = -4,     /*!< 12 Cortex-M3 Debug Monitor Interrupt                 */
  PendSV_IRQn                 = -2,     /*!< 14 Cortex-M3 Pend SV Interrupt                       */
  SysTick_IRQn                = -1,     /*!< 15 Cortex-M3 System Tick Interrupt                   */

/******  STM32 specific Interrupt Numbers *****************************************/
  WWDG_IRQn                   = 0,      /*!< Window WatchDog Interrupt                            */
  PVD_IRQn                    = 1,      /*!< PVD through EXTI Line detection Interrupt            */
  TAMPER_IRQn                 = 2,      /*!< Tamper Interrupt                                     */
  RTC_IRQn                    = 3,      /*!< RTC global Interrupt                                 */
  FLASH_IRQn                  = 4,      /*!< FLASH global Interrupt                               */
  RCC_IRQn                    = 5,      /*!< RCC global Interrupt                                 */
  EXTI0_IRQn                  = 6,      /*!< EXTI Line0 Interrupt                                 */
  EXTI1_IRQn                  = 7,      /*!< EXTI Line1 Interrupt                                 */
  EXTI2_IRQn                  = 8,      /*!< EXTI Line2 Interrupt                                 */
  EXTI3_IRQn                  = 9,      /*!< EXTI Line3 Interrupt                                 */
  EXTI4_IRQn                  = 10,     /*!< EXTI Line4 Interrupt                                 */
  DMA1_Channel1_IRQn          = 11,     /*!< DMA1 Channel 1 global Interrupt                      */
  DMA1_Channel2_IRQn          = 12,     /*!< DMA1 Channel 2 global Interrupt                     
  DMA1_Channel3_IRQn          = 13,     /*!< DMA1 Channel 3 global Interrupt                      
  DMA1_Channel4_IRQn          = 14,     /*!< DMA1 Channel 4 global Interrupt                      
  DMA1_Channel5_IRQn          = 15,     /*!< DMA1 Channel 5 global Interrupt                     
  DMA1_Channel6_IRQn          = 16,     /*!< DMA1 Channel 6 global Interrupt                     
  DMA1_Channel7_IRQn          = 17,     /*!< DMA1 Channel 7 global Interrupt

2.NVIC_IRQChannelPreemptionPriority:抢占优先级(最大取值15) 3.NVIC_IRQChannelSubPriority:响应优先级(最大取值15)                      4.NVIC_IRQChannelCmd:(ENABLE/DISABLE) 使能/失能对应的中断通道

4、中断的具体行为

当CM3开始响应一个中断时,会做如下动作:

  1. 入栈: 把8个寄存器的值压入栈
  2. 取向量:从向量表中找出对应的服务程序入口地址
  3. 选择堆栈指针MSP(主堆栈)/PSP(进程堆栈),更新堆栈指针SP,更新链接寄存器 LR,更新程序计数器PC

入栈:响应异常的第一个动作,就是自动保存现场,依次把xPSR、PC, LR, R12以及R3-R0由 硬 件寄存器自动压入适当的堆栈中。

取向量:数据总线(系统总线)在执行入栈的时候,指令总线从向量表中找出正确的异常向量, 然后在服务程序的入口处预取指。 (由此可以看到各自都有专用总线的好处:入栈与取指这两个工作能同时进行)

更新寄存器:在入栈和取向量操作完成之后,执行服务例程之前,还要更新一系列的寄存器.

SP:在入栈后会把堆栈指针更新到新的位置。在执行服务例程时,将由MSP负 责对堆栈的 访问。

PSR:更新IPSR位段的值为新响应的异常编号。

PC:在取向量完成后,PC将指向服务例程的入口地址,

LR:在出入ISR(Interrupt Service Routines)中断服务程序的时候,LR的值 将得到更新 (在异常进入时由系统计算并赋给LR,并在异常返回时使用它)

5、异常/中断返回

当异常服务例程执行完毕后,需要恢复先前的系统状态,才能使被中断的程序得以继续执行。 异常/中断处理完成后,执行如下处理:

  • 出栈:恢复先前压入栈中的寄存器,堆栈指针的值也改回先前的值
  • 更新NVIC寄存器:伴随着异常的返回,它的活动位也被硬件清除

九、外部中断

1、概述

对于互联型产品,外部中断/事件控制器由20个产生事件/中断请求的边沿检测器组成, 对于其它 产品,则有19个能产生事件/中断请求的边沿检测器。每个输入线可以独立地配置输入类型 和对应的触发事件(上升沿或下降沿或者双边沿都触发)。每个输入线都可以独立地被屏蔽。 挂起寄存器保持着状态线的中断请求。

EXTI:

EXTI 可分为两大部分功能,一个是产生中断,另一个是产生事件

中断: 信号从输入线输入,经过边沿检测电路来控制信号触发(根据上升沿下降沿触发选择寄 存器的设置来控制),如果检测到有效信号后,将该有效信号输出到或门电路,由红色箭头 方向经过请求挂起寄存器和中断屏蔽寄存器,到达与门电路,条件满足送至NVIC

事件: 信号从输入线输入,经过边沿检测电路来控制信号触发(根据上升沿下降沿触发选择寄存器 的设置来控制),如果检测到有效信号后,将该有效信号输出到或门电路,由蓝色箭头方向 经过与门电路,送至买脉冲发生器,产生脉冲。这个脉冲信号可以给其他外设电路使用,比 如定时器 TIM、模拟数字转换器 ADC等等,这样的脉冲信号一般用来触发 TIM 或者 ADC 开始转换。

事件和中断的区别:

产生中断线路目的是把输入信号输入到 NVIC,进一步会运行中断服务函数,实现功能,这 样是软件级的。而产生事件线路目的就是传输一个脉冲信号给其他外设使用,并且是电路级别的信号传输,属于硬件级的。

2、主要特性

  • 每个中断/事件都有独立的触发和屏蔽
  • 每个中断线都有专用的状态位
  • 支持多达20个软件的中断/事件请求
  • 检测脉冲宽度低于APB2时钟宽度的外部信号

3、外部中断/事件线路映像

通用I/O端口以下图的方式连接到16个外部中断/事件线上:

另外四个EXTI线的连接方式如下:

  • EXTI16连接到PVD输出
  • EXTI17连接到RTC闹钟事件
  • EXTI18连接到USB唤醒事件
  • EXTI19连接到以太网唤醒事件(只适用于互联型产品)

4、EXTI相关数据结构与函数说明

初始化函数 :

void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);

 结构体EXTI_InitTypeDef:

typedef struct
{
  uint32_t EXTI_Line;   //中断线            
  EXTIMode_TypeDef EXTI_Mode;       //中断模式                                                                              EXTITrigger_TypeDef EXTI_Trigger;      //中断触发方式                                                                    FunctionalState EXTI_LineCmd;     //ENABLE or DISABLE  
}EXTI_InitTypeDef;

@EXTI_Line:

#define EXTI_Line0       ((uint32_t)0x00001)  /*!< External interrupt line 0 */
#define EXTI_Line1       ((uint32_t)0x00002)  /*!< External interrupt line 1 */
#define EXTI_Line2       ((uint32_t)0x00004)  /*!< External interrupt line 2 */
#define EXTI_Line3       ((uint32_t)0x00008)  /*!< External interrupt line 3 */
#define EXTI_Line4       ((uint32_t)0x00010)  /*!< External interrupt line 4 */
#define EXTI_Line5       ((uint32_t)0x00020)  /*!< External interrupt line 5 */
#define EXTI_Line6       ((uint32_t)0x00040)  /*!< External interrupt line 6 */
#define EXTI_Line7       ((uint32_t)0x00080)  /*!< External interrupt line 7 */
#define EXTI_Line8       ((uint32_t)0x00100)  /*!< External interrupt line 8 */
#define EXTI_Line9       ((uint32_t)0x00200)  /*!< External interrupt line 9 */
#define EXTI_Line10      ((uint32_t)0x00400)  /*!< External interrupt line 10 */
#define EXTI_Line11      ((uint32_t)0x00800)  /*!< External interrupt line 11 */
#define EXTI_Line12      ((uint32_t)0x01000)  /*!< External interrupt line 12 */
#define EXTI_Line13      ((uint32_t)0x02000)  /*!< External interrupt line 13 */
#define EXTI_Line14      ((uint32_t)0x04000)  /*!< External interrupt line 14 */
#define EXTI_Line15      ((uint32_t)0x08000)  /*!< External interrupt line 15 */
#define EXTI_Line16      ((uint32_t)0x10000)  /*!< External interrupt line 16 Connected to the PVD Output */
#define EXTI_Line17      ((uint32_t)0x20000)  /*!< External interrupt line 17 Connected to the RTC Alarm event */
#define EXTI_Line18      ((uint32_t)0x40000)  /*!< External interrupt line 18 Connected to the USB Device/USB OTG FS   Wakeup from suspend event */                                    
#define EXTI_Line19      ((uint32_t)0x80000)  /*!< External interrupt line 19 Connected to the Ethernet Wakeup event */

@EXTIMode:

typedef enum
{
  EXTI_Mode_Interrupt = 0x00,//中断模式
  EXTI_Mode_Event = 0x04//事件模式
}EXTIMode_TypeDef;

@EXTI_Trigger

typedef enum
{
  EXTI_Trigger_Rising = 0x08,//上升沿触发
  EXTI_Trigger_Falling = 0x0C,  //下降沿触发
  EXTI_Trigger_Rising_Falling = 0x10//双边沿触发
}EXTITrigger_TypeDef;

中断相关辅助函数:

获取中断状态:

//参数:中断线

ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);

清空中断标志位:

//参数:中断线

void EXTI_ClearITPendingBit(uint32_t EXTI_Line);

软件产生中断:

void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line)

中断回调函数:

在startup_stm32f10x_xx.s中的中断向量表里:

DCD EXTI0_IRQHandler ; EXTI Line 0

DCD EXTI1_IRQHandler ; EXTI Line 1

DCD EXTI2_IRQHandler ; EXTI Line 2

DCD EXTI3_IRQHandler ; EXTI Line 3

DCD EXTI4_IRQHandler ; EXTI Line 4

DCD EXTI9_5_IRQHandler ; EXTI Line 5…9

DCD EXTI15_10_IRQHandler ; EXTI Line 10…15

十、DMA直接存储器存取

DMA(Direct memory access)直接存储器存取,用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输,无须CPU干预,数据可以通过DMA快速地移动,这就节 省了CPU的资源来做其他操作。

STM32有两个DMA控制器12个通道(DMA1有7个通道,DMA2有5个通道),每个通 道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个 DMA请求的优先权。

1、DMA作用

DMA的作用就是实现数据的直接传输,而去掉了传统数据传输需要CPU寄存器参与的环节,主要涉及四种数据传输模式,其本质还是一样的,都是地址到地址的数据传输。

  • 外设到内存
  • 内存到外设
  • 内存到内存
  • 外设到外设

DMA传输相关参数 :源地址 目标地址 数据传输量 …

2、DMA的主要特征

12个独立的可配置的通道(请求):DMA1有7个通道,DMA2有5个通道,每个通 道都直接连接专用的硬件DMA请求,每个通道都同样支持软件触发。这些功能通过软件来配置:

  • 同一个DMA模块上,多个请求间的优先权可以通过软件编程设置(共有四级:很 高、高、中等和低),优先权设置相等时由硬件决定(请求0优先于请求1,依此类推)
  • 独立数据源和目标数据区的传输宽度包括字节、半字、全字,源地址和目标地址 必须按数据传输宽度对齐。
  • 支持循环的缓冲器管理
  • 每个通道都有3个事件标志(DMA半传输、DMA传输完成和DMA传输出错)
  • FLASH、SRAM、外设的SRAM、APB1、APB2和AHB外设均可作为访问的源和 目标
  • 编程的数据传输数目:最大为65535

3、DMA资源

DMA1控制器:

从外设(TIMx[x=1、2、3、4]、ADC1、SPI1、SPI/I2S2、I2Cx[x=1、2]和USARTx[x=1、 2、3])产生的7个请求,通过逻辑或输入到DMA1控制器。

外设的DMA请求,可以通过设置相应外设寄存器中的控制位,被独立地开启或关闭

4、DMA2控制器

从外设(TIMx[5、6、7、8]、ADC3、SPI/I2S3、UART4、DAC通道1、2和SDIO)产生的5 个请求,经逻辑或输入到DMA2控制器 外设的DMA请求,可以通过设置相应外设寄存器中的DMA控制位,被独立地开启或关闭。

注意:DMA2控制器及相关请求仅存在于大容量产品和互联型产品中

4、stm32DMA相关固件库函数说明

(1)初始化函数

void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx,DMA_InitTypeDef* DMA_InitStruct)

参数:

@DMAy_Channelx:DMA通道

y:1或2,用于选择DMA1或DMA2

x:对于DMA1:1-7,对于DMA2:1-5

@DMA_InitStruct:DMA配置结构体指针

typedef struct

{

uint32_t DMA_PeripheralBaseAddr; //外设地址

uint32_t DMA_MemoryBaseAddr; //存储器地址

uint32_t DMA_DIR; //传输方向

uint32_t DMA_BufferSize; //输出大小

uint32_t DMA_PeripheralInc; //外设地址增量模式

uint32_t DMA_MemoryInc; //存储器地址增量模式

uint32_t DMA_PeripheralDataSize; //外设数据宽度

uint32_t DMA_MemoryDataSize; //存储器数据宽度

uint32_t DMA_Mode; //模式选择

uint32_t DMA_Priority; //通道优先级

uint32_t DMA_M2M; //存储器到存储器模式

}DMA_InitTypeDef;

传输方向:

#define DMA_DIR_PeripheralDST//外设作为目标 ((uint32_t)0x00000010)

#define DMA_DIR_PeripheralSRC//外设作为源 ((uint32_t)0x00000000)

外设地址增量模式:

#define DMA_PeripheralInc_Enable ((uint32_t)0x00000040)

#define DMA_PeripheralInc_Disable ((uint32_t)0x00000000)

存储器地址增量模式:

#define DMA_MemoryInc_Enable ((uint32_t)0x00000080)

#define DMA_MemoryInc_Disable ((uint32_t)0x00000000)

外设数据宽度:

#define DMA_PeripheralDataSize_Byte ((uint32_t)0x00000000)

#define DMA_PeripheralDataSize_HalfWord ((uint32_t)0x00000100)

#define DMA_PeripheralDataSize_Word ((uint32_t)0x00000200)

存储器数据宽度:

#define DMA_MemoryDataSize_Byte ((uint32_t)0x00000000)

#define DMA_MemoryDataSize_HalfWord ((uint32_t)0x00000400)

#define DMA_MemoryDataSize_Word ((uint32_t)0x00000800)

模式选择(DMA_Mode):

#define DMA_Mode_Circular ((uint32_t)0x00000020) //循环模式

#define DMA_Mode_Normal ((uint32_t)0x00000000) //正常模式

通道优先级:

#define DMA_Priority_VeryHigh ((uint32_t)0x00003000)

#define DMA_Priority_High ((uint32_t)0x00002000)

#define DMA_Priority_Medium ((uint32_t)0x00001000)

#define DMA_Priority_Low ((uint32_t)0x00000000)

存储器到存储器模式:

#define DMA_M2M_Enable ((uint32_t)0x00004000)

#define DMA_M2M_Disable ((uint32_t)0x00000000)

DMA通道使能:

void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx,  FunctionalState NewState)

DMA中断配置:

void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT,\  FunctionalState NewState)

其他辅助函数:

DMA清除中断挂起:

void DMA_ClearITPendingBit(uint32_t DMAy_IT)

DMA获取中断状态:

ITStatus DMA_GetITStatus(uint32_t DMAy_IT)

获取传输剩余个数:

uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx)

十一、 串口UART

通用同步异步收发器(USART)提供一种灵活的方法与外部设备之间进行全双工数据交 换,USART利用分数波特率发生器提供宽范围的波特率选择,使用多缓冲器配置的DMA方 式,可以实现高速数据通信。

1、接线方式

接口通过三个引脚与其他设备连接在一起,任何USART双向通信至少需要两个脚:接 收数据输入(RX)和发送数据输出(TX)。

  • RX:接收数据串行输。通过过采样技术来区别数据和噪音,从而恢复数据
  • TX:发送数据输出。当发送器被禁止时,输出引脚恢复到它的I/O端口配置。当发送器 被激活, 并且不发送数据时,TX引脚处于高电平。

同步收发器有时钟线,异步收发器无时钟线:

2、USART框架

  •  SW_RX:数据接收引脚,属于内部引脚。
  • nRTS:请求以发送,n表示低电平有效。如果使能 RTS 流控制,当USART接收器准备好接收新数据时就会将nRTS变成低电平;当接收寄存器已满时,nRTS将被设置为高电平。该引脚 只适用于硬件流控制。
  • nCTS:清除以发送(Clear To Send),n表示低电平有效。如果使能 CTS流控制,发送器在发送下一帧数据之前会检测 nCTS 引脚,如果为低电平,表示可以发送数据,如果为高电平则 在发送完当前数据帧之后停止发送。该引脚只适用于硬件流控制。
  • SCLK:发送器时钟输出引脚。这个引脚仅适用于同步模式。

接收发送数据寄存器:

USART数据寄存器(USART_DR)只有低 9 位有效 :

串口时钟

USART1的时钟来源于APB2总线时钟,最大频率为72MHZ,其他4个时钟来源于APB1 总线时钟,最大频率36MHZ。UART只有异步传输功能,没有SCLK、nCTS和nRTS功能引 脚。

波特率发生器:

接收器和发送器的波特率在USARTDIV的整数和小数寄存器中的值应设置成相同

CK:给USART的时钟(PCLK1用于USART2、3、4、5,PCLK2用于USART1)

十二、定时器

MCU微控制器构成的微型计算机系统中,由于微控制器的工作常常会受到来自外界电 磁场的干扰,造成各种寄存器和内存的数据混乱,从而导致程序指针错误、不在程序区、取出错误的程序指令等,都有可能会导致程序执行陷入死循环,程序的正常运行被打断,由微控制器控制的系统无法继续正常工作,导致整个系统的陷入停滞状态,发生不可预料的后 果。

为了解决以上问题,在微控制器内部集成了一个定时器复位电路,即看门狗电路。 在stm32微控制器中集成了两个时钟外设,分别是独立时钟和窗口时钟,提供了 更高的安全性,时间的精确性和使用灵活性,两个时钟设备(独立时钟、窗口时钟) 可以用来监测和解决由软件错误引起的故障,当计算器达到给定的超时值时,产生系统复位或者触发一个中断(仅适用于窗口时钟)。

1、 独立时钟(IWDG)

由专用的低速时钟(LSI)驱动,即使主时钟发生故障,任能够继续有效。

独立时钟适用于需要看门狗作为一个在主程序之外能够完全独立工作,并且对时间精 度要求低的场合

IWDG主要性能:

  • 自由运行的递减计数器,由LSI驱动
  • 时钟由独立的RC振荡器(LSI)提供(可在停止和待机模式下工作)
  • 看门狗被激活后,则在计数器计数至0x000时产生复位

时钟框架 :

 时钟:

由LSI提供时钟,时钟频率40KHz,经过预分频器分频后的时钟,提供给12bit递减计数器,作为向下技术的频率。 预分频器的分频系数由IWDG_PR预分频寄存器设置:地址偏移:0x04 复位值:0x0000 0000

键寄存器:

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

,由于微控制器的工作常常会受到来自外界电 磁场的干扰,造成各种寄存器和内存的数据混乱,从而导致程序指针错误、不在程序区、取出错误的程序指令等,都有可能会导致程序执行陷入死循环,程序的正常运行被打断,由微控制器控制的系统无法继续正常工作,导致整个系统的陷入停滞状态,发生不可预料的后 果。

为了解决以上问题,在微控制器内部集成了一个定时器复位电路,即看门狗电路。 在stm32微控制器中集成了两个时钟外设,分别是独立时钟和窗口时钟,提供了 更高的安全性,时间的精确性和使用灵活性,两个时钟设备(独立时钟、窗口时钟) 可以用来监测和解决由软件错误引起的故障,当计算器达到给定的超时值时,产生系统复位或者触发一个中断(仅适用于窗口时钟)。

1、 独立时钟(IWDG)

由专用的低速时钟(LSI)驱动,即使主时钟发生故障,任能够继续有效。

独立时钟适用于需要看门狗作为一个在主程序之外能够完全独立工作,并且对时间精 度要求低的场合

IWDG主要性能:

  • 自由运行的递减计数器,由LSI驱动
  • 时钟由独立的RC振荡器(LSI)提供(可在停止和待机模式下工作)
  • 看门狗被激活后,则在计数器计数至0x000时产生复位

时钟框架 :

 时钟:

由LSI提供时钟,时钟频率40KHz,经过预分频器分频后的时钟,提供给12bit递减计数器,作为向下技术的频率。 预分频器的分频系数由IWDG_PR预分频寄存器设置:地址偏移:0x04 复位值:0x0000 0000

键寄存器:

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-lMTzttFm-1715628729651)]

[外链图片转存中…(img-pm4gOOcV-1715628729652)]

[外链图片转存中…(img-ksVwh8Iw-1715628729652)]

[外链图片转存中…(img-5jA5mG1L-1715628729653)]

[外链图片转存中…(img-z5yIrkk6-1715628729653)]

[外链图片转存中…(img-fhYe76hE-1715628729654)]

[外链图片转存中…(img-oaHoXzat-1715628729654)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值