您现在的位置是:首页 >技术交流 >5。STM32裸机开发(4)网站首页技术交流

5。STM32裸机开发(4)

西伯利亚大草原的狼 2024-06-18 08:04:32
简介5。STM32裸机开发(4)

嵌入式软件开发学习过程记录,本部分结合本人的学习经验撰写,系统描述各类基础例程的程序撰写逻辑。构建裸机开发的思维,为RTOS做铺垫(本部分基于库函数版实现),如有不足之处,敬请批评指正。 

(4)中主要讲解串口配置,看门狗配置(独立看门狗、窗口看门狗)

一 USART串口通讯

一些基本的概念在此不再赘述,读者可以自行查阅,即:

串行通信与并行通信

异步通信与同步通信

通信速率:比特率 bitrate

在此解释一下单工、半双工(485、IIC)与全双工(232、SPI)

单工是指数据传输仅能沿一个方向,不能实现反向传输
半双工是指数据传输可以沿两个方向,但需要分时进行(同一时间只能单向传输)(长距离)
全双工是指数据可以同时进行双向传输(短距离)

接口标准串口通信的接口标准有很多,有 RS-232C、RS-232、RS-422A、RS-485 等。 常用的就是 RS-232 和 RS-485。以RS-232为例,在串口通信中,只使用3个管脚,即TXD、RXD、SGND。

RS232 的通信协议比较简单,通常遵循 96-N-8-1 格式。即波特率9600、无校验位、8位数据位、1位停止位。

RS-232C 对逻辑电平也做了规定,如下
在 TXD 和 RXD 数据线上:
1.逻辑 1 为-3~-15V 的电压
2.逻辑 0 为 3~15V 的电压
在 RTS、CTS、DSR、DTR 和 DCD 等控制线上:
1.信号有效(ON 状态)为 3~15V 的电压
2.信号无效(OFF 状态)为-3~-15V 的电压
        由此可见,RS-232C 是用正负电压来表示逻辑状态,与晶体管-晶体管逻辑集成电路(
TTL)以高低电平表示逻辑状态的规定正好相反。而我们 STM32 芯片使用的就是 TTL 电平,所以要实现 STM32 与计算机的串口通信,需要进行 TTL与 RS-232C 电平转换,通常使用的电平转换芯片是 MAX3232
STM32F103ZET6 芯片含有 3 个 USART,2 个 UART 外设
        USART 即通用同步异步收发器,它能够灵活地与外部设备进行全双工数据交换,满足外部设备对工业标准 NRZ 异步串行数据格式的要求。
        UART 即通用异步收发器,它是在 USART 基础上裁剪掉了同步通信功能,同步和异步主要看其时钟是否需要对外提供,这个前面也介绍了,我们平时使用的串口通信基本上都是 UART。

标号1.功能引脚

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

标号2.数据寄存器 

        USART_DR 实际是包含了两个寄存器,一个专门用于发送的可写 TDR,一个专门用于接收的可读 RDR。当进行发送操作时,往 USART_DR 写入数据会自动存储在 TDR 内;当进行读取操作时,向USART_DR 读取数据会自动提取 RDR 数据。

标号3.控制器

        USART 有专门控制发送的发送器、控制接收的接收器,还有唤醒单元、中断控制等等。使用 USART 之前需要向 USART_CR1 寄存器的 UE 位置 1 使能USART。发送或者接收数据字长可选 8 位或 9 位,由 USART_CR1 的 M 位控制。具体参考(STM32F10x参考手册)
标号 4:小数波特率生成
        波特率的概念在前面介绍比特率的时候已经提过,常用的串口通信中都把波特率当作比特率。波特率越大,传输速度就越快。
USART 串口通信配置步骤
(USART 相关库函数在 stm32f10x_usart.c 和 stm32f10x_usart.h 文件 中)
(1)使能串口时钟及 GPIO 端口时钟(老规矩了)
        STM32F103ZET6 芯片具有 5 个串口,对应不同的引脚,串口 1 挂接 在 APB2 总线上,串口 2-串口 5 挂接在 APB1 总线上,根据自己所用串口使能总线时钟和端口时钟。例如使用 USART1,其挂接在 APB2 总线上,并且 USART1 对 应 STM32F103ZET6 芯片管脚的 PA9 和 PA10(看原理图),因此使能时钟函数如下:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能 GPIOA 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);// 使能 USART1 时钟
