【物联网】stm32芯片结构组成,固件库、启动过程、时钟系统、GPIO、NVIC、DMA、UART以及看门狗电路的全面详解

一、stm32的介绍

1、概述 

stm32:

ST:指意法半导体

M:指定微处理器

32:表示计算机处理器位数

与ARM关系:采用ARM推出cortex-A,R,M三系中的M系列,其架构主要基于ARMv7-M实现 

ARM分成三个系列:

Cortex-A:针对多媒体应用

Cortex-R:针对对实时性和性能有一定要求的场景

Cortex-M:针对低功耗高性能的场景 Cortex-M0、Cortex-M3、Cortex-M4

 指令集:精简指令集

不同场景应用具体可以参考产品选型手册;--《 STM8和STM32产品选型手册》 

命名规则: 

F:通用快闪(FlashMemory);

        F类型中F0xx和F1xx系列为2.0~3.6V;F2xx和F4xx系列为1.8~3.6V

L:低电压(1.65~3.6V);

2、stm32芯片内部结构 

SoC:片上集成系统

Cortex-M3详细内部结构: 

 3、stm32最小系统组成

我们使用的stm32芯片型号:stm32f103c8t6

1、供电系统

2、时钟电路(内部时钟源、外部时钟源)

3、复位电路

4、下载的接口电路

5、boot电路 

4、开发相参考手册介绍 

选型手册和数据手册:

        第二个PDF文档是引脚功能硬件相关介绍,

        第四个PDF文档是软件开发需要参考的文档。

        原理图:对于软件开发工程师来讲,查看的目的是找外接设备与STM32的电气连接关系, 为编程做准备。

二、固件库介绍

1、开发方式 

 从开发语言:

  • 汇编语言
  • C语言(效率更高)

stm32单片机:(汇编+C)

 实际开发编程过程中使用的方法:

1、配置MCU中的某个功能模块的寄存器,进行操作

2、使用ST官方提供的固件库驱动操作

ST官方提供了STM32cubemx软件,图形化配置开发软件

2、固件库说明

        固件库:STM32标准外设函数库,简称固件库 

        特点: 主要由功能接口、数据结构、宏等组成,涵盖了微控制器所有外设的性能特征 包括每一个外设驱动描述和应用实例 为开发者访问底层硬件提供了统一的API 无需深入掌握底层硬件实现细节 大大缩短产品开发周期,进而降低了研发成本 容易进行二次开发、升级和维护

        获取st官方提供stm32标准固件库: https://www.stmicroelectronics.com.cn/zh/embedded-software/stm32-standard-peripheral-libraries.html?querycriteria=productId=LN19 

STM32F10x_StdPeriph_Lib_V3.5.0中: 

libraries中 

    CMSIS: Cortex Microcontroller Software Interface Standard,主要是Cortex-M系列处理器与供 应商无关的硬件抽象层 降低了在Cortex-M系列处理器上操作系统的移植难度,简化了软件重复,标准化了软件接口 。

CMSIS主要包含: core_cm3.x、stm32f10x.h、system_stm32f10x.x、 startup_stm32f10x_xx.s 

 固件库重点文件介绍:

  • core_cm3.x:主要针对一些通用寄存器、中断优先级、启动模式相关的内嵌汇编操作接口
  • stm32f10x.h:实现了所有硬件寄存器结构、地址映射、寄存器位操作、基本类型等定义
  • system_stm32f10x.x:系统启动初始化,尤其是系统时钟配置
  • startup_stm32f10x_xx.s:引导启动文件

标准外设驱动STM32F10x_StdPeriph_Driver中: 

inc和src中主要包含: stm32f10x.x

固件库重点文件介绍:

  • misc.x:主要是中断初始化、分组管理等相关接口,实现了用户对中断的配置功能
  • stm32f10x_exit.x:中断服务相关
  • stm32f10x_conf.h:用来统一包含当前系统要用到的功能模块头文件,并实现了 assert_param()(在project下STM32F10x_StdPeriph_Template中)

三、开发环境搭建 

1、keil5软件安装 

 然后再安装相应的芯片支持包:我们用的是stm32f103所以安装1xx系列的支持包。

2、keil工程搭建 

(1)创建目录结构管理

 创建如下:

(2)工程结构管理 

1、打开keil5软件,点击project,创建新的keil5工程

2、选择芯片型号(stm32f103c8)

3、创建管理keil工程内部的目录结构

4、文件添加 

(3)配置

 

安装更新驱动:
 

 

