首页 > 评测 > 亚星娱乐官网注册网站 【技术分享】基于正点原子开发板的中文菜单音乐播放器实现

亚星娱乐官网注册网站 【技术分享】基于正点原子开发板的中文菜单音乐播放器实现

  • 作者:
  • 来源:
  • [导读]
  • 本帖最后由 jinglixixi 于 2023-5-17 18:48 编辑 #申请原创# @21小跑堂 正点原子开发板以外设丰富而著称,基本可以全部支撑起多媒体方面的应用,如数码相框功能(已在前面介绍过)、视频播放功能、文本阅读器
本帖最后由 jinglixixi 于 2023-5-17 18:48 编辑

#申请原创# @21小跑堂
正点原子开发板以外设丰富而著称,基本可以全部支撑起多媒体方面的应用,如数码相框功能(已在前面介绍过)、视频播放功能、文本阅读器功能及音频播放功能等。
这次,就利用这些外设来实现一个具有中文菜单的音乐播放器,所涉及的主要外设为:I2S语音播放电路及字库存储电路,参见图1和图2所示。
图1 I2S语音播放电路
图2 字库存储电路

这里之所以使用闪存W25Q128来构建字库是因为,它的通用性更强,可以直接在编程时就以掌握来设计菜单。而在以往,要设计中文菜单,均是采用构建专用小字库的方式来实现。这就导致在输出汉字时,多是以汉字在小子库中的次序编号来调用字模,故通用性极差。

在W25Q128中,其字模是按列行式来取模的,见图3所示。此外,它共含有3种字库,即GBK12、GBK16及GBK24。
图3 取模方式