(2)GPIO 端口模式设置,设置串口对应的引脚为复用功能
        因为使用引脚的串口功能,所以在配置 GPIO 时要将设置为 复用功能,这里 把串口的 Tx 引脚配置为复用推挽输出, Rx 引脚为浮空输入,数据完全由外部输入决定。如下:
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX //串口输出 PA9
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化串口输入 IO */
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX // 串口输入 PA10
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; // 模拟输入
GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化 GPIO */
(3)初始化串口参数,包含波特率、字长、奇偶校验等参数
        要使用串口功能,必须对串口通信相关参数初始化,其库函数如下:
        第一个参数用于选择串口,第二个参数为结构体变量
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
typedef struct
{
        uint32_t USART_BaudRate; //波特率
        uint16_t USART_WordLength; //字长
        uint16_t USART_StopBits; //停止位
        uint16_t USART_Parity; //校验位
        uint16_t USART_Mode; //USART 模式
        uint16_t USART_HardwareFlowControl; //硬件流控制
} USART_InitTypeDef;
成员变量介绍:
USART_BaudRate:波特率设置。常用的波特率为 4800、9600、115200 等。
标准库函数会根据设定值计算得到 USARTDIV 值 , 并设置USART_BRR 寄存器值。
USART_WordLength:数据帧字长。可以选择为 8 位或者 9 位,通过 USART_CR1
寄存器的 M 位的值决定。如果没有使能奇偶校验控制,一般使用 8 数据位;如果使能了奇偶校验则一般设置为 9 数据位。
USART_StopBits:停止位设置。可选 0.5 个、 1 个、 1.5 个和 2 个停止位,它设定 USART_CR2 寄存器的 STOP[1:0]位的值,一般我们选择 1 个停止位。
USART_Parity:奇偶校验控制选择。可选 USART_Parity_No( 无 校 验 ) 、 USART_Parity_Even( 偶 校 验 ) 以 及 USART_Parity_Odd( 奇 校 验 ) ,它设定 USART_CR1 寄存器的 PCE 位和 PS 位的值。
USART_Mode:USART 模式选择。可以为 USART_Mode_Rx 和 USART_Mode_Tx,
允许使用逻辑或运算选择两个,它设定 USART_CR1 寄存器的 RE 位和 TE 位。
USART_HardwareFlowControl:硬件流控制选择。只有在硬件流控制模式才有效,可以选 择无硬件流 USART_HardwareFlowControl_None 、RTS控制USART_HardwareFlowControl_RTS、CTS 控制 USART_HardwareFlowControl_CTS、
RTS 和 CTS 控制 USART_HardwareFlowControl_RTS_CTS。
(4)使能串口
        配置好串口后,我们还需要使能它,使能串口库函数如下:
void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);
USART_Cmd(USART1, ENABLE); //使能串口 1
(5)设置串口中断类型并使能
        对串口中断类型和使能设置的函数如下:
        第一个参数用来选择串口,第二个参数用来选择串口中断类型,第三个参数用来使能或者失能对应中断。
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);
        由于串口中断类型比较多,所以使用哪种中断,需要独立对它进行配置。比如在接收到数据的时候( RXNE 读数据寄存器非空)
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启接收中断
又比如发送完数据时,要产生中断,可以配置如下:
USART_ITConfig(USART1,USART_IT_TC, ENABLE);
对应的串口中断类型可在 stm32f10x_usart.h 中查找到,如下:
#define USART_IT_PE                ((uint16_t)0x0028)
#define USART_IT_TXE              ((uint16_t)0x0727)
#define USART_IT_TC                ((uint16_t)0x0626)
#define USART_IT_RXNE           ((uint16_t)0x0525)
#define USART_IT_IDLE             ((uint16_t)0x0424)
#define USART_IT_LBD              ((uint16_t)0x0846)
#define USART_IT_CTS              ((uint16_t)0x096A)
#define USART_IT_ERR              ((uint16_t)0x0060)
#define USART_IT_ORE              ((uint16_t)0x0360)
#define USART_IT_NE                ((uint16_t)0x0260)
#define USART_IT_FE                 ((uint16_t)0x0160)
(6)设置串口中断优先级,使能串口中断通道(即NVIC那一套)
        对 NVIC 初始化,NVIC 初始化库函数是 NVIC_Init(),这个在前面讲解 STM32 中断时就已
经介绍过,不清楚的可以回过头看下。
(7)编写串口中断服务的功能函数(串口接收数据-判断数据-触发中断)

         编写一个串口中断服务函数,通过中断函数处理串口产生的相关中断。串口中断服务函数名在 STM32F1 启动文件内就有,USART1 中断函数名如下:

