你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【STM32F769】读取音乐列表

[复制链接]
lugl 发布时间:2025-3-16 19:36

前面,我分享了有关GUI相关的LVGL文章:

【STM32F769I-DISC1】移植LVGL - ST中文论坛活动 ST意法半导体中文论坛

以及FatFs文件系统的文章:

【STM32F769I-DISC1】移植基于FreeRTOS的FATFS - ST中文论坛活动 ST意法半导体中文论坛

现在就结合LVGL+FatFs进行了SD卡中的音乐.wav的读取,并将文件列表存入双向链表中,同时也可以显示到界面中。

【工程结合】

我把两个帖子的代码进行了整合。

image.png

【界面设计】

image.png

【文件列表保存】

我使用双向链表来进行管理,这样就一次获取,之后就只需要对链表进行访问,通过文件名再对SD卡进行读取。

【主要代码】

节点设计:

typedef struct WavFileNode
{
    char filename[256];       // 存储文件名
    struct WavFileNode *prev; // 指向前一个节点
    struct WavFileNode *next; // 指向后一个节点
} WavFileNode;

创建节点:

WavFileNode *createNode(const char *filename)
{
    WavFileNode *newNode = (WavFileNode *)malloc(sizeof(WavFileNode));
    if (newNode == NULL)
    {
        printf("内存分配失败\n");
        return NULL;
    }
    sprintf(newNode->filename, "%s", filename); // 修正拼写错误
    newNode->prev = NULL;
    newNode->next = NULL;
    return newNode;
}

整体源代码我放到回复里。

接下来给lvgl的button编写click事件与文件读取:

image.png

【实现效】

我点击Getfile后即可把SD卡下面的文件读取到界面上:

image.png

【小结】

通过fatfs,可以实现对SD卡的文件读取,下一步将设计音频输出,最终实现一个音乐播放器。

收藏 评论3 发布时间:2025-3-16 19:36

举报

3个回答
lugl 回答时间:2025-3-16 19:37:27

代码read_wav_filename.c:

#include "ff.h"
#include <stdio.h>
#include <stdlib.h>
#include "read_wav_filename.h"
#include <stdbool.h>
WavFileNode *fileList = NULL;
// 创建新节点
WavFileNode *createNode(const char *filename)
{
    WavFileNode *newNode = (WavFileNode *)malloc(sizeof(WavFileNode));
    if (newNode == NULL)
    {
        printf("内存分配失败\n");
        return NULL;
    }
    sprintf(newNode->filename, "%s", filename); // 修正拼写错误
    newNode->prev = NULL;
    newNode->next = NULL;
    return newNode;
}

// 在链表末尾添加新节点
void appendNode(WavFileNode **head, const char *filename)
{
    WavFileNode *newNode = createNode(filename);
    if (*head == NULL)
    {
        *head = newNode;
    }
    else
    {
        WavFileNode *temp = *head;
        while (temp->next != NULL)
        {
            temp = temp->next;
        }
        temp->next = newNode;
        newNode->prev = temp;
    }
}

// 释放双向链表内存
void freeList(WavFileNode *head)
{
    WavFileNode *temp = head;
    while (temp != NULL)
    {
        WavFileNode *next = temp->next;
        free(temp);
        temp = next;
    }
}

// 获取双向链表的尾节点
WavFileNode *getTailNode(WavFileNode *head)
{
    WavFileNode *temp = head;
    while (temp != NULL && temp->next != NULL)
    {
        temp = temp->next;
    }
    return temp;
}

// 获取双向链表的头节点
WavFileNode *getHeadNode(WavFileNode *head)
{
    WavFileNode *temp = head;
    while (temp != NULL && temp->prev != NULL)
    {
        temp = temp->prev;
    }
    return temp;
}

// 读取文件夹中的.wav文件并存储到双向链表中

void readWavFiles(const char *folderPath, WavFileNode **head)
{
    DIR dir;
    FILINFO fileInfo;
    FRESULT res = f_opendir(&dir, folderPath);
    if (res != FR_OK)
    {
        printf("无法打开文件夹\n");
        return;
    }
    while (1)
    {
        res = f_readdir(&dir, &fileInfo);
        if (res != FR_OK || fileInfo.fname[0] == 0)
        {
            break;
        }
        if (fileInfo.fattrib & AM_DIR)
        {
            // 如果是文件夹,则递归读取子文件夹
            continue;
        }
        else
        {
            // 如果是文件,则判断是否为.wav文件
            if (strstr(fileInfo.fname, ".wav") != NULL  && fileInfo.fname[0] != 0)
            {
                // 如果是.wav文件,则将文件名存储到双向链表中
                appendNode(head, fileInfo.fname);
            }
        }
    }
    f_closedir(&dir);
}