四、stm32的启动过程 

1、系统架构 

(1)主系统架构 

四个驱动单元:

Cortex-M3内核 、Dcode总线 、Icode总线 、DMA1&DMA2

四个被动单元:

Internel SRAM 、Internel Flash 、FSMC 、AHB到APB桥。

(2)总线框图 

 (3)总线介绍

        ICode总线(Instruction Code): 该总线将Cortex™-M3内核的指令总线与闪存指令接口相连接。指令预取在此总线上完成

        DCode总线 (Data Code): 该总线将Cortex™-M3内核的DCode总线与闪存存储器的数据接口相连接(常量加载调试访问)

        系统总线:此总线连接Cortex™-M3内核的系统总线(外设总线)到总线矩阵,总线矩阵协调着内核 和DMA间的访问

        DMA总线:此总线将DMA的AHB主控接口与总线矩阵相联,总线矩阵协调着CPU的DCode和 DMA到SRAM、闪存和外设的访问

        总线矩阵:总线矩阵协调内核系统总线和DMA主控总线之间的访问仲裁,仲裁利用轮换算法。在 互联型产品中,总线矩阵包含5个驱动部件(CPU的DCode、系统总线、以太网DMA、 DMA1总线和DMA2总线)和3个从部 件(闪存存储器接口(FLITF)、SRAM和AHB2APB桥)。在其它产品中总线矩阵包含4个驱 动部件(CPU的DCode、系统总线、DMA1总线和DMA2总线)和4个被动部件(闪存存储器接 口(FLITF)、SRAM、FSMC和AHB2APB桥)。AHB外设通过总线矩阵与系统总线相连,允许 DMA访问

        AHB/APB桥(APB):两个AHB/APB桥在AHB和2个APB总线间提供同步连接。APB1操作速度限于36MHz, APB2操作于全速(最高72MHz)。有关连接到每个桥的不同外设的地址映射请参考上表。在 每一次复位以后,所有除SRAM 和FLITF以外的外设都被关闭,在使用一个外设之前,必须 设置寄存器RCC_AHBENR来打开该外设的时钟

2、存储器结构 

        程序存储器、数据存储器、寄存器和输入输出端口,被组织在同一个4G的线性地址空间 中。 可以通过地址的方法访问对应的存储器或寄存器。 

3、启动模式

三种启动模式: 

我们使用的stm32f103c8核心板:boot0 :0 boot1:0

启动方式:从内部的Flash中启

存储器映射: 0x0000 0000 —— 0x0800 0000 映射的内部Flash

4、启动文件

  • cl:互联型产品,stm32f105/107系列
  • vl:超值型产品,stm32f100系列
  • xl:超高密度产品,stm32f101/103系列 

flash容量大小:

  • ld:小容量产品, 小于64KB
  • md:中等容量度产品,64KB和128KB
  • hd:大容量产品,大于128KB 

stm32f103C8 :选择的启动文件->startup_stm32f10x_md.s 

5、启动文件分析 

上电或按下复位按键,从Reset_Handler 开始执行。

在startup_stm32f10x_md.s 中启动代码:

 ; Reset handler 
Reset_Handler PROCEXPORT Reset_Handler [WEAK]
IMPORT __main
IMPORT SystemInitLDR R0, =SystemInitBLX R0LDR R0, =__mainBX R0ENDP

执行的第一个函数:SystemInit

初始化flash接口

初始化设置PLL

初始化设置系统时钟

执行的第二个函数:

__main 属于C库函数,作用:

         完成全局/静态变量的初始化

        初始化堆栈

        库函数的初始化

        程序的跳转,进入用户的main函数入

6、系统复位 

        除了时钟控制器的RCC_CSR寄存器中的复位标志位和备份区域中的寄存器(见图4)以外,系统复位将复位所有寄存器至它们的复位状态。

当发生以下任一事件时,产生一个系统复位:

1.NRST引脚上的低电平(外部复位)

2.窗口看门狗计数终止(WWDG复位)

3.独立看门狗计数终止(IWDG复位)

4.软件复位(SW复位)

5.低功耗管理复位

 可通过查看RCC_CSR控制状态寄存器中的复位状态标志位识别复位事件来源。

 五、时钟系统

1、时钟系统框图

系统时钟的时钟源: HSI(内部高速时钟)、HSE(外部高速时钟)、PLL 、

LSE(外部低速时钟): 可以被选择作为RTC时钟源、

