爆肝9万字,我已从小白晋升ARM嵌入式工程师!带你从零熟悉常用的M4嵌入式功能,建议收藏(含码源)(5)

简介: 此器件具有两个嵌入式看门狗外设,具有安全性高、定时准确及使用灵活的优点。两个看门狗外设(独立和窗口)均可用于检测并解决由软件错误导致的故障'

8 .看门狗

8.1 看门狗简介

此器件具有两个嵌入式看门狗外设,具有安全性高、定时准确及使用灵活的优点。两个看门狗外设(独立和窗口)均可用于检测并解决由软件错误导致的故障;当计数器达到给定的超时值时,触发一个中断(仅适用于窗口型看门狗)或产生系统复位。注意:独立看门狗没有中断,但是可以触发中断服务函数。

8.2 看门狗的作用

2345_image_file_copy_84.jpg

原理图

8.3 看门狗的选择

2345_image_file_copy_85.jpg

独立看门狗用于精度低的场合,窗口看门狗用于精度高的场合。

8.4 独立看门狗

8.4.1 时钟

2345_image_file_copy_86.jpg

8.4.2 LS时钟

2345_image_file_copy_87.jpg

2345_image_file_copy_88.jpg

8.4.3 特性

● 自由运行递减计数器;

● 时钟由独立 RC 振荡器提供(可在待机和停止模式下运行);

● 当递减计数器值达到 0x000 时产生复位(如果看门狗已激活);

8.4.4 预分频

2345_image_file_copy_89.jpg

8.5 独立看门狗初始化

#include "iwdg.h"                  // Device header
void IWDG_Init(u16 PR,u16 RLR)
{
  RCC_LSICmd(ENABLE);  
  IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);  //关闭写保护
  IWDG_SetPrescaler(PR);  //预分频
  IWDG_SetReload(RLR);    //重装载值
  IWDG_Enable();   //启动独立看门狗
  IWDG_ReloadCounter();   //启动一次喂狗,写入0xAAAA,重装载的值才会被传递到计计数器
}

8.6 窗口看门狗

8.6.1 特点

窗口看门狗和独立看门狗不一样的地方在于它具备中断;

2345_image_file_copy_90.jpg

可编程的自由运行递减计数器;

复位条件:当递减计数器值小于 0x40 时复位(如果看门狗已激活);在窗口之外重载递减计数器时复位(如果看门狗已激活)。

中断触发条件:提前唤醒中断 (EWI):当递减计数器等于 0x40 时触发(如果已使能且看门狗已激活)。

8.6.2 原理

除非递减计数器的值在 T6 位变成 0 前被刷新,看门狗电路在

达到预置的时间周期时,会产生一个 MCU 复位。如果在递减计数器达到窗口寄存器值之前刷新控制寄存器中的 7 位递减计数器值,也会产生 MCU 复位。这意味着必须在限定的时间窗口内刷新计数器。

8.6.3  窗口看门狗初始化

  • 时钟

2345_image_file_copy_91.jpg

  • 使用的函数

2345_image_file_copy_92.jpg

  • 分频

2345_image_file_copy_93.jpg

  • 设置窗口值;
  • 使能看门狗中断;

2345_image_file_copy_94.jpg

  • 使能看门狗时,需要设置计数值,但是计数值不能大于窗口值 ;
  • 程序初始化

2345_image_file_copy_95.jpg

  • 2345_image_file_copy_96.jpg
  • 在中断中喂狗;

2345_image_file_copy_97.jpg

8.6.4 源码程序