此外,为了便于中西为的混排,其文字显示函数为:
  1. void text_show_font(uint16_t x, uint16_t y, uint8_t *font, uint8_t size, uint8_t mode, uint16_t color)
  2. {
  3.     uint8_t temp, t, t1;
  4.     uint16_t y0 = y;
  5.     uint8_t *dzk;
  6.     uint8_t csize = (size / 8 + ((size % 8) ? 1 : 0)) * (size);

  7.     if (size != 12 && size != 16 && size != 24 && size != 32)
  8.     {
  9.         return;
  10.     }
  11.     dzk = mymalloc(SRAMIN, size);
  12.     if (dzk == 0) return;
  13.     text_get_hz_mat(font, dzk, size);
  14.     for (t = 0; t
  15.     {
  16.         temp = dzk[t];
  17.         for (t1 = 0; t1 <8; t1++)           // 一个字节
  18.         {
  19.             if (temp & 0x80)            // 1000 0000  从左到右
  20.             {
  21.                 //lcd_draw_point(x, y, color);
  22.                 ili9341_draw_pixel(color, x, y);
  23.             }
  24.             else if (mode == 0)
  25.             {
  26.                 //lcd_draw_point(x, y, g_back_color);
  27.                 ili9341_draw_pixel(g_back_color, x, y);
  28.             }
  29.             temp <<= 1;
  30.             y++;                    //由上至下
  31.             if ((y - y0) == size)
  32.             {
  33.                 y = y0;
  34.                 x++;                //换列   --->存放形式:列行式
  35.                 break;
  36.             }
  37.         }
  38.     }
  39.     myfree(SRAMIN, dzk);
  40. }
复制代码

由于本人所所用的显示屏为MDM-2802显示模块,故对原显示函数中的画点函数进行了相应地替换,并注释掉了原来的函数。
图4 中文播放界面

要实现图4所示的中文播放界面,其主程序如下:
  1. int main(void)
  2. {
  3.     uint8_t key;
  4.     HAL_Init();
  5.     sys_stm32_clock_init(336, 8, 2, 7);
  6.     delay_init(168);
  7.     usart_init(115200);
  8.     usmart_dev.init(84);
  9.     led_init();
  10.     key_init();
  11.     sram_init();
  12.     norflash_init();
  13.     LCD_Init();
  14.     delay_ms(10);
  15.     ili9341_init();
  16.     ili9341_clear(RED);
  17.     BACK_COLOR=RED;
  18.     POINT_COLOR=YELLOW;
  19.     LCD_DrawLine(WHITE ,0, 35, 239, 35);
  20.     LCD_DrawLine(WHITE ,0, 275, 239, 275);
  21.     my_mem_init(SRAMIN);
  22.     my_mem_init(SRAMEX);
  23.     while (sd_init())
  24.     {
  25.            LCD_ShowString(30,50,"SD Card Failed!");
  26.            delay_ms(200);
  27.            delay_ms(200);
  28.     }
  29.     exfuns_init();
  30.     f_mount(fs[0], "0:", 1);
  31.     f_mount(fs[1], "1:", 1);
  32.     while (fonts_init())
  33.     {
  34.             LCD_ShowString(30,50,"Font Error!");
  35.             delay_ms(200);
  36.     }
  37.     es8388_init();
  38.     es8388_adda_cfg(1, 0);
  39.     es8388_output_cfg(1, 1);
  40.     es8388_hpvol_set(25);
  41.     es8388_spkvol_set(26);
  42.     g_back_color=RED;
  43.     text_show_string(30, 13, 200, 16, "中文菜单音乐播放器", 16, 0, YELLOW);
  44.     POINT_COLOR=WHITE;
  45.     text_show_string(30, 50, 200, 16, "1 - 最美的期待", 16, 0, WHITE);
  46.     text_show_string(30, 70, 200, 16, "2 - 野百合也有春天", 16, 0, WHITE);
  47.     text_show_string(30, 90, 200, 16, "3 - 光阴的故事", 16, 0, WHITE);
  48.     text_show_string(30, 110, 200, 16, "4 - 莫斯科郊外的晚上", 16, 0, WHITE);
  49.     text_show_string(30, 130, 200, 16, "5 - 东方之珠", 16, 0, WHITE);
  50.     text_show_string(30, 150, 200, 16, "6 - 光辉岁月", 16, 0, WHITE);
  51.     text_show_string(30, 170, 200, 16, "7 - 同桌的你", 16, 0, WHITE);
  52.     text_show_string(30, 190, 200, 16, "8 - 亚洲雄风", 16, 0, WHITE);
  53.     text_show_string(30, 210, 200, 16, "9 - 咖啡屋", 16, 0, WHITE);
  54.     text_show_string(30, 230, 200, 16, "10- 军港之夜", 16, 0, WHITE);
  55.     POINT_COLOR=YELLOW;
  56.     text_show_string(30, 280, 200, 16, "KEY0:下一首 KEY2:上一首", 16, 0, YELLOW);
  57.     text_show_string(30, 300, 200, 16, "KEY_UP:暂停/播放", 16, 0, YELLOW);
  58.     POINT_COLOR=WHITE;
  59.     key = key_scan(0);
  60.     while(key != KEY1_PRES)
  61.     {
  62.             key = key_scan(0);
  63.     }
  64.     while (1)
  65.     {
  66.             audio_play();
  67.     }
  68. }
复制代码

有了可以进行播放功能的设计了,其中标识当前播放曲目的函数为:
  1. uint8_t audio_play_song(char* fname)
  2. {
  3.     uint8_t res;
  4.     res = exfuns_file_type(fname);
  5.     switch (res)
  6.     {
  7.         case T_WAV:
  8.             POINT_COLOR=0xF800;
  9.             text_show_string(12, 50+(np*20), 200, 16, "*", 16, 0, 0xF800);
  10.             POINT_COLOR=0xFFE0;
  11.             text_show_string(12, 50+(n*20), 200, 16, "*", 16, 0, 0xFFE0);
  12.             np=n;
  13.             res = wav_play_song(fname);
  14.             break;
  15.         default:
  16.             res = KEY0_PRES;
  17.             break;
  18.     }
  19.     return res;
  20. }
复制代码

而获取相应音频播放文件的函数为:
  1. uint16_t audio_get_tnum(char *path)
  2. {
  3.     uint8_t res;
  4.     uint16_t rval = 0;
  5.     DIR tdir;
  6.     FILINFO* tfileinfo;
  7.     tfileinfo = (FILINFO*)mymalloc(SRAMIN, sizeof(FILINFO));
  8.     res = f_opendir(&tdir, (const TCHAR*)path);
  9.     if ((res == FR_OK) && tfileinfo)
  10.     {
  11.         while (1)
  12.         {
  13.             res = f_readdir(&tdir, tfileinfo);
  14.             if ((res != FR_OK) || (tfileinfo->fname[0] == 0))
  15.             {
  16.                 break;
  17.             }
  18.             res = exfuns_file_type(tfileinfo->fname);
  19.             if ((res & 0xF0) == 0x40)
  20.             {
  21.                 rval++;
  22.             }
  23.         }
  24.     }
  25.     myfree(SRAMIN, tfileinfo);
  26.     return rval;
  27. }
复制代码

实现音频播放与乐曲选择的功能函数为:
  1. void audio_play(void)
  2. {
  3.     uint8_t res;
  4.     DIR wavdir;
  5.     FILINFO *wavfileinfo;
  6.     char *pname;
  7.     uint16_t totwavnum;
  8.     uint16_t curindex;
  9.     uint8_t key;
  10.     uint32_t temp;
  11.     uint32_t *wavoffsettbl;
  12.     es8388_adda_cfg(1, 0);
  13.     es8388_output_cfg(1, 1);
  14.     while (f_opendir(&wavdir, "0:/MUSIC"))
  15.     {
  16.             LCD_ShowString(30,190,"MUSIC ERROR");
  17.             delay_ms(200);
  18.             delay_ms(200);
  19.     }
  20.     totwavnum = audio_get_tnum("0:/MUSIC");
  21.     while (totwavnum == NULL)
  22.     {
  23.              LCD_ShowString(30,190,"NO MUSIC !");
  24.              delay_ms(200);
  25.              delay_ms(200);
  26.     }
  27.     wavfileinfo = (FILINFO*)mymalloc(SRAMIN, sizeof(FILINFO));
  28.     pname = mymalloc(SRAMIN, FF_MAX_LFN * 2 + 1);
  29.     wavoffsettbl = mymalloc(SRAMIN, 4 * totwavnum);
  30.     while (!wavfileinfo || !pname || !wavoffsettbl)
  31.     {
  32.             LCD_ShowString(30,190,"memory Failed");
  33.             delay_ms(200);
  34.             delay_ms(200);
  35.     }

  36.     res = f_opendir(&wavdir, "0:/MUSIC");
  37.     if (res == FR_OK)
  38.     {
  39.         curindex = 0;
  40.         while (1)
  41.         {
  42.             temp = wavdir.dptr;
  43.             res = f_readdir(&wavdir, wavfileinfo);
  44.             if ((res != FR_OK) || (wavfileinfo->fname[0] == 0))
  45.             {
  46.                 break;
  47.             }
  48.             res = exfuns_file_type(wavfileinfo->fname);
  49.             if ((res & 0xF0) == 0x40)
  50.             {
  51.                 wavoffsettbl[curindex] = temp;
  52.                 curindex++;
  53.             }
  54.         }
  55.     }
  56.     curindex = 0;
  57.     res = f_opendir(&wavdir, (const TCHAR*)"0:/MUSIC");
  58.     while (res == FR_OK)
  59.     {
  60.         dir_sdi(&wavdir, wavoffsettbl[curindex]);
  61.         res = f_readdir(&wavdir, wavfileinfo);
  62.         if ((res != FR_OK) || (wavfileinfo->fname[0] == 0))
  63.         {
  64.             break;
  65.         }
  66.         strcpy((char*)pname, "0:/MUSIC/");
  67.         strcat((char*)pname, (const char*)wavfileinfo->fname);
  68.         audio_index_show(curindex + 1, totwavnum);
  69.         key = audio_play_song(pname);
  70.         if (key == KEY2_PRES)
  71.         {
  72.             if (curindex)
  73.             {
  74.                 curindex--;
  75.             }
  76.             else
  77.             {
  78.                 curindex = totwavnum - 1;
  79.             }
  80.         }
  81.         else if (key == KEY0_PRES)
  82.         {
  83.             curindex++;
  84.             if (curindex >= totwavnum)
  85.             {
  86.                 curindex = 0;
  87.             }
  88.         }
  89.         else
  90.         {
  91.             break;
  92.         }
  93.         n=curindex;
  94.     }
  95.     myfree(SRAMIN, wavfileinfo);
  96.     myfree(SRAMIN, pname);
  97.     myfree(SRAMIN, wavoffsettbl);
  98. }
复制代码

其中:为板载4个按键所赋予的功能为:
KEY1 :控制进入播放功能
KEY0 :播放下一首
KEY2 :播放前一首
KEY_UP :暂停与恢复播放

经程序的编译与合星娱乐场备用网址,其播放界面如图5所示。
图5 播放界面

视频演示:


  • 本文系21ic原创,未经许可禁止转载!

亚星娱乐官网