自学内容网 自学内容网

stm32中的常用函数

目录

一、定义声明类

1.1 预定义

1.2 条件编译

1.3 extern 声明

1.3 typedef 类型别名

1.4 结构体

二、基础函数

2.1 delay类函数

2.2 printf函数

三、GPIO

3.1 硬件

3.2 通用外设驱动模型

3.3 例程

四、中断

4.1. 什么是中断

4.2. NVIC

4.3. EXTI

4.4. EXTI和IO映射关系

4.5. 如何使用中断

4.6. 例程(外部中断控制一个灯亮灭)

五. 串口通信

5.1. 数据通信的基础概念

5.2. 串口(RS232)

5.3. STM32的USART简介

5.4. HAL库

5.5. USART/UART异步通信配置步骤

5.6. IO引脚复用功能

5.7. 编程实验

六、独立看门狗

6.1. IWDG简介

6.2. STM32系统的复位

6.3. IWDG的作用

6.4. IWDG工作原理

6.5. IWDG配置步骤

6.6. 实验不及时喂狗,系统将复位


一、定义声明类

1.1 预定义
#define LED1(x) do{ x? \ Hal_GPIO_1:\
HAL_GPIO_2);\
}while(0)   //如果成立执行第一句,如果不成立执行第二句
1.2 条件编译

#if 类似If,如果则执行下面
#ifdef 判断是否已被定义
#ifndef 判断是否未被定义,未被定义则执行下面的
#endif 结束标志

1.3 extern 声明

放在函数/变量前,表示函数/变量在其它文件定义,本文引用

extern uint16_t g_usart;
extern void delay_us(uint32_t nus);
1.3 typedef 类型别名

typedef 现有类型 新名字

typedef unsigned char uint8_t;
typedef struct
{
-IO uint32_t CRL;
} gpio_ty;
gpio_ty giox;
1.4 结构体

若干基本数据类型集合组成
struct 结构体名
{
成员列表;
} 变量名列表(可选);

struct student
{
int num;
} stu1,stu2;
struct student stu1,stu2;
stu1.num=10;

二、基础函数

2.1 delay类函数

delay_init()函数
用于延时初始化

void delay_init(uint16_tsysclk)
//输入的unint16为mHz,如f407 168mHz,此处输入168即可

delay_us()函数
微秒延迟函数

delay_us(unit32_t nus)
//unit32为延迟的微秒数

delay_ms()函数
毫秒延迟函数

delay_us(unit16_t nms)
//unit16_t为延迟的微秒数
2.2 printf函数

printf()用户调用->C标准库(stdio.h)->fputc()实现输出
stdio.h包括:printf、scanf、putchar、puts等

(1)输出字符串

printf("字符串\r\n");  //\r\n用于换行

(2)输出控制符

uint32 t temp= 10;
printf("%d\r\n", temp);
/*%d是输出控制符,temp是输出参数*/

(3)printf("输出控制符1输出控制符2……",输出参数1,输出参数2,…);

uint32_t templ=5,uint32 t temp2= 10;
printf("%d%x \r\n", templ,temp2);

(4)printf("非输出控制符 输出控制符 非输出控制符",输出参数);

uint32_t temp= 10;
printf("temp= %d 收到over\r\n", temp);

三、GPIO

3.1 硬件

通用输入输出端口,用于采集外部器件信息或控制外部器件工作(输入输出)

STM32工作电压范围:2~3.6V;GPIO识别电压范围:CMOS(VIL -0.3-1.164V逻辑0 VIH1.833-3.6 逻辑1), TTL(FT 兼容5V);GPIO输出电流:单个IO最大25mA

具备快速翻转特性,每次翻转最快只需两个时钟周期(103默认频率72MHz,最快即36MHz)
每个IO口均可用于中断;
支持8中工作模式。

8种工作模式:
1. 输入浮空:输入用,完全浮空,状态不定(空闲IO状态不定);
2. 输入上拉(Pull->GPIO_PULL):输入用,内部上拉,默认是高电平(空闲IO高电平);
3. 输入下拉:输入用,用内部下拉,默认是低电平(空闲IO低电平);
4. 模拟功能:ADC、DAC(专门用于模拟信号输入输出)
5. 开漏输出:软件的IIC的SDC、SCL等(输出0时外部输出0,不能输出高电平,须外部或内部有上来才能输出高电平-F4内部具有上拉无需外部);
6. 推挽输出:驱动能力强,25mA(max)(可输出高低电平,驱动能力强);
7. 开漏式复用功能:片上外设功能(硬件IIC的SDL、SCL)(不用寄存器控制,由片上外设控制,对于F1同样需要外部上拉输出高电平)
8. 推挽式复用功能(Mode->GPIO_MODE_AF_PP):片上外设功能(SPI的SCK、MISO、MOSI引脚)(片上外设控制,可输出高低电平)