LSI(内部低速时钟): 既可被选择作为RTC时钟源,也可作为独立看门狗时钟源。

  1. 40kHz低速内部RC,可以用于驱动独立看门狗和通过程序选择驱动RTC。RTC用于从停机/待机模式下自动唤醒系统。
  2. 32.768kHz低速外部晶体也可用来通过程序选择驱动RTC(RTCCLK)

 系统时钟sysclk:

1、PCLK1&TIM2-7 ,PCLK最大是36MHz 

2、PCLK2&ADC&TIM1&TIM8 

2、系统时钟初始化过程 

在系统初始化前期:使能了内部高速时钟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

键寄存器:

地址偏移:0x00 复位值:0x0000 0000 (在待机模式复位) 

        IWDG_PR和IWDG_RLR寄存器具有写保护功能。要修改这两个寄存器的值,必须先向 IWDG_KR寄存器中写入0x5555。重装载操作(即写入0xAAAA)也会启动写保护功能。 

重装载寄存器:

地址偏移:0x08   复位值:0x0000 0FFF(待机模式时复位) 

 相关固件库函数:

写使能IWDG_PR 和IWDG_RLR寄存器:

//Enables or disables write access to IWDG_PR and IWDG_RLR registers

#define IWDG_WriteAccess_Enable ((uint16_t)0x5555)

#define IWDG_WriteAccess_Disable ((uint16_t)0x0000)

参数:

@arg IWDG_WriteAccess_Enable

@arg IWDG_WriteAccess_Disable

void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess)

 设置预分频寄存器:

/**  * @brief Sets IWDG Prescaler value.

* @param IWDG_Prescaler: specifies the IWDG Prescaler value.

* This parameter can be one of the following values:

* @arg IWDG_Prescaler_4: IWDG prescaler set to 4

* @arg IWDG_Prescaler_8: IWDG prescaler set to 8

* @arg IWDG_Prescaler_16: IWDG prescaler set to 16

* @arg IWDG_Prescaler_32: IWDG prescaler set to 32

* @arg IWDG_Prescaler_64: IWDG prescaler set to 64

* @arg IWDG_Prescaler_128: IWDG prescaler set to 128

* @arg IWDG_Prescaler_256: IWDG prescaler set to 256

* @retval None 13 */

void IWDG_SetPrescaler(uint8_t IWDG_Prescaler)

设置重装载值: 

/**  * @brief Sets IWDG Reload value.

* @param Reload: specifies the IWDG Reload value.

* This parameter must be a number between 0 and 0x0FFF.

* @retval None

*/         

void IWDG_SetReload(uint16_t Reload) 

 按照 IWDG 重装载寄存器的值重装载 IWDG 计数器:

//#define KR_KEY_Reload ((uint16_t)0xAAAA)

void IWDG_ReloadCounter(void)

{

        IWDG‐>KR = KR_KEY_Reload;

}

使能看门狗定时器:

//#define KR_KEY_Enable ((uint16_t)0xCCCC)

void IWDG_Enable(void)