// 返回下一个.wav文件名
const char *getNextWavFilename(WavFileNode **head)
{
    WavFileNode *temp = *head;
    if (temp == NULL)
    {
        return NULL;
    }
    const char *filename = temp->filename;
    *head = temp->next;
    free(temp);
    return filename;
}

// 判断WavFileNode链表是否为空
bool isWavFileListEmpty(WavFileNode *head)
{
    return head == NULL;
}

// 打印WavFileNode链表中的文件名
void printWavFileList(WavFileNode *head)
{
    uint8_t count = 0;
    WavFileNode *temp = head;
    while (temp!= NULL)
    {
        printf("count:%d: %s\n", count, temp->filename);
        temp = temp->next;
        count++;
    }
}
lugl 回答时间:2025-3-16 19:38:00

read_wav_filename.h:

#ifndef READ_WAV_FILENAME_H
#define READ_WAV_FILENAME_H

#include "ff.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
// 定义双向链表节点结构体
typedef struct WavFileNode
{
    char filename[256];       // 存储文件名
    struct WavFileNode *prev; // 指向前一个节点
    struct WavFileNode *next; // 指向后一个节点
} WavFileNode;

// 声明函数原型
WavFileNode *createNode(const char *filename);
void appendNode(WavFileNode **head, const char *filename);
void freeList(WavFileNode *head);
WavFileNode *getTailNode(WavFileNode *head);
WavFileNode *getHeadNode(WavFileNode *head);
void readWavFiles(const char *folderPath, WavFileNode **head);
const char *getNextWavFilename(WavFileNode **head);
bool isWavFileListEmpty(WavFileNode *head);
void printWavFileList(WavFileNode *head);
#endif // READ_WAV_FILENAME_H
lugl 回答时间:2025-3-16 19:38:33

lvgl代码:




/*********************
 *      INCLUDES
 *********************/
#include <stdio.h>
#include "lvgl.h"
#include "custom.h"
#include <string.h>
/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/

/**********************
 *  STATIC VARIABLES
 **********************/
#include <stdio.h>
#include "file_opera.h"
#include "fatfs.h"
#include <stdio.h>
#include "ff.h"
#include "stdlib.h"
#include "read_wav_filename.h"
/**
 * Create a demo application
 */
extern WavFileNode *fileList ;
void get_wave_file(lv_ui *ui)
{
    static get_state_flag = 0;
    if (get_state_flag == 0)
    {
        get_state_flag = 1;
        readWavFiles("/", &fileList);
    }

    printWavFileList(fileList);
    if (isWavFileListEmpty(fileList))
    {
        printf("No WAV files found.\n");
    }
    else
    {
        char buff[1024] = {0};
        //取取flist中的所有文件名
        WavFileNode *current = fileList;
        while (current != NULL)
        {
            // 使用 snprintf 来拼接文件名,确保不会超出缓冲区大小
            int remaining_space = sizeof(buff) - strlen(buff);
            if (remaining_space > 0)
            {
                snprintf(buff + strlen(buff), remaining_space, "%s\n", current->filename);
            }
            else
            {
                printf("Buffer is full, cannot add more filenames.\n");
                break;
            }
            current = current->next;
        }
        lv_span_set_text(ui->screen_spangroup_1_span, (const char *)buff);
    }

}
static void screen_btn_1_event_handler(lv_event_t *e)
{
    lv_event_code_t code = lv_event_get_code(e);
    //获取事件发生的ui对象
    lv_ui *ui = lv_event_get_user_data(e);
    switch (code)
    {
    case LV_EVENT_CLICKED:
    {
        printf("screen_btn_1 clicked\n");
        get_wave_file(ui);
        break;
    }
    default:
        break;
    }
}

void custom_init(lv_ui *ui)
{
    lv_obj_add_event_cb(ui->screen_btn_1, screen_btn_1_event_handler, LV_EVENT_ALL, ui);
    /* Add your codes here */
}

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版