USART1_IRQHandler

        库函数中用来读取串口中断状态标志位的函数如下:因为串口的中断类型有很多,所以进入中断后,我们需要在中断服务函数开头处通过状态寄存器的值判断此次中断是哪种类型,然后做出相应的控制。
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);
         库函数中还有一个函数用来读取串口状态标志位:USART_GetITStatus 与 USART_GetFlagStatus 功 能 类 似 , 区别就是 USART_GetITStatus 函数会先判断是否使能串口中断,使能后才读取状态标志,而 USART_GetFlagStatus 函数直接读取状态标志
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
清除中断标志位的函数
void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);
#include "usart.h"


void USART1_Init(u32 bound)//USART_Init是一个已经被定义的库函数,所以初始化函数写为USART1_Init
{
    //(1)定义各种结构体变量
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	//初始化串口参数,包含波特率、字长、奇偶校验(解决干扰)等参数————USART串口
	NVIC_InitTypeDef NVIC_InitStructure;
	//设置串口中断优先级,使能串口中断通道————中断
	
	//(2)使能串口时钟及GPIO端口时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能 GPIOA时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能 USART1时钟————USART串口
	
	//(3)GPI0端口模式设置,设置串口对应的GPIO引脚为复用功能
	//配置输出引脚
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;; //原理图上GPIOA的输出引脚TX
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;	 //设置复用推挽输出模式——不是主要功能
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;	  //设置传输速率
	GPIO_Init(GPIOA,&GPIO_InitStructure); 	   /* 初始化GPIO */
	
	//配置接收引脚
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;  //原理图上GPIOA的接收引脚RX
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;	 //设置浮空输入模式
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;	  //设置传输速率
	GPIO_Init(GPIOA,&GPIO_InitStructure); 	   /* 初始化GPIO */
	
	//(4)USART1-串口部分的初始化设置
	USART_InitStructure.USART_BaudRate = bound;//波特率设置4800、9600、15200
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//全双工收发模式
	USART_Init(USART1, &USART_InitStructure); //初始化串口1
	
    //(5)使能串口
	USART_Cmd(USART1, ENABLE);  //使能串口1 
	
	USART_ClearFlag(USART1, USART_FLAG_TC);//清除状态标志
	
	//(6)设置串口中断类型并使能
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启接收非空中断
	
	//(7)由于涉及到了中断,配置NVIC中断优先级
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	
}
	
//(8)编写串口中断服务函数
void USART1_IRQHandler(void) //串口1中断服务程序,函数名定好的不能随便写
//因为串口的中断类型有很多,所以进入中断后,我们需要在中断服务函数开头处通过状态寄存器的值判断此次中断是哪种类型,然后做出相应的控制。
{
	u8 r;
	//把r设置为一个数组,就可以连续存储数据
	// USART_GetITStatus(USART1, USART_IT_RXNE 监测串口,有数据就触发中断
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  
	//读取串口中断状态标志位的函数——>!= RESET不等于0——>产生一个接收中断
	{
		//USART_ReceiveData() 用这个函数,捕获数据
		// 用 r (自定义) 接 这个数据
		r =USART_ReceiveData(USART1);//(USART1->DR);	//读取接收到的数据
		//接到以后 可以进行你想干的事了
		//USART_SendData 串口发送函数 向串口1 发送数据
		USART_SendData(USART1,r);//发送数据
		while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET);
		//发送完成的标志USART_FLAG_TC置1时,则发送完成,所以设不等于1时则跳出循环
	} 
	USART_ClearFlag(USART1,USART_FLAG_TC);//清除状态标志
} 	

二 printf重定向

借助串口,实现原本打印在PC端的printf函数转为将信息打印在串口调试助手上

        要实现这一功能,必须重定义标准库函数里调用的与输出设备相关的函数。比如使用 printf 输出到串口,需要将 fputc 里面的输出指向串口,这一过程就叫重定向。 即只需要将 fputc 里面的输
出指向 STM32 串口即可,fputc 函数有固定的格式,我们只需要在函数内操作STM32 串口即可,即在usart,c文件中添加如下代码:
%d              按照十进制整型数打印
%6d            按照十进制整型数打印,至少 6 个字符宽
%f               按照浮点数打印
%6f             按照浮点数打印,至少 6 个字符宽
%.2f            按照浮点数打印,小数点后有 2 位小数
%6.2f          按照浮点数打印,至少 6 个字符宽,小数点后有 2 位小数
%x              按照十六进制打印
%c              打印字符
%s              打印字符串
int fputc (int ch,FILE *p)
{
  USART_SendData(USART1,(u8)ch);	//将输出指向串口
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
	return ch;
}


