色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

聚豐項目 > 基于手勢識別控制的音樂播放器

基于手勢識別控制的音樂播放器

中科藍(lán)訊公司推出的 AB32VG1 開發(fā)板,這個開發(fā)板自帶 按鍵模塊、audio 模塊和 TF card 模塊,基于該開發(fā)板結(jié)合 OLED12864 模塊作為顯示屏幕,加上 PAJ7620U2 手勢識別模塊,制作了一款基于手勢識別的音樂播放器,這樣就可以實現(xiàn)非接觸式控制音樂播放,這個模塊作為一個基礎(chǔ),之后也能構(gòu)造出更炫酷的作品 該音樂播放器目前實現(xiàn)了如下功能: 1、可以通過 OLED12864 模塊顯示播放器信息。 2、可以通過按鍵控制音樂播放和設(shè)置一些信息。 3、讀取 SD 卡的音樂文件并播放。 4、通過手勢識別模塊控制播放器

Eureka1024 Eureka1024

分享
0 喜歡這個項目
團(tuán)隊介紹

Eureka1024 Eureka1024

團(tuán)隊成員

Eureka1024 軟件開發(fā)

分享
項目簡介
中科藍(lán)訊公司推出的 AB32VG1 開發(fā)板,這個開發(fā)板自帶 按鍵模塊、audio 模塊和 TF card 模塊,基于該開發(fā)板結(jié)合 OLED12864 模塊作為顯示屏幕,加上 PAJ7620U2 手勢識別模塊,制作了一款基于手勢識別的音樂播放器,這樣就可以實現(xiàn)非接觸式控制音樂播放,這個模塊作為一個基礎(chǔ),之后也能構(gòu)造出更炫酷的作品 該音樂播放器目前實現(xiàn)了如下功能: 1、可以通過 OLED12864 模塊顯示播放器信息。 2、可以通過按鍵控制音樂播放和設(shè)置一些信息。 3、讀取 SD 卡的音樂文件并播放。 4、通過手勢識別模塊控制播放器
硬件說明

使用到的模塊如下:


2.1、按鍵模塊(GPIO)

按鍵模塊使用如下 GPIO 引腳:

  • S2 -- PF1 (單擊為向下選擇)

  • S3 -- PF0(單擊為確定,雙擊為返回)

  • S4 -- PA2(單擊為向上選擇)

使用按鍵軟件包:multibutton

2.2、OLED12864 模塊(IIC 協(xié)議)

使用的引腳如下:

  • SDA --  PA6

  • SCL --  PA0

沒有使用 u8g2 的驅(qū)動軟件包,因為內(nèi)存不夠。使用了網(wǎng)上的軟件 IIC 實現(xiàn),做了一些修改。


2.3、SD 卡模塊(SDIO協(xié)議)

使用的 SDIO 協(xié)議對應(yīng)的引腳如下:

  • SD_CMD -- PB0

  • SD_CLK -- PB1

  • SD_DAT -- PB2

  • SD_DET -- PE5

使用到 RT-Thread 提供的 SDIO 驅(qū)動,使用到的組件和服務(wù)層有 DFS、Fatfs 和 POSIX。


2.4、AUDIO 模塊

  • VOUTRP -- DACR

  • VOUTLP -- DACL

  • FMANT -- FM_ANT

  • MICIN -- MICL/PF2

使用到的驅(qū)動 audio device, 軟件包為 wavplayer(需要optparse軟件包),可以用來播放 wav 格式的音樂文件。


2.5、手勢識別模塊(PAJ7620模塊)-- IIC協(xié)議

  • SDA -- PE2

  • SCL -- PE3

  • INT -- PA5

使用了軟件 IIC 驅(qū)動、PAJ7620軟件包。




軟件說明

開發(fā)環(huán)境:

- RT-Thread 版本 latest(2021-10-20)

- RT-Thread Studio版本  V2.12

