歌词显示器开发注意项
📎 原始文档:https://www.kdocs.cn/l/cs2CpQtyeib6 歌词显示器开发注意项
简介:
该文章用于说明歌词显示器开发过程的一些注意项,多用图文的形式说明。
目前市面上的歌词显示器分为两种型态:
- 一体式K歌音箱歌词显示器:这种产品支持蓝牙音频播放U盘等多功能,同时支持歌词的显示。

- 一拖二歌词提词显示器:这种产品仅支持蓝牙连接功能,支持一拖二的歌词显示。

一体式K歌音箱歌词显示器:
一般选用的方案是 AC695N+AD10X灯板。根据AD10X是否有内封flash,做了两份PDF文档说明,如下:
AC695N_使用AD10X灯板(带flash)说明V2.pdf
AC695N_使用AD10X灯板(不带flash)说明.pdf
AD10X芯片常用封装有AD101C8和AD101C0,其中AD101C8为带1M Byte 大小 flash的芯片,而AD101C0 则为不带flash的芯片。
注意事项:
AC695N+AD101C0(不带flash)
- AD101C0的运行逻辑大概如下:
- AC695N和AD101C0上电,AC101C0会运行在maskroom,AC695N正常运行
- 使用接口sh50_isp_up_code()通过SPI接口发送AD10x_code.bin的代码到AD101C0
- AD101C0将接收到的数据存放到RAM空间中,待数据接收完成后复位,运行RAM空间的代码
- AD101C0将收到通过AC695N已经解析好的点阵数据通过串口发送,进行歌词的显示 注意:AD10x_code.bin 文件在 路径AD10X_Resource_led_1.0.0\AD10x_code(bin)\AD10x_code(bin)
默认只提供了三种bin文件
- SPI口使用的IO在 cpu\br23\sh50_isp.c中可以查看

- UART口(串口)使用的IO在 apps\common\update\uart_update_master.c 的MUTIL_CPU_UART_UPDATE_ENABLE宏定义包含中可以查看

- AD10X灯板显示分辨率配置在 apps\soundbox\ui\led_lyric\led_lyric.h,显示逻辑接口在 apps\soundbox\ui\led_lyric\led_lyric.c

- 由于AD101C0无内置flash,需要将字库下载AC695N这边,download.bat需要在-res后加入font.bin gbk2utf8.tab AD10x_code.bin这三个文件

AC695N+AD101C8(带flash)
这种情况字库一般放置在AD101C8,所以AC695N这边不需要下载字库等资源。

UART口(串口)使用的IO在 apps\common\update\uart_update_master.c 的MUTIL_CPU_UART_UPDATE_ENABLE宏定义包含中可以查看

AD10X灯板显示分辨率配置在 apps\soundbox\ui\led_lyric\led_lyric.h,显示逻辑接口在 apps\soundbox\ui\led_lyric\led_lyric.c

AD101C8使用串口工具的SPI接口烧写(成功概率较低),使用方法请浏览以下文章。