二 看门狗

        独立看门狗(Independent Watchdog,简称IWDG)和窗口看门狗(Window Watchdog,简称WWDG)都是 MCU 中常用的看门狗,它们的作用都是在系统死机或者程序运行异常的情况下强制复位系统。

        IWDG 是一种基于定时器的看门狗,其特点是独立于 CPU 运行,只要 MCU 上电接通,IWDG 就开始工作,无需软件干预。IWDG 会定期产生一个重装载信号,须在此期限内喂狗,否则 IWDG 将会产生一个复位信号强制复位整个系统。IWDG 适用于那些对可靠性要求较高的实时应用场景中。

        WWDG 是一种基于窗口的看门狗,其特点是需要依赖 CPU 进行初始化并且需要每次在特定时间内刷新或者重置计数器,否则就会产生复位信号强制复位整个系统。与 IWDG 不同的是,WWDG 有一个可调窗口范围,如果未在这个时间范围内进行重置,WWDG 也会产生复位信号。WWDG 更多地应用于那些需要在不同周期中刷新看门狗的应用场景中。

1)独立看门狗(IWDG)

        独立看门狗简单理解其实就是一个 12 位递减计数器,当计数器从某一个值递减到 0 时(如果看门狗已激活),系统就会产生一次复位。如果在计数器递减到 0 之前刷新了计数器值,那么系统就不会产生复位。这个刷新计数器值过程我们称之为“喂狗”。看门狗功能由 VDD 电压域供电,在停止模式和待机模式下仍能工作。
由于 LSI 的时钟频率并不非常精确,所以独立看门狗只适用于对时间精度要求比较低的场合。

IWDG 配置步骤
(IWDG 相关库函数在 stm32f10x_iwdg.c 和 stm32f10x_iwdg.h 文件中)
(1)开启寄存器访问(给 IWDG_KR 寄存器写入 0X5555)(注意这里没有使能时钟)

        首先, IWDG_PR 和 IWDG_RLR 寄存器具有写访问保护。若要修改寄存器,必须首先对IWDG_KR 寄存器写入代码 0x5555,如果写入其他的值将重新开启写保护。在库函数中实现函数如下:这个函数非常简单,里面的参数就是用来使能或失能写访问,即开启或关闭写访问。

(2)设置 IWDG 预分频系数和重装载值(设置复位时间)

        设置 IWDG 预分频系数函数为:

void IWDG_SetPrescaler(uint8_t IWDG_Prescaler); //设置 IWDG 预分频值

        设置 IWDG 重装载值函数为:

void IWDG_SetReload(uint16_t Reload); //设置 IWDG 重装载值

        设置好 IWDG 的分频系数 pre 和重装载值就可以知道独立看门狗的喂狗时间,也就是看门狗溢出时间,该时间的计算公式前面已经介绍,公式如下:

Tout = (4*2^pre) / 40 * rlr

        其中 Tout 为独立看门狗溢出时间,单位是 ms。pre 是预分频器系数(0-6), rlr 是重装载寄存器的值,公式内的 40 是独立看门狗的时钟。这里需要提醒大家的是,看门狗的时钟不是准确的 40Khz,所以在喂狗的时候,最好不要太晚了,否则,有可能发生看门狗复位。

(3)重载计数器值(喂狗)(给 IWDG_KR 寄存器写入 0XAAAA)

重载计数器值(喂狗)库函数是:,此函数功能是将 IWDG_RLR 寄存器内值重新加载到独立看门狗计数器内,实现喂狗操作。

IWDG_ReloadCounter(); //重装载初值

(4)开启 IWDG(给 IWDG_KR 寄存器写入 0XCCCC)

        开启 IWDG 的库函数是:

注意:IWDG 在一旦启用,就不能再被关闭,想要关闭,只能重启,并且重启之后不能打开 IWDG,否则问题依旧存在。所以如果不用 IWDG 的话,就不要去打开它,免得麻烦。

IWDG_Enable(); //打开独立看门狗

#include "iwdg.h"


void IWDG_Init(u8 pre,u16 rlr)//IWDG配置
{
	IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //开启寄存器,取消寄存器写保护
	IWDG_SetPrescaler(pre);//设置预分频系数pre 0-6
	IWDG_SetReload(rlr);//设置重装载值rlr
	IWDG_ReloadCounter();  //重装载初值(喂狗)
	IWDG_Enable(); //打开独立看门狗(使能)
	
}


