以下是一个使用STM32实现简单的音乐播放器的案例代码:
案例代码中,我们使用了STM32F4 Discovery开发板和SD卡模块。音乐文件以WAV格式存储在SD卡中。主要的功能包括初始化SD卡、读取音乐文件、配置音频输出、播放音乐。
#include "stm32f4xx.h"
#include "stm32f4_discovery.h"
#include <string.h>
/* SD Card Definitions */
#define SD_SPI SPI1
#define SD_SPI_CLK RCC_APB2Periph_SPI1
#define SD_SPI_SCK_PIN GPIO_Pin_5
#define SD_SPI_SCK_GPIO_PORT GPIOA
#define SD_SPI_SCK_GPIO_CLK RCC_AHB1Periph_GPIOA
#define SD_SPI_MISO_PIN GPIO_Pin_6
#define SD_SPI_MISO_GPIO_PORT GPIOA
#define SD_SPI_MISO_GPIO_CLK RCC_AHB1Periph_GPIOA
#define SD_SPI_MOSI_PIN GPIO_Pin_7
#define SD_SPI_MOSI_GPIO_PORT GPIOA
#define SD_SPI_MOSI_GPIO_CLK RCC_AHB1Periph_GPIOA
#define SD_CS_PIN GPIO_Pin_3
#define SD_CS_GPIO_PORT GPIOD
#define SD_CS_GPIO_CLK RCC_AHB1Periph_GPIOD
/* Audio Definitions */
#define AUDIO_CODEC_I2C I2C1
#define AUDIO_I2C_CLK RCC_APB1Periph_I2C1
#define AUDIO_I2S SPI2
#define AUDIO_I2S_CLK RCC_APB1Periph_SPI2
#define AUDIO_I2S_WS_PIN GPIO_Pin_4
#define AUDIO_I2S_WS_GPIO_PORT GPIOB
#define AUDIO_I2S_WS_GPIO_CLK RCC_AHB1Periph_GPIOB
#define AUDIO_I2S_SCK_PIN GPIO_Pin_10
#define AUDIO_I2S_SCK_GPIO_PORT GPIOB
#define AUDIO_I2S_SCK_GPIO_CLK RCC_AHB1Periph_GPIOB
#define AUDIO_I2S_SD_PIN GPIO_Pin_15
#define AUDIO_I2S_SD_GPIO_PORT GPIOB
#define AUDIO_I2S_SD_GPIO_CLK RCC_AHB1Periph_GPIOB
#define AUDIO_I2S_MCK_PIN GPIO_Pin_6
#define AUDIO_I2S_MCK_GPIO_PORT GPIOD
#define AUDIO_I2S_MCK_GPIO_CLK RCC_AHB1Periph_GPIOD
#define AUDIO_I2S_DMA_STREAM DMA1_Stream5
#define AUDIO_I2S_DMA_CHANNEL DMA_Channel_0
#define AUDIO_I2S_DMA_IRQ DMA1_Stream5_IRQn
#define AUDIO_I2S_DMA_FLAG DMA_FLAG_TCIF5
/* WAV File Definitions */
#define CHUNK_ID 0x46464952 // "RIFF"
#define FORMAT 0x45564157 // "WAVE"
#define SUBCHUNK1_ID 0x20746D66 // "fmt "
#define SUBCHUNK2_ID 0x61746164 // "data"
/* Function Prototypes */
void SD_Init(void);
void SD_WriteByte(uint8_t byte);
uint8_t SD_ReadByte(void);
void SD_WriteCmd(uint8_t cmd, uint32_t arg);
uint8_t SD_ReadData(void);
void SD_ReadDataBlock(uint8_t* buffer, uint32_t size);
uint8_t SD_InitCard(void);
uint8_t SD_InitSDIO(void);
uint8_t SD_InitCardIdentify(void);
uint8_t SD_InitCardSetBusWidth(void);
uint8_t SD_ReadSingleBlock(uint32_t sector, uint8_t* buffer);
void SD_ReadWavHeader(uint8_t* buffer, uint32_t* dataStart, uint32_t* dataSize, uint32_t* sampleRate);
void SD_PlayMusic(void);
void SD_PlaySample(uint32_t sampleRate);
void Audio_Init(void);
void Audio_PlaySample(uint32_t sampleRate);
/* Global Variables */
volatile uint8_t SD_Initialized = 0;
volatile uint8_t SDIO_Initialized = 0;
volatile uint8_t SD_CardType = 0;
volatile uint32_t SD_CardCapacity = 0;
int main(void)
{
/* Initialize SD Card */
SD_Init();
/* Initialize Audio Codec */
Audio_Init();
/* Play Music */
SD_PlayMusic();
while (1) {
/* Do Nothing */
}
}
void SD_Init(void)
{
/* Enable GPIO Clocks */
RCC_AHB1PeriphClockCmd(SD_SPI_SCK_GPIO_CLK | SD_SPI_MISO_GPIO_CLK |
SD_SPI_MOSI_GPIO_CLK | SD_CS_GPIO_CLK, ENABLE);
/* Enable SPI Clock */
RCC_APB2PeriphClockCmd(SD_SPI_CLK, ENABLE);
/* Configure SPI Pins */
GPIO_PinAFConfig(SD_SPI_SCK_GPIO_PORT, SD_SPI_SCK_SOURCE, SD_SPI_SCK_AF);
GPIO_PinAFConfig(SD_SPI_MISO_GPIO_PORT, SD_SPI_MISO_SOURCE, SD_SPI_MISO_AF);
GPIO_PinAFConfig(SD_SPI_MOSI_GPIO_PORT, SD_SPI_MOSI_SOURCE, SD_SPI_MOSI_AF);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = SD_SPI_SCK_PIN | SD_SPI_MISO_PIN | SD_SPI_SCK_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure CS Pin */
GPIO_InitStructure.GPIO_Pin = SD_CS_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(SD_CS_GPIO_PORT, &GPIO_InitStructure);
SD_CS_HIGH();
/* Configure SPI */
SPI_InitTypeDef SPI_InitStructure;
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SD_SPI, &SPI_InitStructure);
/* Enable SPI */
SPI_Cmd(SD_SPI, ENABLE);
/* Initialize SD Card */
SD_Initialized = SD_InitCard();
}
void SD_WriteByte(uint8_t byte)
{
/* Wait for SPI to be ready */
while (SPI_I2S_GetFlagStatus(SD_SPI, SPI_I2S_FLAG_TXE) == RESET);
/* Send Byte */
SPI_I2S_SendData(SD_SPI, byte);
/* Wait for SPI to finish operation */
while (SPI_I2S_GetFlagStatus(SD_SPI, SPI_I2S_FLAG_RXNE) == RESET);
}
uint8_t SD_ReadByte(void)
{
/* Wait for SPI to be ready */
while (SPI_I2S_GetFlagStatus(SD_SPI, SPI_I2S_FLAG_TXE) == RESET);
/* Send Dummy Byte */
SPI_I2S_SendData(SD_SPI, 0xFF);
/* Wait for SPI to finish operation */
while (SPI_I2S_GetFlagStatus(SD_SPI, SPI_I2S_FLAG_RXNE) == RESET);
/* Return Read Byte */
return (uint8_t)SPI_I2S_ReceiveData(SD_SPI);
}
void SD_WriteCmd(uint8_t cmd, uint32_t arg)
{
/* Send CMD Header */
SD_WriteByte(0x40 | cmd);
SD_WriteByte(arg >> 24);
SD_WriteByte(arg >> 16);
SD_WriteByte(arg >> 8);
SD_WriteByte(arg);
SD_WriteByte(0x95);
}
uint8_t SD_ReadData(void)
{
/* Wait for correct start byte */
while (SD_ReadByte() != 0xFE);
/* Read Data Byte */
return SD_ReadByte();
}
void SD_ReadDataBlock(uint8_t* buffer, uint32_t size)
{
/* Read Data */
for (uint32_t i = 0; i < size; i++) {
buffer[i] = SD_ReadData();
}
}
uint8_t SD_InitCard(void)
{
/* Set SPI Speed to 400kHz */
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_Init(SD_SPI, &SPI_InitStructure);
/* Set CS Low */
SD_CS_LOW();
/* Send CMD0 - Reset */
SD_WriteCmd(0, 0);
/* Wait for SD Card to initialize */
uint32_t timeout = 0xFFFF;
while ((SD_ReadByte() != 0x01) && timeout) {
timeout--;
}
/* Set CS High */
SD_CS_HIGH();
/* Return Initialization Status */
return (timeout) ? 1 : 0;
}
void SD_ReadWavHeader(uint8_t* buffer, uint32_t* dataStart, uint32_t* dataSize, uint32_t* sampleRate)
{
/* Check RIFF and WAVE Tags */
if ((*(uint32_t*)(buffer + 0) == CHUNK_ID) && (*(uint32_t*)(buffer + 8) == FORMAT)) {
/* Check Format Tag */
if (*(uint16_t*)(buffer + 20) == 1) {
/* Get Sample Rate */