3.2 通用外设驱动模型

四步法:
1. 初始化
(1)时钟设置:选择时钟源,开启时钟源,
(2)参数设置:选择八种模式之一
使用函数:
(3)IO设置
(4)中断设置(开中断、设NVIC)
2. 读函数:从外设读取数据
3. 写函数:往外设写入数据
4. 中断服务函数:根据中断标志,处理外设各种中断事务

常用函数:
用于开启GPIO时钟:__HAL_RCC_GPIOx_CLK_ENABLE() 
用于初始化GPIO:HAL_GPIO_Init()
用于控制IO输出高低电平:HAL_GPIO_WritenPin()
每次调用IO翻转一次:HAL_GPIO_TogglePin()
读取IO电平:HAL_GPIO_ReadPin()

3.3 例程

1. 控制LED灯
对于一个压降为1.83v的led电路,led正端电压3.3V,串联电阻510欧,电流为(3.3-1.83)/510=2.88ma。
8种模式中共4个可以用于输出控制,由于仅简单控制led,无需引入外部,故选择开漏或者推挽。推挽驱动能力强25ma,可以输出高低电平,故可以选择推挽。而开漏输入对于F1没有外部电路无法上拉高电平,但可为高阻态,仍可实现两边高电平。
(1)创建板机驱动文件
在Driver/BSP下创建驱动文件夹LED,添加驱动文件夹,并双击文件夹将新增的led.c文件增加至文文件夹中。

(2)创建驱动文件

led.h
#ifndef __LED_H
#define __LED_H

#include "./SYSTEM/sys/sys.h"
void led_init(void);    //放入头文件,方便调用
#endif

led.c
#include "./BSP/LED/led.h"
void led_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;          //定义GPIO初始化结构体
    
    __HAL_RCC_GPIOF_CLK_ENABLE();               //开启GPIOF时钟
    
    gpio_init_struct.Pin=GPIO_PIN_9;            //选择led角5
    gpio_init_struct.Mode=GPIO_MODE_OUTPUT_PP;  //选择推挽模式
    gpio_init_struct.Speed=GPIO_SPEED_FREQ_LOW; //设置低速
    
    HAL_GPIO_Init(GPIOF, &gpio_init_struct);
    
    HAL_GPIO_WritePin(GPIOF, GPIO_PIN_9, GPIO_PIN_SET);             //设定GPIOF第9个引脚初始输出高电平,即灯灭
    
}

