第十九章 ADC——电压采集
单芯片解决方案,开启全新体验——W55MH32 高性能以太网单片机 W55MH32是WIZnet重磅推出的高性能以...
单芯片解决方案,开启全新体验——W55MH32 高性能以太网单片机
W55MH32是WIZnet重磅推出的高性能以太网单片机,它为用户带来前所未有的集成化体验。这颗芯片将强大的组件集于一身,具体来说,一颗W55MH32内置高性能Arm® Cortex-M3核心,其主频最高可达216MHz;配备1024KB FLASH与96KB SRAM,满足存储与数据处理需求;集成TOE引擎,包含WIZnet全硬件TCP/IP协议栈、内置MAC以及PHY,拥有独立的32KB以太网收发缓存,可供8个独立硬件socket使用。如此配置,真正实现了All-in-One解决方案,为开发者提供极大便利。
在封装规格上,W55MH32 提供了两种选择:QFN100和QFN68。
W55MH32L采用QFN100封装版本,尺寸为12x12mm,其资源丰富,专为各种复杂工控场景设计。它拥有66个GPIO、3个ADC、12通道DMA、17个定时器、2个I2C、5个串口、2个SPI接口(其中1个带I2S接口复用)、1个CAN、1个USB2.0以及1个SDIO接口。如此丰富的外设资源,能够轻松应对工业控制中多样化的连接需求,无论是与各类传感器、执行器的通信,还是对复杂工业协议的支持,都能游刃有余,成为复杂工控领域的理想选择。 同系列还有QFN68封装的W55MH32Q版本,该版本体积更小,仅为8x8mm,成本低,适合集成度高的网关模组等场景,软件使用方法一致。更多信息和资料请进入网站或者私信获取。
此外,本W55MH32支持硬件加密算法单元,WIZnet还推出TOE+SSL应用,涵盖TCP SSL、HTTP SSL以及 MQTT SSL等,为网络通信安全再添保障。
为助力开发者快速上手与深入开发,基于W55MH32L这颗芯片,WIZnet精心打造了配套开发板。开发板集成WIZ-Link芯片,借助一根USB C口数据线,就能轻松实现调试、下载以及串口打印日志等功能。开发板将所有外设全部引出,拓展功能也大幅提升,便于开发者全面评估芯片性能。
若您想获取芯片和开发板的更多详细信息,包括产品特性、技术参数以及价格等,欢迎访问官方网页,我们期待与您共同探索W55MH32的无限可能。
第二十四章 WWDG——窗口看门狗
本章参考资料:《W55MH32参考手册》WWDG章节。
学习本章时,配合《W55MH32参考手册》WWDG章节一起阅读,效果会更佳,特别是涉及到寄存器说明的部分。
1 WWDG简介
W55MH32有两个看门狗,一个是独立看门狗,一个是窗口看门狗。我们知道独立看门狗的工作原理就是一个递减计数器不断的往下递减计数, 当减到0之前如果没有喂狗的话,产生复位。窗口看门狗跟独立看门狗一样,也是一个递减计数器不断的往下递减计数, 当减到一个固定值0X40时还不喂狗的话,产生复位,这个值叫窗口的下限,是固定的值,不能改变。这个是跟独立看门狗类似的地方, 不同的地方是窗口看门狗的计数器的值在减到某一个数之前喂狗的话也会产生复位,这个值叫窗口的上限,上限值由用户独立设置。 窗口看门狗计数器的值必须在上窗口和下窗口之间才可以喂狗,这就是窗口看门狗中窗口两个字的含义。
RLR是重装载寄存器,用来设置独立看门狗的计数器的值。TR是窗口看门狗的计数器的值,由用户独立设置,WR是窗口看门狗的上窗口值,由用户独立设置。
2 WWDG功能框图剖析
WWDG功能框图如下:
2.1 窗口看门狗时钟
窗口看门狗时钟来自PCLK1,PCLK1最大是108M,由RCC时钟控制器开启。
2.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)。
2.3 计数器
窗口看门狗的计数器是一个递减计数器,共有7位,其值存在控制寄存器CR的位6:0,即T[6:0],当7个位全部为1时是0X7F, 这个是最大值,当递减到T6位变成0时,即从0X40变为0X3F时候,会产生看门狗复位。这个值0X40是看门狗能够递减到的最小值, 所以计数器的值只能是:0X40~0X7F之间,实际上真正用来计数的是T[5:0]。当递减计数器递减到0X40的时候,还不会马上产生复位, 如果使能了提前唤醒中断:CFR位9EWI置1,则产生提前唤醒中断,如果真进入了这个中断的话,就说明程序肯定是出问题了, 那么在中断服务程序里面我们就需要做最重要的工作,比如保存重要数据,或者报警等,这个中断我们也叫它死前中断。
2.4 窗口值
我们知道窗口看门狗必须在计数器的值在一个范围内才可以喂狗,其中下窗口的值是固定的0X40,上窗口的值可以改变, 具体的由配置寄存器CFR的位6:0 W[6:0]设置。其值必须大于0X40,如果小于或者等于0X40就是失去了窗口的价值,而且也不能大于计数器的值, 所以必须得小于0X7F。那窗口值具体要设置成多大?这个得根据我们需要监控的程序的运行时间来决定。如果我们要监控的程序段A运行的时间为Ta, 当执行完这段程序之后就要进行喂狗,如果在窗口时间内没有喂狗的话,那程序就肯定是出问题了。一般计数器的值TR设置成最大0X7F,窗口值为WR, 计数器减一个数的时间为T,那么时间:(TR-WR)*T应该稍微小于Ta即可,这样就能做到刚执行完程序段A之后喂狗,起到监控的作用,这样也就可以算出WR的值是多少。
2.5 计算看门狗超时时间
这个图来自数据手册,从图我们知道看门狗超时时间:Twwdg = Tpclk1 x 4096 x 2^wdgtb x (T[5:0] + 1) ms, 当PCLK1 = 36MHZ时,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/36 * 4096 *2^0 =113.7us, 这个就是最短的超时时间。如果T[5:0]全部装满为1,即63,当他减到0X40变成0X3F时,所需的时间就是最大的超时时间=113.7*2^5=113.7*64=7.2768ms。 同理,当WDGTB等于1/2/3时,代入公式即可。
3 WWDG使用方法
WWDG一般被用来监测,由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。比如一个程序段正常运行的时间是50ms, 在运行完这个段程序之后紧接着进行喂狗,如果在规定的时间窗口内还没有喂狗,那就说明我们监控的程序出故障了,跑飞了,那么就会产生系统复位,让程序重新运行。
4 WWDG的中断测试
4.1 代码解析
主要用于进行窗口看门狗(WWDG)的中断测试。以下是对代码各部分的详细解释:
1.头文件包含
#include < stdlib.h > #include < string.h > #include < stdio.h > #include "delay.h" #include "w55mh32.h"
stdlib.h、string.h 和 stdio.h 是标准 C 库头文件,分别提供通用工具函数、字符串操作函数和标准输入输出功能。
delay.h 是自定义头文件,可能用于实现延时功能。
w55mh32.h 是头文件。
2. 全局变量定义
USART_TypeDef *USART_TEST = USART1;
定义了一个指向 USART_TypeDef 类型的指针 USART_TEST,并初始化为 USART1,后续串口操作将使用 USART1。
3. 函数声明
void UART_Configuration(uint32_t bound); uint8_t GetCmd(void); void NVIC_Configuration(void);
UART_Configuration()函数用于配置串口通信,参数 bound 为波特率。
GetCmd()函数用于从串口接收数据。
NVIC_Configuration()函数用于配置嵌套向量中断控制器(NVIC)。
4. main()函数
int main(void) { RCC_ClocksTypeDef clocks; RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); delay_init(); UART_Configuration(115200); RCC_GetClocksFreq(&clocks); printf("n"); printf("SYSCLK: %3.1fMhz, HCLK: %3.1fMhz, PCLK1: %3.1fMhz, PCLK2: %3.1fMhz, ADCCLK: %3.1fMhzn", (float)clocks.SYSCLK_Frequency / 1000000, (float)clocks.HCLK_Frequency / 1000000, (float)clocks.PCLK1_Frequency / 1000000, (float)clocks.PCLK2_Frequency / 1000000, (float)clocks.ADCCLK_Frequency / 1000000); printf("WWDG Int Test.n"); printf("Interrupt Feed Dogn"); WWDG_SetPrescaler(WWDG_Prescaler_8); WWDG_SetWindowValue(0x5F); WWDG_Enable(0x7f); WWDG_ClearFlag(); NVIC_Configuration(); WWDG_EnableIT(); while (1); }
定义 RCC_ClocksTypeDef 类型的变量 clocks,用于存储系统时钟频率信息。
使能窗口看门狗(WWDG)的时钟。
调用 delay_init()函数初始化延时功能。
调用 UART_Configuration()函数配置串口通信,波特率为 115200。
调用 RCC_GetClocksFreq()函数获取系统时钟频率信息,并通过串口输出。
输出提示信息,表明进行窗口看门狗中断测试以及采用中断方式喂狗。
配置窗口看门狗的预分频器、窗口值,并使能窗口看门狗。
清除窗口看门狗的标志位。
调用 NVIC_Configuration()函数配置 NVIC。
使能窗口看门狗的中断功能。
进入无限循环,程序在此处暂停。
5. WWDG_IRQHandler()函数
void WWDG_IRQHandler(void) { WWDG_SetCounter(0x7f); WWDG_ClearFlag(); }
这是窗口看门狗的中断服务函数。当窗口看门狗产生中断时,会执行该函数。函数中:
将窗口看门狗的计数器值设置为 0x7f,即喂狗操作,防止系统复位。
清除窗口看门狗的标志位,以便能处理下一次中断。
6. NVIC_Configuration()函数
void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); }
7. UART_Configuration()函数
void UART_Configuration(uint32_t bound) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = bound; USART_InitStructure.USART_WordLength = USART_WordLength_8b; 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(USART_TEST, &USART_InitStructure); USART_Cmd(USART_TEST, ENABLE); }
此函数用于配置 USART1 串口通信,具体步骤如下:
使能 USART1 和 GPIOA 的时钟。
配置 GPIOA 的 Pin9 为复用推挽输出模式,作为 USART1 的发送引脚。
配置 GPIOA 的 Pin10 为浮空输入模式,作为 USART1 的接收引脚。
配置 USART1 的波特率、数据位、停止位、奇偶校验位、硬件流控制和工作模式。
初始化 USART1 并使能。
8. GetCmd()函数
uint8_t GetCmd(void) { uint8_t tmp = 0; if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE)) { tmp = USART_ReceiveData(USART1); } return tmp; }
该函数用于从 USART1 接收数据。若接收缓冲区非空标志位 USART_FLAG_RXNE 被置位,则从接收缓冲区读取数据并返回。
9. SER_PutChar()函数
int SER_PutChar(int ch) { while (!USART_GetFlagStatus(USART_TEST, USART_FLAG_TC)); USART_SendData(USART_TEST, (uint8_t)ch); return ch; }
此函数用于向 USART1 发送单个字符。等待发送完成标志位 USART_FLAG_TC 被置位后,将字符写入发送缓冲区并返回该字符。
10. fputc()函数
int fputc(int c, FILE *f) { if (c == 'n') { SER_PutChar('r'); } return (SER_PutChar(c)); }
这是标准库 fputc()函数的重定向实现,用于将字符输出到串口。若要输出的字符为换行符 n,先输出回车符 r,再输出换行符。
4.2 下载验证
该程序的主要功能是配置串口通信,输出系统时钟频率信息,同时使能窗口看门狗的中断功能,并通过中断服务函数进行喂狗操作,以防止系统复位。
如果想要了解确认这段代码是否在正确执行“喂狗”(即重置WWDG计数器),在 WWDG_IRQHandler 中断处理函数中添加串口打印语句,每次触发中断时输出调试信息。
修改代码:
void WWDG_IRQHandler(void) { WWDG_SetCounter(0x7f); // 喂狗 WWDG_ClearFlag(); // 清除中断标志 printf("[WWDG] Feed dog! Counter reset to 0x7Fn"); // 添加调试输出 }
然后查看串口打印数据,查看到正在执行“喂狗”:
5 WWDG_Reset
5.1 代码解析
1. 头文件和全局变量
#include < stdlib.h > #include < string.h > #include < stdio.h > #include "delay.h" #include "w55mh32.h" USART_TypeDef *USART_TEST = USART1;
包含了标准库和自定义的头文件。
USART_TEST 是一个指向 USART1 的指针,用于后续串口操作。
2. 函数声明
void UART_Configuration(uint32_t bound); uint8_t GetCmd(void);
UART_Configuration()函数用于配置串口通信。
GetCmd()函数用于从串口接收数据。
3. main()函数
int main(void) { RCC_ClocksTypeDef clocks; RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE); delay_init(); UART_Configuration(115200); RCC_GetClocksFreq(&clocks); printf("n"); printf("SYSCLK: %3.1fMhz, HCLK: %3.1fMhz, PCLK1: %3.1fMhz, PCLK2: %3.1fMhz, ADCCLK: %3.1fMhzn", (float)clocks.SYSCLK_Frequency / 1000000, (float)clocks.HCLK_Frequency / 1000000, (float)clocks.PCLK1_Frequency / 1000000, (float)clocks.PCLK2_Frequency / 1000000, (float)clocks.ADCCLK_Frequency / 1000000); printf("WWDG Reset Test.n"); WWDG_SetPrescaler(WWDG_Prescaler_8); WWDG_SetWindowValue(0x5F); WWDG_Enable(0x7f); while (1); }
时钟和外设初始化:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE) 使能窗口看门狗(WWDG)的时钟。
delay_init() 初始化延时函数。
UART_Configuration(115200) 配置串口通信,波特率为 115200。
RCC_GetClocksFreq(&clocks) 获取系统时钟频率信息。
串口输出信息:
通过 printf()函数输出系统时钟频率信息和测试提示信息。
窗口看门狗配置:
WWDG_SetPrescaler(WWDG_Prescaler_8) 设置窗口看门狗的预分频器为 8。
WWDG_SetWindowValue(0x5F) 设置窗口值为 0x5F。
WWDG_Enable(0x7f) 使能窗口看门狗,初始计数值为 0x7f。
主循环:
while (1); 程序进入无限循环,由于没有对窗口看门狗进行喂狗操作,一段时间后窗口看门狗会触发复位。
4. UART_Configuration()函数
void UART_Configuration(uint32_t bound) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = bound; USART_InitStructure.USART_WordLength = USART_WordLength_8b; 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(USART_TEST, &USART_InitStructure); USART_Cmd(USART_TEST, ENABLE); }
使能 USART1 和 GPIOA 的时钟。
配置 PA9 为复用推挽输出,作为串口发送引脚;配置 PA10 为浮空输入,作为串口接收引脚。
配置串口的波特率、数据位、停止位、奇偶校验等参数。
初始化串口并使能。
5. GetCmd()函数
uint8_t GetCmd(void) { uint8_t tmp = 0; if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE)) { tmp = USART_ReceiveData(USART1); } return tmp; }
检查串口接收缓冲区是否有数据(USART_FLAG_RXNE 标志位)。
如果有数据,从串口接收一个字节的数据并返回。
6. SER_PutChar()和fputc()函数
int SER_PutChar(int ch) { while (!USART_GetFlagStatus(USART_TEST, USART_FLAG_TC)); USART_SendData(USART_TEST, (uint8_t)ch); return ch; } int fputc(int c, FILE *f) { /* Place your implementation of fputc here */ /* e.g. write a character to the USART */ if (c == 'n') { SER_PutChar('r'); } return (SER_PutChar(c)); }
SER_PutChar()函数用于通过串口发送一个字符,等待发送完成标志位(USART_FLAG_TC)置位后再发送。
fputc()函数是 printf()函数的底层实现,当输出换行符 n 时,会先发送回车符 r,然后再发送字符。
这段代码的主要目的是测试窗口看门狗的复位功能。程序启动后,会输出系统时钟信息和测试提示信息,然后配置并使能窗口看门狗。由于在主循环中没有对窗口看门狗进行喂狗操作,窗口看门狗会在一段时间后触发复位,重新启动程序。同时,代码还实现了串口通信功能,用于输出信息和接收数据。
5.2 下载验证
WIZnet 是一家无晶圆厂半导体公司,成立于 1998 年。产品包括互联网处理器 iMCU™,它采用 TOE(TCP/IP 卸载引擎)技术,基于独特的专利全硬连线 TCP/IP。iMCU™ 面向各种应用中的嵌入式互联网设备。
WIZnet 在全球拥有 70 多家分销商,在香港、韩国、美国设有办事处,提供技术支持和产品营销。
香港办事处管理的区域包括:澳大利亚、印度、土耳其、亚洲(韩国和日本除外)。
当前非电脑浏览器正常宽度,请使用移动设备访问本站!