本帖最后由 jinglixixi 于 2022-8-20 14:13 编辑
#申请原创#
MP3音频模块是一种可以串口进行控制的器件,在设计中文菜单式MP3播放器时,用该模块可提高MCU处理的并行性,该设计的整体构成如图1所示。 图1 整体构成 图2 模块构成 在运行过程中,其处理流程图3所示。 图3处理流程图 在使用过程中,通过板上的4个按键可进行歌曲的选取及音量调整等。此外,为了能扩展菜单的容量,还增添了边界自动换页的处理功能,其页面形式如图4所示。 图4界面效果 1. TFT显示屏驱动与界面设计 在该设计中,是采用2.2寸TFT彩屏,它采用SPI接口来工作。 1)引脚配置 TFT屏与开发板连接关系为: BLK-------PB8 CS---------PB7 RS---------PB6 RST-------PB5 SCL------- PB3 SDA------ PB4 为便于控制引脚输出高低电平,其语句定义为: #define LCD_SCK_Low() GPIO_Pins_Reset(GPIOB, GPIO_PIN_3) //CLK #define LCD_SCK_High() GPIO_Pins_Set(GPIOB, GPIO_PIN_3) #define LCD_SDI_Low() GPIO_Pins_Reset(GPIOB, GPIO_PIN_4) //DIN #define LCD_SDI_High() GPIO_Pins_Set(GPIOB,GPIO_PIN_4) #define LCD_REST_Low() GPIO_Pins_Reset(GPIOB, GPIO_PIN_5) //RES #define LCD_REST_High() GPIO_Pins_Set(GPIOB, GPIO_PIN_5) #define LCD_DC_Low() GPIO_Pins_Reset(GPIOB, GPIO_PIN_6) //DC #define LCD_DC_High() GPIO_Pins_Set(GPIOB,GPIO_PIN_6) #define LCD_CS_Low() GPIO_Pins_Reset(GPIOB, GPIO_PIN_7) //CS #define LCD_CS_High() GPIO_Pins_Set(GPIOB,GPIO_PIN_7) #define LCD_LED_High() GPIO_Pins_Set(GPIOB,GPIO_PIN_8) //BLK 对TFT屏所用引脚的配置函数为: void app_tft_init(void)
{
GPIO_InitType GPIO_InitStructure;
RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOA);
GPIO_Structure_Initialize(&GPIO_InitStructure);
GPIO_InitStructure.Pin= GPIO_PIN_5|GPIO_PIN_7;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUT_PP;
GPIO_InitStructure.GPIO_Current = GPIO_DS_4MA;
GPIO_Peripheral_Initialize(GPIOA, &GPIO_InitStructure);
RCC_AHB_Peripheral_Clock_Enable(RCC_AHB_PERIPH_GPIOB);
GPIO_Structure_Initialize(&GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUT_PP;
GPIO_InitStructure.GPIO_Current = GPIO_DS_4MA;
GPIO_Peripheral_Initialize(GPIOB, &GPIO_InitStructure);
LCD_LED_High();
}
2)初始化 为使TFT屏工作,其初始化函数为: void tft_Init(void)
{
LCD_REST_Low();
SysTick_Delay_Ms(20);
LCD_REST_High();
SysTick_Delay_Ms(20);
LCD_CS_Low();
LCD_WR_REG(0xCB);
LCD_WR_DATA8(0x39);
LCD_WR_DATA8(0x2C);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x34);
LCD_WR_DATA8(0x02);
LCD_WR_REG(0xCF);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0XC1);
LCD_WR_DATA8(0X30);
LCD_WR_REG(0xE8);
LCD_WR_DATA8(0x85);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x78);
LCD_WR_REG(0xEA);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x00);
LCD_WR_REG(0xED);
LCD_WR_DATA8(0x64);
LCD_WR_DATA8(0x03);
LCD_WR_DATA8(0X12);
LCD_WR_DATA8(0X81);
LCD_WR_REG(0xF7);
LCD_WR_DATA8(0x20);
LCD_WR_REG(0xC0);
LCD_WR_DATA8(0x23);
LCD_WR_REG(0xC1);
LCD_WR_DATA8(0x10);
LCD_WR_REG(0xC5);
LCD_WR_DATA8(0x3e);
LCD_WR_DATA8(0x28);
LCD_WR_REG(0xC7);
LCD_WR_DATA8(0x86);
LCD_WR_REG(0x36);
LCD_WR_DATA8(0x48);
LCD_WR_REG(0x3A);
LCD_WR_DATA8(0x55);
LCD_WR_REG(0xB1);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x18);
LCD_WR_REG(0xB6);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x82);
LCD_WR_DATA8(0x27);
LCD_WR_REG(0xF2);
LCD_WR_DATA8(0x00);
LCD_WR_REG(0x26);
LCD_WR_DATA8(0x01);
LCD_WR_REG(0xE0);
LCD_WR_DATA8(0x0F);
LCD_WR_DATA8(0x31);
LCD_WR_DATA8(0x2B);
LCD_WR_DATA8(0x0C);
LCD_WR_DATA8(0x0E);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x4E);
LCD_WR_DATA8(0xF1);
LCD_WR_DATA8(0x37);
LCD_WR_DATA8(0x07);
LCD_WR_DATA8(0x10);
LCD_WR_DATA8(0x03);
LCD_WR_DATA8(0x0E);
LCD_WR_DATA8(0x09);
LCD_WR_DATA8(0x00);
LCD_WR_REG(0XE1);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x0E);
LCD_WR_DATA8(0x14);
LCD_WR_DATA8(0x03);
LCD_WR_DATA8(0x11);
LCD_WR_DATA8(0x07);
LCD_WR_DATA8(0x31);
LCD_WR_DATA8(0xC1);
LCD_WR_DATA8(0x48);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x0F);
LCD_WR_DATA8(0x0C);
LCD_WR_DATA8(0x31);
LCD_WR_DATA8(0x36);
LCD_WR_DATA8(0x0F);
LCD_WR_REG(0x11);
SysTick_Delay_Ms(120);
LCD_WR_REG(0x29);
LCD_WR_REG(0x2c);
}
3)界面实现 该播放控制器的界面由图案和菜单构成,为便于控制,是按界面结构显示和菜单显示两部分来完成。 实现图案显示的函数为: void show_tb(unsigned int x,unsigned int y)
{
unsigned int i,j,k;
unsigned int da;
k=0;
for(i=0;i<50;i++)
{
for(j=0;j<50;j++)
{
da=gImage_tb[k*2];
da<<=8;
da|=gImage_tb[k*2+1];
POINT_COLOR=da;
LCD_DrawPoint(x-j,y+i);
k++;
}
}
}
实现界面结构显示的函数为: void LCD_JM()
{
LCD_Clear(RED);
LCD_Fill(0,0,239,50,WHITE);
show_tb(60,0);
BACK_COLOR=WHITE;
POINT_COLOR=RED;
LCD_ShowChar(80,16,'M',1);
LCD_ShowChar(90,16,'P',1);
LCD_ShowChar(100,16,'3',1);
showhanzi16(115,16,32);
showhanzi16(135,16,33);
showhanzi16(155,16,34);
showhanzi16(175,16,35);
showhanzi16(195,16,36);
LCD_Fill(0,287,239,319,WHITE);
BACK_COLOR=WHITE;
POINT_COLOR=RED;
LCD_ShowString(60,294,"BY: jinglixixi");
}
2. 中文菜单与选择处理 由于在菜单中是实现中文歌单,故需按菜单内容来构建中文字库。 1)字模提取 使用图5所示的字模提取软件,可辅助完成中文字库的构建,其提取格式见图6所示。 图5字模提取 图6字模格式 相应的字模存储结构为: unsigned char hanzi16[]=
{
0x80,0x20,0x82,0x20,0xF4,0x17,0x84,0x08,0x80,0x00,0xE1,0x23,0x02,0x20,0xEA,0x13,
0x28,0x0A,0x24,0x42,0xE7,0x43,0x24,0x22,0x44,0x21,0x04,0x17,0xF4,0x08,0x20,0x04,/*"澎",0*/
0x80,0x00,0x84,0x78,0x88,0x48,0xE8,0x4B,0x81,0x48,0x82,0x78,0x82,0x48,0xE8,0x4B,
0x28,0x4A,0x24,0x7A,0x27,0x4A,0xE4,0x4B,0x24,0x4A,0x04,0x44,0x04,0x54,0x00,0x22,/*"湖",1*/
0x80,0x00,0x04,0x01,0xF8,0x3F,0x88,0x04,0xA1,0x14,0x92,0x24,0x02,0x00,0xE8,0x0F,
0x08,0x08,0xE4,0x0F,0x27,0x00,0xE4,0x1F,0x04,0x10,0x04,0x10,0x04,0x0A,0x00,0x04,/*"湾",2*/
...
}
配合上面的字库结构,其汉字显示函数为: void showhanzi16(unsigned int x,unsigned int y,unsigned char index)
{
unsigned char i,j,k;
const unsigned char *temp=hanzi16;
temp+=index*32;
Address_set(x,y,x+16-1,y+16-1);
for(j=0;j<16;j++)
{
for(k=0;k<2;k++)
{
for(i=0;i<8;i++)
{
if((*temp&(1<<i))!=0)
{
LCD_WR_DATA(POINT_COLOR);
}
else
{
LCD_WR_DATA(BACK_COLOR);
}
}
temp++;
}
}
}
2)中文菜单 利用中文字库,实现中文菜单显示的函数为: void LCD_MENU()
{
BACK_COLOR=RED;
POINT_COLOR=YELLOW;
showhanzi16(60,75,0);
showhanzi16(80,75,1);
showhanzi16(100,75,2);
showhanzi16(30,75,37);
showhanzi16(60,105,3);
showhanzi16(80,105,4);
showhanzi16(100,105,5);
showhanzi16(120,105,6);
showhanzi16(60,135,7);
showhanzi16(80,135,8);
showhanzi16(60,165,9);
showhanzi16(80,165,10);
showhanzi16(60,195,11);
showhanzi16(80,195,12);
showhanzi16(100,195,13);
showhanzi16(120,195,14);
showhanzi16(60,225,15);
showhanzi16(80,225,16);
showhanzi16(100,225,17);
showhanzi16(120,225,18);
showhanzi16(140,225,19);
showhanzi16(60,255,20);
showhanzi16(80,255,21);
showhanzi16(100,255,22);
showhanzi16(120,255,23);
showhanzi16(140,255,24);
showhanzi16(160,255,25);
showhanzi16(180,255,26);
}
3)选择处理与指示 在开发板上,共有5个按键,除复位键外,皆可用于程序控制,其原理图见图7所示。 图7 LED与KEY电路 为便于MP3的控制,其中各键的功能分配如下: S1------PA4----下一首 S2------PA5----上一首 S3------PA6----确认 S6------PA0----音量 此外,为了便于观察还使用D1和D2来指示S1和S2键的操作状态。 在歌曲选择时,是通过星型的光标来指示的,在确认后即可播放选择的歌曲。 实现按键选择及播放的测试程序如下: void sele()
{
BACK_COLOR=RED;
POINT_COLOR=YELLOW;
h=75;
i=0;
while(1)
{
if(GPIO_Input_Pin_Data_Get(GPIOA, GPIO_PIN_4)==0)
{
GPIO_Pins_Set(GPIOA, GPIO_PIN_1);
if(i<6)
{
i++;
LCD_Fill(30,h,50,h+20,RED);
h=h+30;
showhanzi16(30,h,37);
}
}
else
{
GPIO_Pins_Reset(GPIOA, GPIO_PIN_1);
}
if(GPIO_Input_Pin_Data_Get(GPIOA, GPIO_PIN_5)==0)
{
GPIO_Pins_Set(GPIOA, GPIO_PIN_7);
if(i>0)
{
i--;
LCD_Fill(30,h,50,h+20,RED);
h=h-30;
showhanzi16(30,h,37);
}
}
else
{
GPIO_Pins_Reset(GPIOA, GPIO_PIN_7);
}
if(GPIO_Input_Pin_Data_Get(GPIOA, GPIO_PIN_6)==0)
{
playn(i);
TxCounter=0;
while (TxCounter < 10)
{
USART_Data_Send(USARTy, cmd3[TxCounter]);
TxCounter++;
while(USART_Flag_Status_Get(USARTy, USART_FLAG_TXDE) == RESET);
}
}
SysTick_Delay_Ms(200);
}
}
3. MP3播放模块控制 MP3播放模块是一款可以串口通信进行控制的器件,其引脚分别如图8所示。 其实,在使用中除电源引脚外,它只占用一个串口输出引脚,即PA9。 此外,由于该模块的通讯波特率为9600bps,故需在此波特率下工作。 图8MP3播放模块 1)串口通信 字节指令发送是控制MP3播放模块的关键,其程序为: TxCounter=0;
while (TxCounter < 10)
{
USART_Data_Send(USARTy, cmd[TxCounter]);
TxCounter++;
while(USART_Flag_Status_Get(USARTy, USART_FLAG_TXDE) == RESET);
}
2)播放控制 MP3播放指定乐曲是靠指定音乐序号来完成的,其生成相应播放指令的函数为: void playn(int index)
{
int i;
unsigned char checksum = 0;
cmd3[5] = (unsigned char)(index >> 8);
cmd3[6] = (unsigned char)(index);
for (i=2; i<8; i++)
{
checksum += cmd3[i];
}
cmd3[8] = (unsigned char)~checksum;
}
3)音量调节 为在播放过程中对音量加以动态调节,是使用s6键,由于只有一个键可用,故其调节模式为先由低到高调整,在跌倒到最低音量开始增大调节。 控制音量调节的函数为: void setVolume(unsigned char index)
{
unsigned char checksum = 0;
int i;
cmd6[6] = (unsigned char)(index);
for (i=2; i<8; i++)
{
checksum += cmd6[i];
}
cmd6[8] = (unsigned char)~checksum;
}
MP3播放模块的指令测试如图9所示,说明它已能进行播放控制。 图9 指令发送测试 结束语: 尽管N32G430的长项不在于音乐播放,但这不妨碍我们以技术手段来达到我们的目标。 在N32G430开发板上实现语音的播放还是十分具有特色和实用价值的。当然,它也适用于其它进行语音提示等人机交互场合。 视频演示:
|