- AB32VG1 開發(fā)板 BSP 版本 V1.08


音樂播放器雖說功能不多,但是不同的狀態(tài)切換還是蠻多的,所以理所當(dāng)然會想到使用狀態(tài)機(jī)的方式實現(xiàn)。


目前實現(xiàn)的狀態(tài)主要包括如下幾個,同時,該樹狀圖也表明了狀態(tài)間的轉(zhuǎn)移關(guān)系。


image.png


網(wǎng)上關(guān)于狀態(tài)機(jī)的實現(xiàn)有很多方法,我看了好多文章都是直接一個狀態(tài)對應(yīng)一個動作函數(shù),但是應(yīng)用在音樂播放器上會有點(diǎn)問題,因為如果你一個狀態(tài)對應(yīng)一個函數(shù)的話,如果你的音樂歌曲有幾百首,那豈不是有幾百個函數(shù),所以我對一般的狀態(tài)機(jī)做了點(diǎn)改進(jìn)。


如下代碼所示,主要是狀態(tài)轉(zhuǎn)移表的實現(xiàn),該表給出了所有狀態(tài)對應(yīng)的情況,以及狀態(tài)轉(zhuǎn)移的跳轉(zhuǎn)位置。

typedef struct
{
    uint8_t coordinate;      //當(dāng)前狀態(tài)索引號
    uint8_t back;            //返回
    void (*enter_operation)(int8_t* );     //指向執(zhí)行函數(shù),作為當(dāng)前狀態(tài)執(zhí)行的操作

    //當(dāng) entry鍵按下時  sub_base_addr提供子狀態(tài)的基地址索引,sub_offset_addr提供偏移量,兩者相加,得到下一個狀態(tài)
    uint8_t sub_base_addr;   //子狀態(tài)基地址
    uint8_t sub_offset_addr; //子狀態(tài)偏移地址 (用于記錄下一步要跳轉(zhuǎn)到的子狀態(tài))

    uint8_t leaf_node_flag;  //標(biāo)志是否為葉子節(jié)點(diǎn)(最底層的狀態(tài)),方便在該狀態(tài)下按確定可以實現(xiàn)返回功能
} Menu_table;


//針對下表,一些想法:其實可以增加一個變量來實現(xiàn)樹的收縮的(解決音樂播放時,點(diǎn)擊任意一首歌進(jìn)入的是同一個狀態(tài),目前是enter事件給特殊,如果還有,就思考了)
//初始化菜單所處在的各個狀態(tài)
Menu_table  table[]=
{   //索引   - back -  function(當(dāng)前)  - 子狀態(tài)基地址(固定)   -   子狀態(tài)偏移地址   -    標(biāo)志是否為葉子節(jié)點(diǎn)
    {  0,    0,      (*load_menu),       1,             0,           0},   //0加載界面

    {  1,    1,      (*main_menu),       2,             0,           0},   //1主菜單界面

    {  2,    1,      (*playlists),       4,             0,           0},   //歌單
    {  3,    1,    (*settings_list),     5,             0,           0},   //設(shè)置

    //播放的子菜單
    {  4,    2,      (*music_play),      0,             0,           0},   //音樂播放控制:(2-1)

    //設(shè)置菜單的子菜單
    {  5,    3,      (*volume_control),  0,             1,           1},   //音量控制
    {  6,    3,    (*language_setting),  0,             1,           1},   //語言設(shè)置
    {  7,    3,  (*brightness_setting),  0,             1,           1},   //亮度設(shè)置
};


狀態(tài)轉(zhuǎn)移主要是按鍵來實現(xiàn)的,每個按鍵按下,就會觸發(fā)狀態(tài)轉(zhuǎn)移,狀態(tài)轉(zhuǎn)移的代碼如下所示:

