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;	
}

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

拥抱 Spring 全新 OAuth 解决方案

以下全文 Spring Authorization Server 简称为: SAS 背景 Spring 团队正式宣布 Spring Security OAuth 停止维护,该项目将不会再进行任何的迭代 目前 Spring 生态中的 OAuth2 授权服务器是 Spring Authorization Server 已经可以正式生产使用 作为 SpringBoot 3.0…

FastThreadLocal 原理解析

FastThreadLocal 每个 FastThread 包含一个 FastThreadLocalMap,每个 FastThreadLocalThread 中的多个 FastThreadLocal 占用不同的索引。每个 InternalThreadLocalMap 的第一个元素保存了所有的 ThreadLocal 对象。之后的元素保存了每个 ThreadLocal 对应的 value …

SpringBoot 之 Tomcat 与 Undertow 容器性能对比

一、前言🔥 环境说明:Windows10 Idea2021.3.2 Jdk1.8 SpringBoot 2.3.1.RELEASE 在上一篇《SpringBoot 之配置 Undertow 容器》一文中写道:“Undertow 的性能和内存使用方面都要优于 Tomcat 容器”, 这一期,我就要给大家来求证…

批处理文件(.bat)启动redis及任何软件(同理)

批处理文件 每次从文件根目录用配置文件格式来启动redis太麻烦了 可以在桌面上使用批处理文件(.bat)启动Redis,请按照以下步骤进行操作: 打开文本编辑器,如记事本。 在编辑器中输入以下内容: 将文件保存…

【JavaSE】Java基础语法(三十六):File IO流

文章目录 1. File1.1 File类概述和构造方法1.2 绝对路径和相对路径1.3 File 类的常用方法1.4 递归删除文件夹及其下面的文件 2. IO2.1 分类2.2 字节输出流2.3 字节输入流2.4 文件的拷贝2.5 文件拷贝效率优化2.6 释放资源2.7 缓冲流2.8 编码表 3. commons-io 工具包3.1 API 1. F…

gitlab搭建与认证登录

gitlab搭建与认证登录 gitlab的安装配置gitlab中Ldap认证配置 gitlab的安装配置 参考链接: Gitlab 仓库搭建(详细版) 以下4项注意点: gitlab安装包,直接访问在浏览器上下载速度很慢,可复制链接到迅雷中进…

怎样用一周时间研究 ChatGPT

我是怎样用一周时间研究 ChatGPT 的? 上周大概开了 20 多个会,其中有一些是见了觉得今年可能会比较活跃出手的机构,其余见的绝大多数是和 ChatGPT 相关。 我后面就以 ChatGPT 为例,讲下我是如何快速一周 cover 一个赛道的&#x…

机器视觉怎么对陶瓷板的外观尺寸进行自动检测?

随着工业自动化的不断发展,机器视觉技术在制造业中的应用越来越广泛。在陶瓷板行业中,机器视觉技术可以用于自动检测陶瓷板的外观尺寸,提高生产效率和产品质量。下面我们来介绍机器视觉如何对陶瓷板的外观尺寸进行自动检测。 一、检测原理 …

vue常用指令

vue是前端框架&#xff0c;使用vue指令时需要导入vue.js文件&#xff1b;vue的常用指令有以下这些&#xff1a; v-bind、v-model&#xff1a;双向绑定数据、链接 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8">&…

SAP-MM-采购申请字段解析

采购申请抬头以及行项目字段解析 1、采购申请类型&#xff1a; 对PR进行分类&#xff1b; 控制PR行项目的编号间隔&#xff1b; 控制PR编号范围&#xff0c;以及是否内/外部给号&#xff1b; 控制PR的屏幕选择格式&#xff1b; 控制PR是否允许凭证抬头审批&#xff0c;如果允…

什么是MQTT?mqtt协议和http协议区别

摘要&#xff1a; 什么是MQTT&#xff1f;MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;译为&#xff1a;消息队列遥测传输&#xff0c;是一种轻量级的通讯协议&#xff0c;用于在网络上传输消息。MQTT 最初由 IBM 发布&#xff0c;后来成为 OASIS&#xf…

会话跟踪cookie和session

什么是会话跟踪技术 会话&#xff1a;用户打开浏览器&#xff0c;访问web服务器的资源&#xff0c;会话建立&#xff0c;直到有一方断开连接&#xff0c;会话结束。在一次会话中可能包含多次请求和响应。 会话跟踪&#xff1a;一种维护浏览器状态的方法&#xff0c;服务器需…

vivo互联网视频播放体验优化的探索与实践

随着vivo互联网在视频业务领域的不断扩展&#xff0c;在多样化的业务场景下&#xff0c;如何提升每个用户的视频播放体验&#xff0c;保障最优的播放流畅度和清晰度&#xff0c;vivo互联网技术团队做了很多尝试与突破。LiveVideoStackCon 2022北京站邀请vivo互联网研发经理王道…

python接口自动化测试之unittest自动化测试框架基本使用

目录 unittest简单介绍 unittest基础使用 unittest.Testcase setUp tearDown setUpClass tearDownClass 测试用例 unittest.main() unitteest提供的各种断言方式 unittest测试用例跳过执行 跳过执行测试用例共有四种写法 self.skipTest(reason) 跳过执行测试用例注…

eBay如何实现多账号登录以及防关联?

随着跨境电商的快速发展&#xff0c;亚马逊&#xff0c;eBay已成为人们熟知的电商平台。“不把鸡蛋放在同一个篮子里”&#xff0c;多账号运营店铺有许多显而易见的好处。 但由于亚马逊平台封号状况愈演愈烈&#xff0c;不少卖家把战线转移到了eBay平台。随着入驻人数的增加&a…

Solidity拓展:数学运算过程中数据长度溢出的问题

在数学运算过程中假如超过了长度则值会变成该类型的最小值&#xff0c;如果小于了该长度则变成最大值 数据上溢 uint8 numA 255; numA;uint8的定义域为[0,255]&#xff0c;现在numA已经到顶了&#xff0c;numA会使num变成0(由于256已经超过定义域&#xff0c;它会越过256&…

Redis事务及网络处理

一 Redis事务 redis开启事务后&#xff0c;会把接下来的所有命令缓存到一个单独的队列中&#xff0c;在提交事务时&#xff0c;使这些命令不可被分割的一起执行完成。 如果使用了watch命令监视某一个key&#xff0c;如果在开启事务之后&#xff0c;提交事务之前&#xff0c;有…

FreeRTOS:队列

目录 前言一、队列简介1.1数据存储1.2多任务访问1.3出队阻塞1.4入队阻塞1.5队列操作过程图示1.5.1创建队列1.5.2向队列发送第一个消息1.5.3向队列发送第二个消息1.5.4从队列中读取消息 二、队列结构体三、队列创建3.1创建函数3.2函数xQueueCreateStatic()3.3函数xQueueCreate()…

Spring Security入门

1. Spring Security 简介 Spring Security 是一个高度可定制的身份验证和访问控制框架&#xff0c;它基于 Spring 框架&#xff0c;并可与 Spring 全家桶无缝集成。该框架可以精确控制用户对应用程序的访问&#xff0c;控制用户的角色和权限等。 Spring Security 最早是由 Be…

又名管道和无名管道

一、进程间通信&#xff08;IPC&#xff0c;InterProcess Communication&#xff09; 概念&#xff1a;就是进程和进程之间交换信息。 常用通信方式 无名管道&#xff08;pipe&#xff09; 有名管道 &#xff08;fifo&#xff09; 信号&#xff08;signal&#xff09; 共…