创建主函数

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"      
int main(void)
{
    HAL_Init();                                 /* 初始化HAL库 */
    sys_stm32_clock_init(336, 8, 2, 7);         /* 设置时钟,168Mhz */
    delay_init(168);                            /* 延时初始化 */
    led_init();                                 /* 初始化LED */

    while(1)
    {
        HAL_GPIO_WritePin(GPIOF, GPIO_PIN_9, GPIO_PIN_SET); //灯灭
        delay_ms(1000);
        HAL_GPIO_WritePin(GPIOF, GPIO_PIN_9, GPIO_PIN_RESET);  //灯亮
        delay_ms(1000);
        
    }
 

2. 按键控制LED
读取按键转态,可从浮空、上拉、下拉和模拟输入输出选择,开关只有0和1两种状态,从前三种选即可。对于如下图按键电路,开关按下时接地为低电平,断开时为使其为高电平,故需选择上拉模式。由于浮空状态不确定有可能高有可能低,故选择输入上拉模式。

较流水灯,我们增加按键的定义和初始化,以及按键按下的读取:

#define KEY_PORT0 GPIO_PIN_4 //定义按键引脚

void key_init(void)    //按键初始化
{
    GPIO_InitTypeDef gpio_init_struct;          //定义GPIO初始化结构体
    
    __HAL_RCC_GPIOE_CLK_ENABLE();               //开启GPIOE时钟
    
    gpio_init_struct.Mode=GPIO_MODE_INPUT;  //选择输入模式
    gpio_init_struct.Pull=GPIO_PULLUP;      //选择输入上拉
    gpio_init_struct.Pin=KEY_PORT0;
    HAL_GPIO_Init(GPIOE, &gpio_init_struct);
}

uint8_t key_scan(void)    //按键读取函数
{
    if(HAL_GPIO_ReadPin(GPIOE, KEY_PORT0) ==0 )
    {
        delay_ms(10);   //消抖
        if(HAL_GPIO_ReadPin(GPIOE, KEY_PORT0) ==0)
        {
            while(HAL_GPIO_ReadPin(GPIOE, KEY_PORT0) ==0); //若处于按下状态则一直等待
            return 1;   //按键按下
        }
    }
    return 0;   //按键没有按下
}

int main(void)
{
    HAL_Init();                                 /* 初始化HAL库 */
    sys_stm32_clock_init(336, 8, 2, 7);         /* 设置时钟,168Mhz */
    delay_init(168);                            /* 延时初始化 */
    led_init();                                 /* 初始化LED */
    key_init();
    while(1)
    {
        if (key_scan())
        {
            HAL_GPIO_TogglePin(GPIOF, LED_PORT0);
            HAL_GPIO_TogglePin(GPIOF, LED_PORT1);
        }
        else
        {
            delay_ms(10);
        }
    }
}

四、中断

4.1. 什么是中断

打断CPU执行正常的程序,转而处理紧急程序,然后返回原暂停程序继续执行。
中断意义:高效处理紧急程序,不会一直占用CPU资源。
中断简图:GPIO(上拉输入、下拉输入、浮空输入)->AFIO(F1)/SYSCFG(F4/F7)->EXTI(屏蔽,上升/下降沿)->NVIC(使能、优先级控制)->CPU(处理中断)

4.2. NVIC

NVIC基本概念:嵌套向量中断控制器,属于内核(M3/4/7),支持256个中断(16内核+240外部),支持256个优先级,允许裁剪(ST公司裁剪到16个优先级)。
NVIC工作原理:对于外部中断,首先经过ISER/ICER即使能/失能控制器决定是否通过->经过IPR进行优先级排序->送入CPU;对于内部中断,不经过ISER或ICER直接送入SHPR()与IPR同级,进行优先级比对->送入CPU;
基本概念:
(1)抢占优先级(pre):高优先级可以打断正在执行的低优先级中断;
(2)响应优先级(sub):抢占优先级相同时,响应优先级高的先执行,但是不能互相打断;
(3)抢占和响应都相同的情况,自然优先级越高,先执行;
(4)自然优先级:中断向量表的优先级;
(5)数值越小,优先级越高
STM32中断优先级分组:0(0位抢占优先级,4为响应优先级-16个),1(1位抢占优先级-2个,3为响应优先级-8个),2(2位抢占优先级-4个,2为响应优先级-4个),3(3位抢占优先级-8个,1为响应优先级-2个),4(4位抢占优先级-16个,0位响应优先级0个)
一个工程中,一般只设置一次中断优先级分组

NVIC的使用:
(1)设置中断分组:使用函数 HAL_NVIC_SetPriorityGrouping  (正点原子HAL_Init默认分组为2)
(2)设置中断优先级:使用函数HAL_NVIC_SetPriority
(3)使能中断:使用函数HAL_NVIC_EnableIRQ

4.3. EXTI

基本概念:外部中断事件控制器,包含20个产生事件/中断请求的边沿检测器,总共20条EXTI线(F1);
中断:要进入NVIC,有相应的中断服务函数,需要CPU处理
事件:不进入NVIC,仅用于内部硬件自动控制,如:TIM、DMA、ADC
EXTI线0~15:对应GPIO PIN0~15;
EXTI线16:PVD输出;
EXTI线17:RTC闹钟事件;
EXTI线18:USB OTG HS唤醒事件(能够在系统处于停止或者CPU出于CStop模式时生成唤醒事件的外设)
主要特性:每条EXTI线都可以单独配置,选择类型(中断或事件)、触发方式(上升沿、下降沿或者双边沿)、支持软件触发、开启/屏蔽、有挂起状态位
工作原理:对于外部输入,输入进来->边沿检测电路(根据上升沿/下降沿寄存器的配置,判断输入是否满足,如上升为1下降为0,则上升沿可以通过,如果都为0则始终不通过)->或门(选择软件触发或者硬件触发)->请求挂起寄存器->与门(另一测:中断屏蔽寄存器)

4.4. EXTI和IO映射关系

AFIO(F1):复用功能IO,用于重映射和外部中断映射配置
(1)调试IO配置
(2)重映射IO配置
(3)外部中断配置:配置EXTI中断线0-15对应到哪个具体IO口;
配置AFIO寄存器之前要使能AFIO时钟,使用函数__HAL_RCC_AFIO_CLK_ENABLE(); 
SYSCFG(F4/F7):系统配置控制器,用于外部中断映射配置,使用函数__HAL_RCC_SYSCFG_CLK_ENABLE(); 使能;
EXTI与IO的对应关系:
(1)EXTI0即控制Px0(0为A~K),由EXTI0[3:0]位控制决定(F1),一个时间只能连接一个;对于F4灯使用SYSCFG_EXTICER1的位控制;

4.5. 如何使用中断

设置输入模式(GPIO)->设置EXTI和IO映射关系(AFIO或SYSCFG)->EXTI(上升沿等)->NVIC(中断分组、优先级、使能)->CPU;
外设中断(USART/TIM/SPI)->NVIC->CPU
GPIO外部中断配置步骤:
(1)使能GPIO时钟;
(2)设置GPIO输入模式;(上下拉,浮空)
(3)使能AFIO/SYSCFG时钟;
(4)设置EXTI和IO对应关系;
(5)设置EXTI屏蔽,上下沿;
(6)设置NVIC:设置优先级分组、设置优先级、使能中断;
(7)设计中断服务函数:编写对应中断服务函数,清中断标志
使用HAL库,步骤2-5使用HAL_GPIO_Init一步到位

STM32 HAL库设置步骤(GPIO外部中断)
(1)使能GPIO时钟,使用__HAL_RCC_GPIOx_CLK_ENABLE
(2)GPIO/AFIO(SYSCFG)/EXTI,使用HAL_GPIO_Init
(3)设置中断分组:HAL_NVIC_SetPriorityGrouping,此函数只设置一次
(4)设置中断优先级:HAL_NVIC_SetPriority
(5)使能中断:HAL_NVIC_EnableIRQ
(6)设计中断服务函数:EXTIx_IRQHandle,中断服务函数,设置中断标志

通用外设驱动模型(四步法):
(1)初始化:时钟设置、参数设置、IO设置、中断设置值(开中断、设NVIC)(可选)
(2)读函数(可选):从外设读取数据
(3)写函数(可选):往外设写入数据
(4)中断服务函数(可选):根据中断标志,处理各种中断事务

4.6. 例程(外部中断控制一个灯亮灭)


选择KEY0作为LED灯中断控制,按下为低电平,不按下上拉为高电平,选择下降沿触发

/* 定义 exti.h 头文件 */
#ifndef __EXTI_H
#define __EXTI_H
#include "./SYSTEM/sys/sys.h"
#define EXTI_PORT GPIO_PIN_4
void exti_init(void);
#endif

/* 定义 exti.c */ 文件
#include "./BSP/EXTI/exti.h"
#include "./BSP/LED/led.h"
#include "./SYSTEM/delay/delay.h"
/* 中断初始化函数*/
void exti_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;          //定义GPIO初始化结构体
    
    __HAL_RCC_GPIOE_CLK_ENABLE();               //开启GPIOF时钟
    
    gpio_init_struct.Pin=EXTI_PORT;            //选择led角9
    gpio_init_struct.Mode=GPIO_MODE_IT_FALLING;  //选择中断_下降沿触发
    gpio_init_struct.Pull=GPIO_PULLUP;          //设置上拉
    HAL_GPIO_Init(GPIOE, &gpio_init_struct);
    
    /* 优先组已设为2故不必再设*/
    HAL_NVIC_SetPriority(EXTI4_IRQn, 2, 0);     /* 设定中断优先级,其中PIN为4故选择EXTI4,设定抢占优先级为2,响应优先级为0 */
    HAL_NVIC_EnableIRQ(EXTI4_IRQn);
}
/* 中断服务函数 */
void EXTI4_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(EXTI_PORT); /*公共处理函数,当中断发生时调用此函数,此函数再调用回调函数*/
}
/* 中断回调函数 无需在头文件申明,已在内部申明*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    delay_ms(20); //消抖
    if(GPIO_Pin == EXTI_PORT)       //如果是设定的端口触发则执行
    {
        if(HAL_GPIO_ReadPin(GPIOE, EXTI_PORT) == 0)
        {
            HAL_GPIO_TogglePin(GPIOF, LED_PORT0);
        }
    }
}

五. 串口通信

5.1. 数据通信的基础概念

(1)串行/并行通信
串行:数据逐位按顺序依次传输,传输速率低,抗干扰能力强,通信距离较长,成本低
并行:数据各位通过多条线同时传输,传输速率较高,抗干扰能力较弱,通信距离较短,成本较高
单工:数据只能沿一个方向传输;
半双工:信道只有一个,数据可以沿两个方向传输,但需要分时;
全双工:信道有两条,数据可以同时进行双向传输。
同步通信:存在同步时钟,共用同一时钟信号,在同步时钟基础上进行通信;
异步通信:包含起始位、数据位、数据校验位和停止位,即没有时钟信号,加入一些同步信号。
比特率:每秒钟传送的比特数,单位bit/s;
波特率:每秒钟传送的码元数,单位Baud(如9编码11,上升沿编码1等)
比特率=波特率*log2M,M表示每个码元承载的信息量(二进制则为2,四进制位4)
二进制系统,波特率数值上等于比特率(市场上都为二进制设备,故一般二者数值相等)

(2)串行通信接口
UART:存在TXD发送端、RXD接受端、GND公共地,属于异步通信,全双工;
1-wire:一根数据线(发送/接收),异步通信,半双工;
IIC:包括SCL同步时钟、SDA数据输入/输出,属于同步通信,半双工;
SPI:包括SCK同步时钟、MISO主机输入从机输出、MOSI主机输出从机输入、CS片选信号,同步通信,全双工。

5.2. 串口(RS232)

定义:按位发送和接收的接口,如RS232/422/485等;
RS232(DB9):包括TXD(pin3)串口数据输出,RXD(pin2)串口数据输入、地线(pin5)信号地;
RS232电平:逻辑1:-15V~-3V,逻辑0:+3V~+15V;(STM32 CMOS电平,逻辑1 3.3V,逻辑0 0V)(51单片机 TTL 逻辑1 5V,逻辑0 0V)
CMOS/TTL电平不能与RS-232电平直接交换信息
(1)通信示意图(电平转换芯片,可以用MAX3232或SP3232等)

两个设备之间的TXD和RXD,必需交差连接,方可正常通信
(2)STM32串口与电脑USB口通信示意图

一帧数据的内容:启动位(占一个位长,保持逻辑0电平),有效数据位(可选5/6/7/8/9个位畅,LSB最低有效位位0在前,MSB最高有效位在后),校验位(可选占1个位长,也可以没有该位),停止位(必需有,可选占0.5/1/2个位畅,保持逻辑1电平)

5.3. STM32的USART简介

USART通用同步异步收发器,UART通用异步收发器;
USART和UART均可以与外部设备进行全双工异步通信;
串口数据接收过程:外部设备->串行数据输入(RXD引脚)->接收移动位寄存器->接收数据寄存器(RDR)->数据寄存器(DR)->CPU(F1/F4)
发送过程:CPU->数据寄存器(DR)->发送数据寄存器(TDR)->发送移位寄存器->TXD(串行数据输出)->外部设备;
设置波特率:波特率计算公式baud=fck(串口时钟, USART1为PCLK2 72M, 其它串口PCLK1 36M )/(16*USARTDIV分频),如:波特率设为115200,带入公式可得USARTDIV=39.0625

5.4. HAL库

HAL_PPP_Init()->用于初始化PPP外设的工作参数(GPIO/NVIC/CLOCK等)
如:USART,HAL_UART_Init()->调用MSP函数HAL_UART_Msp_Init()
HAL中断回调 HAL_PPP_IRQHandle()->调用一系列中断回调函数HAL_PPP_xxxCallback() (根据回调函数类型,编写对应的中断处理程序,用户可以选择是否重新定义该函数)

5.5. USART/UART异步通信配置步骤

(1)配置串口工作参数:HAL_UART_Init()
(2)串口底层初始化:HAL_UART_MspInit()
(3)开启串口异步接收中断:HAL_UART_Recive_IT()
(4)设置优先级,使能中断:HAL_NVIC_EnableIRQ()
(5)编写中断服务函数:USARTx_IRQHandle()、UARTx_IRQHandle()
(6)串口数据发送:USART_DR、HAL_UART_Transmit()
函数:HAL_UART_Init,可以设置波特率、字长、停止位、奇偶校验位、UART模式、硬件流设置、过采样设置;
函数:HAL_UART_Recive_IT(UART_HandleTypeDef*huart, uint8_t *pData, uint16_t Size),以中断的方式接收指定字节的数据,形参1是结构体类型指针变量、形参2是指向接收数据缓冲区、形参3是要接收的数据大小(以字节为单位)
函数:USART_DR、HAL_UART_Transmit(UART_HandleTypeDef*huart, uint8_t *pData, uint16_t Size, uint32_t Timeout),以阻塞的方式发送指定字节数据,形参1结构体指针变量、形参2指向要发送的数据地址、形参3要发送的数据大小、形参4设置的超时时间(以ms为单位)

5.6. IO引脚复用功能

通用:IO端口的输入或输出由GPIO外设控制;
复用:IO端口的输入或输出是由其它非GPIO外设控制;
IO复用冲突:同一时间IO只能用作一种复用功能,可考虑重映射功能(对于F4往后每个IO均有一个复用器。采用16路复用功能输入,复用器一次仅允许一个外设的复用功能连接至引脚,通过GPIOx_AFRL和GAIOx_AHRH寄存器配置,复位完成后,所有IO都会连接到系统的复用功能0)

5.7. 编程实验
/* main文件 */
usart_init(115200);                         /* 初始化串口 */
    while(1)
    {
        if(g_usart1_rx_flag==1)
        {
            HAL_UART_Transmit(&g_uart1_handle, (uint8_t *)g_rx_buffer,1 ,1000); /*发送,其中1000是超时*/
            while(__HAL_UART_GET_FLAG(&g_uart1_handle, UART_FLAG_TC) != 1);     /*若未发送完,即标志位不为1,则一直等待*/
            printf("\r\n\r\n");             /* 插入换行 */
            g_usart1_rx_flag=0;
        }
        else
        {
            delay_ms(10);                       /*若未收到,延时10ms*/
        }
    }
}

