- 2024-11-15
-
发表了主题帖:
CW32L010学习笔记
CW32学习开发笔记
# 硬件原理图:
## 主芯片
![image-20241114103849101](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114103849101.png)
引脚封装图:
![image-20241114104051352](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114104051352.png)
CW32L010 是基于 eFlash 的单芯片低功耗微控制器,集成了主频高达 48MHz 的 ARM® Cortex®-M0+ 内核、
高速嵌入式存储器(多至 64K 字节 FLASH 和多至 4K 字节 SRAM)以及一系列全面的增强型外设和 I/O 口。
所有型号都提供全套的通信接口(二路 UART、一路 SPI 和一路 I2C)、12 位高速 ADC、四组通用和基本定时器、
一组低功耗定时器以及一组高级控制 PWM 定时器。
## 供电电源
使用type-c直接供电即可,不需要再接其他电源转换芯片,CW32L010 可以在 -40℃到 85℃的温度范围内工作,供电电压宽达 1.62V ~ 5.5V。支持 Sleep 和 DeepSleep两种低功耗工作模式。
![image-20241114104435067](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114104435067.png)
## 复位电路
![image-20241114104524841](C:/Users/syz/AppData/Roaming/Typora/typora-user-images/image-20241114104524841.png)
## 滤波电路
![image-20241114104852343](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114104852343.png)
## 内部稳压
![image-20241114105052457](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114105052457.png)
![image-20241114105024829](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114105024829.png)
## 调试下载
默认使用SWD接口下载程序,原理图如下:
![image-20241114105146199](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114105146199.png)
## 板载指示灯
用于查看系统运行状态,原理图如下:
![image-20241114110648242](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114110648242.png)
# 软件功能
## 工程创建
具体如何创建工程就不所说明了,官方例程都有说明,我主要说下的我的目录结构设计:
![image-20241114105830013](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114105830013.png)
## 串口通讯
内部集成 2 个通用异步收发器 (UART),支持异步全双工、同步半双工和单线半双工模式,支持硬件数据流控
和多机通信,还支持 LIN(局域互连网络);可编程数据帧结构,可以通过小数波特率发生器提供宽范围的
波特率选择。内置定时器模块,支持等待超时检测、接收空闲检测、自动波特率检测和通用定时功能。
UART 控制器工作在双时钟域下,允许在深度休眠模式下进行数据的接收,接收完成中断可以唤醒 MCU 回到
运行模式。注意:仅 UART1 支持 LIN 和定时器功能;UART2 可通过片内外设互联与 BTIM/GTIM/ATIM 的从模式协同工
作实现超时定时器相关功能。我们接着实现串口通讯功能;
- 1.串口功能硬件引脚
![image-20241114135526600](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114135526600.png)
使用串口2来是实现通讯,再看引脚的复用功能。
![image-20241114135659092](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114135659092.png)
- 2.代码实现
```C
#include "bsp_uart2.h"
#include "cw32l010_gpio.h"
#include "cw32l010_uart.h"
#include "stdio.h"
#include "cw32l010_sysctrl.h"
//UARTx
#define DEBUG_UARTx CW_UART2
#define DEBUG_UART_CLK SYSCTRL_APB1_PERIPH_UART2
#define DEBUG_UART_APBClkENx SYSCTRL_APBPeriphClk_Enable1
#define DEBUG_UART_BaudRate 115200
#define DEBUG_UART_UclkFreq HSIOSC_VALUE //串口全速运行
//UARTx GPIO
#define DEBUG_UART_GPIO_CLK (SYSCTRL_AHB_PERIPH_GPIOB)
#define DEBUG_UART_TX_GPIO_PORT CW_GPIOB
#define DEBUG_UART_TX_GPIO_PIN GPIO_PIN_5
#define DEBUG_UART_RX_GPIO_PORT CW_GPIOB
#define DEBUG_UART_RX_GPIO_PIN GPIO_PIN_6
//GPIO AF
#define DEBUG_UART_AFTX PB05_AFx_UART2TXD()
#define DEBUG_UART_AFRX PB06_AFx_UART2RXD()
static void UART_Configuration(void)
{
// //外设时钟使能,放在外设里面自己进行使能
DEBUG_UART_APBClkENx(DEBUG_UART_CLK, ENABLE);
UART_InitTypeDef UART_InitStructure = {0};
UART_InitStructure.UART_BaudRate = DEBUG_UART_BaudRate;
UART_InitStructure.UART_Over = UART_Over_16;
UART_InitStructure.UART_Source = UART_Source_PCLK;
UART_InitStructure.UART_UclkFreq = DEBUG_UART_UclkFreq;
UART_InitStructure.UART_StartBit = UART_StartBit_FE;
UART_InitStructure.UART_StopBits = UART_StopBits_1;
UART_InitStructure.UART_Parity = UART_Parity_No ;
UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;
UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx;
UART_Init(DEBUG_UARTx, &UART_InitStructure);
}
/**
* @brief 配置GPIO
*
*/
static void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
//外设时钟使能,放在外设里面自己进行使能
SYSCTRL_AHBPeriphClk_Enable(DEBUG_UART_GPIO_CLK, ENABLE);
GPIO_WritePin(DEBUG_UART_TX_GPIO_PORT, DEBUG_UART_TX_GPIO_PIN,GPIO_Pin_SET); // 设置TXD的默认电平为高,空闲
GPIO_InitStructure.Pins = DEBUG_UART_TX_GPIO_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_Init(DEBUG_UART_TX_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pins = DEBUG_UART_RX_GPIO_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;
GPIO_Init(DEBUG_UART_RX_GPIO_PORT, &GPIO_InitStructure);
//UART TX RX 复用
DEBUG_UART_AFTX;
DEBUG_UART_AFRX;
}
void UART2_Configuration(void)
{
UART_Configuration();
GPIO_Configuration();
}
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
* @brief Retargets the C library printf function to the UART.
*
*/
PUTCHAR_PROTOTYPE
{
UART_SendData_8bit(DEBUG_UARTx, (uint8_t)ch);
while (UART_GetFlagStatus(DEBUG_UARTx, UART_FLAG_TXE) == RESET);
return ch;
}
size_t __write(int handle, const unsigned char * buffer, size_t size)
{
size_t nChars = 0;
if (buffer == 0)
{
/*
* This means that we should flush internal buffers. Since we
* don't we just return. (Remember, "handle" == -1 means that all
* handles should be flushed.)
*/
return 0;
}
for (/* Empty */; size != 0; --size)
{
UART_SendData_8bit(DEBUG_UARTx, *buffer++);
while (UART_GetFlagStatus(DEBUG_UARTx, UART_FLAG_TXE) == RESET);
++nChars;
}
return nChars;
}
/******************************************************************************
* EOF (not truncated)
******************************************************************************/
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
```
- 3.编写打印测试函数
```C
static void Printf_Function(void)
{
DEBUG_LOG("\r\n");
DEBUG_LOG(" Compile time:");
DEBUG_LOG(__DATE__);
DEBUG_LOG(" ");
DEBUG_LOG(__TIME__);
DEBUG_LOG("\r\n+-------------------+\r\n");
DEBUG_LOG("%s,%s,%d,%s\r\n", __FUNCTION__,__FILE__,__LINE__,__DATE__);
DEBUG_LOG("\r\n+-------------------+\r\n");
}
```
- 4.查看串口终端信息
使用MobaXterm终端工具查看:
![image-20241114140550582](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114140550582.png)
- 5.注意点
为了让代码支持GNU扩展,keil设置需要注意:
![image-20241114140950288](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114140950288.png)
同时,串口打印的时候,添加头文件`"stdio.h"`;
## GPIO口输入输出
根据板载资源,使用板载的LED来测试。前面硬件说明的时候提到,使用的引脚为PB00;就直接上代码了。
- 1.编写驱动代码
```C
#include "drv_led.h"
// 初始化 LED 引脚
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__SYSCTRL_GPIOB_CLK_ENABLE();
GPIO_InitStruct.IT = GPIO_IT_NONE;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pins = LED_GPIO_PINS;
GPIO_Init(LED_GPIO_PORT, &GPIO_InitStruct);
}
// 控制 LED 开关
void LED_Control(GPIO_PinState state)
{
GPIO_WritePin(LED_GPIO_PORT, LED_GPIO_PINS,state);
}
// 切换 LED 状态
void LED_Toggle(void) {
GPIO_TogglePin(LED_GPIO_PORT, LED_GPIO_PINS);
}
// 读取 LED 状态
int LED_Read(void) {
return GPIO_ReadPin(LED_GPIO_PORT, LED_GPIO_PINS) == GPIO_Pin_SET ? 1 : 0;
}
// 定义并初始化 LED 操作结构体实例
LED_Ops_t myLED = {
.init = LED_Init,
.control = LED_Control,
.toggle = LED_Toggle,
.read = LED_Read
};
```
- 2.编写测试程序
```C
int32_t main(void)
{
bsp_init();
driver_init();
while(1)
{
SysTickDelay(1000);
myLED.toggle();
}
}
```
调试下载之后,可直接观察板载LED灯是否在循环闪烁。
## 调试等级
- 1.直接上代码,调试等级头文件;
```C
#ifndef __LOG_H
#define __LOG_H
#include
#include
#include
#include
#define GLOB_LOG_EVEL LOG_DEBUG
typedef enum {
FALSE,
TRUE
} status;
// 定义日志级别
typedef enum {
LOG_DEBUG,
LOG_INFO,
LOG_WARNING,
LOG_ERROR
} LogLevel;
//extern LogMsg lmsg;
// 颜色
#define Blue "\033[34m" // Blue
#define Green "\033[32m" // Green
#define Yellow "\033[33m" // Yellow
#define Red "\033[31m" // Red
#define Reset "\033[0m" // Reset color
// 记录日志的宏定义
#define LOG_MESSAGE(format, ...) printf("[NTP]:%s(),Line:%05d: " format "\r\n", __FUNCTION__, __LINE__, ##__VA_ARGS__)
void LOG_MSG(LogLevel level, const char *message);
#endif
```
- 2.功能函数实现文件:
```C
#include "log.h"
// 日志输出函数
void LOG_MSG(LogLevel level, const char *message) {
switch (level) {
case LOG_DEBUG:
printf(Blue "DEBUG: %s" Reset "\r\n", message);
break;
case LOG_INFO:
printf(Green "INFO: %s" Reset "\r\n", message);
break;
case LOG_WARNING:
printf(Yellow "WARNING: %s" Reset "\r\n", message);
break;
case LOG_ERROR:
printf(Red "ERROR: %s" Reset "\r\n", message);
break;
default:
printf("UNKNOWN: %s\n", message);
break;
}
}
```
- 3.编写测试函数
```C
/*宏定义错误码信息*/
static void Error_Code_Info(void)
{
DEBUG_LOG("%d", SYSTEM_OK);
DEBUG_LOG("%d", SYSTEM_ERR_E_1);
DEBUG_LOG("%d", SYSTEM_ERR_E_2);
DEBUG_LOG("%d", SYSTEM_ERR_MQTT_INFO_ERROR);
LOG_MSG(LOG_DEBUG, "This is a debug message");
LOG_MSG(LOG_INFO, "This is an info message");
LOG_MSG(LOG_WARNING, "This is a warning message");
LOG_MSG(LOG_ERROR, "This is an error message");
}
```
- 4.终端输出
![image-20241114145804066](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241114145804066.png)
## 串口中断
CW32单片机的串口有好几种工作方式,异步全双工,同步半双工,单线半双工,由于没有DMA通道,为了避免频繁的进入中断,采用串口接收中断,串口查询发送方式实现收发;
配置简单队列消息,实现方式如下:
- 1、定义队列结构
```C
#define myQ2_SIZE 512
#define RxBuffer2_SIZE myQ2_SIZE
typedef volatile struct
{
uint8_t m_getIdx;
uint8_t m_putIdx;
uint8_t m_entry[ myQ2_SIZE ];
} myQ2;
extern myQ2 volatile RxBuffer2;
extern myQ2 volatile TxBuffer2;
void UART2_Buffer_Init(void);
```
- 2、初始化队列结构
```C
myQ2 volatile RxBuffer2;
myQ2 volatile TxBuffer2;
void UART2_Buffer_Init(void)
{
CBUF_Init(RxBuffer2);
CBUF_Init(TxBuffer2);
}
```
- 3、使能串口接收中断
```C
void NVIC_Configuration(void)
{
//优先级,无优先级分组
NVIC_SetPriority(DEBUG_UART_IRQ, 0);
//UARTx中断使能
NVIC_EnableIRQ(DEBUG_UART_IRQ);
//使能UARTx RC中断
UART_ITConfig(DEBUG_UARTx, UART_IT_RC, ENABLE);
UART_ClearITPendingBit(CW_UART2, UART_IT_RC);
}
```
- 4、编写测试函数,实现串口功能收发
```C
int32_t main(void)
{
bsp_init();
driver_init();
while(1)
{
uint16_t dataLen=0;
dataLen = CBUF_Len(RxBuffer2);
if(dataLen!=0)
{
//拷贝数据
memcpy((char*)TxBuffer2.m_entry,(char*)RxBuffer2.m_entry,dataLen);
//查询发送数据
UART_SendBuf_Polling(CW_UART2,TxBuffer2.m_entry,dataLen);
USART2_Clear();
}
SysTickDelay(1000);
myLED.toggle();
}
}
```
- 5、查看串口终端收发
![image-20241115144847070](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241115144847070.png)
从截图可以看出,当前收发数据一致;
## 控制台Shell
下面介绍下开源项目是 letter-shell,一个功能强大的嵌入式shell,letter shell 3.x是一个C语言编写的,可以嵌入在程序中的嵌入式shell,通俗一点说就是一个串口命令行,可以通过命令行调用、运行程序中的函数。目前 letter-shell 3.0版本支持的功能有:
- 命令自动补全
- 快捷键功能定义
- 命令权限管理
- 用户管理
- 变量支持
> 项目地址:https://github.com/NevermindZZT/letter-shell
移植过程:
- 1.复制源码到工程中:
![image-20241115165344228](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241115165344228.png)
- 2.在自定义接口`shell_port.c`中实现自己的串口读写函数
```C
#include "shell.h"
#include "main.h"
#include "bsp_uart2.h"
#include "shell_port.h"
Shell shell;
char shellBuffer[512];
/**
* @brief 用户shell写
*
* @param data 数据
* @param len 数据长度
*
* @return short 实际写入的数据长度
*/
short userShellWrite(char *data, unsigned short len)
{
UART_SendBuf_Polling(CW_UART2,(uint8_t *)data, len);
return len;
}
/**
* @brief 用户shell读
*
* @param data 数据
* @param len 数据长度
*
* @return short 实际读取到
*/
short userShellRead(char *data, unsigned short len)
{
return UART2_GetString((uint8_t *)data, len);
}
/**
* @brief 用户shell上锁
*
* @param shell shell
*
* @return int 0
*/
int userShellLock(Shell *shell)
{
return 0;
}
/**
* @brief 用户shell解锁
*
* @param shell shell
*
* @return int 0
*/
int userShellUnlock(Shell *shell)
{
return 0;
}
/**
* @brief 用户shell初始化
*
*/
void userShellInit(void)
{
//注册自己实现的写函数
shell.write = userShellWrite;
// shell.read = userShellRead;
//调用shell初始化函数
shellInit(&shell, shellBuffer, 512);
}
```
- 3.在终端函数中定义
对于裸机环境,在主循环中调用`shellTask`,或者在接收到数据时,调用`shellHandler`,我这里在中断中调用
```C
void UART2_IRQHandler(void)
{
/* USER CODE BEGIN */
uint8_t TxRxBuffer;
if (UART_GetITStatus(CW_UART2, UART_IT_RC) != RESET)
{
/*使用简易队列进行接收数据*/
TxRxBuffer = UART_ReceiveData_8bit(CW_UART2);
shellHandler(&shell,TxRxBuffer);
CBUF_Push(RxBuffer2, TxRxBuffer);
UART_ClearITPendingBit(CW_UART2, UART_IT_RC);
}
/* USER CODE END */
}
```
- 4.调用初始化shell
```C
userShellInit();
```
- 5.串口终端实现结果
![image-20241115170003058](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241115170003058.png)
查看当前系统时钟:
![image-20241115170036353](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20241115170036353.png)
其他实现方式,参考官方文档说明。
- 2024-11-05
-
加入了学习《自己动手写操作系统》,观看 通过修改SP,来修改调用的函数
-
加入了学习《自己动手写操作系统》,观看 自己动手写操作系统
- 2024-08-26
-
加入了学习《CH582 微信小程序控制LED》,观看 CH582 微信小程序控制LED
-
加入了学习《CH582 蓝牙控制LED》,观看 CH582 蓝牙控制LED
- 2024-08-19
-
回复了主题帖:
NUCLEO-H533RE开发板测评10(LVGL综合应用)
wangerxian 发表于 2024-8-19 17:09
老兄的Keil配色挺别致的,和屏幕设计一个配色
常规配置
-
回复了主题帖:
NUCLEO-H533RE开发板测评10(LVGL综合应用)
秦天qintian0303 发表于 2024-8-18 21:36
你这屏有点大啊,幸亏STM32H533的主频够高
图形化就选择一个屏幕大点的
- 2024-08-17
-
发表了主题帖:
NUCLEO-H533RE开发板测评10(LVGL综合应用)
## 10.LVGL显示温湿度
### 10.1:SHT30温湿度模块
采用SHT30温湿度模块来获取温湿度数据,模块如下:
![image-20240817163127313](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240817163127313.png)
接口是IIC,使用PB6和PB7。使用cubemx配置,具体前面的文章的IIC配置,基本一致。SHT30的i2c地址是0x44;
其中温湿度数据处理函数:
```C
void sHT30 Read(float *temperature, float *humidity)
{
uint8 t buf[6];
float temp, hum;
buf[0]= 0x2c;
buf[1]= 0x06;
HAL I2C Master Transmit(&hi2c1,SHT30 I2C ADDRESS, buf, 2, 1000);HAL Delay(20);
HAL I2C Master Receive(&hi2c1,SHT30 I2C ADDRESS, buf, 6, 1000);
uint16 t st = buf[e]
- 2024-08-15
-
发表了主题帖:
NUCLEO-H533RE开发板测评09(HASH算法加密)
群里已经看到关于AES加解密的,这里就评测下hash算法加密
## 9:HASH算法加密
在现代计算机领域,数据的完整性和安全性是非常重要的,为了保证数据的完整性,我们需要使用一些算法进行数据校验。其中,哈希算法是最常用的一种算法之一,SHA1、SHA256、SHA384和SHA512都是SHAHash Algorithm)系列的哈希算法,它们的区别主要在于输出长度和运算速度。
![image-20240815152458282](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240815152458282.png)
### 9.1:SHA1验证
下面结合板子进行测试,首先测试SHA1,配置cubemx,使能hash算法;
![image-20240815152847192](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240815152847192.png)
自动化生成代码之后,初始化hash算法,调用如下函数:
```
MX_HASH_Init();
```
打比方初始化设置需要加密的内容为“123456”,SHA1的结果为
```C
7c4a8d09ca3762af61e59520943dc26494f8941b
```
打开hash校验算法网址
https://tool.528sq.cn/allencrypt/
![image-20240815153205026](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240815153205026.png)
编写测试代码:
```
if (HAL_HASH_Start(&hhash, (uint8_t *)Input, INPUT_TAB_SIZE, aDigest, 0xFF) != HAL_OK)
{
Error_Handler();
}
for(int i=0;i
- 2024-08-14
-
回复了主题帖:
NUCLEO-H533RE开发板测评08(LVGL移植)
Jacktang 发表于 2024-8-14 07:17
效果不错,后续针对LVGL进行优化会更好
是的,后续有时间针对LVGL好好开发,还有,SPI使用杜邦线连接,感觉时速比较慢
- 2024-08-13
-
发表了主题帖:
NUCLEO-H533RE开发板测评08(LVGL移植)
打开LVGL Guider编辑器,创建工程
![image-20240809230102539](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240809230102539.png)
选择LVGL版本,是用V8.3
![image-20240809230127272](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240809230127272.png)
选择模拟器
![image-20240809230149762](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240809230149762.png)
设计LVGL界面:
![image-20240809231545113](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240809231545113.png)
修改样式和中英文显示:
![image-20240813160225545](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240813160225545.png)
使用官方工具不用关心中文字符问题;
保存文件:
![image-20240813154757988](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240813154757988.png)
移植LVGL项目工程,打开git,下载LVGL8.3的工程包
https://gitcode.com/gh_mirrors/lv/lvgl/tree/release/v8.3?init=initRepo,
![image-20240813155029716](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240813155029716.png)
具体移植过程就有部多讲了,例程比较多,其中显示画点的函数需要先测试调通;
```C
/*Flush the content of the internal buffer the specific area on the display
*You can use DMA or any hardware acceleration to do this operation in the background but
*'lv_disp_flush_ready()' has to be called when finished.*/
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
if(disp_flush_enabled) {
/*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
int32_t x;
int32_t y;
for(y = area->y1; y y2; y++) {
for(x = area->x1; x x2; x++) {
/*Put a pixel to the display. For example:*/
/*put_px(x, y, *color_p)*/
POINT_COLOR=color_p->full;
LCD_DrawPoint(x,y);//画一个点
color_p++;
}
}
}
/*IMPORTANT!!!
*Inform the graphics library that you are ready with the flushing*/
lv_disp_flush_ready(disp_drv);
}
```
初始化函数,也是官方的例程,需要跑通,我这里没有使用触摸,先显示图形界面,确保整个移植业务流程跑通
```C
LCD_Init(); //液晶屏初始化,就是LCD显示驱动
lv_init(); // LVGL 初始化
lv_port_disp_init(); // 注册LVGL的显示任务
// lv_port_indev_init(); // 注册LVGL的触屏检测任务,没有触摸可以屏蔽
// HAL_TIM_Base_Start_IT(&htim6); //也可以先取消,这个用于lvgl业务处理
// 按钮
lv_obj_t *myBtn = lv_btn_create(lv_scr_act()); // 创建按钮; 父对象:当前活动屏幕
lv_obj_set_pos(myBtn, 10, 10); // 设置坐标
lv_obj_set_size(myBtn, 120, 50); // 设置大小
// 按钮上的文本
lv_obj_t *label_btn = lv_label_create(myBtn); // 创建文本标签,父对象:上面的btn按钮
lv_obj_align(label_btn, LV_ALIGN_CENTER, 0, 0); // 对齐于:父对象
lv_label_set_text(label_btn, "Test"); // 设置标签的文本
// 独立的标签
lv_obj_t *myLabel = lv_label_create(lv_scr_act()); // 创建文本标签; 父对象:当前活动屏幕
lv_label_set_text(myLabel, "Hello world!"); // 设置标签的文本
lv_obj_align(myLabel, LV_ALIGN_CENTER, 0, 0); // 对齐于:父对象
lv_obj_align_to(myBtn, myLabel, LV_ALIGN_OUT_TOP_MID, 0, -20); // 对齐于:某对象
```
程序烧录之后,能显示界面,说明LVGL例程移植没有问题;
![image-20240813155642646](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240813155642646.png)
能出现这个界面,说明整个移植过程没有问题,后续将使用的LVGL界面文件添加进来,并进行初始化。
```
setup_ui(&guider_ui); // 初始化 UI
events_init(&guider_ui); // 初始化 事件
```
最后,实现结果如下:
![image-20240813155906189](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240813155906189.png)
后续针对LVGL进行优化设计;
- 2024-08-09
-
发表了主题帖:
NUCLEO-H533RE开发板测评07(SPI应用)
本次测评下SPI接口,采用4.0的LCD的屏幕
![image-20240809212109658](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240809212109658.png)
硬件接口如下:
| 序号 | 引脚标号 | 说明 |
| ------------------------------------------------------------ | --------- | --------------------------------------------------- |
| 1 | VCC | 5V/3.3V电源输入 |
| 2 | GND | 接地 |
| 3 | CS | 液晶屏片选信号,低电平使能 |
| 4 | RESET | 液晶屏复位信号,低电平复位 |
| 5 | DC/RS | 液晶屏命令/数据选择信号,低电平:命令,高电平:数据 |
| 6 | SDI(MOSI) | 液晶屏SPI总线写数据信号 |
| 7 | SCK | 液晶屏SPI总线时钟信号 |
| 8 | LED | 背光控制,高电平点亮,如无需控制则接3.3V常亮 |
| 9 | SDO(MISO) | SPI总线读数据信号,如无需读取功能则可不接 |
| (以下为触摸屏信号线接线,如无需触摸或者模块本身不带触摸功能,可不连接) | | |
| 10 | T_CLK | 触摸SPI总线时钟信号 |
| 11 | T_CS | 触摸屏片选信号,低电平使能 |
| 12 | T_DIN | 触摸SPI总线输入 |
| 13 | T_DO | 触摸SPI总线输出 |
| 14 | T_IRQ | 触摸屏中断信号,检测到触摸时为低电平 |
软件编程:
CubeMX设置
配置SPI为全双工
![image-20240809212847806](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240809212847806.png)
![image-20240809212904634](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240809212904634.png)
设置波特率为20Mbit/s,也可以设置更高,理论上可以达到100MBit/s;这里采用杜邦线连接,最高时速达不到;
总界面配置如下:
![image-20240809213112597](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240809213112597.png)
采用SPI1通讯;
软件代码程序编程:
SPI写函数:
```C
u8 SPI_WriteByte(SPI_TypeDef* SPIx,u8 Byte)
{
HAL_SPI_Transmit(&hspi1, &Byte, 1, 0x100);
}
```
GPIO口配置函数
```C
void LCD_GPIOInit(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin : PA5 */
GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
```
LCD初始化函数:
```C
void LCD_Init(void)
{
// SPI1_Init(); //硬件SPI1初始化
LCD_GPIOInit();//LCD GPIO初始化
LCD_RESET(); //LCD 复位
//*************4.0inch ILI9486初始化**********//
LCD_WR_REG(0XF1);
LCD_WR_DATA(0x36);
LCD_WR_DATA(0x04);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x3C);
LCD_WR_DATA(0X0F);
LCD_WR_DATA(0x8F);
LCD_WR_REG(0XF2);
LCD_WR_DATA(0x18);
LCD_WR_DATA(0xA3);
LCD_WR_DATA(0x12);
LCD_WR_DATA(0x02);
LCD_WR_DATA(0XB2);
LCD_WR_DATA(0x12);
LCD_WR_DATA(0xFF);
LCD_WR_DATA(0x10);
LCD_WR_DATA(0x00);
LCD_WR_REG(0XF8);
LCD_WR_DATA(0x21);
LCD_WR_DATA(0x04);
LCD_WR_REG(0XF9);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x08);
LCD_WR_REG(0x36);
LCD_WR_DATA(0x08);
LCD_WR_REG(0xB4);
LCD_WR_DATA(0x00);
LCD_WR_REG(0xC1);
LCD_WR_DATA(0x47); //0x41
LCD_WR_REG(0xC5);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0xAF); //0x91
LCD_WR_DATA(0x80);
LCD_WR_DATA(0x00);
LCD_WR_REG(0xE0);
LCD_WR_DATA(0x0F);
LCD_WR_DATA(0x1F);
LCD_WR_DATA(0x1C);
LCD_WR_DATA(0x0C);
LCD_WR_DATA(0x0F);
LCD_WR_DATA(0x08);
LCD_WR_DATA(0x48);
LCD_WR_DATA(0x98);
LCD_WR_DATA(0x37);
LCD_WR_DATA(0x0A);
LCD_WR_DATA(0x13);
LCD_WR_DATA(0x04);
LCD_WR_DATA(0x11);
LCD_WR_DATA(0x0D);
LCD_WR_DATA(0x00);
LCD_WR_REG(0xE1);
LCD_WR_DATA(0x0F);
LCD_WR_DATA(0x32);
LCD_WR_DATA(0x2E);
LCD_WR_DATA(0x0B);
LCD_WR_DATA(0x0D);
LCD_WR_DATA(0x05);
LCD_WR_DATA(0x47);
LCD_WR_DATA(0x75);
LCD_WR_DATA(0x37);
LCD_WR_DATA(0x06);
LCD_WR_DATA(0x10);
LCD_WR_DATA(0x03);
LCD_WR_DATA(0x24);
LCD_WR_DATA(0x20);
LCD_WR_DATA(0x00);
LCD_WR_REG(0x3A);
LCD_WR_DATA(0x66);
LCD_WR_REG(0x11);
LCD_WR_REG(0x36);
LCD_WR_DATA(0x28);
HAL_Delay(120);
LCD_WR_REG(0x29);
LCD_direction(USE_HORIZONTAL);//设置LCD显示方向
// LCD_LED=1;//点亮背光
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET);
LCD_Clear(WHITE);//清全屏白色
}
```
英文字符显示:
```C
void English_Font_test(void)
{
DrawTestPage("测试5:英文显示测试");
Show_Str(10,30,BLUE,YELLOW,"6X12:abcdefghijklmnopqrstuvwxyz0123456789",12,0);
Show_Str(10,45,BLUE,YELLOW,"6X12:ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",12,1);
Show_Str(10,60,BLUE,YELLOW,"6X12:~!@#$%^&*()_+{}:?/|-+.",12,0);
Show_Str(10,80,BLUE,YELLOW,"8X16:abcdefghijklmnopqrstuvwxyz0123456789",16,0);
Show_Str(10,100,BLUE,YELLOW,"8X16:ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",16,1);
Show_Str(10,120,BLUE,YELLOW,"8X16:~!@#$%^&*()_+{}:?/|-+.",16,0);
HAL_Delay(1200);
}
```
实现结果:
![image-20240809222227032](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240809222227032.png)
中文显示:
```C
void Chinese_Font_test(void)
{
DrawTestPage("测试6:中文显示测试");
Show_Str(10,30,BLUE,YELLOW,"16X16:字体测试",16,0);
Show_Str(10,50,BLUE,YELLOW,"16X16:字体测试",16,0);
Show_Str(10,70,BLUE,YELLOW,"24X24:中文测试",24,1);
Show_Str(10,100,BLUE,YELLOW,"32X32:字体测试",32,1);
HAL_Delay(1200);
}
```
实现结果:
![image-20240809222911415](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240809222911415.png)
- 2024-08-07
-
发表了主题帖:
NUCLEO-H533RE开发板测评06(IIC应用)
## 6:IIC驱动
使用硬件IIC来驱动OLED显示,查看板子的IIC接口。
![image-20240807160214538](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240807160214538.png)
OLED显示接口:
![image-20240807160401461](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240807160401461.png)
cubemx配置接口
![image-20240807160454509](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240807160454509.png)
配置参数选择默认就好,IIC速度为100KHz;
IIC通讯时序图:
![image-20240807160959714](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240807160959714.png)
程序编写:
IIC初始化配置:
```C
I2C_HandleTypeDef hi2c1;
/* I2C1 init function */
void MX_I2C1_Init(void)
{
/* USER CODE BEGIN I2C1_Init 0 */
/* USER CODE END I2C1_Init 0 */
/* USER CODE BEGIN I2C1_Init 1 */
/* USER CODE END I2C1_Init 1 */
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x10909CEC;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
/** Configure Analogue filter
*/
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
{
Error_Handler();
}
/** Configure Digital filter
*/
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2C1_Init 2 */
/* USER CODE END I2C1_Init 2 */
}
```
关键的IIC读写函数
```
uint8_t CMD_Data[25]={
0xAE,//关闭显示
0xD5,//设置时钟分频因子,震荡频率
0x80, //[3:0],分频因子;[7:4],震荡频率
0xA8,//设置驱动路数
0X3F,//默认0X3F(1/64)
0xD3,//设置显示偏移
0X00,//默认为0
0x40,//设置显示开始行 [5:0],行数.
0x8D,//电荷泵设置
0x14,//bit2,开启/关闭
0x20,//设置内存地址模式
0x02,//[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
0xA1,//段重定义设置,bit0:0,0->0;1,0->127;
0xC8,//设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
0xDA,//设置COM硬件引脚配置
0x12,//[5:4]配置
0x81,//对比度设置
0xEF,//1~255;默认0X7F (亮度设置,越大越亮)
0xD9,//设置预充电周期
0xf1,//[3:0],PHASE 1;[7:4],PHASE 2;
0xDB,//设置VCOMH 电压倍率
0x30,//[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;
0xA4,//全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
0xA6,//设置显示方式;bit0:1,反相显示;0,正常显示
0xAF,//开启显示
}; //初始化命令
#define OLED_ADDRESS 0x78
void WriteCmd_init(void)
{
uint8_t i = 0;
for(i=0; i120){x=0;y+=2;}
j++;
}
}
void OLED_P8x16Str(uint8_t x,uint8_t y,uint8_t ch[])
{
uint8_t c=0,i=0,j=0;
while (ch[j]!='\0')
{
c =ch[j]-32;
if(x>120){x=0;y++;}
OLED_Set_Pos(x,y);
for(i=0;i
- 2024-07-31
-
发表了主题帖:
NUCLEO-H533RE开发板测评05(FreeRTOS应用)
## 5:FreeRTOS应用
### 5.1:CubeMX配置
打开现有工程,找到FreeRTOS的相关配置,如下:
![image-20240731110706756](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240731110706756.png)
当前配置为灰色,需要下载一下对应的资源包,以方便有对应的源码,进行install一下。
![image-20240731110836687](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240731110836687.png)
安装完成后,就有相应的freertos配置了。
![image-20240731110937585](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240731110937585.png)
安装完成之后进行配置:
![image-20240731111050368](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240731111050368.png)
接着配置RTOS
![image-20240731115508004](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240731115508004.png)
### 5.2:创建任务
我们创建2个任务,一个任务LED闪烁,一个任务串口1秒打印一次数据;
LED 闪烁任务:
```
void StartDefaultTask1(void *argument)
{
/* USER CODE BEGIN defaultTask */
/* Infinite loop */
for(;;)
{
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);
vTaskDelay(500);
}
/* USER CODE END defaultTask */
}
```
串口打印任务:
```
void StartDefaultTask2(void *argument)
{
/* USER CODE BEGIN defaultTask */
/* Infinite loop */
for(;;)
{
printf("1000ms\r\n");
vTaskDelay(1000);
}
/* USER CODE END defaultTask */
}
```
在“MX_FREERTOS_Init”函数中,初始化创建这两个任务:
```
xTaskCreate(
StartDefaultTask2, // 函数指针, 任务函数
"printf_task", // 任务的名字
200, // 栈大小,单位为word,10表示40字节
NULL, // 调用任务函数时传入的参数
osPriorityNormal, // 优先级
NULL); // 任务句柄, 以后使用它来操作这个任务
xTaskCreate(
StartDefaultTask1, // 函数指针, 任务函数
"led_task", // 任务的名字
200, // 栈大小,单位为word,10表示40字节
NULL, // 调用任务函数时传入的参数
osPriorityNormal, // 优先级
NULL); // 任务句柄, 以后使用它来操作这个任务
```
5.3:实现结果
可以根据串口输出,查看自己的任务是否执行;
![image-20240731120441787](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240731120441787.png)
- 2024-07-30
-
发表了主题帖:
NUCLEO-H533RE开发板测评04(IAP应用升级)
## 4:FLASH操作
### 4.1:flash説明
![image-20240716153824296](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240716153824296.png)
![image-20240716155759579](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240716155759579.png)
![image-20240716155823792](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240716155823792.png)
![image-20240716155857648](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240716155857648.png)
顾名思义,单片机的flash有512个字节,有2个存储库,分别为256个字节,前面在做擦除操作的时候,后面可以进行写入擦做,每个扇区大小为8,共64个扇区。现在的单片机越来越强大,功能也越来越多,这里先使用熟悉传统的读写操作。
其中FLASH操作函数为:
```C
HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, Address, ((uint32_t)QuadWord))
```
每次写入数据为16个字节,128位。参考函数定义说明:
```C
/**
* @brief Program a quad-word at a specified address.
* @param TypeProgram Indicate the way to program at a specified address.
* This parameter can be a value of @ref FLASH_Type_Program
* @param FlashAddress specifies the address to be programmed.
* This parameter shall be aligned to the Flash word (128-bit)
* @param DataAddress specifies the address of data to be programmed
* This parameter shall be 32-bit aligned
* @retval HAL_StatusTypeDef HAL Status
*/
HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t FlashAddress, uint32_t DataAddress)
```
FLASH读写程序:
```
/*在更新内部Flash时候禁用指令缓存*/
if (HAL_ICACHE_Disable() != HAL_OK)
{
Error_Handler();
}
/*解锁Flash以启用对Flash控制寄存器的访问*/
HAL_FLASH_Unlock();
/* 擦除用户Flash区域*/
/*(由Flash USER START ADDR和FLASH USER END _ADDR定义的区域)*/
/* Get the 1st sector to erase */
FirstSector = GetSector(FLASH_USER_START_ADDR);
gpio_port_set();
setSysRunState(STATE_RUN); //开始运行
uart_device_init(DEV_UART2); // 使能DMA接收
__HAL_LINKDMA(&huart2, hdmatx, handle_GPDMA1_Channel1); // 使能串口 DMA 发送
printf("init_ok\r\n");
setSysUpdateState(INIT);
printf("FLASH_BANK_SIZE=%d\r\n",FLASH_BANK_SIZE/1024);
/* Get the 1st sector to erase */
FirstSector = GetSector(FLASH_USER_START_ADDR);
printf("FirstSector=%d\r\n",FirstSector);
/* Get the number of sector to erase from 1st sector*/
NbOfSectors = GetSector(FLASH_USER_END_ADDR) - FirstSector + 1;
printf("NbOfSectors=%d\r\n",NbOfSectors);
/* Get the bank */
BankNumber = GetBank(FLASH_USER_START_ADDR);
printf("BankNumber=%d",BankNumber);
/* Fill EraseInit structure*/
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS; //擦除类型
EraseInitStruct.Banks = BankNumber;
EraseInitStruct.Sector = FirstSector;
EraseInitStruct.NbSectors = NbOfSectors;
if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK)
{
while (1)
{
Error_Handler();
}
}
Address = FLASH_USER_START_ADDR;
while (Address < FLASH_USER_END_ADDR)
{
/*往Flash里面写数据*/
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, Address, ((uint32_t)QuadWord)) == HAL_OK)
{
Address = Address + 16;
}
else
{
while (1)
{
Error_Handler();
}
}
}
/* 锁定Flash以禁止对Flash控制寄存器的访问 (建议用于保护FLASH存储器免受可能的意外操作) */
HAL_FLASH_Lock();
/* Re-enable instruction cache */
if(HAL_ICACHE_Enable() != HAL_OK)
{
Error_Handler();
}
MemoryProgramStatus = Check_Program(FLASH_USER_START_ADDR, FLASH_USER_END_ADDR, QuadWord);
/*Check if there is an issue to program data*/
if(MemoryProgramStatus != 0)
{
printf("Flash_Write_Read_Failure\r\n");
}
else
{
printf("Flash_Write_Read_Success\r\n");
}
```
### 4.2:FLASH设置
IAP程序设置
![image-20240730225734670](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240730225734670.png)
APP地址和标志位地址设置:
```
#define APP_START_ADDR 0x0800C000
#define APP_END_ADDR 0x08040000
#define IAP_UPGRADE_FLAG_ADDR (APP_END_ADDR-8192) //一个扇区有8K
```
APP程序设置
![image-20240730225758164](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240730225758164.png)
代码设置:
```C
SCB->VTOR = FLASH_BASE | 0xC000; //重映射向量表
```
APP跳转处理
```C
void iap_load_app(uint32_t appxaddr)
{
__disable_irq ();//关闭总中断
JumpAddress = *(__IO uint32_t*) (appxaddr + 4);
JumpToApplication = (pFunction) JumpAddress;
__set_MSP(*(__IO uint32_t*) appxaddr);//设置MSP堆栈指针值
JumpToApplication();
}
```
### 4.3:自定义通讯协议
| 名称 | 帧头 | 长度 | 具体数据 | 校验CRC16 |
| ---- | ------ | ------ | ------------------------ | --------- |
| 长度 | 2 | 2 | N | 2 |
| 值 | 0x55AA | 0x0101 | 包含命令,地址,数据等等 | 0x0102 |
### 4.4:上位机界面
![image-20240730230748526](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240730230748526.png)
### 4.5:实现过程
https://www.bilibili.com/video/BV1VFvCexEud/?vd_source=d89384d7551b55d1559dd2bf89310863
- 2024-07-22
-
回复了主题帖:
STM32H533样例程序出错
bigbat 发表于 2024-7-19 15:24
该项目是ST公司的例程ADC_MultiChannelSingleConversion
只要执行就回停在硬件出错循环里
&n ...
测试需要怎么接线,需要什么外设吗?
- 2024-07-16
-
回复了主题帖:
NUCLEO-H533RE开发板测评03(低功耗模式应用)
freebsder 发表于 2024-7-15 18:46
谢谢分享,期待后续!
大家一起学习交流
-
回复了主题帖:
NUCLEO-H533RE开发板测评03(低功耗模式应用)
怀揣少年梦 发表于 2024-7-15 21:49
我测试的好像没有这么高,我看看我哪里有问题
我测试的是,在低功耗模式是,睡眠,停止和待机模式,都是按键唤醒,加了任务,定时器这些,比你的功耗要高些,后续还需要优化
- 2024-07-15
-
发表了主题帖:
NUCLEO-H533RE开发板测评03(低功耗模式应用)
# 低功耗模式概述:
![image-20240715113933244](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240715113933244.png)
先说明下几个测电流接口:
![image-20240712112846019](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240712112846019.png)
测试电流接口:
![image-20240712113059852](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240712113059852.png)
DD measurement指测量供电电流。
### 3.1:睡眠模式
当中断/事件发生时,所有外围设备继续工作,并可以醒CPU。我们使用板载按键来实现唤醒。
![image-20240711174427807](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240711174427807.png)
設置PC13為外部中斷模式。
![image-20240711175521001](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240711175521001.png)
当前有以下几个任务:
1:RTC时钟任务;
2:定时器LED 灯闪烁任务
3:串口收发任务
编写代码:
使用状态机切换系统运行状态
```C
typedef enum
{
STATE_IDLE, /**< 空闲状态*/
STATE_RUN, /**< 运行状态*/
STATE_SLEEP, /**< 睡眠状态*/
STATE_STOP, /**< 停止模式*/
STATE_STANDBY, /**< 待机模式*/
}Run_State;
```
根据状态来切换运行模式:
```
void task4_hook(void)
{
RTC_TimeShow(aShowTime); //执行RTC任务
setTimeCountData(COUNT_ADD); //时间计数
GlobalData retrievedData = getData(); //获取计数值
printf("retrievedData.timeCount=%d\r\n",retrievedData.timeCount);
if(retrievedData.timeCount ==10)
{
setSysRunState(STATE_SLEEP); //进入睡眠模式测试
// setSysRunState(STATE_STOP); //进入停止模式测试
// setSysRunState(STATE_STANDBY); //进入待机模式测试
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET); //关闭LED灯
}
// DEBUG_LOG("1s\r\n");
}
```
```
// 状态转换函数
void transitionToNextState(void) {
GlobalData retrievedData = getData(); //获取信息
switch (retrievedData.sysRunState) {
case STATE_IDLE:
HAL_ResumeTick();
setTimeCountData(COUNT_ZERO); //计数清0
setSysRunState(STATE_RUN);
break;
case STATE_RUN:
//TODO
break;
case STATE_SLEEP:
/*进入睡眠模式前准备工作*/
printf("cpu run into sleep....rn");
HAL_SuspendTick(); /*暂停Tick增量以防止Systick中断唤醒。否则Systick中断将在1ms内唤醒设备*/
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
break;
case STATE_STOP:
/*进入停止模式前准备工作*/
printf("cpu run into stop....rn");
HAL_SuspendTick(); /*暂停Tick增量以防止Systick中断唤醒。否则Systick中断将在1ms内唤醒设备*/
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON,PWR_STOPENTRY_WFI);
break;
case STATE_STANDBY:
/*进入待机模式前准备工作*/
printf("cpu run into standby....rn");
HAL_SuspendTick(); /*暂停Tick增量以防止Systick中断唤醒。否则Systick中断将在1ms内唤醒设备*/
HAL_PWR_EnterSTANDBYMode();
break;
default:
break;
}
}
```
使用外部中断实现各个模式的唤醒
```
void EXTI13_IRQHandler(void)
{
/* USER CODE BEGIN EXTI13_IRQn 0 */
/* USER CODE END EXTI13_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
/* USER CODE BEGIN EXTI13_IRQn 1 */
/* USER CODE END EXTI13_IRQn 1 */
}
```
然后用万用表接到JP2两端,查看系统运行电流。
系统运行时工作电流:
![image-20240715103249627](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240715103249627.png)
功耗30ma左右;
进入睡眠模式电流:
![image-20240715103324650](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240715103324650.png)
功耗15ma左右;
停止模式功耗:
![image-20240715103637521](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240715103637521.png)
功耗0.34ma左右;
![image-20240715103724108](https://boreyun.oss-cn-shanghai.aliyuncs.com/image-20240715103724108.png)
功耗3.7ua左右;
具体视频如下:
https://www.bilibili.com/video/BV1jE4m1R7ay/?spm_id_from=333.999.0.0&vd_source=d89384d7551b55d1559dd2bf89310863
当前测试状态,使用按键来唤醒不同低功耗模式,整体功耗测试下来比官方的要高,后续针对具体低功耗要求进行优化。
- 2024-07-10
-
回复了主题帖:
NUCLEO-H533RE开发板测评02(串口-DMA-GPIO-定时器-RTC等各类外设实现)
Jacktang 发表于 2024-7-10 07:48
视频讲解的很细心啊,学习了
GPDMA還有一個 linked-list.還沒看,感覺也很有用