#include "wwdg.h"                  // Device header
#include "stdio.h" 
int n;
void WWDG_Init(u8 WindowValue,u8 Counter)
{
    NVIC_InitTypeDef WWDG_NVIC;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);   //使能时钟
  WWDG_SetPrescaler(WWDG_Prescaler_8);   //8分频  WWDG counter clock = (PCLK1/4096)/8
  WWDG_SetWindowValue(WindowValue);     //设置窗口值
  WWDG_NVIC.NVIC_IRQChannel = WWDG_IRQn;
  WWDG_NVIC.NVIC_IRQChannelPreemptionPriority = 0;  //抢占为0
  WWDG_NVIC.NVIC_IRQChannelSubPriority = 0;//响应为0
  WWDG_NVIC.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&WWDG_NVIC);  
  n=Counter;
  WWDG_EnableIT();   //使能窗口看门狗中断
  WWDG_Enable(Counter);   //使能看门狗,设置计数值,传递大于0x40的值,防止初始化后产生一次复位
}
//窗口看门狗中断
void WWDG_IRQHandler(void)
{
  WWDG_SetCounter(n);  //设置计数值,喂狗 
  WWDG_ClearFlag();    //EWIF: 提前唤醒中断标志,清中断标志位  
  //printf("喂狗了\r\n");   //2-3ms  
}

9. RS485

学习该内容的目的:学会使用485实现一主多从的数据通信控制

9.1 概念

学会使用485实现一主多从的数据通信控制;

9.2 物理(硬件)接口标准

按照电平分类可以分成TTL、RS232、RS422、RS485,下面逐一介绍;

9.2.1 TTL电平

高电平:2.4-5V;51单片机工作电压是5V;IO口输出高电平就是5V;

低电平:0~0.4v;

数字电路中,由TTL电子元器件组成电路使用的电平。电平是个电压范围,规定输出高电平>2.4V,输出低电平<0.4V。在室温下,一般输出高电平是3.5V,输出低电平是0.2V。最小输入高电平和低电平:输入高电平>=2.0V,输入低电平<=0.8V,噪声容限是0.4V。

2345_image_file_copy_98.jpg

我们之前使用的USART(UART),默认为TTL电平,我们单片机的I/O输入输出的电平是和TTL兼容;USART(UART)按3.3V来说,正常1米之内。

9.2.2 RS232

高电平:电平为逻辑“ 1”时: -3V~-15V;

低电平:电平为逻辑“ 0”时: +3V~+15V;

2345_image_file_copy_99.jpg

传输距离:50英尺,一英尺=0.38米;50英尺=15.24米;

2345_image_file_copy_100.jpg

传输速度:20Kbps,一收一发模式

9.2.3 RS422

标准:1收10发;传输距离4000英尺=1219.2米

9.2.4 RS485

RS-485 标准是为弥补 RS-232 通信距离短、速率低等缺点而产生的。 RS-485 标准只规

定了平衡发送器和接收器的电特性,而没有规定接插件、传输电缆和应用层通信协议。

发送器和接收器:

2345_image_file_copy_101.jpg

高电平:+2-+6V;低电平:-2--6V;

性能参数:

2345_image_file_copy_102.jpg2345_image_file_copy_103.jpg

电缆最大距离:4000*0.3048=1219米;传输速度90Kbps;

RS485芯片:作为一种常用的通讯接口器件, RS-485/RS-422 芯片可以在许多半导体公司的“标准接口器件”栏目中“收发器”类元件中找到对应的型号;比如 Sipex 公司(器件前缀为 SP)、Maxim 公司(器件前缀为 MAX)、 TI 公司(器件前缀为 SN)、 Intersil 公司(器件前缀为 ISL 或LTC)等各大半导体公司。

9.3 一主一从通信

9.3.1 主机接线

引脚连接

2345_image_file_copy_104.jpg

发送数据:DE引脚使能为高电平,可以发送,同时把RE接收关闭,输出高电平;

2345_image_file_copy_105.jpg

接收数据:RE引脚使能为低电平,可以接收,同时把DE发送关闭,输出低电平

2345_image_file_copy_106.jpg

PG8引脚输出:高电平发送数据;低电平接收数据

2345_image_file_copy_107.jpg

9.3.2 丛机接线

2345_image_file_copy_108.jpg

2345_image_file_copy_109.jpg

9.3.3 主从机接线原理

2345_image_file_copy_110.jpgimage.jpeg

9.4 主机程序