/* usart.h文件文件 */
extern UART_HandleTypeDef g_uart1_handle;       /* UART句柄 */
extern uint8_t g_rx_buffer[1];                  /* 接收数据缓冲区 发送接收1个字符*/
extern uint8_t g_usart1_rx_flag;                   /*串口接收到数据标志*/

/* usart.c文件 */
 /* 串口1初始化*/
 uint8_t g_rx_buffer[1];                  /* 接收数据缓冲区 发送接收1个字符*/
 uint8_t g_usart1_rx_flag=0;                   /*串口接收到数据标志*/
 UART_HandleTypeDef g_uart1_handle;                  /* UART句柄 */
void usart_init(uint32_t baudrate)
{
    g_uart1_handle.Instance = USART1;                           /* 使用串口1 USART1 */
    g_uart1_handle.Init.BaudRate = baudrate;                    /* 波特率 由初始化函数输入给定*/
    g_uart1_handle.Init.WordLength = UART_WORDLENGTH_8B;        /* 字长为8位数据格式 */
    g_uart1_handle.Init.StopBits = UART_STOPBITS_1;             /* 一个停止位 */
    g_uart1_handle.Init.Parity = UART_PARITY_NONE;              /* 无奇偶校验位 */
    g_uart1_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;        /* 无硬件流控 */
    g_uart1_handle.Init.Mode = UART_MODE_TX_RX;                 /* 收发模式 */
    HAL_UART_Init(&g_uart1_handle);                             /* 使能UART1 */
    
    /* 开启串口异步接收中断,形参1是句柄,形参2是接收数据缓冲区,形参3要接收的数据大小(以字节为单位)*/
    HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, 1);
}


