基于stm32和RDA5851S蓝牙模块的歌名歌手同步显示

整理东西整理出了几块RDA5851S模块

本着物尽其用的原则,我查了一下相关资料,发现是在车载上用的,还可以进行AT控制

看到这里我觉得还好,因为这种可以AT控制的蓝牙模块还是比较常见的,

本着试一试的心思,接电源线,想到接功放和喇叭太费事儿,直接连接了一个耳机口,插上耳机,通电

蓝牙名称还是很好找的  CAR KIT ,点击蓝牙连接,手机放歌,耳机里传出了声音,一切正常,除了没有蓝牙连接提示音,断开连接提示音。

接着用USB转串口接到蓝牙的RX TX上,数据显示乱码,切换波特率,再来。。。

终于,波特率57600情况下,显示正常了,哎等等,怎么还有乱码?

换歌再来,还是乱码

灵机一动,放个英文歌

发现了新大陆

MI1后面就是歌名

MI2后面就是歌手

那么问题来了,汉字歌名怎么不行呢?

看看16进制到底发了什么

找个转换工具转一下

喜出望外,说明汉字歌曲是可以的,但为什么这里可以显示,串口助手就不行?

换一个支持改编码的串口助手

原来如此,模块发送出来是UTF-8编码的数据,英文数字因为编码一样可以正常显示,而汉字编码则为乱码。找到原因就好办了。

因为单片机显示汉字是GBK编码的字库,而现在是UTF-8编码,UTF-8可以转GBK吗?查查查起来。。。

UTF-8不能直接转GBK,但是UTF-8可以转成Unicode,而Unicode经过一个大表可以对应到GBK。

代码实现

/************************************************************************
* 函数名称: StrProcess_UTF8toGBK
* 函数功能: 将网络上 utf8 的字符串转换为 GBK 字符串 使得兼容 原子LCD屏驱动程序
* 函数输入: void input: c_utf8 原utf8 字符串 同时 新的 gbk字符串会将其覆盖
* length 你想要设置的 中间缓存块的大小
* 函数输出: void output:字符总数 (一个中文算两个字节)
* 作者 :
* 文件依存:
* #include “ff.h”
* #include “malloc.h”
* #include “stm32f10x.h”
************************************************************************/
int16_t StrProcess_UTF8toGBK(u8 *c_utf8, u16 length)
{
    char low;
    char high;
    char middle;

    // ff_uni2oem(,FF_CODE_PAGE);
    /* !< 首先 将 utf8 转换成标准 Unicode 然后查表将 Unicode 转化为GBK */
    u16 outputSize = 0; //记录转换后的gbk字符串长度
    u8 *pInput = c_utf8;
    u8 *c_gbk = mymalloc(0, length); /* !< 申请内存,也可以外部传入一个 数据缓存空间 */
    u8 *pOutput = c_gbk;
    u16 *uni = (u16 *)c_gbk;
    u16 gbk;
    /* !< 以下中间代码来自于 CSDN @bladeandmaster88 公开的源码 */
    while (*pInput)
    {
        if (*pInput > 0x00 && *pInput <= 0x7F) //处理单字节UTF8字符(英文字母、数字)
        {
            *pOutput = *pInput;
            pOutput += 1;
            *pOutput = 0; //小端法表示,在高地址填补0
        }
        else if (((*pInput) & 0xE0) == 0xC0) //处理双字节UTF8字符
        {
            high = *pInput;
            pInput += 1;
            low = *pInput;
            if ((low & 0xC0) != 0x80) //检查是否为合法的UTF8字符表示
            {
                return -1; //如果不是则报错
            }

            *pOutput = (high << 6) + (low & 0x3F);
            pOutput++;
            *pOutput = (high >> 2) & 0x07;
        }
        else if (((*pInput) & 0xF0) == 0xE0) //处理三字节UTF8字符
        {
            high = *pInput;
            pInput++;
            middle = *pInput;
            pInput++;
            low = *pInput;
            if (((middle & 0xC0) != 0x80) || ((low & 0xC0) != 0x80))
            {
                return -1;
            }
            *pOutput = (middle << 6) + (low & 0x3F);//取出middle的低两位与low的低6位,组合成unicode字符的低8位
            pOutput++;
            *pOutput = (high << 4) + ((middle >> 2) & 0x0F); //取出high的低四位与middle的中间四位,组合成unicode字符的高8位
        }
        else //对于其他字节数的UTF8字符不进行处理
        {
            return -1;
        }
        pInput++;//处理下一个utf8字符
        pOutput++;
    }
    //unicode字符串后面,有两个\0
    *pOutput = 0;
    pOutput++;
    *pOutput = 0;
    /* !< 感谢 @bladeandmaster88 的开源支持 */
    pInput = c_utf8;
    while(*uni != 0)

    {
        gbk = ff_convert((WCHAR) * uni, 0);
        //    gbk = ff_uni2oem(*uni,FF_CODE_PAGE);        /* !< Unicode 向 GBK 转换函数  */
        uni++;
        if(gbk & 0xff00)
        {
            *pInput = ((gbk & 0xff00) >> 8);
            pInput++;
            *pInput = (gbk & 0x00ff);
            pInput++;
            outputSize += 2;
        }
        else
        {
            *pInput = (gbk & 0x00ff);
            pInput++;
            outputSize++;
        }


    }
    *pInput = '\0';         /* !< 加上结束符号 */
    myfree(0, c_gbk);       /* !< 释放内存 */
    return outputSize;
}

