赞
踩
一、stm32的介绍
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);
SoC:片上集成系统
Cortex-M3详细内部结构:
我们使用的stm32芯片型号:stm32f103c8t6
1、供电系统
2、时钟电路(内部时钟源、外部时钟源)
3、复位电路
4、下载的接口电路
5、boot电路
选型手册和数据手册:
第二个PDF文档是引脚功能硬件相关介绍,
第四个PDF文档是软件开发需要参考的文档。
原理图:对于软件开发工程师来讲,查看的目的是找外接设备与STM32的电气连接关系, 为编程做准备。
从开发语言:
stm32单片机:(汇编+C)
实际开发编程过程中使用的方法:
1、配置MCU中的某个功能模块的寄存器,进行操作
2、使用ST官方提供的固件库驱动操作
ST官方提供了STM32cubemx软件,图形化配置开发软件。
固件库: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
固件库重点文件介绍:
标准外设驱动STM32F10x_StdPeriph_Driver中:
inc和src中主要包含: stm32f10x.x
固件库重点文件介绍:
然后再安装相应的芯片支持包:我们用的是stm32f103所以安装1xx系列的支持包。
(1)创建目录结构管理
创建如下:
(2)工程结构管理
1、打开keil5软件,点击project,创建新的keil5工程
2、选择芯片型号(stm32f103c8)
3、创建管理keil工程内部的目录结构
4、文件添加
(3)配置
安装更新驱动:
(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来打开该外设的时钟
程序存储器、数据存储器、寄存器和输入输出端口,被组织在同一个4G的线性地址空间 中。 可以通过地址的方法访问对应的存储器或寄存器。
三种启动模式:
我们使用的stm32f103c8核心板:boot0 :0 boot1:0
启动方式:从内部的Flash中启
存储器映射: 0x0000 0000 —— 0x0800 0000 映射的内部Flash
flash容量大小:
stm32f103C8 :选择的启动文件->startup_stm32f10x_md.s
上电或按下复位按键,从Reset_Handler 开始执行。
在startup_stm32f10x_md.s 中启动代码:
- ; Reset handler
- Reset_Handler PROC
- EXPORT Reset_Handler [WEAK]
- IMPORT __main
- IMPORT SystemInit
- LDR R0, =SystemInit
- BLX R0
- LDR R0, =__main
- BX R0
- ENDP
执行的第一个函数:SystemInit
初始化flash接口
初始化设置PLL
初始化设置系统时钟
执行的第二个函数:
__main 属于C库函数,作用:
完成全局/静态变量的初始化
初始化堆栈
库函数的初始化
程序的跳转,进入用户的main函数入
除了时钟控制器的RCC_CSR寄存器中的复位标志位和备份区域中的寄存器(见图4)以外,系统复位将复位所有寄存器至它们的复位状态。
当发生以下任一事件时,产生一个系统复位:
1.NRST引脚上的低电平(外部复位)
2.窗口看门狗计数终止(WWDG复位)
3.独立看门狗计数终止(IWDG复位)
4.软件复位(SW复位)
5.低功耗管理复位
可通过查看RCC_CSR控制状态寄存器中的复位状态标志位识别复位事件来源。
系统时钟的时钟源: HSI(内部高速时钟)、HSE(外部高速时钟)、PLL 、
LSE(外部低速时钟): 可以被选择作为RTC时钟源、
LSI(内部低速时钟): 既可被选择作为RTC时钟源,也可作为独立看门狗时钟源。
系统时钟sysclk:
1、PCLK1&TIM2-7 ,PCLK最大是36MHz
2、PCLK2&ADC&TIM1&TIM8
在系统初始化前期:使能了内部高速时钟HSI
RCC->CR |= (uint32_t)0x00000001;
RCC->CFGR &= (uint32_t)0xF8FF0000;
设置系统时钟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
根据数据手册中列出的每个IO端口的特定硬件特征,GPIO端口的每个位可以由软件分别配置成多种模式。
功能:
输入(Input):
浮空:
模拟:
上拉:
下拉:
输出(Output):
推挽:推挽输出有一定的驱动能力,可以真正的输出高低电平
开漏:实际是没有驱动能力的,想要驱动设备,需要外部有驱动电路支持
开启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)
先复位,点击运行到断点位置,多次点击往下执行查看寄存器电平变化:
2000=0010 0000 0000 0000,第十三位置1,即引脚13输出高电平:
共有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请求
PWM:脉冲宽度调制(频率可以设定,占空比可动态调节)
(1)原理说明
每个定时器有4路输出通道:OC1——OC4 有RCC给到TIM2——TIM7的时钟频率是72MHz
结构体: 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)
tim4定时器引脚为PB6-PB9
示波器看对应引脚的输出波形
NVIC(Nest Vector Interrupt Controller),嵌套中断向量控制器,作用是管理中断嵌套,核心任务是管理中断优先级。
特点:
嵌套向量中断控制器(NVIC)和处理器核的接口紧密相连,可以实现中断的低延迟处理和高效地处理晚到的中断。
NVIC给每个中断赋予抢占优先级和响应优先级。关系如下:
每个中断源都需要被指定这两种优先级,Cortex-M3核定义了8个bit用于设置中断源的优先 级,这8个bit可以有以下8种分配方式:
Cortex-M3允许具有较少中断源时使用较少的寄存器位指定中断源的优先级,因此STM32 中断优先级的寄存器位只用到AIRCR高四位,共有以下几种组合:
使用固件库函数配置中断优先级(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)
每个外部中断都由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) 使能/失能对应的中断通道
当CM3开始响应一个中断时,会做如下动作:
入栈:响应异常的第一个动作,就是自动保存现场,依次把xPSR、PC, LR, R12以及R3-R0由 硬 件寄存器自动压入适当的堆栈中。
取向量:数据总线(系统总线)在执行入栈的时候,指令总线从向量表中找出正确的异常向量, 然后在服务程序的入口处预取指。 (由此可以看到各自都有专用总线的好处:入栈与取指这两个工作能同时进行)
更新寄存器:在入栈和取向量操作完成之后,执行服务例程之前,还要更新一系列的寄存器.
SP:在入栈后会把堆栈指针更新到新的位置。在执行服务例程时,将由MSP负 责对堆栈的 访问。
PSR:更新IPSR位段的值为新响应的异常编号。
PC:在取向量完成后,PC将指向服务例程的入口地址,
LR:在出入ISR(Interrupt Service Routines)中断服务程序的时候,LR的值 将得到更新 (在异常进入时由系统计算并赋给LR,并在异常返回时使用它)
当异常服务例程执行完毕后,需要恢复先前的系统状态,才能使被中断的程序得以继续执行。 异常/中断处理完成后,执行如下处理:
对于互联型产品,外部中断/事件控制器由20个产生事件/中断请求的边沿检测器组成, 对于其它 产品,则有19个能产生事件/中断请求的边沿检测器。每个输入线可以独立地配置输入类型 和对应的触发事件(上升沿或下降沿或者双边沿都触发)。每个输入线都可以独立地被屏蔽。 挂起寄存器保持着状态线的中断请求。
EXTI:
EXTI 可分为两大部分功能,一个是产生中断,另一个是产生事件:
中断: 信号从输入线输入,经过边沿检测电路来控制信号触发(根据上升沿下降沿触发选择寄 存器的设置来控制),如果检测到有效信号后,将该有效信号输出到或门电路,由红色箭头 方向经过请求挂起寄存器和中断屏蔽寄存器,到达与门电路,条件满足送至NVIC
事件: 信号从输入线输入,经过边沿检测电路来控制信号触发(根据上升沿下降沿触发选择寄存器 的设置来控制),如果检测到有效信号后,将该有效信号输出到或门电路,由蓝色箭头方向 经过与门电路,送至买脉冲发生器,产生脉冲。这个脉冲信号可以给其他外设电路使用,比 如定时器 TIM、模拟数字转换器 ADC等等,这样的脉冲信号一般用来触发 TIM 或者 ADC 开始转换。
事件和中断的区别:
产生中断线路目的是把输入信号输入到 NVIC,进一步会运行中断服务函数,实现功能,这 样是软件级的。而产生事件线路目的就是传输一个脉冲信号给其他外设使用,并且是电路级别的信号传输,属于硬件级的。
通用I/O端口以下图的方式连接到16个外部中断/事件线上:
另外四个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(Direct memory access)直接存储器存取,用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输,无须CPU干预,数据可以通过DMA快速地移动,这就节 省了CPU的资源来做其他操作。
STM32有两个DMA控制器共12个通道(DMA1有7个通道,DMA2有5个通道),每个通 道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个 DMA请求的优先权。
DMA的作用就是实现数据的直接传输,而去掉了传统数据传输需要CPU寄存器参与的环节,主要涉及四种数据传输模式,其本质还是一样的,都是地址到地址的数据传输。
DMA传输相关参数 :源地址 目标地址 数据传输量 ...
12个独立的可配置的通道(请求):DMA1有7个通道,DMA2有5个通道,每个通 道都直接连接专用的硬件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控制器及相关请求仅存在于大容量产品和互联型产品中
(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)
通用同步异步收发器(USART)提供一种灵活的方法与外部设备之间进行全双工数据交 换,USART利用分数波特率发生器提供宽范围的波特率选择,使用多缓冲器配置的DMA方 式,可以实现高速数据通信。
接口通过三个引脚与其他设备连接在一起,任何USART双向通信至少需要两个脚:接 收数据输入(RX)和发送数据输出(TX)。
同步收发器有时钟线,异步收发器无时钟线:
接收发送数据寄存器:
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微控制器中集成了两个时钟外设,分别是独立时钟和窗口时钟,提供了 更高的安全性,时间的精确性和使用灵活性,两个时钟设备(独立时钟、窗口时钟) 可以用来监测和解决由软件错误引起的故障,当计算器达到给定的超时值时,产生系统复位或者触发一个中断(仅适用于窗口时钟)。
由专用的低速时钟(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;
}
通常被用来监测,由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序 列而产生的软件故障。
由从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);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。