/*串口底层初始化*/
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
    GPIO_InitTypeDef gpio_init_struct;                          /*定义初始化结构体变量*/
    if(huart->Instance == USART_UX)                             /* 如果是串口1,进行串口1 MSP初始化 */
    {
        USART_UX_CLK_ENABLE();                                  /* USART1 时钟使能 */
        USART_TX_GPIO_CLK_ENABLE();                             /* 发送引脚时钟使能 */
        USART_RX_GPIO_CLK_ENABLE();                             /* 接收引脚时钟使能 */

        gpio_init_struct.Pin = USART_TX_GPIO_PIN;               /* TX引脚 */
        gpio_init_struct.Mode = GPIO_MODE_AF_PP;                /* 复用推挽 */
        gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */
        gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* 高速 */
        gpio_init_struct.Alternate = USART_TX_GPIO_AF;          /* 复用为USART1 */
        HAL_GPIO_Init(USART_TX_GPIO_PORT, &gpio_init_struct);   /* 初始化发送引脚 */

        gpio_init_struct.Pin = USART_RX_GPIO_PIN;               /* RX引脚 */
        gpio_init_struct.Alternate = USART_RX_GPIO_AF;          /* 复用为USART1 */
        HAL_GPIO_Init(USART_RX_GPIO_PORT, &gpio_init_struct);   /* 初始化接收引脚 */

#if USART_EN_RX
        HAL_NVIC_EnableIRQ(USART_UX_IRQn);                      /* 使能USART1中断通道 */
        HAL_NVIC_SetPriority(USART_UX_IRQn, 3, 3);              /* 抢占优先级3,子优先级3 */
#endif
    }
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    g_usart1_rx_flag=1;         /*查询此变量即可知道已接收数据*/
}
void USART_UX_IRQHandler(void)
{ 

    HAL_UART_IRQHandler(&g_uart1_handle);       /* 调用HAL库中断处理公用函数 */
    HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, 1); /*调用完后会失能,故再次调用*/

}