#include "rs485.h"                  // Device header
#define RE_DE PGout(8)   //发送/接收器共用一个引脚
void RS485_Init(int bps)  
{
  GPIO_InitTypeDef u2_TXRX,RE;
  USART_InitTypeDef u2;
  NVIC_InitTypeDef u2_NVIC;
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOG,ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
  GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_USART2);
  GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_USART2);
  //PG8-发送/接收器使能
  RE.GPIO_Mode =GPIO_Mode_OUT;
  RE.GPIO_OType = GPIO_OType_PP;
  RE.GPIO_Pin = GPIO_Pin_8;
  RE.GPIO_PuPd = GPIO_PuPd_DOWN;   //默认下拉
  RE.GPIO_Speed = GPIO_High_Speed;
  GPIO_Init(GPIOG,&RE);   
  //PA9-发送
  u2_TXRX.GPIO_Mode =GPIO_Mode_AF;
  u2_TXRX.GPIO_OType = GPIO_OType_PP;
  u2_TXRX.GPIO_Pin = GPIO_Pin_2;
  u2_TXRX.GPIO_PuPd = GPIO_PuPd_UP;   //默认下拉
  u2_TXRX.GPIO_Speed = GPIO_High_Speed;
  GPIO_Init(GPIOA,&u2_TXRX);   //根据u2_TXRX配置的参数进行初始化
  //PA10-接收
  u2_TXRX.GPIO_Mode =GPIO_Mode_AF;
  u2_TXRX.GPIO_OType = GPIO_OType_PP;
  u2_TXRX.GPIO_Pin = GPIO_Pin_3;
  u2_TXRX.GPIO_PuPd = GPIO_PuPd_NOPULL;   //默认下拉
  u2_TXRX.GPIO_Speed = GPIO_High_Speed;
  GPIO_Init(GPIOA,&u2_TXRX);
  //USART
  u2.USART_BaudRate=bps;   //波特率
  u2.USART_HardwareFlowControl=USART_HardwareFlowControl_None;  //无硬件流
  u2.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;  //发送和接收
  u2.USART_Parity=USART_Parity_No;      //无校验
  u2.USART_StopBits=USART_StopBits_1;     //停止位
  u2.USART_WordLength=USART_WordLength_8b;  //数据位
  USART_Init(USART2, &u2);   //根据u2配置的参数进行初始化
  //记得分开写中断
  USART_ITConfig(USART2, USART_IT_RXNE,ENABLE);   //使能串口接收中断
  USART_ITConfig(USART2, USART_IT_IDLE,ENABLE);   //使能串口空闲中断 
  u2_NVIC.NVIC_IRQChannel = USART2_IRQn;
  u2_NVIC.NVIC_IRQChannelPreemptionPriority = 1;  //抢占为1
  u2_NVIC.NVIC_IRQChannelSubPriority = 1;//响应为0
  u2_NVIC.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&u2_NVIC);  
  USART_Cmd(USART2, ENABLE);  //使能串口进行工作
}
/********************************************************************
函数功能:串口1发送1个字节的字符数据
参数1:data:你要发送的数据
参数2:无
返回值:无
作者:xxx
********************************************************************/
void RS485_sendbyte(char data)
{
  RE_DE=1;    //使能485发送
  while(!(USART_GetFlagStatus(USART2,USART_FLAG_TC))); //等待判断发送寄存器为空
  USART_SendData(USART2,data);
  while(!(USART_GetFlagStatus(USART2,USART_FLAG_TC))); //等待为空,说明发送完毕
  RE_DE=0;    //关闭发送,默认接收
}
/********************************************************************
函数功能:串口1发送一串字符数据
参数1:data:你要发送的数据
参数2:无
返回值:无
作者:xxx
********************************************************************/
void RS485_sendstring(char *data)
{
  RE_DE=1;    //使能485发送
  while(*data != '\0')//循环发送,直到遇到\0,停止发送
  {
    while(!(USART_GetFlagStatus(USART2,USART_FLAG_TC))); //等待判断发送寄存器为空
    USART_SendData(USART2,*data++);
  }
  while(!(USART_GetFlagStatus(USART2,USART_FLAG_TC)));  //等待字符串最后一个数据发送完毕
  RE_DE=0;    //关闭发送,默认接收
}
//接收中断+空闲中断
struct U2_DATA  rs485={0,0,0};  //定义结构体变量,同时初始化为0
//接收中断:每收到一个字符数据就会执行一次USART2_IRQHandler中断服务函数
//空闲中断:收完数据之后,串口产生空闲,会自动执行一次USART2_IRQHandler中断服务函数
void USART2_IRQHandler(void)
{
  if(USART_GetITStatus(USART2, USART_IT_RXNE)==SET)   //接收中断,存储数据
  {
    rs485.buf[rs485.len]=USART_ReceiveData(USART2);  //读数据并清除中断标志位
    rs485.len++;  //自增,为下个数据存储做准备
  }else if(USART_GetITStatus(USART2, USART_IT_IDLE)==SET)  //空闲中断,接收数据结束
  {
    USART_ClearITPendingBit(USART2, USART_IT_IDLE);  //读SR
    USART_ReceiveData(USART2);   //读DR     
    rs485.ok_flag=1;          //接收完成
    rs485.buf[rs485.len]='\0';  //添加结束符   
  }
}