如果AD101C8已经成功烧录过一次,有代码在芯片内,则可以进行串口升级,操作方法同样参考第4点说明。
由于强制升级工具spi的下载方式不稳定,针对AD10x内封flash的封装,升级方案如下: 第一次 裸片由 1 托 2 来完成升级 第二次之后,就可以选择强制升级工具的串口升级方式来下载调试。为方便AD10X开发下载调试AD10X端提供下载工具和上位机,ad100_uart_update.exe,文件在AD10X代码文件夹内 ad100_uart_update_tools.rar
使用方法如下:
为方便AD10X调试显示内容及初步验证程序运行,提供串口调试工具上位机,用于串口推显示数据给到灯板具体显示所需内容。 AD10x灯板串口工具升级_ad100_led_test_v2_修正中文显示.rar
使用办法及注意事项:
1、config.ini 中可自行修改自己电脑上具体使用对应的串口 COM 口,接线的话,电脑串口工具的TX与灯板的RX 相接,主要是 发命令给到灯板做通信
2、同时可以使用该工具做串口升级的功能(注意升级的程序与自己原本下载的程序key 是否一致,默认压缩包解压出来的bin 文件不带key ,最好都能替换成自己程序下的bin 文件而不是用默认的)
分别输入 upfw 和 upft 指令,可以对应升级 工具同级目录下的ad100_update_code.bin 和 ad100_update_all.bin ,区别在于 upfw就是升级code区域,upft就是升级code+字库
而 ad100_update_code.bin 就是仅仅为code 区域的代码,
ad100_update_all.bin 为 code+字库 的代码。
3、与灯板通信成功后,会有请输入要显示的文字的输入串口,输入你想要显示的内容即可。
若是遇到异常情况如下:一直处于read timeout 和error 的报错,那么就是与灯板的串口通信不成功,跟串口的TX和RX 不接上灯板的表现一模一样。
PS:(特殊情况,用于界面有显示让输入显示文字的界面,但是实际灯板没有显示出来所需要的文字时,完全不亮的情况debug) 若是串口的TX与灯板的RX不去通信(悬空时不连接),而使用这个工具进入了正常页面让输入显示的文字时,这个时候需要删掉原有的"AD10x灯板串口工具升级_ad100_led_test_v2_修正中文显示"压缩包里面的内容,重新解压出来新的文件就会正常。即正常有请输入要显示的文字页面,一定是要跟灯板正常通信之后才有的界面,不然就是异常了需要重新解压压缩包里面的文件出来。
一拖二歌词提词显示器:
一般选用的方案是 AC696N+AD101C0,使用最省成本的方案。
AC696N_一拖二蓝牙提词器说明.pdf
注意事项:
AC696N+AD101C0(不带flash),一拖二蓝牙提词器
- 可以参照AC695N+AD101C0(不带flash)的说明
FAQ
1、695NV3.1.2,#define UI_LED_LRC_DECODE_FONT 0 配置无字库的宏定义后会造成死机问题
需要修改
void lyrics_update_font(u8 *str, u16 len, LRC_SHOW_INFO *show_info)
{
#if UI_LED_LRC_DECODE_FONT
if (f_info.pixel.file.fd == NULL) {
printf("err, font file not open\n");
return;
}
#endif
u16 str_curr_crc;
static u16 str_last_crc = 0;
str_curr_crc = CRC16(str, len);
if (str_last_crc == str_curr_crc && lrc_status.lrc_show_status_update_flag == 0 && lrc_check_online_flag) {
return;
}
if (len == 0) {
lrc_status.lrc_show_status_update_flag = 0;
return;
}
#if UI_LED_LRC_DECODE_FONT
os_mutex_pend(&show_mutex, 0);
#endif
/* 记录当前字符串内容和长度,在更新显示参数实时刷新时需要用到 */
if (lrc_status.lrc_record_str && lrc_status.lrc_show_status_update_flag == 0) {
free(lrc_status.lrc_record_str);
lrc_status.lrc_record_str = NULL;
}
if (lrc_status.lrc_record_str == NULL) {
lrc_status.lrc_record_str = zalloc(len);
}
lrc_status.lrc_record_len = len;
memcpy(lrc_status.lrc_record_str, str, len);
/* 记录当前字符串内容和长度,在更新显示参数实时刷新时需要用到 */
str_last_crc = str_curr_crc;
#if (UI_LED_LRC_DECODE_FONT == 0)
lrc_buf_push(str, len);
lrc_status.lrc_show_status_update_flag = 0;
// os_mutex_post(&show_mutex);
return;
#endif
u16 scroll_speed;
u8 rotate, flip;
os_mutex_pend(&mutex, 0);
if (show_info == NULL) {
rotate = lrc_status.lrc_rotate;
flip = lrc_status.lrc_flip;
scroll_speed = lrc_status.lrc_scroll_speed;
} else {
rotate = show_info->rotate;
flip = show_info->flip;
scroll_speed = show_info->scroll_speed;
}
if (font_lyrics_scroll_timer_id) {
sys_timer_del(font_lyrics_scroll_timer_id);
font_lyrics_scroll_timer_id = 0;
}
if (lrc_update_info.str) {
free(lrc_update_info.str);
lrc_update_info.str = NULL;
}
lrc_update_info.str = malloc(len);
memcpy(lrc_update_info.str, str, len);
lrc_update_info.len = len;
lrc_update_info.lyrics_info.scroll_offset = 0;
lrc_update_info.lyrics_info.rotate = rotate;
lrc_update_info.lyrics_info.flip = flip;
lrc_update_info.sum_width = Font_GetStringWidth(lrc_update_info.str, len, &(lrc_update_info.lyrics_info));
lrc_update_info.lyrics_info.center_offset = (lrc_update_info.sum_width < LED_WIDTH) ? ((LED_WIDTH - lrc_update_info.sum_width) / 2) : 0;
os_mutex_post(&show_mutex);
if (lrc_update_info.sum_width <= LED_WIDTH) {
lyrics_scroll_font((void *)&lrc_update_info);
} else {
if (font_lyrics_scroll_timer_id == 0) {
font_lyrics_scroll_timer_id = sys_timer_add((void *)&lrc_update_info, lyrics_scroll_font, scroll_speed);
}
}
lrc_status.lrc_show_status_update_flag = 0;
os_mutex_post(&mutex);
}