```
feat(bluetooth): 添加多按钮支持和WiFi连接音频反馈 添加MultiButton库支持多按键功能,重构SPI显示屏驱动代码, 迁移MP3音频文件至正确目录并集成WiFi连接状态音频提示音。 - 添加Multi_Button.c源文件和相关头文件包含 - 重构spi_st7735s.c中的数组初始化格式,优化代码可读性 - 将MP3音频文件从Development_Docs/MP3迁移到Core/Bsp/BSP_Device/bsp_mp3/MP3 - 在WiFi连接过程中添加MP3音频反馈(连接成功/失败提示音) - 优化ST7735显示屏驱动中的DMA传输模式支持 ```
This commit is contained in:
@@ -43,6 +43,7 @@ add_executable(${CMAKE_PROJECT_NAME}
|
||||
Core/Bsp/BSP_Device/spi_st7735s/spi_st7735s.c
|
||||
Core/Bsp/BSP_Device/spi_st7735s/fonts.c
|
||||
Core/Bsp/BSP_Device/bsp_mp3/mp3_driver.c
|
||||
Core/Bsp/MultiButton-master/Multi_Button.c
|
||||
)
|
||||
# Add STM32CubeMX generated sources
|
||||
add_subdirectory(cmake/stm32cubemx)
|
||||
@@ -68,6 +69,7 @@ target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE
|
||||
Core/Bsp/BSP_Device/device_ctrl
|
||||
Core/Bsp/BSP_Device/spi_st7735s
|
||||
Core/Bsp/BSP_Device/bsp_mp3
|
||||
Core/Bsp/MultiButton-master
|
||||
)
|
||||
|
||||
# Add project symbols (macros)
|
||||
|
||||
@@ -7,7 +7,7 @@ extern "C" {
|
||||
|
||||
#include "stm32f1xx_hal.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#include "mp3_play_index.h"
|
||||
/* MP3命令定义 */
|
||||
#define MP3_HEADER 0x7E // 帧头
|
||||
#define MP3_VERSION 0xFF // 版本号
|
||||
|
||||
@@ -6,117 +6,185 @@
|
||||
#define DELAY 0x80
|
||||
|
||||
// based on Adafruit ST7735 library for Arduino
|
||||
static const uint8_t
|
||||
init_cmds1[] = { // Init for 7735R, part 1 (red or green tab)
|
||||
static const uint8_t init_cmds1[] =
|
||||
{ // Init for 7735R, part 1 (red or green tab)
|
||||
15, // 15 commands in list:
|
||||
ST7735_SWRESET, DELAY, // 1: Software reset, 0 args, w/delay
|
||||
ST7735_SWRESET,
|
||||
DELAY, // 1: Software reset, 0 args, w/delay
|
||||
150, // 150 ms delay
|
||||
ST7735_SLPOUT, DELAY, // 2: Out of sleep mode, 0 args, w/delay
|
||||
ST7735_SLPOUT,
|
||||
DELAY, // 2: Out of sleep mode, 0 args, w/delay
|
||||
255, // 500 ms delay
|
||||
ST7735_FRMCTR1, 3, // 3: Frame rate ctrl - normal mode, 3 args:
|
||||
0x01, 0x2C, 0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D)
|
||||
ST7735_FRMCTR2, 3, // 4: Frame rate control - idle mode, 3 args:
|
||||
0x01, 0x2C, 0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D)
|
||||
ST7735_FRMCTR3, 6, // 5: Frame rate ctrl - partial mode, 6 args:
|
||||
0x01, 0x2C, 0x2D, // Dot inversion mode
|
||||
0x01, 0x2C, 0x2D, // Line inversion mode
|
||||
ST7735_INVCTR, 1, // 6: Display inversion ctrl, 1 arg, no delay:
|
||||
ST7735_FRMCTR1,
|
||||
3, // 3: Frame rate ctrl - normal mode, 3 args:
|
||||
0x01,
|
||||
0x2C,
|
||||
0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D)
|
||||
ST7735_FRMCTR2,
|
||||
3, // 4: Frame rate control - idle mode, 3 args:
|
||||
0x01,
|
||||
0x2C,
|
||||
0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D)
|
||||
ST7735_FRMCTR3,
|
||||
6, // 5: Frame rate ctrl - partial mode, 6 args:
|
||||
0x01,
|
||||
0x2C,
|
||||
0x2D, // Dot inversion mode
|
||||
0x01,
|
||||
0x2C,
|
||||
0x2D, // Line inversion mode
|
||||
ST7735_INVCTR,
|
||||
1, // 6: Display inversion ctrl, 1 arg, no delay:
|
||||
0x07, // No inversion
|
||||
ST7735_PWCTR1, 3, // 7: Power control, 3 args, no delay:
|
||||
ST7735_PWCTR1,
|
||||
3, // 7: Power control, 3 args, no delay:
|
||||
0xA2,
|
||||
0x02, // -4.6V
|
||||
0x84, // AUTO mode
|
||||
ST7735_PWCTR2, 1, // 8: Power control, 1 arg, no delay:
|
||||
ST7735_PWCTR2,
|
||||
1, // 8: Power control, 1 arg, no delay:
|
||||
0xC5, // VGH25 = 2.4C VGSEL = -10 VGH = 3 * AVDD
|
||||
ST7735_PWCTR3, 2, // 9: Power control, 2 args, no delay:
|
||||
ST7735_PWCTR3,
|
||||
2, // 9: Power control, 2 args, no delay:
|
||||
0x0A, // Opamp current small
|
||||
0x00, // Boost frequency
|
||||
ST7735_PWCTR4, 2, // 10: Power control, 2 args, no delay:
|
||||
ST7735_PWCTR4,
|
||||
2, // 10: Power control, 2 args, no delay:
|
||||
0x8A, // BCLK/2, Opamp current small & Medium low
|
||||
0x2A,
|
||||
ST7735_PWCTR5, 2, // 11: Power control, 2 args, no delay:
|
||||
0x8A, 0xEE,
|
||||
ST7735_VMCTR1, 1, // 12: Power control, 1 arg, no delay:
|
||||
ST7735_PWCTR5,
|
||||
2, // 11: Power control, 2 args, no delay:
|
||||
0x8A,
|
||||
0xEE,
|
||||
ST7735_VMCTR1,
|
||||
1, // 12: Power control, 1 arg, no delay:
|
||||
0x0E,
|
||||
ST7735_INVOFF, 0, // 13: Don't invert display, no args, no delay
|
||||
ST7735_MADCTL, 1, // 14: Memory access control (directions), 1 arg:
|
||||
ST7735_INVOFF,
|
||||
0, // 13: Don't invert display, no args, no delay
|
||||
ST7735_MADCTL,
|
||||
1, // 14: Memory access control (directions), 1 arg:
|
||||
ST7735_ROTATION, // row addr/col addr, bottom to top refresh
|
||||
ST7735_COLMOD, 1, // 15: set color mode, 1 arg, no delay:
|
||||
ST7735_COLMOD,
|
||||
1, // 15: set color mode, 1 arg, no delay:
|
||||
0x05}, // 16-bit color
|
||||
|
||||
#if (defined(ST7735_IS_128X128) || defined(ST7735_IS_160X128))
|
||||
init_cmds2[] = { // Init for 7735R, part 2 (1.44" display)
|
||||
init_cmds2[] =
|
||||
{ // Init for 7735R, part 2 (1.44" display)
|
||||
2, // 2 commands in list:
|
||||
ST7735_CASET, 4, // 1: Column addr set, 4 args, no delay:
|
||||
0x00, 0x00, // XSTART = 0
|
||||
0x00, 0x7F, // XEND = 127
|
||||
ST7735_RASET, 4, // 2: Row addr set, 4 args, no delay:
|
||||
0x00, 0x00, // XSTART = 0
|
||||
0x00, 0x7F}, // XEND = 127
|
||||
ST7735_CASET,
|
||||
4, // 1: Column addr set, 4 args, no delay:
|
||||
0x00,
|
||||
0x00, // XSTART = 0
|
||||
0x00,
|
||||
0x7F, // XEND = 127
|
||||
ST7735_RASET,
|
||||
4, // 2: Row addr set, 4 args, no delay:
|
||||
0x00,
|
||||
0x00, // XSTART = 0
|
||||
0x00,
|
||||
0x7F}, // XEND = 127
|
||||
#endif // ST7735_IS_128X128
|
||||
|
||||
#ifdef ST7735_IS_160X80
|
||||
init_cmds2[] = { // Init for 7735S, part 2 (160x80 display)
|
||||
init_cmds2[] =
|
||||
{ // Init for 7735S, part 2 (160x80 display)
|
||||
3, // 3 commands in list:
|
||||
ST7735_CASET, 4, // 1: Column addr set, 4 args, no delay:
|
||||
0x00, 0x00, // XSTART = 0
|
||||
0x00, 0x4F, // XEND = 79
|
||||
ST7735_RASET, 4, // 2: Row addr set, 4 args, no delay:
|
||||
0x00, 0x00, // XSTART = 0
|
||||
0x00, 0x9F, // XEND = 159
|
||||
ST7735_INVON, 0}, // 3: Invert colors
|
||||
ST7735_CASET,
|
||||
4, // 1: Column addr set, 4 args, no delay:
|
||||
0x00,
|
||||
0x00, // XSTART = 0
|
||||
0x00,
|
||||
0x4F, // XEND = 79
|
||||
ST7735_RASET,
|
||||
4, // 2: Row addr set, 4 args, no delay:
|
||||
0x00,
|
||||
0x00, // XSTART = 0
|
||||
0x00,
|
||||
0x9F, // XEND = 159
|
||||
ST7735_INVON,
|
||||
0}, // 3: Invert colors
|
||||
#endif
|
||||
|
||||
init_cmds3[] = { // Init for 7735R, part 3 (red or green tab)
|
||||
4, // 4 commands in list:
|
||||
ST7735_GMCTRP1, 16, // 1: Gamma Adjustments (pos. polarity), 16 args, no delay:
|
||||
0x02, 0x1c, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2d, 0x29, 0x25, 0x2B, 0x39, 0x00, 0x01, 0x03, 0x10, ST7735_GMCTRN1, 16, // 2: Gamma Adjustments (neg. polarity), 16 args, no delay:
|
||||
0x03, 0x1d, 0x07, 0x06, 0x2E, 0x2C, 0x29, 0x2D, 0x2E, 0x2E, 0x37, 0x3F, 0x00, 0x00, 0x02, 0x10, ST7735_NORON, DELAY, // 3: Normal display on, no args, w/delay
|
||||
ST7735_GMCTRP1,
|
||||
16, // 1: Gamma Adjustments (pos. polarity), 16 args, no delay:
|
||||
0x02,
|
||||
0x1c,
|
||||
0x07,
|
||||
0x12,
|
||||
0x37,
|
||||
0x32,
|
||||
0x29,
|
||||
0x2d,
|
||||
0x29,
|
||||
0x25,
|
||||
0x2B,
|
||||
0x39,
|
||||
0x00,
|
||||
0x01,
|
||||
0x03,
|
||||
0x10,
|
||||
ST7735_GMCTRN1,
|
||||
16, // 2: Gamma Adjustments (neg. polarity), 16 args, no delay:
|
||||
0x03,
|
||||
0x1d,
|
||||
0x07,
|
||||
0x06,
|
||||
0x2E,
|
||||
0x2C,
|
||||
0x29,
|
||||
0x2D,
|
||||
0x2E,
|
||||
0x2E,
|
||||
0x37,
|
||||
0x3F,
|
||||
0x00,
|
||||
0x00,
|
||||
0x02,
|
||||
0x10,
|
||||
ST7735_NORON,
|
||||
DELAY, // 3: Normal display on, no args, w/delay
|
||||
10, // 10 ms delay
|
||||
ST7735_DISPON, DELAY, // 4: Main screen turn on, no args w/delay
|
||||
ST7735_DISPON,
|
||||
DELAY, // 4: Main screen turn on, no args w/delay
|
||||
100}; // 100 ms delay
|
||||
|
||||
static void ST7735_Select()
|
||||
{
|
||||
static void ST7735_Select() {
|
||||
HAL_GPIO_WritePin(ST7735_CS_GPIO_Port, ST7735_CS_Pin, GPIO_PIN_RESET);
|
||||
}
|
||||
|
||||
void ST7735_Unselect()
|
||||
{
|
||||
void ST7735_Unselect() {
|
||||
HAL_GPIO_WritePin(ST7735_CS_GPIO_Port, ST7735_CS_Pin, GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
static void ST7735_Reset()
|
||||
{
|
||||
static void ST7735_Reset() {
|
||||
HAL_GPIO_WritePin(ST7735_RES_GPIO_Port, ST7735_RES_Pin, GPIO_PIN_RESET);
|
||||
HAL_Delay(5);
|
||||
HAL_GPIO_WritePin(ST7735_RES_GPIO_Port, ST7735_RES_Pin, GPIO_PIN_SET);
|
||||
}
|
||||
|
||||
static void ST7735_WriteCommand(uint8_t cmd)
|
||||
{
|
||||
static void ST7735_WriteCommand(uint8_t cmd) {
|
||||
HAL_GPIO_WritePin(ST7735_DC_GPIO_Port, ST7735_DC_Pin, GPIO_PIN_RESET);
|
||||
|
||||
HAL_SPI_Transmit(&ST7735_SPI_PORT, &cmd, sizeof(cmd), HAL_MAX_DELAY);
|
||||
// HAL_SPI_Transmit_DMA(&ST7735_SPI_PORT, &cmd, sizeof(cmd));
|
||||
}
|
||||
|
||||
static void ST7735_WriteData(uint8_t *buff, size_t buff_size)
|
||||
{
|
||||
static void ST7735_WriteData(uint8_t *buff, size_t buff_size) {
|
||||
HAL_GPIO_WritePin(ST7735_DC_GPIO_Port, ST7735_DC_Pin, GPIO_PIN_SET);
|
||||
|
||||
HAL_SPI_Transmit(&ST7735_SPI_PORT, buff, buff_size, HAL_MAX_DELAY);
|
||||
// HAL_SPI_Transmit_DMA(&ST7735_SPI_PORT, buff, buff_size);
|
||||
}
|
||||
|
||||
static void ST7735_ExecuteCommandList(const uint8_t *addr)
|
||||
{
|
||||
static void ST7735_ExecuteCommandList(const uint8_t *addr) {
|
||||
uint8_t numCommands, numArgs;
|
||||
uint16_t ms;
|
||||
|
||||
numCommands = *addr++;
|
||||
while (numCommands--)
|
||||
{
|
||||
while (numCommands--) {
|
||||
uint8_t cmd = *addr++;
|
||||
ST7735_WriteCommand(cmd);
|
||||
|
||||
@@ -124,14 +192,12 @@ static void ST7735_ExecuteCommandList(const uint8_t *addr)
|
||||
// If high bit set, delay follows args
|
||||
ms = numArgs & DELAY;
|
||||
numArgs &= ~DELAY;
|
||||
if (numArgs)
|
||||
{
|
||||
if (numArgs) {
|
||||
ST7735_WriteData((uint8_t *)addr, numArgs);
|
||||
addr += numArgs;
|
||||
}
|
||||
|
||||
if (ms)
|
||||
{
|
||||
if (ms) {
|
||||
ms = *addr++;
|
||||
if (ms == 255)
|
||||
ms = 500;
|
||||
@@ -151,8 +217,8 @@ static void ST7735_ExecuteCommandList(const uint8_t *addr)
|
||||
* @param x1 显示窗口右下角的X坐标
|
||||
* @param y1 显示窗口右下角的Y坐标
|
||||
*/
|
||||
static void ST7735_SetAddressWindow(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1)
|
||||
{
|
||||
static void ST7735_SetAddressWindow(uint8_t x0, uint8_t y0, uint8_t x1,
|
||||
uint8_t y1) {
|
||||
// column address set
|
||||
ST7735_WriteCommand(ST7735_CASET);
|
||||
// 设置列地址范围,考虑到显示区域的起始偏移
|
||||
@@ -178,8 +244,7 @@ static void ST7735_SetAddressWindow(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t
|
||||
* 以及初始化完成后填充屏幕为黄色。这些操作确保了显示器能够正确配置并进入
|
||||
* 可显示状态。
|
||||
*/
|
||||
void ST7735_Init()
|
||||
{
|
||||
void ST7735_Init() {
|
||||
// 选择ST7735设备,准备进行初始化
|
||||
ST7735_Select();
|
||||
|
||||
@@ -216,8 +281,7 @@ void ST7735_Init()
|
||||
* @param y 纵坐标,表示像素点在显示屏上的垂直位置。
|
||||
* @param color 像素点的颜色值,采用RGB565格式。
|
||||
*/
|
||||
void ST7735_DrawPixel(uint16_t x, uint16_t y, uint16_t color)
|
||||
{
|
||||
void ST7735_DrawPixel(uint16_t x, uint16_t y, uint16_t color) {
|
||||
// 检查坐标是否超出显示屏边界
|
||||
if ((x >= ST7735_WIDTH) || (y >= ST7735_HEIGHT))
|
||||
return;
|
||||
@@ -254,8 +318,8 @@ void ST7735_DrawPixel(uint16_t x, uint16_t y, uint16_t color)
|
||||
* @param color 字符的颜色
|
||||
* @param bgcolor 背景颜色
|
||||
*/
|
||||
static void ST7735_WriteChar(uint16_t x, uint16_t y, char ch, FontDef *font, uint16_t color, uint16_t bgcolor)
|
||||
{
|
||||
static void ST7735_WriteChar(uint16_t x, uint16_t y, char ch, FontDef *font,
|
||||
uint16_t color, uint16_t bgcolor) {
|
||||
// 定义循环变量和临时变量
|
||||
uint32_t i, b, j;
|
||||
|
||||
@@ -263,25 +327,24 @@ static void ST7735_WriteChar(uint16_t x, uint16_t y, char ch, FontDef *font, uin
|
||||
ST7735_SetAddressWindow(x, y, x + font->width - 1, y + font->height - 1);
|
||||
|
||||
// 遍历字符的每一行
|
||||
for (i = 0; i < font->height; i++)
|
||||
{
|
||||
for (i = 0; i < font->height; i++) {
|
||||
// 获取当前行的字形数据
|
||||
b = font->data[(ch - 32) * font->height + i];
|
||||
// 遍历当前行的每一列
|
||||
for (j = 0; j < font->width; j++)
|
||||
{
|
||||
for (j = 0; j < font->width; j++) {
|
||||
// 检查当前列是否为前景色
|
||||
if ((b << j) & 0x8000)
|
||||
{
|
||||
if ((b << j) & 0x8000) {
|
||||
// 是前景色,则发送颜色数据到显示屏
|
||||
uint8_t data[] = {color >> 8, color & 0xFF};
|
||||
ST7735_WriteData(data, sizeof(data));
|
||||
}
|
||||
else
|
||||
{
|
||||
// ST7735_WriteData(data, sizeof(data));
|
||||
HAL_GPIO_WritePin(ST7735_DC_GPIO_Port, ST7735_DC_Pin, GPIO_PIN_SET);
|
||||
HAL_SPI_Transmit_DMA(&ST7735_SPI_PORT, data, sizeof(data));
|
||||
} else {
|
||||
// 不是前景色,则发送背景色数据到显示屏
|
||||
uint8_t data[] = {bgcolor >> 8, bgcolor & 0xFF};
|
||||
ST7735_WriteData(data, sizeof(data));
|
||||
// ST7735_WriteData(data, sizeof(data));
|
||||
HAL_GPIO_WritePin(ST7735_DC_GPIO_Port, ST7735_DC_Pin, GPIO_PIN_SET);
|
||||
HAL_SPI_Transmit_DMA(&ST7735_SPI_PORT, data, sizeof(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -290,8 +353,8 @@ static void ST7735_WriteChar(uint16_t x, uint16_t y, char ch, FontDef *font, uin
|
||||
/*
|
||||
Simpler (and probably slower) implementation:
|
||||
|
||||
static void ST7735_WriteChar(uint16_t x, uint16_t y, char ch, FontDef font, uint16_t color) {
|
||||
uint32_t i, b, j;
|
||||
static void ST7735_WriteChar(uint16_t x, uint16_t y, char ch, FontDef font,
|
||||
uint16_t color) { uint32_t i, b, j;
|
||||
|
||||
for(i = 0; i < font->height; i++) {
|
||||
b = font->data[(ch - 32) * font->height + i];
|
||||
@@ -304,23 +367,19 @@ static void ST7735_WriteChar(uint16_t x, uint16_t y, char ch, FontDef font, uint
|
||||
}
|
||||
*/
|
||||
|
||||
void ST7735_WriteString(uint16_t x, uint16_t y, const char *str, FontDef *font, uint16_t color, uint16_t bgcolor)
|
||||
{
|
||||
void ST7735_WriteString(uint16_t x, uint16_t y, const char *str, FontDef *font,
|
||||
uint16_t color, uint16_t bgcolor) {
|
||||
ST7735_Select();
|
||||
|
||||
while (*str)
|
||||
{
|
||||
if (x + font->width >= ST7735_WIDTH)
|
||||
{
|
||||
while (*str) {
|
||||
if (x + font->width >= ST7735_WIDTH) {
|
||||
x = 0;
|
||||
y += font->height;
|
||||
if (y + font->height >= ST7735_HEIGHT)
|
||||
{
|
||||
if (y + font->height >= ST7735_HEIGHT) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (*str == ' ')
|
||||
{
|
||||
if (*str == ' ') {
|
||||
// skip spaces in the beginning of the new line
|
||||
str++;
|
||||
continue;
|
||||
@@ -348,8 +407,8 @@ void ST7735_WriteString(uint16_t x, uint16_t y, const char *str, FontDef *font,
|
||||
* @param h 矩形的高度
|
||||
* @param color 用于填充矩形的颜色
|
||||
*/
|
||||
void ST7735_FillRectangle(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color)
|
||||
{
|
||||
void ST7735_FillRectangle(uint16_t x, uint16_t y, uint16_t w, uint16_t h,
|
||||
uint16_t color) {
|
||||
// clipping
|
||||
if ((x >= ST7735_WIDTH) || (y >= ST7735_HEIGHT))
|
||||
return;
|
||||
@@ -368,12 +427,11 @@ void ST7735_FillRectangle(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16
|
||||
// Set the data/command pin to data mode
|
||||
HAL_GPIO_WritePin(ST7735_DC_GPIO_Port, ST7735_DC_Pin, GPIO_PIN_SET);
|
||||
// Send the color data for each pixel in the rectangle
|
||||
for (y = h; y > 0; y--)
|
||||
{
|
||||
for (x = w; x > 0; x--)
|
||||
{
|
||||
for (y = h; y > 0; y--) {
|
||||
for (x = w; x > 0; x--) {
|
||||
|
||||
// HAL_SPI_Transmit(&ST7735_SPI_PORT, data, sizeof(data), HAL_MAX_DELAY);
|
||||
// HAL_SPI_Transmit(&ST7735_SPI_PORT, data, sizeof(data),
|
||||
// HAL_MAX_DELAY);
|
||||
HAL_SPI_Transmit_DMA(&ST7735_SPI_PORT, data, sizeof(data));
|
||||
}
|
||||
}
|
||||
@@ -384,8 +442,8 @@ void ST7735_FillRectangle(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16
|
||||
|
||||
// Fill a rectangle area on the ST7735 LCD screen with a specified color
|
||||
// This function is optimized for speed, suitable for filling large areas
|
||||
void ST7735_FillRectangleFast(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color)
|
||||
{
|
||||
void ST7735_FillRectangleFast(uint16_t x, uint16_t y, uint16_t w, uint16_t h,
|
||||
uint16_t color) {
|
||||
// clipping
|
||||
if ((x >= ST7735_WIDTH) || (y >= ST7735_HEIGHT))
|
||||
return;
|
||||
@@ -417,10 +475,11 @@ void ST7735_FillRectangleFast(uint16_t x, uint16_t y, uint16_t w, uint16_t h, ui
|
||||
*
|
||||
* @param color 要填充的颜色值。
|
||||
*/
|
||||
void ST7735_FillScreen(uint16_t color)
|
||||
{
|
||||
// 使用FillRectangle函数填充整个屏幕,起始坐标为(0, 0),覆盖整个屏幕宽度和高度。
|
||||
ST7735_FillRectangle(0, 0, ST7735_WIDTH, ST7735_HEIGHT, color);
|
||||
void ST7735_FillScreen(uint16_t color) {
|
||||
// 使用FillRectangle函数填充整个屏幕,起始坐标为(0,
|
||||
// 0),覆盖整个屏幕宽度和高度。
|
||||
// ST7735_FillRectangle(0, 0, ST7735_WIDTH, ST7735_HEIGHT, color);
|
||||
ST7735_FillRectangleFast(0, 0, ST7735_WIDTH, ST7735_HEIGHT, color);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -429,12 +488,12 @@ void ST7735_FillScreen(uint16_t color)
|
||||
* 使用指定的颜色填充整个屏幕。该函数通过调用ST7735_FillRectangleFast函数,
|
||||
* 设置填充区域为整个屏幕的宽度和高度来实现快速填充屏幕的效果。
|
||||
*
|
||||
* @param color 填充屏幕所使用的颜色值。这是一个16位的颜色值,适用于ST7735显示屏。
|
||||
* @param color
|
||||
* 填充屏幕所使用的颜色值。这是一个16位的颜色值,适用于ST7735显示屏。
|
||||
*/
|
||||
void ST7735_FillScreenFast(uint16_t color)
|
||||
{
|
||||
// 调用快速填充矩形函数,参数为(起始X坐标, 起始Y坐标, 屏幕宽度, 屏幕高度, 颜色)
|
||||
// 用于填充整个屏幕为指定的颜色
|
||||
void ST7735_FillScreenFast(uint16_t color) {
|
||||
// 调用快速填充矩形函数,参数为(起始X坐标, 起始Y坐标, 屏幕宽度, 屏幕高度,
|
||||
// 颜色) 用于填充整个屏幕为指定的颜色
|
||||
ST7735_FillRectangleFast(0, 0, ST7735_WIDTH, ST7735_HEIGHT, color);
|
||||
}
|
||||
|
||||
@@ -451,8 +510,8 @@ void ST7735_FillScreenFast(uint16_t color)
|
||||
* @param h 图像的高度
|
||||
* @param data 图像数据指针,图像数据是16位的RGB565格式
|
||||
*/
|
||||
void ST7735_DrawImage(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint16_t *data)
|
||||
{
|
||||
void ST7735_DrawImage(uint16_t x, uint16_t y, uint16_t w, uint16_t h,
|
||||
const uint16_t *data) {
|
||||
// 检查图像的起始坐标是否超出液晶屏的边界
|
||||
if ((x >= ST7735_WIDTH) || (y >= ST7735_HEIGHT))
|
||||
return;
|
||||
@@ -481,10 +540,10 @@ void ST7735_DrawImage(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint
|
||||
/**
|
||||
* ST7735_InvertColors函数用于控制ST7735显示屏的颜色反转功能。
|
||||
*
|
||||
* @param invert 一个布尔值,决定是否反转显示屏的颜色。如果invert为true,颜色将反转;如果为false,颜色将保持正常。
|
||||
* @param invert
|
||||
* 一个布尔值,决定是否反转显示屏的颜色。如果invert为true,颜色将反转;如果为false,颜色将保持正常。
|
||||
*/
|
||||
void ST7735_InvertColors(bool invert)
|
||||
{
|
||||
void ST7735_InvertColors(bool invert) {
|
||||
// 选择ST7735显示屏以进行通信。
|
||||
ST7735_Select();
|
||||
|
||||
@@ -503,8 +562,7 @@ void ST7735_InvertColors(bool invert)
|
||||
*
|
||||
* @param gamma 伽马曲线定义,指定要设置的伽马曲线
|
||||
*/
|
||||
void ST7735_SetGamma(GammaDef gamma)
|
||||
{
|
||||
void ST7735_SetGamma(GammaDef gamma) {
|
||||
// 选择ST7735显示器以进行通信
|
||||
ST7735_Select();
|
||||
|
||||
|
||||
@@ -274,6 +274,11 @@ extern "C"
|
||||
// 解释:在使用ST7735显示屏之前,必须调用此函数进行初始化设置
|
||||
void ST7735_Init(void);
|
||||
|
||||
// 启用/禁用DMA传输模式
|
||||
// 参数:enable - true启用DMA模式,false禁用DMA模式
|
||||
// 解释:初始化完成后调用此函数启用DMA模式可大幅提升刷屏速度
|
||||
void ST7735_EnableDMA(bool enable);
|
||||
|
||||
// 在指定位置绘制一个像素点
|
||||
// 参数:x - 像素点的X坐标;y - 像素点的Y坐标;color - 像素点的颜色
|
||||
// 解释:此函数用于在显示屏上的特定位置绘制一个单一颜色的像素点
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "cmsis_os.h"
|
||||
#include "cmsis_os2.h"
|
||||
#include "elog.h"
|
||||
#include "mp3_driver.h" // 添加MP3模块头文件
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -201,16 +202,19 @@ uint8_t WIFI_Connect_WiFi(const char *ssid, const char *password,
|
||||
elog_i(TAG, "等待WiFi基础连接响应...");
|
||||
if (!WIFI_WaitEvent("OK", "ERROR", 3000)) {
|
||||
elog_e(TAG, "WiFi基础连接失败");
|
||||
MP3_Play(WIFI_CONNECT_FAIL); // WiFi连接失败,播放提示音
|
||||
return 0;
|
||||
}
|
||||
|
||||
elog_i(TAG, "等待WiFi详细连接结果...");
|
||||
if (!WIFI_WaitEvent("+CWJAP:1", "+CWJAP:0", timeout_ms)) {
|
||||
elog_e(TAG, "WiFi详细连接失败");
|
||||
MP3_Play(WIFI_CONNECT_FAIL); // WiFi连接失败,播放提示音
|
||||
return 0;
|
||||
}
|
||||
|
||||
elog_i(TAG, "WiFi连接成功");
|
||||
MP3_Play(WIFI_CONNECT_OK); // WiFi连接成功,播放提示音
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
292
Core/Bsp/MultiButton-master/multi_button.c
Normal file
292
Core/Bsp/MultiButton-master/multi_button.c
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Zibin Zheng <znbin@qq.com>
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
#include "multi_button.h"
|
||||
|
||||
// Macro for callback execution with null check
|
||||
#define EVENT_CB(ev) do { if(handle->cb[ev]) handle->cb[ev](handle); } while(0)
|
||||
|
||||
// Button handle list head
|
||||
static Button* head_handle = NULL;
|
||||
|
||||
// Forward declarations
|
||||
static void button_handler(Button* handle);
|
||||
static inline uint8_t button_read_level(Button* handle);
|
||||
|
||||
/**
|
||||
* @brief Initialize the button struct handle
|
||||
* @param handle: the button handle struct
|
||||
* @param pin_level: read the HAL GPIO of the connected button level
|
||||
* @param active_level: pressed GPIO level
|
||||
* @param button_id: the button id
|
||||
* @retval None
|
||||
*/
|
||||
void button_init(Button* handle, uint8_t(*pin_level)(uint8_t), uint8_t active_level, uint8_t button_id)
|
||||
{
|
||||
if (!handle || !pin_level) return; // parameter validation
|
||||
|
||||
memset(handle, 0, sizeof(Button));
|
||||
handle->event = (uint8_t)BTN_NONE_PRESS;
|
||||
handle->hal_button_level = pin_level;
|
||||
handle->button_level = !active_level; // initialize to opposite of active level
|
||||
handle->active_level = active_level;
|
||||
handle->button_id = button_id;
|
||||
handle->state = BTN_STATE_IDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Attach the button event callback function
|
||||
* @param handle: the button handle struct
|
||||
* @param event: trigger event type
|
||||
* @param cb: callback function
|
||||
* @retval None
|
||||
*/
|
||||
void button_attach(Button* handle, ButtonEvent event, BtnCallback cb)
|
||||
{
|
||||
if (!handle || event >= BTN_EVENT_COUNT) return; // parameter validation
|
||||
handle->cb[event] = cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Detach the button event callback function
|
||||
* @param handle: the button handle struct
|
||||
* @param event: trigger event type
|
||||
* @retval None
|
||||
*/
|
||||
void button_detach(Button* handle, ButtonEvent event)
|
||||
{
|
||||
if (!handle || event >= BTN_EVENT_COUNT) return; // parameter validation
|
||||
handle->cb[event] = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the button event that happened
|
||||
* @param handle: the button handle struct
|
||||
* @retval button event
|
||||
*/
|
||||
ButtonEvent button_get_event(Button* handle)
|
||||
{
|
||||
if (!handle) return BTN_NONE_PRESS;
|
||||
return (ButtonEvent)(handle->event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the repeat count of button presses
|
||||
* @param handle: the button handle struct
|
||||
* @retval repeat count
|
||||
*/
|
||||
uint8_t button_get_repeat_count(Button* handle)
|
||||
{
|
||||
if (!handle) return 0;
|
||||
return handle->repeat;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset button state to idle
|
||||
* @param handle: the button handle struct
|
||||
* @retval None
|
||||
*/
|
||||
void button_reset(Button* handle)
|
||||
{
|
||||
if (!handle) return;
|
||||
handle->state = BTN_STATE_IDLE;
|
||||
handle->ticks = 0;
|
||||
handle->repeat = 0;
|
||||
handle->event = (uint8_t)BTN_NONE_PRESS;
|
||||
handle->debounce_cnt = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if button is currently pressed
|
||||
* @param handle: the button handle struct
|
||||
* @retval 1: pressed, 0: not pressed, -1: error
|
||||
*/
|
||||
int button_is_pressed(Button* handle)
|
||||
{
|
||||
if (!handle) return -1;
|
||||
return (handle->button_level == handle->active_level) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read button level with inline optimization
|
||||
* @param handle: the button handle struct
|
||||
* @retval button level
|
||||
*/
|
||||
static inline uint8_t button_read_level(Button* handle)
|
||||
{
|
||||
return handle->hal_button_level(handle->button_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Button driver core function, driver state machine
|
||||
* @param handle: the button handle struct
|
||||
* @retval None
|
||||
*/
|
||||
static void button_handler(Button* handle)
|
||||
{
|
||||
uint8_t read_gpio_level = button_read_level(handle);
|
||||
|
||||
// Increment ticks counter when not in idle state
|
||||
if (handle->state > BTN_STATE_IDLE) {
|
||||
handle->ticks++;
|
||||
}
|
||||
|
||||
/*------------Button debounce handling---------------*/
|
||||
if (read_gpio_level != handle->button_level) {
|
||||
// Continue reading same new level for debounce
|
||||
if (++(handle->debounce_cnt) >= DEBOUNCE_TICKS) {
|
||||
handle->button_level = read_gpio_level;
|
||||
handle->debounce_cnt = 0;
|
||||
}
|
||||
} else {
|
||||
// Level not changed, reset counter
|
||||
handle->debounce_cnt = 0;
|
||||
}
|
||||
|
||||
/*-----------------State machine-------------------*/
|
||||
switch (handle->state) {
|
||||
case BTN_STATE_IDLE:
|
||||
if (handle->button_level == handle->active_level) {
|
||||
// Button press detected
|
||||
handle->event = (uint8_t)BTN_PRESS_DOWN;
|
||||
EVENT_CB(BTN_PRESS_DOWN);
|
||||
handle->ticks = 0;
|
||||
handle->repeat = 1;
|
||||
handle->state = BTN_STATE_PRESS;
|
||||
} else {
|
||||
handle->event = (uint8_t)BTN_NONE_PRESS;
|
||||
}
|
||||
break;
|
||||
|
||||
case BTN_STATE_PRESS:
|
||||
if (handle->button_level != handle->active_level) {
|
||||
// Button released
|
||||
handle->event = (uint8_t)BTN_PRESS_UP;
|
||||
EVENT_CB(BTN_PRESS_UP);
|
||||
handle->ticks = 0;
|
||||
handle->state = BTN_STATE_RELEASE;
|
||||
} else if (handle->ticks > LONG_TICKS) {
|
||||
// Long press detected
|
||||
handle->event = (uint8_t)BTN_LONG_PRESS_START;
|
||||
EVENT_CB(BTN_LONG_PRESS_START);
|
||||
handle->state = BTN_STATE_LONG_HOLD;
|
||||
}
|
||||
break;
|
||||
|
||||
case BTN_STATE_RELEASE:
|
||||
if (handle->button_level == handle->active_level) {
|
||||
// Button pressed again
|
||||
handle->event = (uint8_t)BTN_PRESS_DOWN;
|
||||
EVENT_CB(BTN_PRESS_DOWN);
|
||||
if (handle->repeat < PRESS_REPEAT_MAX_NUM) {
|
||||
handle->repeat++;
|
||||
}
|
||||
EVENT_CB(BTN_PRESS_REPEAT);
|
||||
handle->ticks = 0;
|
||||
handle->state = BTN_STATE_REPEAT;
|
||||
} else if (handle->ticks > SHORT_TICKS) {
|
||||
// Timeout reached, determine click type
|
||||
if (handle->repeat == 1) {
|
||||
handle->event = (uint8_t)BTN_SINGLE_CLICK;
|
||||
EVENT_CB(BTN_SINGLE_CLICK);
|
||||
} else if (handle->repeat == 2) {
|
||||
handle->event = (uint8_t)BTN_DOUBLE_CLICK;
|
||||
EVENT_CB(BTN_DOUBLE_CLICK);
|
||||
}
|
||||
handle->state = BTN_STATE_IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
case BTN_STATE_REPEAT:
|
||||
if (handle->button_level != handle->active_level) {
|
||||
// Button released
|
||||
handle->event = (uint8_t)BTN_PRESS_UP;
|
||||
EVENT_CB(BTN_PRESS_UP);
|
||||
if (handle->ticks < SHORT_TICKS) {
|
||||
handle->ticks = 0;
|
||||
handle->state = BTN_STATE_RELEASE; // Continue waiting for more presses
|
||||
} else {
|
||||
handle->state = BTN_STATE_IDLE; // End of sequence
|
||||
}
|
||||
} else if (handle->ticks > SHORT_TICKS) {
|
||||
// Held down too long, treat as normal press
|
||||
handle->state = BTN_STATE_PRESS;
|
||||
}
|
||||
break;
|
||||
|
||||
case BTN_STATE_LONG_HOLD:
|
||||
if (handle->button_level == handle->active_level) {
|
||||
// Continue holding
|
||||
handle->event = (uint8_t)BTN_LONG_PRESS_HOLD;
|
||||
EVENT_CB(BTN_LONG_PRESS_HOLD);
|
||||
} else {
|
||||
// Released from long press
|
||||
handle->event = (uint8_t)BTN_PRESS_UP;
|
||||
EVENT_CB(BTN_PRESS_UP);
|
||||
handle->state = BTN_STATE_IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Invalid state, reset to idle
|
||||
handle->state = BTN_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start the button work, add the handle into work list
|
||||
* @param handle: target handle struct
|
||||
* @retval 0: succeed, -1: already exist, -2: invalid parameter
|
||||
*/
|
||||
int button_start(Button* handle)
|
||||
{
|
||||
if (!handle) return -2; // invalid parameter
|
||||
|
||||
Button* target = head_handle;
|
||||
while (target) {
|
||||
if (target == handle) return -1; // already exist
|
||||
target = target->next;
|
||||
}
|
||||
|
||||
handle->next = head_handle;
|
||||
head_handle = handle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop the button work, remove the handle from work list
|
||||
* @param handle: target handle struct
|
||||
* @retval None
|
||||
*/
|
||||
void button_stop(Button* handle)
|
||||
{
|
||||
if (!handle) return; // parameter validation
|
||||
|
||||
Button** curr;
|
||||
for (curr = &head_handle; *curr; ) {
|
||||
Button* entry = *curr;
|
||||
if (entry == handle) {
|
||||
*curr = entry->next;
|
||||
entry->next = NULL; // clear next pointer
|
||||
return;
|
||||
} else {
|
||||
curr = &entry->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Background ticks, timer repeat invoking interval 5ms
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void button_ticks(void)
|
||||
{
|
||||
Button* target;
|
||||
for (target = head_handle; target; target = target->next) {
|
||||
button_handler(target);
|
||||
}
|
||||
}
|
||||
84
Core/Bsp/MultiButton-master/multi_button.h
Normal file
84
Core/Bsp/MultiButton-master/multi_button.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Zibin Zheng <znbin@qq.com>
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
#ifndef _MULTI_BUTTON_H_
|
||||
#define _MULTI_BUTTON_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
// Configuration constants - can be modified according to your needs
|
||||
#define TICKS_INTERVAL 5 // ms - timer interrupt interval
|
||||
#define DEBOUNCE_TICKS 3 // MAX 7 (0 ~ 7) - debounce filter depth
|
||||
#define SHORT_TICKS (300 / TICKS_INTERVAL) // short press threshold
|
||||
#define LONG_TICKS (1000 / TICKS_INTERVAL) // long press threshold
|
||||
#define PRESS_REPEAT_MAX_NUM 15 // maximum repeat counter value
|
||||
|
||||
// Forward declaration
|
||||
typedef struct _Button Button;
|
||||
|
||||
// Button callback function type
|
||||
typedef void (*BtnCallback)(Button* btn_handle);
|
||||
|
||||
// Button event types
|
||||
typedef enum {
|
||||
BTN_PRESS_DOWN = 0, // button pressed down
|
||||
BTN_PRESS_UP, // button released
|
||||
BTN_PRESS_REPEAT, // repeated press detected
|
||||
BTN_SINGLE_CLICK, // single click completed
|
||||
BTN_DOUBLE_CLICK, // double click completed
|
||||
BTN_LONG_PRESS_START, // long press started
|
||||
BTN_LONG_PRESS_HOLD, // long press holding
|
||||
BTN_EVENT_COUNT, // total number of events
|
||||
BTN_NONE_PRESS // no event
|
||||
} ButtonEvent;
|
||||
|
||||
// Button state machine states
|
||||
typedef enum {
|
||||
BTN_STATE_IDLE = 0, // idle state
|
||||
BTN_STATE_PRESS, // pressed state
|
||||
BTN_STATE_RELEASE, // released state waiting for timeout
|
||||
BTN_STATE_REPEAT, // repeat press state
|
||||
BTN_STATE_LONG_HOLD // long press hold state
|
||||
} ButtonState;
|
||||
|
||||
// Button structure
|
||||
struct _Button {
|
||||
uint16_t ticks; // tick counter
|
||||
uint8_t repeat : 4; // repeat counter (0-15)
|
||||
uint8_t event : 4; // current event (0-15)
|
||||
uint8_t state : 3; // state machine state (0-7)
|
||||
uint8_t debounce_cnt : 3; // debounce counter (0-7)
|
||||
uint8_t active_level : 1; // active GPIO level (0 or 1)
|
||||
uint8_t button_level : 1; // current button level
|
||||
uint8_t button_id; // button identifier
|
||||
uint8_t (*hal_button_level)(uint8_t button_id); // HAL function to read GPIO
|
||||
BtnCallback cb[BTN_EVENT_COUNT]; // callback function array
|
||||
Button* next; // next button in linked list
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Public API functions
|
||||
void button_init(Button* handle, uint8_t(*pin_level)(uint8_t), uint8_t active_level, uint8_t button_id);
|
||||
void button_attach(Button* handle, ButtonEvent event, BtnCallback cb);
|
||||
void button_detach(Button* handle, ButtonEvent event);
|
||||
ButtonEvent button_get_event(Button* handle);
|
||||
int button_start(Button* handle);
|
||||
void button_stop(Button* handle);
|
||||
void button_ticks(void);
|
||||
|
||||
// Utility functions
|
||||
uint8_t button_get_repeat_count(Button* handle);
|
||||
void button_reset(Button* handle);
|
||||
int button_is_pressed(Button* handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -63,8 +63,8 @@ void Error_Handler(void);
|
||||
#define KEY2_GPIO_Port GPIOC
|
||||
#define KEY3_Pin GPIO_PIN_2
|
||||
#define KEY3_GPIO_Port GPIOC
|
||||
#define KEY3C3_Pin GPIO_PIN_3
|
||||
#define KEY3C3_GPIO_Port GPIOC
|
||||
#define KEY4_Pin GPIO_PIN_3
|
||||
#define KEY4_GPIO_Port GPIOC
|
||||
#define HX711_DOUT_Pin GPIO_PIN_2
|
||||
#define HX711_DOUT_GPIO_Port GPIOA
|
||||
#define HX711_SCK_Pin GPIO_PIN_3
|
||||
|
||||
@@ -19,10 +19,9 @@
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "FreeRTOS.h"
|
||||
#include "cmsis_os.h"
|
||||
#include "main.h"
|
||||
#include "task.h"
|
||||
|
||||
#include "main.h"
|
||||
#include "cmsis_os.h"
|
||||
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
@@ -30,10 +29,10 @@
|
||||
#include "dx_wf_24.h"
|
||||
#include "elog.h"
|
||||
#include "mp3_driver.h"
|
||||
#include "mp3_play_index.h"
|
||||
#include "multi_button.h"
|
||||
#include "spi_st7735s.h"
|
||||
#include "stdio.h"
|
||||
#include "mp3_play_index.h"
|
||||
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
@@ -45,7 +44,11 @@
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PD */
|
||||
#define TAG "Main"
|
||||
|
||||
/******************** 按键功能定义 ********************/
|
||||
#define KEY1_MODE_SWITCH // 按键1:模式切换(自动/手动)
|
||||
#define KEY2_MANUAL_FEED // 按键2:手动喂食(仅手动模式有效)
|
||||
#define KEY3_DISPLAY_NEXT // 按键3:切换显示界面
|
||||
#define KEY4_TIME_SET // 按键4:长按设置时间
|
||||
/* USER CODE END PD */
|
||||
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
@@ -56,6 +59,28 @@
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Variables */
|
||||
|
||||
// LCD页面枚举定义
|
||||
typedef enum {
|
||||
LCD_PAGE_TIME = 0, // 时间显示页面
|
||||
LCD_PAGE_TEMP_HUMI, // 温湿度页面
|
||||
LCD_PAGE_FOOD_WEIGHT, // 食物重量页面
|
||||
LCD_PAGE_WATER_LEVEL, // 水位页面
|
||||
LCD_PAGE_SYSTEM_STATUS // 系统状态页面
|
||||
} LCD_Page_t;
|
||||
|
||||
// 传感器数据结构体
|
||||
typedef struct {
|
||||
float temperature; // 温度值
|
||||
float humidity; // 湿度值
|
||||
float food_weight; // 食物重量
|
||||
uint8_t water_level; // 水位状态 (0=无水, 1=有水)
|
||||
uint8_t system_mode; // 系统模式 (0=手动, 1=自动)
|
||||
} Sensor_Data_t;
|
||||
|
||||
// 全局变量
|
||||
static LCD_Page_t current_page = LCD_PAGE_TIME; // 当前显示页面
|
||||
static Sensor_Data_t sensor_data = {0}; // 传感器数据
|
||||
|
||||
/* USER CODE END Variables */
|
||||
/* Definitions for defaultTask */
|
||||
osThreadId_t defaultTaskHandle;
|
||||
@@ -78,15 +103,30 @@ const osThreadAttr_t LCD_SHOW_Task_attributes = {
|
||||
.stack_size = 1024 * 4,
|
||||
.priority = (osPriority_t) osPriorityHigh,
|
||||
};
|
||||
/* Definitions for button */
|
||||
osThreadId_t buttonHandle;
|
||||
const osThreadAttr_t button_attributes = {
|
||||
.name = "button",
|
||||
.stack_size = 512 * 4,
|
||||
.priority = (osPriority_t) osPriorityRealtime2,
|
||||
};
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
/* USER CODE BEGIN FunctionPrototypes */
|
||||
|
||||
void LCD_NextPage(void);
|
||||
void LCD_PrevPage(void);
|
||||
void LCD_SetPage(LCD_Page_t page);
|
||||
LCD_Page_t LCD_GetCurrentPage(void);
|
||||
void LCD_UpdateSensorData(float temp, float humi, float weight, uint8_t water,
|
||||
uint8_t mode);
|
||||
Sensor_Data_t *LCD_GetSensorData(void);
|
||||
void user_button_init(void);
|
||||
/* USER CODE END FunctionPrototypes */
|
||||
|
||||
void StartDefaultTask(void *argument);
|
||||
extern void wifi_task_mqtt(void *argument);
|
||||
void LCD_Task(void *argument);
|
||||
void button_task(void *argument);
|
||||
|
||||
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
|
||||
|
||||
@@ -118,8 +158,7 @@ void MX_FREERTOS_Init(void) {
|
||||
|
||||
/* Create the thread(s) */
|
||||
/* creation of defaultTask */
|
||||
defaultTaskHandle =
|
||||
osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
|
||||
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
|
||||
|
||||
/* creation of wifi_mqtt */
|
||||
wifi_mqttHandle = osThreadNew(wifi_task_mqtt, NULL, &wifi_mqtt_attributes);
|
||||
@@ -127,6 +166,9 @@ void MX_FREERTOS_Init(void) {
|
||||
/* creation of LCD_SHOW_Task */
|
||||
LCD_SHOW_TaskHandle = osThreadNew(LCD_Task, NULL, &LCD_SHOW_Task_attributes);
|
||||
|
||||
/* creation of button */
|
||||
buttonHandle = osThreadNew(button_task, NULL, &button_attributes);
|
||||
|
||||
/* USER CODE BEGIN RTOS_THREADS */
|
||||
/* add threads, ... */
|
||||
/* USER CODE END RTOS_THREADS */
|
||||
@@ -134,6 +176,7 @@ void MX_FREERTOS_Init(void) {
|
||||
/* USER CODE BEGIN RTOS_EVENTS */
|
||||
/* add events, ... */
|
||||
/* USER CODE END RTOS_EVENTS */
|
||||
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN Header_StartDefaultTask */
|
||||
@@ -143,7 +186,8 @@ void MX_FREERTOS_Init(void) {
|
||||
* @retval None
|
||||
*/
|
||||
/* USER CODE END Header_StartDefaultTask */
|
||||
void StartDefaultTask(void *argument) {
|
||||
void StartDefaultTask(void *argument)
|
||||
{
|
||||
/* USER CODE BEGIN StartDefaultTask */
|
||||
// 1. 打开运行灯
|
||||
Device_Control(DEVICE_LED_RUN, 1);
|
||||
@@ -159,7 +203,7 @@ void StartDefaultTask(void *argument) {
|
||||
}
|
||||
|
||||
elog_i("MP3", "模块初始化完成");
|
||||
MP3_Play(SYS_POWER_ON);
|
||||
MP3_Play(SYS_POWER_ON); // 播放系统启动音
|
||||
|
||||
/* Infinite loop */
|
||||
for (;;) {
|
||||
@@ -179,36 +223,117 @@ void StartDefaultTask(void *argument) {
|
||||
* @retval None
|
||||
*/
|
||||
/* USER CODE END Header_LCD_Task */
|
||||
void LCD_Task(void *argument) {
|
||||
void LCD_Task(void *argument)
|
||||
{
|
||||
/* USER CODE BEGIN LCD_Task */
|
||||
|
||||
char time_str[16];
|
||||
char display_str[32];
|
||||
SNTP_Time_t now;
|
||||
uint16_t text_color = ST7735_BLACK;
|
||||
uint16_t bg_color = ST7735_WHITE;
|
||||
uint16_t text_color = ST7735_WHITE;
|
||||
uint16_t bg_color = ST7735_BLACK;
|
||||
|
||||
// 显示区域参数 - 适配160x80横屏
|
||||
// 宽度160px,高度80px,使用较小字体确保内容完整显示
|
||||
|
||||
// 初始化传感器数据 - 全部设置为NC状态
|
||||
sensor_data.temperature = 0.0f; // NC - 未检测到温度
|
||||
sensor_data.humidity = 0.0f; // NC - 未检测到湿度
|
||||
sensor_data.food_weight = 0.0f; // NC - 未检测到重量
|
||||
sensor_data.water_level = 0; // NC - 未检测到水
|
||||
sensor_data.system_mode = 1; // 自动模式
|
||||
|
||||
// 显示时间的区域大小,假设字体16x24
|
||||
const uint16_t x = 0;
|
||||
const uint16_t y = 0;
|
||||
const uint16_t w = 6 * 16; // 6个字符,每个字符16px宽
|
||||
const uint16_t h = 24; // 高度与字体匹配
|
||||
/* Infinite loop */
|
||||
for (;;) {
|
||||
// 根据当前页面显示不同内容
|
||||
switch (current_page) {
|
||||
|
||||
case LCD_PAGE_TIME:
|
||||
// 时间显示页面
|
||||
ST7735_FillScreen(bg_color);
|
||||
ST7735_WriteString(2, 2, "Time", &Font_7x10, text_color, bg_color);
|
||||
|
||||
if (WIFI_Is_Time_Valid()) {
|
||||
WIFI_Get_SNTP_Time();
|
||||
now = WIFI_Get_Current_Time();
|
||||
if (now.valid) {
|
||||
snprintf(time_str, sizeof(time_str), "%02d:%02d:%02d", now.hour,
|
||||
snprintf(display_str, sizeof(display_str), "%02d:%02d:%02d", now.hour,
|
||||
now.minute, now.second);
|
||||
} else {
|
||||
snprintf(time_str, sizeof(time_str), "--:--:--");
|
||||
snprintf(display_str, sizeof(display_str), "--:--:--");
|
||||
}
|
||||
ST7735_WriteString(10, 20, display_str, &Font_16x26, text_color, bg_color);
|
||||
} else {
|
||||
ST7735_WriteString(10, 20, "--:--:--", &Font_16x26, text_color, bg_color);
|
||||
}
|
||||
break;
|
||||
|
||||
case LCD_PAGE_TEMP_HUMI:
|
||||
// 温湿度页面
|
||||
ST7735_FillScreen(bg_color);
|
||||
ST7735_WriteString(2, 2, "Temp & Humi", &Font_7x10, text_color, bg_color);
|
||||
|
||||
// 显示温度
|
||||
snprintf(display_str, sizeof(display_str), "T: %.1f C", sensor_data.temperature);
|
||||
ST7735_WriteString(5, 20, display_str, &Font_11x18, text_color, bg_color);
|
||||
|
||||
// 显示湿度
|
||||
snprintf(display_str, sizeof(display_str), "H: %.1f %%", sensor_data.humidity);
|
||||
ST7735_WriteString(5, 45, display_str, &Font_11x18, text_color, bg_color);
|
||||
break;
|
||||
|
||||
case LCD_PAGE_FOOD_WEIGHT:
|
||||
// 食物重量页面
|
||||
ST7735_FillScreen(bg_color);
|
||||
ST7735_WriteString(2, 2, "Food Weight", &Font_7x10, text_color, bg_color);
|
||||
|
||||
// 显示食物重量
|
||||
snprintf(display_str, sizeof(display_str), "%.1f g", sensor_data.food_weight);
|
||||
ST7735_WriteString(25, 20, display_str, &Font_16x26, text_color, bg_color);
|
||||
|
||||
// 显示状态
|
||||
if (sensor_data.food_weight < 50.0f) {
|
||||
ST7735_WriteString(20, 55, "Low", &Font_11x18, ST7735_RED, bg_color);
|
||||
} else if (sensor_data.food_weight < 100.0f) {
|
||||
ST7735_WriteString(15, 55, "Medium", &Font_11x18, ST7735_YELLOW, bg_color);
|
||||
} else {
|
||||
ST7735_WriteString(20, 55, "Good", &Font_11x18, ST7735_GREEN, bg_color);
|
||||
}
|
||||
break;
|
||||
|
||||
case LCD_PAGE_WATER_LEVEL:
|
||||
// 水位页面
|
||||
ST7735_FillScreen(bg_color);
|
||||
ST7735_WriteString(2, 2, "Water Level", &Font_7x10, text_color, bg_color);
|
||||
|
||||
// 根据水位传感器状态显示
|
||||
if (sensor_data.water_level == 0) {
|
||||
ST7735_WriteString(20, 20, "NO WATER", &Font_16x26, ST7735_RED, bg_color);
|
||||
ST7735_WriteString(35, 55, "Add water", &Font_11x18, ST7735_YELLOW, bg_color);
|
||||
} else {
|
||||
ST7735_WriteString(50, 25, "OK", &Font_16x26, ST7735_GREEN, bg_color);
|
||||
ST7735_WriteString(35, 55, "Water OK", &Font_11x18, text_color, bg_color);
|
||||
}
|
||||
break;
|
||||
|
||||
case LCD_PAGE_SYSTEM_STATUS:
|
||||
// 系统状态页面
|
||||
ST7735_FillScreen(bg_color);
|
||||
ST7735_WriteString(2, 2, "System Status", &Font_7x10, text_color, bg_color);
|
||||
|
||||
// 显示WiFi状态
|
||||
if (WIFI_Is_Time_Valid()) {
|
||||
ST7735_WriteString(5, 20, "WiFi: OK", &Font_11x18, ST7735_GREEN, bg_color);
|
||||
} else {
|
||||
ST7735_WriteString(5, 20, "WiFi: OFF", &Font_11x18, ST7735_RED, bg_color);
|
||||
}
|
||||
|
||||
// 先清空显示区域
|
||||
ST7735_FillRectangleFast(x, y, w, h, bg_color);
|
||||
|
||||
// 写入时间
|
||||
ST7735_WriteString(x, y, time_str, &Font_16x26, text_color, bg_color);
|
||||
// 显示系统模式
|
||||
if (sensor_data.system_mode) {
|
||||
ST7735_WriteString(5, 45, "Mode: AUTO", &Font_11x18, text_color, bg_color);
|
||||
} else {
|
||||
ST7735_WriteString(5, 45, "Mode: MANUAL", &Font_11x18, text_color, bg_color);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
osDelay(1000);
|
||||
@@ -216,7 +341,173 @@ void LCD_Task(void *argument) {
|
||||
/* USER CODE END LCD_Task */
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN Header_button_task */
|
||||
/**
|
||||
* @brief Function implementing the button thread.
|
||||
* @param argument: Not used
|
||||
* @retval None
|
||||
*/
|
||||
/* USER CODE END Header_button_task */
|
||||
void button_task(void *argument)
|
||||
{
|
||||
/* USER CODE BEGIN button_task */
|
||||
user_button_init();
|
||||
|
||||
/* Infinite loop */
|
||||
for(;;)
|
||||
{
|
||||
button_ticks();
|
||||
osDelay(5);
|
||||
}
|
||||
/* USER CODE END button_task */
|
||||
}
|
||||
|
||||
/* Private application code --------------------------------------------------*/
|
||||
/* USER CODE BEGIN Application */
|
||||
|
||||
// 按键库实现部分//
|
||||
|
||||
/* USER CODE BEGIN KEY Prototypes */
|
||||
|
||||
static Button KEY1; // 按键1
|
||||
static Button KEY2; // 按键2
|
||||
static Button KEY3; // 按键3
|
||||
static Button KEY4; // 按键4
|
||||
|
||||
uint8_t read_button_gpio(uint8_t button_id) {
|
||||
switch (button_id) {
|
||||
case 1:
|
||||
return HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin);
|
||||
break;
|
||||
case 2:
|
||||
return HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin);
|
||||
break;
|
||||
case 3:
|
||||
return HAL_GPIO_ReadPin(KEY3_GPIO_Port, KEY3_Pin);
|
||||
break;
|
||||
case 4:
|
||||
return HAL_GPIO_ReadPin(KEY4_GPIO_Port, KEY4_Pin);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void key1_single_click_handler(Button *btn) { elog_i("KEY", "按键1单击"); }
|
||||
|
||||
void key2_single_click_handler(Button *btn) { elog_i("KEY", "按键2单击"); }
|
||||
|
||||
void key3_single_click_handler(Button *btn) {
|
||||
elog_i("KEY", "按键3单击");
|
||||
LCD_NextPage();
|
||||
}
|
||||
|
||||
void key4_single_click_handler(Button *btn) { elog_i("KEY", "按键4单击"); }
|
||||
|
||||
void user_button_init(void) {
|
||||
// 初始化按键 (active_level: 0=低电平有效, 1=高电平有效)
|
||||
button_init(&KEY1, read_button_gpio, 0, 1);
|
||||
button_init(&KEY2, read_button_gpio, 0, 2);
|
||||
button_init(&KEY3, read_button_gpio, 0, 3);
|
||||
button_init(&KEY4, read_button_gpio, 0, 4);
|
||||
|
||||
elog_i("BUTTON", "按键初始化完成");
|
||||
|
||||
// 设置按键回调函数
|
||||
button_attach(&KEY1, BTN_SINGLE_CLICK, key1_single_click_handler);
|
||||
button_attach(&KEY2, BTN_SINGLE_CLICK, key2_single_click_handler);
|
||||
button_attach(&KEY3, BTN_SINGLE_CLICK, key3_single_click_handler);
|
||||
button_attach(&KEY4, BTN_SINGLE_CLICK, key4_single_click_handler);
|
||||
|
||||
elog_i("BUTTON", "按键回调函数设置完成");
|
||||
|
||||
// 启动按键任务
|
||||
button_start(&KEY1);
|
||||
button_start(&KEY2);
|
||||
button_start(&KEY3);
|
||||
button_start(&KEY4);
|
||||
|
||||
elog_i("BUTTON", "按键任务已启动");
|
||||
}
|
||||
/* USER CODE END KEY Prototypes */
|
||||
|
||||
/* USER CODE BEGIN LCD_Page_Functions */
|
||||
/**
|
||||
* @brief 切换到下一个显示页面
|
||||
* @retval None
|
||||
*/
|
||||
void LCD_NextPage(void) {
|
||||
current_page = (current_page + 1) % 5; // 循环切换5个页面
|
||||
elog_i("LCD", "切换到页面 %d", current_page + 1);
|
||||
|
||||
// 播放页面切换提示音
|
||||
MP3_Play(PARAM_SAVE_OK); // 使用参数保存成功的音效作为页面切换提示
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 切换到上一个显示页面
|
||||
* @retval None
|
||||
*/
|
||||
void LCD_PrevPage(void) {
|
||||
if (current_page == 0) {
|
||||
current_page = 4;
|
||||
} else {
|
||||
current_page--;
|
||||
}
|
||||
elog_i("LCD", "切换到页面 %d", current_page + 1);
|
||||
|
||||
// 播放页面切换提示音
|
||||
MP3_Play(PARAM_SAVE_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置当前显示页面
|
||||
* @param page: 目标页面索引 (0-4)
|
||||
* @retval None
|
||||
*/
|
||||
void LCD_SetPage(LCD_Page_t page) {
|
||||
if (page < 5) {
|
||||
current_page = page;
|
||||
elog_i("LCD", "设置页面为 %d", page + 1);
|
||||
MP3_Play(PARAM_SAVE_OK);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取当前页面索引
|
||||
* @retval 当前页面索引
|
||||
*/
|
||||
LCD_Page_t LCD_GetCurrentPage(void) { return current_page; }
|
||||
|
||||
/**
|
||||
* @brief 更新传感器数据
|
||||
* @param temp: 温度值
|
||||
* @param humi: 湿度值
|
||||
* @param weight: 食物重量
|
||||
* @param water: 水位状态 (0=无水, 1=有水)
|
||||
* @param mode: 系统模式
|
||||
* @retval None
|
||||
*/
|
||||
void LCD_UpdateSensorData(float temp, float humi, float weight, uint8_t water,
|
||||
uint8_t mode) {
|
||||
sensor_data.temperature = temp;
|
||||
sensor_data.humidity = humi;
|
||||
sensor_data.food_weight = weight;
|
||||
sensor_data.water_level = water;
|
||||
sensor_data.system_mode = mode;
|
||||
|
||||
elog_i("LCD", "传感器数据更新: T=%.1fC H=%.1f%% W=%.1fg Water=%s Mode=%s",
|
||||
temp, humi, weight, water ? "DETECTED" : "NONE",
|
||||
mode ? "AUTO" : "MANUAL");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取传感器数据指针
|
||||
* @retval 传感器数据结构体指针
|
||||
*/
|
||||
Sensor_Data_t *LCD_GetSensorData(void) { return &sensor_data; }
|
||||
|
||||
/* USER CODE END LCD_Page_Functions */
|
||||
|
||||
/* USER CODE END Application */
|
||||
|
||||
|
||||
@@ -60,10 +60,10 @@ void MX_GPIO_Init(void)
|
||||
/*Configure GPIO pin Output Level */
|
||||
HAL_GPIO_WritePin(GPIOB, LED2_Pin|LED1_Pin, GPIO_PIN_SET);
|
||||
|
||||
/*Configure GPIO pins : KEY1_Pin KEY2_Pin KEY3_Pin KEY3C3_Pin */
|
||||
GPIO_InitStruct.Pin = KEY1_Pin|KEY2_Pin|KEY3_Pin|KEY3C3_Pin;
|
||||
/*Configure GPIO pins : KEY1_Pin KEY2_Pin KEY3_Pin KEY4_Pin */
|
||||
GPIO_InitStruct.Pin = KEY1_Pin|KEY2_Pin|KEY3_Pin|KEY4_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pin : HX711_DOUT_Pin */
|
||||
|
||||
@@ -45,7 +45,7 @@ void MX_SPI1_Init(void)
|
||||
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
|
||||
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
|
||||
hspi1.Init.NSS = SPI_NSS_SOFT;
|
||||
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
|
||||
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
|
||||
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
||||
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
|
||||
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
||||
|
||||
41
README.md
41
README.md
@@ -36,4 +36,43 @@
|
||||
- `WIFI_Get_Current_Time()`:获取存储的当前时间(返回结构体副本)
|
||||
- `WIFI_Is_Time_Valid()`:检查时间是否有效
|
||||
|
||||
### 使用示例:
|
||||
## MP3 音频播放功能
|
||||
|
||||
本工程集成了 MP3 音频播放功能,用于提供各种系统状态和事件的语音提示。相关的音频索引定义在 `Core/Bsp/BSP_Device/bsp_mp3/mp3_play_index.h` 文件中。
|
||||
|
||||
### 音频提示分类:
|
||||
|
||||
#### 系统状态与初始化
|
||||
- `SYS_POWER_ON` (1): 系统上电完成,智能宠物喂食系统启动完成,进入待机模式
|
||||
- `WIFI_CONNECT_OK` (2): WiFi连接成功,云平台数据同步已开启
|
||||
- `WIFI_CONNECT_FAIL` (3): WiFi连接失败,请检查网络配置
|
||||
|
||||
#### 喂食模块
|
||||
- `FEED_AUTO_START` (4): 自动喂食启动,步进电机开始出粮
|
||||
- `FEED_IN_PROGRESS` (5): 正在出粮,称重模块实时监测中
|
||||
- `FEED_COMPLETE` (6): 喂食完成,当前食物重量已达设定值
|
||||
- `FEED_MANUAL_TRIGGER` (7): 手动喂食指令已接收,开始出粮
|
||||
- `FOOD_LOW_ALARM` (8): 食物余量不足警告,请及时添加
|
||||
|
||||
#### 喂水模块
|
||||
- `WATER_REFILL_START` (9): 水位低于阈值,水泵启动,开始自动补水
|
||||
- `WATER_REFILL_DONE` (10): 补水完成,水位已达设定上限
|
||||
- `WATER_LOW_ALARM` (11): 水位过低警告,请检查水源或水泵
|
||||
- `WATER_PIR_REFILL` (12): 检测到宠物靠近且水位偏低,启动自动补水
|
||||
|
||||
#### 模式切换
|
||||
- `MODE_AUTO` (13): 已切换至自动运行模式
|
||||
- `MODE_MANUAL` (14): 已切换至手动控制模式
|
||||
|
||||
#### 参数设置
|
||||
- `PARAM_SAVE_OK` (15): 参数设置已保存,系统配置已更新
|
||||
- `PARAM_TIME_SET` (16): 自动喂食时间已更新
|
||||
- `PARAM_WEIGHT_SET` (17): 喂食重量阈值已更新
|
||||
|
||||
#### 远程控制与异常
|
||||
- `REMOTE_CMD_RECEIVED` (18): 接收到微信小程序远程控制指令
|
||||
- `DATA_UPLOAD_FAIL` (19): 数据上传失败,请检查网络连接
|
||||
- `SYS_ERROR_ALARM` (20): 系统检测到异常,请检查硬件模块
|
||||
|
||||
### 使用说明:
|
||||
系统通过调用相应的音频索引值来播放对应的提示音,为用户提供直观的听觉反馈,增强用户体验。
|
||||
20
hahha.ioc
20
hahha.ioc
@@ -35,7 +35,7 @@ Dma.USART1_TX.0.Priority=DMA_PRIORITY_VERY_HIGH
|
||||
Dma.USART1_TX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority
|
||||
FREERTOS.FootprintOK=true
|
||||
FREERTOS.IPParameters=Tasks01,FootprintOK,configTOTAL_HEAP_SIZE
|
||||
FREERTOS.Tasks01=defaultTask,41,256,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL;wifi_mqtt,40,3000,wifi_task_mqtt,As external,NULL,Dynamic,NULL,NULL;LCD_SHOW_Task,40,1024,LCD_Task,Default,NULL,Dynamic,NULL,NULL
|
||||
FREERTOS.Tasks01=defaultTask,41,256,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL;wifi_mqtt,40,3000,wifi_task_mqtt,As external,NULL,Dynamic,NULL,NULL;LCD_SHOW_Task,40,1024,LCD_Task,Default,NULL,Dynamic,NULL,NULL;button,50,512,button_task,Default,NULL,Dynamic,NULL,NULL
|
||||
FREERTOS.configTOTAL_HEAP_SIZE=30000
|
||||
File.Version=6
|
||||
GPIO.groupedBy=Group By Peripherals
|
||||
@@ -177,12 +177,14 @@ PB6.Mode=I2C
|
||||
PB6.Signal=I2C1_SCL
|
||||
PB7.Mode=I2C
|
||||
PB7.Signal=I2C1_SDA
|
||||
PC0.GPIOParameters=GPIO_Label
|
||||
PC0.GPIOParameters=GPIO_PuPd,GPIO_Label
|
||||
PC0.GPIO_Label=KEY1
|
||||
PC0.GPIO_PuPd=GPIO_PULLUP
|
||||
PC0.Locked=true
|
||||
PC0.Signal=GPIO_Input
|
||||
PC1.GPIOParameters=GPIO_Label
|
||||
PC1.GPIOParameters=GPIO_PuPd,GPIO_Label
|
||||
PC1.GPIO_Label=KEY2
|
||||
PC1.GPIO_PuPd=GPIO_PULLUP
|
||||
PC1.Locked=true
|
||||
PC1.Signal=GPIO_Input
|
||||
PC12.Mode=Asynchronous
|
||||
@@ -191,12 +193,14 @@ PC14-OSC32_IN.Mode=LSE-External-Oscillator
|
||||
PC14-OSC32_IN.Signal=RCC_OSC32_IN
|
||||
PC15-OSC32_OUT.Mode=LSE-External-Oscillator
|
||||
PC15-OSC32_OUT.Signal=RCC_OSC32_OUT
|
||||
PC2.GPIOParameters=GPIO_Label
|
||||
PC2.GPIOParameters=GPIO_PuPd,GPIO_Label
|
||||
PC2.GPIO_Label=KEY3
|
||||
PC2.GPIO_PuPd=GPIO_PULLUP
|
||||
PC2.Locked=true
|
||||
PC2.Signal=GPIO_Input
|
||||
PC3.GPIOParameters=GPIO_Label
|
||||
PC3.GPIO_Label=KEY3
|
||||
PC3.GPIOParameters=GPIO_PuPd,GPIO_Label
|
||||
PC3.GPIO_Label=KEY4
|
||||
PC3.GPIO_PuPd=GPIO_PULLUP
|
||||
PC3.Locked=true
|
||||
PC3.Signal=GPIO_Input
|
||||
PC4.GPIOParameters=GPIO_Label
|
||||
@@ -291,8 +295,8 @@ RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK
|
||||
RCC.TimSysFreq_Value=72000000
|
||||
RCC.USBFreq_Value=72000000
|
||||
RCC.VCOOutput2Freq_Value=8000000
|
||||
SPI1.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_8
|
||||
SPI1.CalculateBaudRate=9.0 MBits/s
|
||||
SPI1.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_4
|
||||
SPI1.CalculateBaudRate=18.0 MBits/s
|
||||
SPI1.Direction=SPI_DIRECTION_2LINES
|
||||
SPI1.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,BaudRatePrescaler
|
||||
SPI1.Mode=SPI_MODE_MASTER
|
||||
|
||||
Reference in New Issue
Block a user