9.5 从机程序

#include "rs485.h"                  // Device header
#include "delay.h" 
#define RE_DE PAout(12)
void RS485_Init(int bps)  
{
  GPIO_InitTypeDef U3_TXRX,re;
  USART_InitTypeDef U3;
  NVIC_InitTypeDef NVIC_U3;
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE); //RCC
  re.GPIO_Mode=GPIO_Mode_Out_PP;    //复用推挽输出模式       GPIO
  re.GPIO_Pin=GPIO_Pin_12;      //引脚9
  re.GPIO_Speed=GPIO_Speed_50MHz;   //最高速50Mhz
  GPIO_Init(GPIOA, &re);        //根据U1_TXRX配置的参数进行初始化
  //PB10发送
  U3_TXRX.GPIO_Mode=GPIO_Mode_AF_PP;    //复用推挽输出模式       GPIO
  U3_TXRX.GPIO_Pin=GPIO_Pin_10;     //引脚9
  U3_TXRX.GPIO_Speed=GPIO_Speed_50MHz;  //最高速50Mhz
  GPIO_Init(GPIOB, &U3_TXRX);       //根据U1_TXRX配置的参数进行初始化
  //PB11-接收
  U3_TXRX.GPIO_Mode=GPIO_Mode_IPU;      //上拉输入模式
  U3_TXRX.GPIO_Pin=GPIO_Pin_11;     //引脚10
  U3_TXRX.GPIO_Speed=GPIO_Speed_50MHz;  //最高速50Mhz
  GPIO_Init(GPIOB, &U3_TXRX);       //根据U1_TXRX配置的参数进行初始化
  //USART
  U3.USART_BaudRate=bps;   //波特率
  U3.USART_HardwareFlowControl=USART_HardwareFlowControl_None;  //无硬件流
  U3.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;  //发送和接收
  U3.USART_Parity=USART_Parity_No;      //无校验
  U3.USART_StopBits=USART_StopBits_1;     //停止位
  U3.USART_WordLength=USART_WordLength_8b;  //数据位
  USART_Init(USART3, &U3);   //根据U1配置的参数进行初始化
  NVIC_U3.NVIC_IRQChannel=USART3_IRQn;   //设置的NVIC优先级的中断编号
  NVIC_U3.NVIC_IRQChannelCmd=ENABLE;
  NVIC_U3.NVIC_IRQChannelPreemptionPriority=2;  //抢占优先级
  NVIC_U3.NVIC_IRQChannelSubPriority=0;     //响应优先级
  NVIC_Init(&NVIC_U3);
  //记得分开写中断
  USART_ITConfig(USART3, USART_IT_RXNE,ENABLE);   //使能串口接收中断
  USART_ITConfig(USART3, USART_IT_IDLE,ENABLE);   //使能串口空闲中断 
  //NVIC_EnableIRQ(37);     //使能RS485中断编号 
  USART_Cmd(USART3, ENABLE);  //使能串口进行工作
  RE_DE=0;  //默认接收数据
}
/********************************************************************
函数功能:串口1发送1个字节的字符数据
参数1:data:你要发送的数据
参数2:无
返回值:无
作者:xxx
********************************************************************/
void RS485_sendbyte(char data)
{
  RE_DE=1;//使能485发送
  while(!(USART_GetFlagStatus(USART3,USART_FLAG_TC))); //等待判断发送寄存器为空
  USART_SendData(USART3,data);
  while(!(USART_GetFlagStatus(USART3,USART_FLAG_TC))); //等待为空,发送完成
  RE_DE=0; //关闭发送,默认接收
}
/********************************************************************
函数功能:串口1发送一串字符数据
参数1:data:你要发送的数据
参数2:无
返回值:无
作者:xxx
********************************************************************/
void RS485_sendstring(char *data)
{
  RE_DE=1;    //使能485发送
  while(*data != '\0')//循环发送,直到遇到\0,停止发送
  {
    while(!(USART_GetFlagStatus(USART3,USART_FLAG_TC))); //等待判断发送寄存器为空
    USART_SendData(USART3,*data++);
  }
  while(!(USART_GetFlagStatus(USART3,USART_FLAG_TC)));  //等待字符串最后一个数据发送完毕
  RE_DE=0;    //关闭发送,默认接收
}
// 原来的
//接收中断+空闲中断
struct U3_DATA  rs485={0,0,0};  //定义结构体变量,同时初始化为0
//接收中断:每收到一个字符数据就会执行一次RS485_IRQHandler中断服务函数
//空闲中断:收完数据之后,串口产生空闲,会自动执行一次RS485_IRQHandler中断服务函数
void USART3_IRQHandler(void)
{
  if(USART_GetITStatus(USART3, USART_IT_RXNE)==SET)   //接收中断,存储数据
  {
    rs485.buf[rs485.len]=USART_ReceiveData(USART3);  //读数据并清除中断标志位
    rs485.len++;  //自增,为下个数据存储做准备 
  }else if(USART_GetITStatus(USART3, USART_IT_IDLE)==SET)  //空闲中断,接收数据结束
  {
    USART_ClearITPendingBit(USART3, USART_IT_IDLE);  //读SR
    USART_ReceiveData(USART3);   //读DR
    rs485.ok_flag=1;          //接收完成
    rs485.buf[rs485.len]='\0';  //添加结束符
  }
}