{

        IWDG‐>KR = KR_KEY_Enable;

 2、窗口时钟( wwdg)

        通常被用来监测,由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序 列而产生的软件故障。

        由从APB1时钟分频后得到的时钟驱动,通过可配置的时间窗口来监测应用程序非正常的过迟或过早操作。窗口时钟最合适那些要求时钟在精确计时窗口起作用的程序。 

 WWDG框架:

 产生复位的两种情况:

第一种:

        1和2经过与门后,产生复位。即:WDGA位为1,T6为0(取反后为1,经过或门电路后路 径2为1),也就是WWDG_CR寄存器递减到0x40后,再减1,编程0x3F的时候,T6位,由 1变为0。 

         WDGA位为1时,当T6:0 > W6:0 且写入WWDG_CR(即刷新计数值)产生复位中断

 WWDG时序:

        配置寄存器(WWDG_CFR) 中包含窗口的上限值:要避免产生复位,递减计数器必须在其值 小于窗口寄存器的数值并且大于0x3F时被重新装载 

 时钟:

        WWDG时钟来自于PCLK1(36MHz),由窗口时钟WDGTB预分频器分频后,提供 给6bit递减计数器作为向下计数得频率。

控制寄存器(WWDG_CR):

 配置寄存器(WWDG_CFR):

 相关固件库函数:

WWDG默认配置:

void WWDG_DeInit(void)

设置预分频:

@arg WWDG_Prescaler_1: WWDG counter clock = (PCLK1/4096)/1

@arg WWDG_Prescaler_2: WWDG counter clock = (PCLK1/4096)/2

@arg WWDG_Prescaler_4: WWDG counter clock = (PCLK1/4096)/4

@arg WWDG_Prescaler_8: WWDG counter clock = (PCLK1/4096)/8

void WWDG_SetPrescaler(uint32_t WWDG_Prescaler) 

设置窗口值(即设置WWDG_CFR寄存器值):

//This parameter value must be lower than 0x80

void WWDG_SetWindowValue(uint8_t WindowValue) 

设置计数值(即设置WWDG_CR寄存器值):

//This parameter must be a number between 0x40 and 0x7F

void WWDG_SetCounter(uint8_t Counter)

 使能 WWDG 并装入计数器值:

//This parameter must be a number between 0x40 and 0x7F

void WWDG_Enable(uint8_t Counter)

使能中断:

void WWDG_EnableIT(void); 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/271640.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

开源模型应用落地-工具使用篇-Ollama(六)

一、前言 在AI大模型百花齐放的时代&#xff0c;很多人都对新兴技术充满了热情&#xff0c;都想尝试一下。但是&#xff0c;实际上要入门AI技术的门槛非常高。除了需要高端设备&#xff0c;还需要面临复杂的部署和安装过程&#xff0c;这让很多人望而却步。不过&#xff0c;随着…

RFID-科技的“隐秘耳语者”

RFID-科技的“隐秘耳语者” 想象一下&#xff0c;你身处一个光线昏暗的环境中&#xff0c;周围的一切都被厚厚的阴影笼罩。这时&#xff0c;你需要识别并获取一个物体的信息&#xff0c;你会选择怎么做&#xff1f;是点亮灯光&#xff0c;用肉眼仔细观察&#xff0c;还是打开扫…

神经网络的矢量化,训练与激活函数

我们现在再回到我们的神经元部分&#xff0c;来看我们如何用python进行正向传递。 单层的正向传递&#xff1a; 我们回到我们的线性回归的函数。我们每个神经元通过上述的方法&#xff0c;就可以得到我们的激发值&#xff0c;从而可以继续进行下一层。 我们用这个方法就可以得…

智慧城市如何助力疫情防控:科技赋能城市安全

目录 一、引言 二、智慧城市与疫情防控的紧密结合 三、智慧城市在疫情防控中的具体应用 1、智能监测与预警系统 2、智慧医疗与健康管理 3、智能交通与物流管理 4、智慧社区与基层防控 四、科技赋能城市安全的未来展望 五、结论 一、引言 近年来&#xff0c;全球范围内…

Platformview在iOS与Android上的实现方式对比

Android中早期版本Platformview的实现基于Virtual Display。VirtualDisplay方案的原理是&#xff0c;先将Native View绘制到虚显&#xff0c;然后Flutter通过从虚显输出中获取纹理并将其与自己内部的widget树进行合成&#xff0c;最后作为Flutter在 Android 上更大的纹理输出的…

链表|206.反转链表

力扣题目链接 struct ListNode* reverseList(struct ListNode* head){//保存cur的下一个结点struct ListNode* temp;//pre指针指向前一个当前结点的前一个结点struct ListNode* pre NULL;//用head代替cur&#xff0c;也可以再定义一个cur结点指向head。while(head) {//保存下…

测试常用的Linux命令

前言 直接操作硬件 将把操作硬件的代码封装成系统调用&#xff0c;供程序员使用 虚拟机软件 可以模拟的具有完整硬件系统的功能 可以在虚拟机上安装不同的操作系统 Linux内核只有一个&#xff0c;发行版有很多种 内核来运行程序和管理像磁盘和打印机等硬件设备的核心程序 终端…

高清数学公式视频素材、科学公式和方程式视频素材下载

适用于科普、解说的自媒体视频剪辑素材&#xff0c;黑色背景数学、科学公式和方程式视频素材下载。 视频编码&#xff1a;H.264 | 分辨率&#xff1a;3840x2160 (4K) | 无需插件 | 文件大小&#xff1a;16.12MB 来自PR视频素材&#xff0c;下载地址&#xff1a;https://prmuban…

NTFS Disk by Omi NTFS for mac v1.1.4中文版

NTFS Disk by Omi NTFS for Mac&#xff1a;NTFS文件系统的无缝桥梁 软件下载&#xff1a;NTFS Disk by Omi NTFS for mac v1.1.4中文版 &#x1f310; 跨平台访问&#xff0c;文件无阻 NTFS Disk by Omi NTFS for Mac 为您的Mac提供了对NTFS文件系统的无缝访问。无论您是在Win…

Crow 编译和环境搭建

Crow与其说是编译&#xff0c;倒不如说是环境搭建。Crow只需要包含头文件&#xff0c;所以不用编译生成lib。 Crow环境搭建 boost&#xff08;可以不编译boost&#xff0c;只需要boost头文件即可&#xff09;asio &#xff08;可以不编译&#xff0c;直接包含头文件。不能直接…

Ethersacn的交易数据是什么样的(2)

分析 Raw Transanction RLP&#xff08;Recursive Length Prefix&#xff09;是一种以太坊中用于序列化数据的编码方式。它被用于将各种数据结构转换为二进制格式&#xff0c;以便在以太坊中传输和存储。RLP 是一种递归的编码方式&#xff0c;允许对复杂的数据结构进行编码。所…

typeorm-入门

简述 typeorm是一个数据库orm框架&#xff0c;在nestjs官网中有提到&#xff0c;可以充分发挥利用typescript的特性&#xff0c;当然也支持js其中涉及的概念包括 DataSource 数据源&#xff0c;Connection 连接数据库Entity 实体&#xff0c;实体类映射数据库表Relation 关系…

redis实现分布式全局唯一id

目录 一、前言二、如何通过Redis设计一个分布式全局唯一ID生成工具2.1 使用 Redis 计数器实现2.2 使用 Redis Hash结构实现 三、通过代码实现分布式全局唯一ID工具3.1 导入依赖配置3.2 配置yml文件3.3 序列化配置3.4 编写获取工具3.5 测试获取工具 四、运行结果 一、前言 在很…

安康杯安全知识竞赛上的讲话稿

各位领导、同志们&#xff1a; 经过近半个月时间的准备&#xff0c;南五十家子镇平泉首届安康杯安全生产知识竞赛初赛在今天圆满落下帏幕&#xff0c;经过紧张激烈的角逐&#xff0c; 代表队、 代表队和 代表队分别获得本次竞赛的第一、二、三名让我们以热烈的掌声表示祝…

LLM PreTraining from scratch -- 大模型从头开始预训练指北

最近做了一些大模型训练相关的训练相关的技术储备&#xff0c;在内部平台上完成了多机多卡的llm 预训练的尝试&#xff0c;具体的过程大致如下&#xff1a; 数据准备&#xff1a; 大语言模型的训练依赖于与之匹配的语料数据&#xff0c;在开源社区有一群人在自发的整理高质量的…

读《文明之光》第1册总结

人类几千年的文明史和地球的历史相比&#xff0c;实在是太短暂了&#xff0c;大约相当于几分钟和一年的关系。人类已经走过的路&#xff0c;相比今后要走的漫漫长路&#xff0c;只能算是刚刚起步。如果跳出一个个具体事件&#xff0c;站在历史的高度去看&#xff0c;我们会发现…

前端实现一个绕圆心转动的功能

得知了转换关系&#xff0c;我们就可以定义一个变量 angle 来表示我们这个 div 做圆周运动时绕圆心转过的角度&#xff0c;则弧度&#xff08;radian&#xff09; 为 radian &#xff08;angle*π&#xff09;/180 我们先在草稿纸上演练一遍我们的逻辑是否可行。让我们先准备一…

货运物流小程序开发功能 发货运输更简单

随着互联网的快速发展&#xff0c;线上接单已经成为物流行业的主流趋势。货运物流接单小程序作为物流企业的得力助手&#xff0c;能够提高运输效率、降低成本、提升服务质量&#xff0c;成为物流行业的发展新方向。 1. 用户注册与登录功能&#xff1a;用户可以通过手机号、邮箱…

光谱下的养殖业:数据可视化的现代变革

在数字化时代&#xff0c;数据可视化在养殖业中崭露头角&#xff0c;为这一传统行业注入了新的活力。无论是家禽养殖还是水产养殖&#xff0c;数据可视化都以其直观、高效的特点&#xff0c;为养殖业带来了全新的发展机遇。下面我就以可视化从业者的角度&#xff0c;简单聊聊这…

华为od机试C卷-开源项目热度榜单

1、题目描述 某个开源社区希望将最近热度比较高的开源项目出一个榜单&#xff0c;推荐给社区里面的开发者。 对于每个开源项目&#xff0c;开发者可以进行关注(watch)、收藏(star)、fork、提issue、提交合并请求(MR)等。 数据库里面统计了每个开源项目关注、收藏、fork、issue…