void IWDG_FeedDog(void)  //喂狗的动作
{
	IWDG_ReloadCounter();  //重装载初值
}

2)窗口看门狗(WWDG)

        窗口看门狗 WWDG 其实和独立看门狗类似,它是一个 7 位递减计数器不断的往下递减计数, 当减到一个固定值 0X40 时还不喂狗的话,产生一个 MCU 复位,这个值叫窗口的下限,是固定的值,不能改变。这个和独立看门狗是类似的,不同的是窗口看门狗的计数器的值在减到某一个数之前喂狗的话也会产生复位,这个值叫窗口的上限,上限值由用户独立设置。窗口看门狗计数器的值必须在上窗口和下窗口之间才可以刷新(喂狗),这也是窗口看门狗中“窗口”两个字的含义。

      从图中看到,T[6:0]是窗口控制寄存器(WWDG_CR)的低7位,W[6:0]是窗口配置寄存器(WWDG_CFR)低 7 位。T[6:0]就是窗口看门狗的计数器值,而W[6:0]是窗口看门狗的上窗口,下窗口是固定值 0X40。当窗口看门狗的计数器在上窗口值之外或者低于下窗口值被刷新都会产生复位。

        上窗口值(W[6:0])是由用户自己设定的,根据实际要求来设计窗口值,但是一定要确保窗口值大于 0X40,否则窗口就不存在了。窗口看门狗 WWDG 通常被用来监测,由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。

WWDG 配置步骤
(WWDG 相关库函数在 stm32f10x_wwdg.c 和 stm32f10x_wwdg.h 文件中)
(1)使能 WWDG 时钟
        WWDG 不同于 IWDG,IWDG 有自己独立的 LSI 时钟,所以不存在使能问题,而WWDG 使用的是 APB1 时钟,需要先使能时钟。在库函数中实现函数如下:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);
(2)设置 WWDG 窗口值和分频数(设置复位时间)
        设置 WWDG 窗口值函数为:且窗口值最大值为 0X7F,最小不能低于 0X40,否则就失去了窗口的意义。
void WWDG_SetWindowValue(uint8_t WindowValue);
        设置 WWDG 分频数函数为:且分频系数可以为 WWDG_Prescaler_1、WWDG_Prescaler_2 、WWDG_Prescaler_4、WWDG_Prescaler_8。
void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);
(3)开启 WWDG 中断并分组
        通常对窗口看门狗进行喂狗是在提前唤醒中断内操作,所以需要打开 WWDG的中断功能,并且配置对应的中断通道及分组。 库函数如下:
WWDG_EnableIT();
(4)设置计数器初始值并使能 WWDG
        库函数中提供了一个同时设置计数器初始值和使能 WWDG 的函数,如下:注意计数器最大值不能大于 OX7F。
void WWDG_Enable(uint8_t Counter);
库函数还提供了一个独立设置计数器值的函数,如下:
void WWDG_SetCounter(uint8_t Counter);
(5)编写 WWDG 中断服务函数(自编写功能函数)
WWDG_IRQHandler
        在中断内要进行喂狗,可以直接调用 WWDG_SetCounter()函数,给它传递一个窗口值即可,特别注意,在中断内喂狗一定要快,否则当看门狗计数器值减到0X3F 时将产生复位。然后清除 WWDG 中断状态标志位 EWIF,函数如下:
WWDG_ClearFlag(); //清除窗口看门狗状态标志
#include "wwdg.h"
#include "led.h"
#include "SysTick.h"


void WWDG_Init(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE); //开启窗口看门狗的时钟

	WWDG_SetWindowValue(0x5f);//设置窗口值
	WWDG_SetPrescaler(WWDG_Prescaler_8);//设置分频值
	
    //中断初始化
	NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;//窗口中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;		//子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化NVIC寄存器
	
	WWDG_Enable(0x7f); //使能窗口看门狗并初始化计数器值
	WWDG_ClearFlag(); //清除窗口看门狗状态标志(这一句必须加上,否则进入不了中断)
	WWDG_EnableIT(); //开启中断
	
}


void WWDG_IRQHandler(void)
{
	WWDG_SetCounter(0x7f); //重新赋值
	WWDG_ClearFlag(); //清除窗口看门狗状态标志
	led2=!led2;	
}

 

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。