STM32F407 串口和看门狗

串口配置

串口发送和接收的方法一般有三种:查询、中断和DMA。由于CPU的资源占用问题,一般采用中断或DMA方式来实现。HAL库的串口接收只支持接收定长数据,不定长数据的接收和发送需要自己编写函数,这里我们不定长发送用DMA空闲中断实现。

中断方式

接收回调函数:每一次接受一个数据都会进入这个接收回调函数。
发送回调函数:每一次发送一个数据都会进入这个发送回调函数。
在cubemx中设置串口的中断优先级,在主函数当中设置接收语句。然后再在回调函数当中写接收语句和发送语句。

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//回调函数
{
	HAL_UART_Transmit_IT(&huart1,buffer,3);
	HAL_UART_Receive_IT(&huart1,buffer,3);
}

DMA方式

在开启中断的前提下,再在cubemx中开启串口一的DMA接收和DMA的发送。
代码部分直接把函数中的"IT"改为“DMA”。

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//回调函数
{
	HAL_UART_Transmit_DMA(&huart1,buffer,3);
	HAL_UART_Receive_DMA(&huart1,buffer,3);
}

不定长接收

每一次发送的数据不一定是固定的长度。
用开启空闲中断的方式来实现不定长接收。因为cubemx当中没有开启空闲中断的回调函数,所以我们手动开启空闲中断,再在中断服务函数当中编写空闲中断函数。保留原来编写的中断接收区,以及主函数当中的发送语句。再在中断.c文件当中定义接收区的全局变量。

__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);//开启空闲中断
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
	if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE)!=RESET)
	{
		__HAL_UART_CLEAR_IDLEFLAG(&huart1);
		HAL_UART_DMAStop(&huart1);
		uint8_t len=3-__HAL_DMA_GET_COUNTER(huart1.hdmatx);
		HAL_UART_Transmit_DMA(&huart1,buffer,len);
		//memset(buffer,0,3);
		HAL_UART_Receive_DMA(&huart1,buffer,3);
		
	}
  /* USER CODE END USART1_IRQn 0 */
    HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}

窗口看门狗

原理讲解

之所以称为窗口,是因为其喂狗时间是一个有上下限的范围内,可以通过设定时间寄存器,设定其上限时间和下限时间:喂狗时间不能过早也不能过晚。
在这里插入图片描述

  1. ①窗口看门狗时钟
    窗口看门狗时钟来自PCLK1,PCLK1最大是45M,由RCC时钟控制器开启。

  2. ②计数器时钟
    计数器时钟由CK计时器时钟经过预分频器分频得到,分频系数由配置寄存器CFR的位8:7 WDGTB[1:0]配置,可以是[0,1,2,3],其中CK计时器时钟=PCLK1/4096,除以4096是手册规定的,没有为什么。所以计数器的时钟CNT_CK=PCLK1/4096/(2^WDGTB),
    这就可以算出计数器减一个数的时间T= 1/CNT_CK = Tpclk1 * 4096 * (2^WDGTB)。

  3. ③计数器
    窗口看门狗的计数器是一个递减计数器,共有7位,其值存在控制寄存器CR的位6:0,即T[6:0],当7个位全部为1时是0X7F,这个是最大值,当递减到T6位变成0时,即从0X40变为0X3F时候,会产生看门狗复位。这个值0X40是看门狗能够递减到的最小值,所以计数器的值只能是:0X40~0X7F之间,实际上用来计数的是T[5:0]。当递减计数器递减到0X40的时候,还不会马上产生复位,如果使能了提前唤醒中断:CFR位9 EWI 置1,则产生提前唤醒中断,如果真进入了这个中断的话,就说明程序肯定是出问题了,
    那么在中断服务程序里面我们就需要做最重要的工作,比如保存重要数据,或者报警等,这个中断我们也叫它死前中断。

  4. ④窗口值
    我们知道窗口看门狗必须在计数器的值在一个范围内才可以喂狗,其中下窗口的值是固定的0X40,上窗口的值可以改变,具体的由配置寄存器CFR的位6:0 W[6:0]设置。其值必须大于0X40,如果小鱼或者等于0X40就是失去了窗口的价值,而且也不能大于计数器的值,所以必须得小于0X7F。那窗口值具体要设置成多大?这个得根据我们需要监控的程序的运行时间来决定。如果我们要监控的程序段A运行的时间为Ta,当执行完这段程序之后就要进行喂狗,如果在窗口时间内没有喂狗的话,那程序就肯定是出问题了。一般计数器的值TR设置成最大0X7F,窗口值为WR,计数器减一个数的时间为T,那么时间:(TR-WR)*T应该稍微大于Ta即可,这样就能做到刚执行完程序段A之后喂狗,起到监控的作用,这样也就可以算出WR的值是多少。

  5. ⑤计算看门狗超时时间
    在这里插入图片描述
    这个图来自数据手册,从图我们知道看门狗超时时间:Twwdg = Tpclk1 x 4096 x 2^wdgtb x (T[5:0] + 1) ms,当PCLK1 = 30MHZ时,WDGTB取不同的值时有最小和最大的超时时间,那这个最小和最大的超时时间该怎么理解,又是怎么算出来的? 讲起来有点绕,这里我稍微讲解下WDGTB=0时是怎么算的。递减计数器有7位T[6:0] ,当位6变为0的时候就会产生复位,实际上有效的计数位是T[5:0],而且T6必须先设置为1。如果T[5:0]=0时,递减计数器再减一次,就产生复位了,那这减一的时间就等于计数器的周期=1/CNT_CK = Tpclk1 * 4096 * (2^WDGTB) = 1/30 * 4096 2^0 = 136.53us,这个就是最短的超时时间。如果T[5:0]全部装满为1,即63,当他减到0X40变成0X3F时,所需的时间就是最大的超时时间=113.72^5=136.53*64=8.74ms。同理,当WDGTB等于1/2/3时,代入公式即可。

WWDG一般被用来监测,由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。比如一个程序段正常运行的时间是50ms,在运行完这个段程序之后紧接着进行喂狗,如果在规定的时间窗口内还没有喂狗,那就说明我们监控的程序出故障了,跑飞了,那么就会产生系统复位,让程序重新运行。

代码实现

在中断回调函数中喂狗,如果LED灯快速闪烁,说明喂狗成功!
在CubeMx当中开启窗口看门狗,并且设定时钟、计时器和窗口值,必要时开启中断,可以在中断中喂狗。
在这里插入图片描述
在这里插入图片描述
生成的keil工程中的主函数当中,已经初始化窗口看门狗,只需要重新写回调函数即可。

void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hwwdg);
  HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_9);  
  HAL_WWDG_Refresh(hwwdg);    
}
  • 26
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值