/* 菜單界面顯示線程入口函數(shù) */
static void menu_thread_entry(void *parameter)
{
    rt_uint32_t e;
    int8_t k;

    while(1)
    {
        if (rt_event_recv(&control_event,
                           (UP_FLAG | ENTRY_FLAG | RETURN_FLAG | DOWN_FLAG),
                           RT_EVENT_FLAG_OR,
                           RT_WAITING_FOREVER, &e) == RT_EOK)
        {
            //向上
            if (rt_event_recv(&control_event,
                               UP_FLAG,
                               RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
                               RT_WAITING_NO, &e) == RT_EOK)
            {
                table[func_index].sub_offset_addr -= 1;
                table[func_index].enter_operation(&table[func_index].sub_offset_addr);
            }

            //確定
            if (rt_event_recv(&control_event,
                               ENTRY_FLAG,
                               RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
                               RT_WAITING_NO, &e) == RT_EOK)
            {
                if(table[func_index].leaf_node_flag)
                {
                    func_index = table[func_index].back; //返回上一級菜單位置
                    table[func_index].enter_operation(&table[func_index].sub_offset_addr);
                }
                else if(func_index == 2)  //音樂播放則特殊點(diǎn)(所有音樂進(jìn)入同一個狀態(tài))
                {
                    k = table[func_index].sub_offset_addr;
                    func_index = 4;
                    table[func_index].sub_offset_addr = k;
                    table[func_index].enter_operation(&table[func_index].sub_offset_addr);
                }
                else
                {
                    func_index = table[func_index].sub_base_addr + table[func_index].sub_offset_addr;
                    table[func_index].enter_operation(&table[func_index].sub_offset_addr);
                }
            }

             //返回
             if (rt_event_recv(&control_event,
                                RETURN_FLAG,
                                RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
                                RT_WAITING_NO, &e) == RT_EOK)
             {
                 func_index = table[func_index].back;
                 table[func_index].enter_operation(&table[func_index].sub_offset_addr);
             }


            //向下
            if (rt_event_recv(&control_event,
                               DOWN_FLAG,
                               RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR,
                               RT_WAITING_NO, &e) == RT_EOK)
            {
                table[func_index].sub_offset_addr += 1;
                table[func_index].enter_operation(&table[func_index].sub_offset_addr);
            }
        }
    }
}
演示效果

演示效果如下:

以下是代碼的 gitee 地址:

https://gitee.com/Eureka1024/MusicPlayerBasedOnGestureRecognition

評論區(qū)(0 )
主站蜘蛛池模板: 国产精品日本无码久久一老A | 99国产在线观看| 毛片免费大全| 99视频在线观看免费| 色婷婷五月综合中文字幕| 国产精品免费视频能看| 亚洲国产成人精品无码区99| 久久99国产精品无码AV| 91九色视频在线观看| 色鲁97精品国产亚洲AV高| 国偷自产AV一区二区三区健身房| 中国女人逼| 三级黄色在线免费观看| 娇妻中日久久持久久| bl高h肉文| 亚洲精品国产自在在线观看| 妹妹的第一次有点紧| 国产高清视频青青青在线| 亚洲一卡二卡三卡四卡无卡麻豆 | 亚洲精品在线网址| 你是淫荡的我的女王| 国产精品午夜小视频观看| 34g污奶绵uk甩奶| 熟女人妻水多爽中文字幕| 巨污全肉np一女多男| 国产成人无码视频一区二区三区| 欲乱艳荡少寡妇全文免费| 色列少女漫画| 久久全国免费观看视频| 国产成人h在线视频| 91av成年影院在线播放| 香蕉久久夜色精品国产小说| 内射白浆一区二区在线观看| 国产午夜免费不卡精品理论片| a亚洲在线观看不卡高清| 亚洲色综合中文字幕在线| 色男人的天堂久久综合| 美女脱18以下禁止看免费| 国内精品久久久久影院老司 | 美女拉开腿让男生桶到爽| 国产久青青青青在线观看|