六、独立看门狗

6.1. IWDG简介

IWDG, Independent watchdog, 独立看门狗
IWDG的本质,能产生系统复位信号的计数器
IWDG的特性,递减的计数器,时钟由独立的RC振荡器提供(可在待机和停机模式下运行),看门狗激活后,当递减计数器计数到0x000时产生复位
喂狗,计数器计数到0之前,重装在计数器的值,防止复位

6.2. STM32系统的复位

(1)NRST引脚的低电平(外部复位);
(2)窗口看门狗计数终止(WWDG复位);
(3)独立看门狗计数终止(IWDG复位);
(4)软件复位(SW复位);
(5)低功耗管理复位

6.3. IWDG的作用

(1)异常:外界电磁干扰或者自身系统(硬件或软件)异常造成程序跑飞(陷入某个死循环)
(2)作用:检测外界电磁干扰或硬件异常导致的程序跑飞问题
(3)应用:在一些高稳定性的产品中,并且对时间精度要求较低的场合
独立看门狗是异常处理的最后手段,不可依赖,应在设计时尽量避免异常的发生!
CPU必须及时喂狗,否则系统复位重启!

6.4. IWDG工作原理

(1)启用IWDG后,LSI时钟会自动开启;
(2)LSI时钟频率并不精确,F1用40KHz,F4/F7/H7用32kHz进行计算;
(3)键寄存器(key):写入0xAAAA进行喂狗,写入0x5555解除PR和PLR寄存器的访问保护,写入0xCCCC启动看门狗工作;
(4)预分频寄存器(IWDG_PR):设置000预分频=4,001=8,010=16,011=32,100=64,101=128,110=256,111=256;
(5)重装载计数器(IWDG_RLR):寄存器写入0xAAAA时,重装载值会被传送至计数器中;
(6)IWDG溢出事件计算:Tout=(psc*rlr)/fiwdg,其中Tout是溢出时间, fiwdg是看门狗的时钟源频率, psc是看门狗预分频系数,rlr是看门狗重装载值;
(7)IWDG最短最长超时时间:F1(40kHz):分频系数设置为4,最短时间0.1ms,分频系数设置为256,最长分频时间26214.4ms;F4(32kHz):最短时间0.125ms,最长时间32768ms。

6.5. IWDG配置步骤

(1)取消PR/RLR寄存器写保护,设置IWDG预分频系数和重装载值,启动IWDG。使用HAL_IWDG_Init(),使能IWDG,设置预分频系数和重转载值;
(2)及时喂狗,写入0xAAAA到IWDG_KR。使用HAL_IWDG_Refresh(),把重装载寄存器的值重载到计数器中,喂狗

6.6. 实验不及时喂狗,系统将复位

设计程序实现:系统初始化后,串口打印“您还没有喂狗,请及时喂狗!!!\r\n”,初始化IWDG的溢出时间为1s,判断1s内是否喂狗?若未喂狗则系统复位,喂狗则串口打印:已经喂狗\r\n”


原文地址:https://blog.csdn.net/qq_35379989/article/details/143721989

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!