蓝牙数据解析

void Data_Analysis()
{
    char *ptr;
    uint8_t lenth = 0;
    uint8_t i = 0;

    ptr = strstr((char *)STR_BUF, "IB");		//已连接
    if(ptr != NULL)
    {
        Connect_Flag = 1;
    }
    else
    {
        ptr = strstr((char *)STR_BUF, "IA");		//断开连接
        if(ptr != NULL)
        {
            Connect_Flag = 0;
        }
    }
    ptr = strstr((char *)STR_BUF, "MB");		//开始播放
    if(ptr != NULL)
    {
        Play_Flag = 1;
    }
    else
    {
        ptr = strstr((char *)STR_BUF, "MA");		//停止播放
        if(ptr != NULL)
        {
            Play_Flag = 0;
        }
    }
    ptr = strstr((char *)STR_BUF, "MI1");		//歌名
    if(ptr != NULL)
    {
        Connect_Flag = 1;
        Play_Flag = 1;
        ptr = ptr + 3;
        lenth = 127;
        i = 0;
        memset(STR_Name , 0 , 127);
        while ((*ptr != 0x0D) && (lenth --))
        {
            STR_Name[i++] = *(ptr++);
        }
    }
    ptr = strstr((char *)STR_BUF, "MI2");		//歌手
    if(ptr != NULL)
    {
        ptr = ptr + 3;
        lenth = 127;
        i = 0;
        memset(STR_Singer , 0 , 127);
        while ((*ptr != 0x0D) && (lenth --))
        {
            STR_Singer[i++] = *(ptr++);
        }
    }
}

接下来就是STM32显示了

接着又画了一下PCB,毕竟总是连着线也不太好,带有充电电路,小集成功放,MOS管控制蓝牙电源,状态指示灯等(毕竟这个蓝牙没连接提示音)。

焊接调试好没问题。

自动居中显示,如果超长则滚动显示