相关文章
|
2月前
|
监控 网络协议 安全
验证嵌入式ARM32环境中4G模块的有效方法
验证嵌入式ARM32环境中4G模块的有效方法
100 0
|
3天前
|
存储 Ubuntu 编译器
合肥中科深谷嵌入式项目实战——基于ARM语音识别的智能家居系统(三)
合肥中科深谷嵌入式项目实战——基于ARM语音识别的智能家居系统(三)
合肥中科深谷嵌入式项目实战——基于ARM语音识别的智能家居系统(三)
|
3天前
|
Ubuntu Unix Linux
合肥中科深谷嵌入式项目实战——基于ARM语音识别的智能家居系统(一)
合肥中科深谷嵌入式项目实战——基于ARM语音识别的智能家居系统(一)
|
3天前
|
Linux 编译器 语音技术
合肥中科深谷嵌入式项目实战——基于ARM语音识别的智能家居系统(二)
合肥中科深谷嵌入式项目实战——基于ARM语音识别的智能家居系统(二)
|
4天前
|
存储 算法 Linux
详细解读ARM嵌入式整理
详细解读ARM嵌入式整理
|
2月前
|
物联网 编译器 测试技术
【嵌入式 交叉编译器】如何在 ARM 架构下选择和使用高版本交叉编译器
【嵌入式 交叉编译器】如何在 ARM 架构下选择和使用高版本交叉编译器
560 7
|
2月前
|
安全 Unix Linux
【ARM】在NUC977上搭建基于boa的嵌入式web服务器
【ARM】在NUC977上搭建基于boa的嵌入式web服务器
|
2月前
|
存储 机器学习/深度学习 人工智能
嵌入式中一文搞懂ARM处理器架构
嵌入式中一文搞懂ARM处理器架构
82 1
|
11月前
|
编译器 C语言
ARM与C语言的混合编程【嵌入式系统】
ARM与C语言的混合编程【嵌入式系统】
99 0
|
11月前
|
存储 芯片
ARM简单程序设计【嵌入式系统】
ARM简单程序设计【嵌入式系统】
124 0