最近忽然想起了前几年学习51单片机时有一个大名鼎鼎的12864模块没有使用,原因是当时使用的程序模块驱动有问题,也没有深究。然而我买的这个模块是V2.0版,带有中文字库,还是很实用的,因此我打算在STM32开发板上试一下看看效果如何。首先我找出了《新概念51单片机C语言教程——入门、提高、开发、拓展全攻略》这本书,参考里面的12864模块驱动程序,结果很顺利,除了端口初始化外,几乎不用做任何改动就可以在miniSTM32开发板上使用。
然后我打算做一个试验,参考正点原子的例程识别SD卡,读出第一个扇区的内容并通过串口输出。
12864模块的接线方式(管脚1为正面右起第一个引脚,采用串行接线方式):
引脚1 VSS -- GND 模块电源
引脚2 VDD -- +5V 模块电源
引脚4 RS(CS) -- PB8 串行片选
引脚5 R/W(SID) -- PB9 串行数据
引脚6 E(CLK) -- PB10 串行时钟
引脚15 PSB -- GND 高电平为6800通信,低电平为3线SPI通信
引脚19 BLA -- +5V 背光电源
引脚20 BLK -- GND 背光电源
SD卡模块的接线方式:
引脚1 CD/DAT3 (SPI模式CS) -- PA3
引脚2 CMD(SPI模式MOSI) -- PA7
引脚3 VSS
引脚4 VCC
引脚5 CLK(SPI模式CLK) -- PA5
引脚6 VSS
引脚7 DAT0(SPI模式MISO) -- PA6
引脚8 DAT1
引脚9 DAT2
要点和注意事项:
1)由于液晶模块对电压的波动很敏感,为了保证显示效果,这里的引脚大部分都是焊接的,杜邦线的效果就和面包板上的引线一样连接不太可靠。
2)由于使用SPI1外设读取SD卡时使用了PA3,PA5,PA6,PA7引脚,其他外设就不能再使用这几个引脚了。
下面的图片是试验结果 :
这是从SD卡0扇区读出的内容,最后两个字节是55AA
很多从51单片机开始学习的新手估计对文件系统有一种神秘感,通过正点原子的例程我也是首次接触到FatFS文件系统,这个文件系统已经在嵌入式领域广泛使用,主要包括ff.c, ff.h, ffconf.h, diskio.c, diskio.h等文件,初学者先仔细看看ffconf.h,ff.h和diskio.h三个头文件就能对FatFS文件系统有一个初步印象以便消除陌生感。这里的试验内容是使用FatFS读出SD卡中的所有文件,并以目录名/文件名的形式通过串口打印出来,同时找出其中的歌曲并显示到12864模块上。
要点和注意事项:
1)要找出SD卡中的所有文件,首先要为SD卡工作区申请内存,然后挂载SD卡磁盘到0:分区。接着使用f_opendir()和f_readdir()函数从根目录开始递归扫描,
通过分析FILINFO中的fattrib属性,如果是目录则切换目录继续扫描,如果是文件则输出路径+文件名,如果使用f_typetell()函数发现文件是音乐则输出文件名到12864屏幕。
2)由于Fatfs文件系统默认的长文件名长度为255,如果递归扫描磁盘的文件会消耗较多的内存,为了节约内存,长文件名默认长度可以改为30左右。
下面的图片是试验结果 :
接下来我打算使用SPI1和Fatfs文件系统读取SD卡中的歌曲,然后通过定时器TIM3的通道1和通道2以PWM波形的方式播放wav音乐,定时器TIM3的比较值就是读取到的wav的数据,由定时器TIM2的中断来更新。歌曲的采样率决定了预装载值arr和预分频系数psc的乘积,即psc X arr = 72000000/采样率,如果是8bit音乐要保证arr>=256,如果是16bit音乐要保证arr>=2048(11bit)。由于网上关于使用PWM方式播放wav文件的相关信息不太多,因此有很多细节需要自己摸索排查。经过几天的努力也参考了网上不少文章(比如DAC方式播放wav的文章),终于播放出音乐,目前采样率为11025的8位wav音乐播放的效果一般,杂音也比较明显。
要点和注意事项:
1)歌曲缓冲区buffer的使用分为前后两个半段,具体来说假设buffer长度为4096,当前半段的数据写入CCR1到2048位时,则读文件标志ready置1,前后段标志位flag则取反,当读取到4096位时也是ready置1和flag取反。while循环中如果ready为1,说明需要读文件了,如果flag为1则将读到的数据放入buffer前半段,如果flag为0则将读到的数据放入buffer后半段。总之buffer读操作和写操作总是前后两个半段错开。
2)要想播放wav歌曲,首先需要熟悉WAV文件的格式,我在网上找到了一个使用ALSA音频库播放WAV的程序alsa_play.c,可以先在pc上用此程序播放wav音乐,以便熟悉WAV文件头。另外为了熟悉使用TIM3定时器的PWM功能,可以先做一个呼吸灯。
3)由于SPI1读取SD卡用到了PA5,PA6,PA7引脚,而TIM3通道1和通道2的默认输出引脚是PA6,PA7,如果采用半重映射到PB4PB5,需要禁用JTAG/SWD,故采用完全重映射到PC6PC7,并且在端口配置时需要使能AFIO时钟。
4)在播放WAV音乐时发现采样率是音质的关键,如果使用16bit数据,由于需要截断到12bit或11bit效果并不好,对于STM32如果使用单声道8bit,可以使用44100Hz的采样率。
5)在调试过程中发现像LED0=1这类使用宏的语句容易出问题,我这里引起的问题是中断服务程序卡死,另外一开始我想把buffer定义为u8 *buffer[2],使用时也可能出问题,希望自己在嵌入式领域要注意C语言用法的规范。
6) 最后切记对于8bit(包括单声道和双声道)wav文件,读取到的音频数据要减去0x80,如果觉得音量太大,可以再除以2以降低音量。
以下是采用PWM方式播放的《我和我的祖国》百度云链接(在尝试采用DAC方式播放后发现音质更好但要接有源音箱):
链接: https://pan.baidu.com/s/10nap5aZC1IEWXQD_UoGu3g 提取码: zmc6
以下是DAC方式播放WAV音乐的项目源码:
链接: https://pan.baidu.com/s/1QlucA0IVGA8iHdaa7vOt0g 提取码: 7pgn