void Dis_Play()
{
    uint8_t STR_Name_len;
    uint8_t STR_Singer_len;
    int8_t STR_Name_can;
    int8_t STR_Singer_can;
    uint8_t STR_Name_symbol = 0;
    uint8_t STR_Singer_symbol = 0;
    int8_t i , j ;

    if(Play_Flag)
    {
        Lcd_P16x16Ch(88, 0, (uint8_t *)"播放", 0);
        Connect_Flag = 1;
    }
    else
    {
        if(Connect_Flag)
        {
            Lcd_P16x16Ch(88, 0, (uint8_t *)"暂停", 0);
        }

    }
    if(Connect_Flag)
    {
        Lcd_P16x16Ch(8, 0, (uint8_t *)"已连接", 0);
				LED2_ON;
    }
    else
    {
        Lcd_P16x16Ch(8, 0, (uint8_t *)"未连接", 0);
				LED2_OFF;
    }

    Lcd_fill(0, 4, 128, 4, 0);


    if(STR_Name_lenth > 16)	//歌名超长滚动处理
    {
        STR_Name_can = STR_Name_lenth - STR_Name_num ;

        if(STR_Name_can < 0)
        {
            STR_Name_num = 0;
            STR_Name_can = STR_Name_lenth - STR_Name_num ;
        }

        if(STR_Name_can > 16)
        {

            for(i = 0 ; i < 16 ; i ++)
            {
                if(STR_Name [i + STR_Name_num] <= 0x80)
                {
                    STR_Name_symbol ++;
                }
                Dis_STR_Name[i] = STR_Name [i + STR_Name_num] ;
            }

        }
        else
        {
            for(i = 0 ; i < STR_Name_can ; i ++)
            {
                Dis_STR_Name[i] = STR_Name [i + STR_Name_num] ;
            }
            Dis_STR_Name[i ++] = 0x20 ;
            Dis_STR_Name[i ++] = 0x20 ;
            STR_Name_can = STR_Name_can + 2 ;
            j = 0 ;
            for(; i < 16 ; i++)
            {
                Dis_STR_Name[i] = STR_Name [j++] ;
            }

            for(i = 0; i < 16 ; i++)
            {
                if(Dis_STR_Name[i] <= 0x80)
                {
                    STR_Name_symbol ++;
                }
            }

        }


        if(STR_Name_symbol % 2)
        {
            Dis_STR_Name[15] = 0;
        }
        if(Dis_STR_Name[0] <= 0x80)
        {
            STR_Name_num += 1;
        }
        else
        {
            STR_Name_num += 2;
        }

        STR_Name_len = 0;
    }
    else		//歌名自动居中处理
    {
        memset(Dis_STR_Name , 0 , 16);
        for(i = 0 ; i < STR_Name_lenth ; i ++)
        {
            Dis_STR_Name[i] = STR_Name [i] ;
        }
        STR_Name_len = (128 - STR_Name_lenth * 8) / 2;
    }



    if(STR_Singer_lenth > 16)	//歌手超长滚动处理
    {
        STR_Singer_can = STR_Singer_lenth - STR_Singer_num ;

        if(STR_Singer_can < 0)
        {
            STR_Singer_num = 0;
            STR_Singer_can = STR_Singer_lenth - STR_Singer_num ;
        }

        if(STR_Singer_can > 16)
        {

            for(i = 0 ; i < 16 ; i ++)
            {
                if(STR_Singer [i + STR_Singer_num] <= 0x80)
                {
                    STR_Singer_symbol ++;
                }
                Dis_STR_Singer[i] = STR_Singer [i + STR_Singer_num] ;
            }

        }
        else
        {
            for(i = 0 ; i < STR_Singer_can ; i ++)
            {
                Dis_STR_Singer[i] = STR_Singer [i + STR_Singer_num] ;
            }
            Dis_STR_Singer[i ++] = 0x20 ;
            Dis_STR_Singer[i ++] = 0x20 ;
            STR_Singer_can = STR_Singer_can + 2 ;
            j = 0 ;
            for(; i < 16 ; i++)
            {
                Dis_STR_Singer[i] = STR_Singer [j++] ;
            }

            for(i = 0; i < 16 ; i++)
            {
                if(Dis_STR_Singer[i] <= 0x80)
                {
                    STR_Singer_symbol ++;
                }
            }

        }


        if(STR_Singer_symbol % 2)
        {
            Dis_STR_Singer[15] = 0;
        }
        if(Dis_STR_Singer[0] <= 0x80)
        {
            STR_Singer_num += 1;
        }
        else
        {
            STR_Singer_num += 2;
        }

        STR_Singer_len = 0;
    }
    else	//歌手自动居中处理
    {
        memset(Dis_STR_Singer , 0 , 16);
        for(i = 0 ; i < STR_Singer_lenth ; i ++)
        {
            Dis_STR_Singer[i] = STR_Singer [i] ;
        }
        STR_Singer_len = (128 - STR_Singer_lenth * 8) / 2;
    }

    Lcd_P16x16Ch(STR_Name_len, 4, Dis_STR_Name, 0);		//歌名显示
    Lcd_P16x16Ch(STR_Singer_len, 6, Dis_STR_Singer, 0);		//歌手显示

}

 

大功告成,试了一下,几乎所有音乐软件都可以(主流的那几个都试了,包括自带的音乐播放器,还有一些游戏背景音乐也可以)可以同步显示歌名歌手,再也不用为不知道现在放的什么歌而苦恼了,也不用打开手机查看了。

以下就是全部下载资料https://download.csdn.net/download/qq_22848695/13106771

 

后续:因为汉字显示是Unicode通过一个大表可以对应到GBK,而这个表只有基本汉字(意思就是没有一些生僻字和部分特殊符号),即使这样,程序也达到了190K,不过实际使用中影响不大,我切了几十首歌才有一个因为特殊符号乱码的(可能我找的歌也不到位)。

 

 

 

  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
STM32控制两个RDA5820的过程如下: 首先,在STM32的GPIO引脚中选择两个不同的引脚作为数据传输的引脚和控制引脚。可以通过STM32的开发环境配置这些引脚,并将其设置为输出模式。 然后,使用SPI或I2C总线将STM32与RDA5820连接起来。SPI是一种串行通信协议,而I2C是一种串行总线协议,它们都可以用于与外部设备进行通信。可以通过设置STM32的寄存器来初始化和配置SPI或I2C通信参数,例如时钟频率、数据位数等。 接下来,通过STM32的代码控制,将音频数据传输到RDA5820。首先,将音频数据写入STM32的寄存器或缓冲区中,然后使用SPI或I2C通信协议将数据发送到RDA5820。可以使用STM32提供的相关函数进行数据传输操作。 在数据传输过程中,还需要控制RDA5820的工作模式和设置参数。例如,可以通过SPI或I2C通信协议发送控制指令来设置RDA5820的音量、均衡器、功率等参数。这些控制指令可以通过STM32的代码编写和发送。 最后,根据需要,可以使用STM32的定时器功能来控制两个RDA5820的同步。定时器可以用来生成时钟信号,用于RDA5820的时序控制,以确保两个RDA5820在同一时间内进行同步操作。 综上所述,通过使用STM32的GPIO、SPI或I2C通信协议,以及定时器功能,可以实现对两个RDA5820的控制。通过STM32与RDA5820之间的数据传输和控制,可以实现音频数据的处理和音频效果的调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值