jinglixixi 发表于 2016-7-19 16:28

【21ic分享赛】 基于51单片机的MP3点播器 续1

三、功能实现
除了硬件方面的设计,要实现相应的功能目标,软件的设计也是不可或缺的。为了更好地进行设计,先来了解一下整体的处理流程。
MP3点播器的处理流程为:
选择歌曲播放的方向(前2项)->选择歌曲->选择播放中的控制功能(后4项)->轮回处理
了解处理后,我们再看一看需要解决的任务,它主要包含3部分:
1)显示功能的设计
2)按键功能的设计
3)通讯功能的设计
在开发过程中,由于所用的单片机只是一个最小系统,使用是借用另一块带有RS232串口通讯功能的单片机来进行开发与测试的,其使用方式如图11所示。
图11外挂RS232串口通讯下载程序
1. 显示功能的设计受OLED屏显示信息量的限制,在歌曲选择时,是随着选择来更换歌曲名称;而在播放控制时,是通过控制工具栏的符号闪动来提示当前供选择的功能项,其处理效果如图12所示。图12功能项闪动提示效果
在显示方面,涉及的功能函数有:OLED 初始化函数、清屏函数、字符显示函数、数值显示函数汉字显示函数、及菜单显示函数等。OLED 初始化函数如下:void OLED_Init(void)
{        
    OLED_WR_Byte(0xAE,OLED_CMD);
        OLED_WR_Byte(0x00,OLED_CMD);
        OLED_WR_Byte(0x10,OLED_CMD);
        OLED_WR_Byte(0x40,OLED_CMD);
        OLED_WR_Byte(0xB0,OLED_CMD);
        OLED_WR_Byte(0x81,OLED_CMD);
        OLED_WR_Byte(0xFF,OLED_CMD);
        OLED_WR_Byte(0xA1,OLED_CMD);
        OLED_WR_Byte(0xA6,OLED_CMD);
        OLED_WR_Byte(0xA8,OLED_CMD);
        OLED_WR_Byte(0x3F,OLED_CMD);
        OLED_WR_Byte(0xC8,OLED_CMD);
        OLED_WR_Byte(0xD3,OLED_CMD);
        OLED_WR_Byte(0x00,OLED_CMD);
        OLED_WR_Byte(0xD5,OLED_CMD);
        OLED_WR_Byte(0x80,OLED_CMD);
        OLED_WR_Byte(0xD8,OLED_CMD);
        OLED_WR_Byte(0x05,OLED_CMD);
        OLED_WR_Byte(0xD9,OLED_CMD);
        OLED_WR_Byte(0xF1,OLED_CMD);
        OLED_WR_Byte(0xDA,OLED_CMD);
        OLED_WR_Byte(0x12,OLED_CMD);
        OLED_WR_Byte(0xDB,OLED_CMD);
        OLED_WR_Byte(0x30,OLED_CMD);
        OLED_WR_Byte(0x8D,OLED_CMD);
        OLED_WR_Byte(0x14,OLED_CMD);
        OLED_WR_Byte(0xAF,OLED_CMD);
} 清屏函数如下:void OLED_Clear(void)
{
        u8 i,n;                  
        for(i=0;i<8;i++)
        {
                OLED_WR_Byte (0xb0+i,OLED_CMD);   
                OLED_WR_Byte (0x00,OLED_CMD);   
                OLED_WR_Byte (0x10,OLED_CMD);      
                for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA);
        }
}在字符显示过程中,要有字符库的支持,以6*8点字模为例其结构如下:const unsigned char code F6x8[] =                {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,// sp0x00, 0x00, 0x00, 0x2f, 0x00, 0x00,// !0x00, 0x00, 0x07, 0x00, 0x07, 0x00,// "。。。0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E,// 00x00, 0x00, 0x42, 0x7F, 0x40, 0x00,// 10x00, 0x42, 0x61, 0x51, 0x49, 0x46,// 2。。。}字符显示函数如下:void OLED_Clear(void)
{
        u8 i,n;                  
        for(i=0;i<8;i++)
        {
                OLED_WR_Byte (0xb0+i,OLED_CMD);   
                OLED_WR_Byte (0x00,OLED_CMD);   
                OLED_WR_Byte (0x10,OLED_CMD);      
                for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA);
        }
}
在字符显示过程中,要有字符库的支持,以6*8点字模为例其结构如下:const unsigned char code F6x8[] =                {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,// sp0x00, 0x00, 0x00, 0x2f, 0x00, 0x00,// !0x00, 0x00, 0x07, 0x00, 0x07, 0x00,// "。。。0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E,// 00x00, 0x00, 0x42, 0x7F, 0x40, 0x00,// 10x00, 0x42, 0x61, 0x51, 0x49, 0x46,// 2。。。}字符显示函数如下:void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size)
{             
          unsigned char c=0,i=0;       
                c=chr-' ';               
                if(x>Max_Column-1){x=0;y=y+2;}
                if(Char_Size ==16)
                        {
                        OLED_Set_Pos(x,y);       
                        for(i=0;i<8;i++)
                        OLED_WR_Byte(F8X16,OLED_DATA);
                        OLED_Set_Pos(x,y+1);
                        for(i=0;i<8;i++)
                        OLED_WR_Byte(F8X16,OLED_DATA);
                        }
                        else
            {       
                                OLED_Set_Pos(x,y);
                                for(i=0;i<6;i++)
                                OLED_WR_Byte(F6x8,OLED_DATA);
                   }
}数值显示函数如下:void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2)
{                
        u8 t,temp;
        u8 enshow=0;                                                  
        for(t=0;t<len;t++)
        {
                temp=(num/oled_pow(10,len-t-1))%10;
                if(enshow==0&&t<(len-1))
                {
                        if(temp==0)
                        {
                                OLED_ShowChar(x+(size2/2)*t,y,' ',size2);
                                continue;
                        }else enshow=1;
                }
               OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2);
        }
}与字符相同,汉字的显示也需要字库的支持,受存储空间的限制这里是自行构建了一个仅供菜单显示用的小字库,其结构如下:unsigned char code Hzk[]={ //点(0) 播(1) 器(2) 设(3) 计(4) {0x00,0x00,0xC0,0x40,0x40,0x40,0x7F,0x48,0x48,0x48,0x48,0xC8,0x08,0x08,0x00,0x00},{0x80,0x40,0x37,0x04,0x04,0x14,0x64,0x04,0x14,0x64,0x04,0x07,0x10,0xE0,0x00,0x00},/*"点",0*/{0x10,0x10,0xFF,0x10,0x90,0x82,0x56,0x3A,0x12,0x7F,0x11,0x39,0x55,0x90,0x80,0x00},{0x42,0x82,0x7F,0x01,0x00,0x00,0xFF,0x49,0x49,0x7F,0x49,0x49,0xFF,0x00,0x00,0x00},/*"播",1*/{0x80,0x80,0x9E,0x92,0x92,0x92,0x9E,0xE0,0x80,0x9E,0xB2,0xD2,0x92,0x9E,0x80,0x00},{0x08,0x08,0xF4,0x94,0x92,0x92,0xF1,0x00,0x01,0xF2,0x92,0x94,0x94,0xF8,0x08,0x00},/*"器",2*/。。。}汉字显示函数如下:void OLED_ShowCHinese(u8 x,u8 y,u8 no)
{                                
        u8 t,adder=0;
        OLED_Set_Pos(x,y);       
    for(t=0;t<16;t++)
                {
                                OLED_WR_Byte(Hzk,OLED_DATA);
                                adder+=1;
       }       
                OLED_Set_Pos(x,y+1);       
      for(t=0;t<16;t++)
                {       
                                OLED_WR_Byte(Hzk,OLED_DATA);
                                adder+=1;
      }                                       
}受程序存储空间的限制,在设计过程中是采用测试的方法来逐渐添加菜单内容的,在建到十首歌时已达到7K左右(STC89C52为8K芯片),就没再继续添加,估计还可以添加几首吧。由于是采用小字库设计菜单,在使用时是按排列顺序来建立映射关系的,设计时出于方便是为每个菜单项设计了一个小函数以供调用,以“放心去飞”为例,其显示函数为:void cd10()
{   // 放心去飞
        OLED_Clearp();   // 局部清除函数
        OLED_ShowCHinese(18,2,41);// 放
        OLED_ShowCHinese(36,2,42);// 心
        OLED_ShowCHinese(54,2,43);// 去
        OLED_ShowCHinese(72,2,44);// 飞
}若想参考更全的OLED资料,可参考“中景园电子0.96OLED显示屏_C51系列_IIC_例程推荐”。

21ic小喇叭 发表于 2016-7-20 10:41

分享的都是大牛啊

jinglixixi 发表于 2016-7-20 10:46

21ic小喇叭 发表于 2016-7-20 10:41
分享的都是大牛啊

过奖了!多谢了。
页: [1]
查看完整版本: 【21ic分享赛】 基于51单片机的MP3点播器 续1