[MM32生态]EVB-L0136开发学习分享

 简介

MM32L0130系列MCU是灵动微电子新推出的低功耗产品,内核使用32位的高性能Arm® Cortex-M0+ 微控制器,最高工作频率可达到48MHz,内置高速存储器,丰富的增强型 I/O 端口和多种外设。可适用于空调遥控器、温控器、耳/额温枪、便携医疗设备、气/水/电等仪表、小家电等应用领域。


 

MM32L0130系列MCU主要特性

u  内核与系统

Ø  32-bit Arm® Cortex®-M0+

Ø  工作频率可达48MHz

u  存储器

Ø  多达 64KB 的 Flash 存储器

Ø  多达 8KB SRAM

Ø  Boot loader 支持片内 Flash 在线系统编程(ISP)

u  时钟、复位和电源管理

Ø  1.8V ∼ 5.5V 供电

Ø  上电/断电复位(POR/PDR) 、可编程电压监测器(PVD)

Ø  外部 4 ∼ 24MHz 高速晶体振荡器

Ø  外部 32.768KHz 低速振荡器(带 LSE Bypass 功能)

Ø  内置经出厂调校的8MHz 高速 RC 振荡器,全温度范围内偏差不超过 ±2.5%

Ø  PLL 支持 CPU 最高运行在 48MHz,支持多种分频模式

Ø  内置 16.384KHz 低速振荡器,全温度范围内频率偏差不超过 ±3.5%

u  低功耗

Ø  多种低功耗模式,包括:低功耗运行(Low Power Run)、睡眠(Sleep)、低功耗睡眠(Low Power Sleep)、停机(Stop)、深度停机(Deep Stop)、 待机(Standby)和关机(Shutdown)模式

u  1 个 5 通道 DMA 控制器,支持外设类型包括定时器、ADC、UART、LPUART、I2C、SPI 和SLCD

u  9 个定时器

Ø  2 个 16 位通用定时器(TIM3 /TIM4),有多达 4 个输入捕获/输出比较通道,可用于IR 控制解码

Ø  2 个 16 位基本定时器(TIM16/ TIM17),有 1 个输入捕获/输出比较通道,1 组互补输出, 支持死区生成,紧急停止, 调制器门电路用于 IR 控制

Ø  1 个低功耗定时器(LPTIM),可在除待机和关机模式外的所有模式唤醒 CPU

Ø  2 个看门狗定时器(独立型的 IWDG 和窗口型的 WWDG)

Ø  1 个 RTC 计数器,支持日历功能

Ø  1 个 Systick 定时器: 24 位自减型计数器

u  多达 57 个快速 I/O 端口:

Ø  所有 I/O 口可以映像到 16 个外部中断

Ø  所有端口均可输入输出电压不高于VDD 的信号

u  多达 6 个通信接口

Ø  2 个 UART 接口

Ø  1 个低功耗 UART 接口(LPUART)

Ø  1 个 I2C 接口

Ø  2 个 SPI 接口(2 个I2S 接口)

u  1 个红外信号调制模块(Infra-Red Modulator, IRM),支持 ASK/PSK/FSK 调制

u  1 个段码式液晶驱动模块(SLCD),可驱动 40x4 或 36x8 个段码

u  1 个 12 位模数转换器(ADC),1us 转换时间,多达 15 个外部输入通道,1个内部输入通道

Ø  转换范围:0 ∼ VDDA

Ø  支持采样时间和分辨率配置

Ø  片上温度传感器

Ø  片上电压传感器

u  1 个比较器

u  CRC 计算单元,8/16/32 位多项式可配置

u  96 位芯片唯一 ID(UID)

u  调试模式

Ø  串行调试接口(SWD) 接口

u  采用 LQFP64 和 LQFP48 封装


 

准备开发环境

1、EVB-L0130开发板

2、J-LINK调试下载器

3、USB转TLL工具

4、音箱、USB数据线

EVB-L0130属于MM32EVBoard系列开发板,板载芯片为MM32L0136C7P,带有丰富的外设资源:支持高达 4KV EFT 抗干扰能力、支持 SWD 下载调试接口、4个用户按键、1个复位按键、4个用户LED、2路UART 连接器、1个给开发板供电USB 连接器、1个8Mbit 的 SPI Flash 存储器、1个2048bit 的 I2C 存储器、4个功能选择开关(I2S或是LCD)、1个3.5mm 耳机插座,用于 I2SL/R 音频输出、1个无源扬声器、3路模拟输入电位器、1个板载段码 LCD显示屏……

实现功能

1.     基于EVB-L0130创建基础工程,移植MultiTime开源软件库,结合SysTick定时器实现系统的任务管理和调度

2.     移植Letter-shell_2.x开源软件库,结合板载的UART1接口,实现串口打印、在线联机调试的功能

3.     实现板载4颗LED灯的闪烁控制

4.     移植MultiButton开源软件库,结合板载的4个功能按键,实现按键扫描、检测和处理的功能

5.     通过DMA中断方式实现对板载3路模拟量输入的ADC采样,可通过实时看到当前的采样结果

6.     通过MCU的硬件I2C接口,对板载有EEPROM存储芯片进行读写操作

7.     移植SFUD开源软件库,再通过MCU的硬件SPI接口,对板载的SPIFLASH存储芯片进行读、写、擦除等操作

8.     通过TIM定时器的PWM输出功能,实现对板载蜂鸣器的控制,让其发出指定的提示音

9.     结合段位LCD显示屏的真值表、MCU与LCD的硬件连接,实现对板载LCD的显示驱动,通过查表方式,实现灵活显示,便程序更具有可读性、更便于移植和功能实现

10.   通过MCU内部自带的RTC模块,再结合段位LCD显示屏,实现实时时钟显示的功能,通过软件代码实现自动初始化日期、时间的功能

11.   通过板载的IRDA发送头和接收头,结合MCU内部自带的IRM模块实现红外数据的发送、接收功能

12.   通过实现XMODEM传输协议与SPI FLASH的读写操作,实现上位机软件将数据/文件写入到板载SPI FLASH存储芯片的功能,对于XMODEM的通讯操作使用了消息队列的处理方式

13.   通过I2S接口,实现播放SPI FLASH存储芯片中存放的WAV音频文件,通过音箱进行播放;在播放过程中我们使用DMA加双缓存,通过乒乓操作的方式进行,让音频播放更加流畅,不至于出现卡顿的效果

实验过程中需要注意点:

1、上述所有的功能均已实现,有基于MindSDK和LibSample标准库两个版本,根据个人习惯选择相应版本,对于作者而言,这两个其实都差不多,只是底层不太一样,上层的功能和应用没有太大影响

2、所有的功能可以单独测试,也可以组合测试,可以通过修改config.h头文件中的宏定义来开关相对应的功能

3、EVB-L0130开发板上有4个切换开关,是用来切换MCU的GPIO是用来控制LCD显示的,还是用来操作I2S播放音频的,所以在做LCD和I2S实验时,需要将这4个切换开关拨正确,这两个功能的实验也不能同时完成

4、通过EVB-L0130开发板的原理图,我们看到MCU与LCD的连接部分,LCD并不是所有的引脚都连接到MCU上的,这就导致LCD上的段位不可能显示完全

5、我手上的EVB-L0130是初代的版本,暂时还做不了低功耗的测试,这个官方应该会地后面的硬件版本上更新过来吧……

ADC & DMA功能实现:

#if ENABLE_ADC





/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

/* Private macro -------------------------------------------------------------*/





/* Private variables ---------------------------------------------------------*/

MultiTimer ADC_MultiTimer;





/* Private variables ---------------------------------------------------------*/

float RV1_Voltage = 0.0;

float RV2_Voltage = 0.0;

float RV3_Voltage = 0.0;





/* Private variables ---------------------------------------------------------*/

uint16_t ADC_Flag  =  0;

uint16_t ADC_Buffer[30];





/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/





/* Exported variables --------------------------------------------------------*/

/* Exported function prototypes ----------------------------------------------*/





/*******************************************************************************

 * [url=home.php?mod=space&uid=247401]@brief[/url]       

 * @param       

 * @retval      

 * [url=home.php?mod=space&uid=93590]@Attention[/url]   

*******************************************************************************/

void ADC_MultiTimerCallback(MultiTimer *timer, void *userData)

{

    uint32_t ADC0_Value = 0;

    uint32_t ADC1_Value = 0;

    uint32_t ADC2_Value = 0;



    if(ADC_Flag == 1)

    {

        ADC_Flag = 0;



        for(uint8_t i = 0; i < 30;)

        {

            ADC0_Value += ADC_Buffer[i++];

            ADC1_Value += ADC_Buffer[i++];

            ADC2_Value += ADC_Buffer[i++];

        }



        RV1_Voltage = ((float)(ADC0_Value) / 4096.0) * 3.3 / 10.0;

        RV2_Voltage = ((float)(ADC1_Value) / 4096.0) * 3.3 / 10.0;

        RV3_Voltage = ((float)(ADC2_Value) / 4096.0) * 3.3 / 10.0;



        ADC_SoftwareStartConvCmd(ADC1, ENABLE);

    }



    MultiTimerStart(&ADC_MultiTimer, 250, ADC_MultiTimerCallback, "ADC");

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void mADC_Init(void)

{

    ADC_InitTypeDef  ADC_InitStructure;

    DMA_InitTypeDef  DMA_InitStruct;

    GPIO_InitTypeDef GPIO_InitStructure;

    NVIC_InitTypeDef NVIC_InitStruct;



    RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);



    GPIO_StructInit(&GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AIN;

    GPIO_Init(GPIOA, &GPIO_InitStructure);



    NVIC_InitStruct.NVIC_IRQChannel = DMA1_Channel1_IRQn;

    NVIC_InitStruct.NVIC_IRQChannelPriority = 2;

    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStruct);



    RCC_AHBPeriphClockCmd(RCC_AHBENR_DMA1, ENABLE);



    DMA_DeInit(DMA1_Channel1);



    DMA_StructInit(&DMA_InitStruct);

    DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);

    DMA_InitStruct.DMA_MemoryBaseAddr     = (uint32_t)&ADC_Buffer;

    DMA_InitStruct.DMA_DIR                = DMA_DIR_PeripheralSRC;

    DMA_InitStruct.DMA_BufferSize         = 30;

    DMA_InitStruct.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;

    DMA_InitStruct.DMA_MemoryInc          = DMA_MemoryInc_Enable;

    DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

    DMA_InitStruct.DMA_MemoryDataSize     = DMA_MemoryDataSize_HalfWord;

    DMA_InitStruct.DMA_Mode               = DMA_Mode_Circular;

    DMA_InitStruct.DMA_Priority           = DMA_Priority_High;

    DMA_InitStruct.DMA_M2M                = DMA_M2M_Disable;

    DMA_InitStruct.DMA_Auto_reload        = DMA_Auto_Reload_Disable;

    DMA_Init(DMA1_Channel1, &DMA_InitStruct);



    if(DMA_InitStruct.DMA_PeripheralBaseAddr == ((uint32_t)(&ADC1->DR)))

    {

        DMA_SetChannelMuxSource(DMA1_Channel1, DMA1_MUX_ADC1);



        if(DMA_GetChannelMuxSource(DMA1_Channel1) != DMA1_MUX_ADC1) 

        {

            while(1);

        }

    }



    DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);

    DMA_Cmd(DMA1_Channel1, ENABLE);



    RCC_APB2PeriphClockCmd(RCC_APB2ENR_ADC1, ENABLE);



    ADC_StructInit(&ADC_InitStructure);

    ADC_InitStructure.ADC_Resolution         = ADC_Resolution_12b;

    ADC_InitStructure.ADC_PRESCARE           = ADC_PCLK2_PRESCARE_16;

    ADC_InitStructure.ADC_Mode               = ADC_Mode_Continue;

    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;

    ADC_InitStructure.ADC_ExternalTrigConv   = ADC1_ExternalTrigConv_T3_CC3;

    ADC_InitStructure.ADC_DataAlign          = ADC_DataAlign_Right;

    ADC_Init(ADC1, &ADC_InitStructure);



    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 0, ADC_Samctl_240_5);

    ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_Samctl_240_5);

    ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 2, ADC_Samctl_240_5);



    ADC_DMACmd(ADC1, ENABLE);

    ADC_Cmd(ADC1, ENABLE);



    ADC_SoftwareStartConvCmd(ADC1, ENABLE);



    MultiTimerStart(&ADC_MultiTimer, 250, ADC_MultiTimerCallback, "ADC");

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void DMA1_Channel1_IRQHandler(void)

{

    ADC_SoftwareStartConvCmd(ADC1, DISABLE);

    DMA_ClearITPendingBit(DMA1_IT_TC1);

    ADC_Flag = 1;

}





#endifBUZZER & TIM & PWM功能实现:
#if ENABLE_BUZZER





/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

/* Private macro -------------------------------------------------------------*/





/* Private variables ---------------------------------------------------------*/

MultiTimer BUZZER_MultiTimer;





/* Private variables ---------------------------------------------------------*/

BUZZER_TypeDef BUZZER_TAB[] =

{

    {50, 100, 1},

    {50, 100, 1},

    {50, 100, 0},

};





/* Private variables ---------------------------------------------------------*/

volatile uint8_t BUZZER_Flag = 0;





/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/





/* Exported variables --------------------------------------------------------*/

/* Exported function prototypes ----------------------------------------------*/





#if 1





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void BUZZER_MultiTimerCallback(MultiTimer *timer, void *userData)

{

    static uint8_t State = 0, Index = 0;



    if(State == 0)

    {

        State = 1;  BUZZER_Flag = 1;



        MultiTimerStart(&BUZZER_MultiTimer, BUZZER_TAB[Index].PlayMS, BUZZER_MultiTimerCallback, "BUZZER");

    }

    else

    {

        State = 0;  BUZZER_Flag = 0;



        if(BUZZER_TAB[Index].KeepOn)

        {

            MultiTimerStart(&BUZZER_MultiTimer, BUZZER_TAB[Index++].WaitMS, BUZZER_MultiTimerCallback, "BUZZER");

        }

        else

        {

            Index = 0;

        }

    }

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void BUZZER_Init(void)

{

    GPIO_InitTypeDef        GPIO_InitStructure;

    NVIC_InitTypeDef        NVIC_InitStructure;

    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;



    RCC_ClocksTypeDef  RCC_Clocks;

    RCC_GetClocksFreq(&RCC_Clocks);



    RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);



    GPIO_StructInit(&GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_6;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;

    GPIO_Init(GPIOA, &GPIO_InitStructure);



    NVIC_InitStructure.NVIC_IRQChannel = TIM16_IRQn;

    NVIC_InitStructure.NVIC_IRQChannelPriority = 1;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);



    RCC_APB2PeriphClockCmd(RCC_APB2ENR_TIM16, ENABLE);



    TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);

    TIM_TimeBaseStructure.TIM_Prescaler         = (RCC_Clocks.SYSCLK_Frequency / 1000000 - 1);

    TIM_TimeBaseStructure.TIM_ClockDivision     = TIM_CKD_DIV1;

    TIM_TimeBaseStructure.TIM_Period            = (500 - 1);

    TIM_TimeBaseStructure.TIM_CounterMode       = TIM_CounterMode_Up;

    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;

    TIM_TimeBaseInit(TIM16, &TIM_TimeBaseStructure);



    TIM_ITConfig(TIM16, TIM_IT_Update, ENABLE);



    TIM_Cmd(TIM16, ENABLE);



    MultiTimerStart(&BUZZER_MultiTimer, 100, BUZZER_MultiTimerCallback, "BUZZER");

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void TIM16_IRQHandler(void)

{

    static BitAction Value = Bit_RESET;



    if(TIM_GetITStatus(TIM16, TIM_IT_Update) != RESET)

    {

        if(BUZZER_Flag == 1)

        {

            if(Value == Bit_RESET)  Value = Bit_SET;

            else                    Value = Bit_RESET;



            GPIO_WriteBit(GPIOA, GPIO_Pin_6, Value);

        }



        TIM_ClearITPendingBit(TIM16, TIM_IT_Update);

    }

}





#else





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void BUZZER_MultiTimerCallback(MultiTimer *timer, void *userData)

{

    static uint8_t State = 0, Index = 0;



    if(State == 0)

    {

        State = 1;  TIM_SetCompare1(TIM3, 500);



        MultiTimerStart(&BUZZER_MultiTimer, BUZZER_TAB[Index].PlayMS, BUZZER_MultiTimerCallback, "BUZZER");

    }

    else

    {

        State = 0;  TIM_SetCompare1(TIM3, 0);



        if(BUZZER_TAB[Index].KeepOn)

        {

            MultiTimerStart(&BUZZER_MultiTimer, BUZZER_TAB[Index++].WaitMS, BUZZER_MultiTimerCallback, "BUZZER");

        }

        else

        {

            Index = 0;

        }

    }

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void BUZZER_Init(void)

{

    GPIO_InitTypeDef        GPIO_InitStructure;

    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

    TIM_OCInitTypeDef       TIM_OCInitStructure;



    RCC_ClocksTypeDef  RCC_Clocks;

    RCC_GetClocksFreq(&RCC_Clocks);



    RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);



    GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_1);



    GPIO_StructInit(&GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_6;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;

    GPIO_Init(GPIOA, &GPIO_InitStructure);



    RCC_APB1PeriphClockCmd(RCC_APB1ENR_TIM3, ENABLE);



    TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);

    TIM_TimeBaseStructure.TIM_Prescaler         = (RCC_Clocks.PCLK1_Frequency / 1000000 - 1);

    TIM_TimeBaseStructure.TIM_ClockDivision     = TIM_CKD_DIV1;

    TIM_TimeBaseStructure.TIM_Period            = (1000 - 1);

    TIM_TimeBaseStructure.TIM_CounterMode       = TIM_CounterMode_Up;

    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;

    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);



    TIM_OCStructInit(&TIM_OCInitStructure);

    TIM_OCInitStructure.TIM_OCMode       = TIM_OCMode_PWM2;

    TIM_OCInitStructure.TIM_OutputState  = TIM_OutputState_Enable;

    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;

    TIM_OCInitStructure.TIM_Pulse        = 0;

    TIM_OCInitStructure.TIM_OCPolarity   = TIM_OCPolarity_High;

    TIM_OC1Init(TIM3, &TIM_OCInitStructure);



    TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);

    TIM_ARRPreloadConfig(TIM3, ENABLE);



    TIM_Cmd(TIM3, ENABLE);



    TIM_CtrlPWMOutputs(TIM3, ENABLE);



    MultiTimerStart(&BUZZER_MultiTimer, 100, BUZZER_MultiTimerCallback, "BUZZER");

}





#endif





#endif

EEPROM & I2C功能实现:

复制

#if ENABLE_EEPROM





/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/

/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/





/* Exported variables --------------------------------------------------------*/

/* Exported function prototypes ----------------------------------------------*/





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void I2C_GetBuffer(uint8_t Address, uint8_t *Buffer, uint8_t Length)

{

    uint8_t Flag = 0, Count = 0;



    I2C_SendData(I2C1, Address);

    while(!I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE));



    for(uint8_t i = 0; i < Length; i++)

    {

        while(1)

        {

            if((I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFNF)) && (Flag == 0))

            {

                I2C_ReadCmd(I2C1);   Count++;

                if(Count == Length) Flag = 1;

            }



            if(I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_RFNE))

            {

                Buffer[i] = I2C_ReceiveData(I2C1);     break;

            }

        }

    }



    I2C_GenerateSTOP(I2C1, ENABLE);

    while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_STOP_DET));

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void I2C_PutBuffer(uint8_t Address, uint8_t *Buffer, uint8_t Length)

{

    I2C_SendData(I2C1, Address);

    while(!I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE));



    for(uint8_t i = 0; i < Length; i++)

    {

        I2C_SendData(I2C1, *Buffer++);

        while(!I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE));

    }



    I2C_GenerateSTOP(I2C1, ENABLE);

    while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_STOP_DET));

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void EEPROM_ReadData(uint8_t Address, uint8_t *Buffer, uint8_t Length)

{

    I2C_GetBuffer(Address, Buffer, Length);

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void EEPROM_WriteData(uint8_t Address, uint8_t *Buffer, uint8_t Length)

{

    uint8_t Start, StartCount, PageNumber, FinalCount;



    if((Address % EEPROM_PAGE_SIZE) == 0)

    {

        StartCount = 0;

        PageNumber = Length / EEPROM_PAGE_SIZE;

        FinalCount = Length % EEPROM_PAGE_SIZE;

    }

    else

    {

        Start = Address % EEPROM_PAGE_SIZE;



        if(((Start + Length) / EEPROM_PAGE_SIZE) == 0)

        {

            StartCount = Length;

            PageNumber = 0;

            FinalCount = 0;

        }

        else

        {

            StartCount = EEPROM_PAGE_SIZE - Start;

            PageNumber = (Length - StartCount) / EEPROM_PAGE_SIZE;

            FinalCount = (Length - StartCount) % EEPROM_PAGE_SIZE;

        }

    }



    if(StartCount)

    {

        I2C_PutBuffer(Address, Buffer, StartCount);

        Address += StartCount;

        Buffer  += StartCount;



        printf("\r\nWait A Moument...");    SysTick_DelayMS(10);

    }



    while(PageNumber--)

    {

        I2C_PutBuffer(Address, Buffer, EEPROM_PAGE_SIZE);



        Address += EEPROM_PAGE_SIZE;

        Buffer  += EEPROM_PAGE_SIZE;



        printf("\r\nWait A Moument...");    SysTick_DelayMS(10);

    }



    if(FinalCount)

    {

        I2C_PutBuffer(Address, Buffer, FinalCount);

    }

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void EEPROM_Init(void)

{

    GPIO_InitTypeDef GPIO_InitStructure;

    I2C_InitTypeDef  I2C_InitStructure;



    RCC_APB1PeriphClockCmd(RCC_APB1ENR_I2C1, ENABLE);



    I2C_StructInit(&I2C_InitStructure);

    I2C_InitStructure.I2C_Mode       = I2C_Mode_MASTER;

    I2C_InitStructure.I2C_OwnAddress = 0;

    I2C_InitStructure.I2C_Speed      = I2C_Speed_STANDARD;

    I2C_InitStructure.I2C_ClockSpeed = 100000;

    I2C_Init(I2C1, &I2C_InitStructure);



    I2C_Send7bitAddress(I2C1, EEPROM_I2C_ADDRESS, I2C_Direction_Transmitter);



    I2C_Cmd(I2C1, ENABLE);



    RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB, ENABLE);



    GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_3);

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_3);



    GPIO_StructInit(&GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_10 | GPIO_Pin_11;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;

    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_OD;

    GPIO_Init(GPIOB, &GPIO_InitStructure);

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void EEPROM_Demo(void)

{

    uint8_t rBuffer[20], wBuffer[20];

    uint8_t Address = 0;

    uint8_t Length = 20;



    for(uint8_t i = 0; i < Length; i++)

    {

        rBuffer[i] = 0;

        wBuffer[i] = i;

    }



    printf("\r\n\r\nEEPROM Write Data : ");



    EEPROM_WriteData(Address, wBuffer, Length);



    printf("OK");   SysTick_DelayMS(10);



    printf("\r\n\r\nEEPROM Read  Data : \r\n");



    EEPROM_ReadData(Address, rBuffer, Length);



    for(uint8_t i = 0; i < Length; i++)

    {

        printf("0x%02x ", rBuffer[i]);



        if(((i + 1) % 10) == 0) printf("\r\n");

    }



    printf("\r\n\r\n");

}





#endifSPI FLASH & SFUD功能实现:

/* Includes ------------------------------------------------------------------*/

#include <sfud.h>





/* Private typedef -----------------------------------------------------------*/





/* Private define ------------------------------------------------------------*/

#define SFUD_DEMO_BUFFER_SIZE      (512)





/* Private macro -------------------------------------------------------------*/





/* Private variables ---------------------------------------------------------*/

uint8_t sfud_demo_buf[SFUD_DEMO_BUFFER_SIZE];





/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/





/* Exported variables --------------------------------------------------------*/

/* Exported function prototypes ----------------------------------------------*/





/*******************************************************************************

 * @brief       SFUD demo for the first flash device test

 * @param       addr flash start address

 * @param       size test flash size

 * @param       size test flash data buffer

 * @retval      

 * @attention   

*******************************************************************************/

void sfud_demo(uint32_t addr, size_t size, uint8_t *data)

{

    sfud_err result = SFUD_SUCCESS;



    const sfud_flash *flash = sfud_get_device_table() + 0;



    size_t i;



    /* prepare write data */

    for(i = 0; i < size; i++)

    {

        data[i] = i;

    }



    /* erase test */

    result = sfud_erase(flash, addr, size);



    if(result == SFUD_SUCCESS)

    {

        printf("\r\nErase the %s flash data finish. Start from 0x%08X, size is %d.\r\n", flash->name, addr, size);

    }

    else

    {

        printf("\r\nErase the %s flash data failed.\r\n", flash->name);

        return;

    }



    /* write test */

    result = sfud_write(flash, addr, size, data);



    if(result == SFUD_SUCCESS)

    {

        printf("\r\nWrite the %s flash data finish. Start from 0x%08X, size is %d.\r\n", flash->name, addr, size);

    }

    else

    {

        printf("\r\nWrite the %s flash data failed.\r\n", flash->name);

        return;

    }



    /* read test */

    result = sfud_read(flash, addr, size, data);



    if(result == SFUD_SUCCESS)

    {

        printf("\r\nRead the %s flash data success. Start from 0x%08X, size is %d. The data is:\r\n", flash->name, addr, size);



        printf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\r\n");



        for(i = 0; i < size; i++)

        {

            if((i % 16) == 0)

            {

                printf("[%08X] ", addr + i);

            }



            printf("%02X ", data[i]);



            if(((i + 1) % 16 == 0) || (i == size - 1))

            {

                printf("\r\n");

            }

        }



        printf("\r\n");

    }

    else

    {

        printf("\r\nRead the %s flash data failed.\r\n", flash->name);

    }



    /* data check */

    for(i = 0; i < size; i++)

    {

        if(data[i] != i % 256)

        {

            printf("\r\nRead and check write data has an error. Write the %s flash data failed.\r\n", flash->name);

            break;

        }

    }



    if(i == size)

    {

        printf("\r\nThe %s flash test is success.\r\n", flash->name);

    }

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void SPI_FLASH_Init(void)

{

    printf("\r\n");



    if(sfud_init() == SFUD_SUCCESS)

    {

        sfud_demo(0, sizeof(sfud_demo_buf), sfud_demo_buf);

    }

}

RTC & LCD功能实现:

复制

#if ENABLE_RTC





/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

/* Private macro -------------------------------------------------------------*/





/* Private variables ---------------------------------------------------------*/

MultiTimer RTC_MultiTimer;





/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/





/* Exported variables --------------------------------------------------------*/

/* Exported function prototypes ----------------------------------------------*/





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

uint8_t RTC_GetWeek(uint16_t Year, uint8_t Month, uint8_t Day)

{

    int w, c, y;



    /* Month 1 Or 2 of This Year Must Be As Last Month 13 Or 14 */

    if((Month == 1) || (Month == 2))

    {

        Month += 12;

        Year  -= 1;

    }



    w = 0;          /* Weekday */

    c = Year / 100; /* Century */

    y = Year % 100; /* Year    */



    w = y + (y / 4) + (c / 4) - (2 * c) + (26 * (Month + 1) / 10) + Day - 1;



    while(w < 0) w += 7;



    w %= 7;



    return w;

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void RTC_LoadDefault(RTCCAL_DateTypeDef *RTCCAL_Date, RTCCAL_TimeTypeDef *RTCCAL_Time)

{

    char    date[20], time[20];

    char    text[6][5];

    uint8_t index = 0, month = 0;



    memset(date, 0, sizeof(date));

    memset(time, 0, sizeof(time));

    memset(text, 0, sizeof(text)); 



    memcpy(date, __DATE__, sizeof(__DATE__));

    memcpy(time, __TIME__, sizeof(__TIME__));



    char *str;



    str = strtok(date, " ");



    while(str != NULL)

    {

        memcpy(text[index], str, strlen(str));

        index++;



        str = strtok(NULL, " ");

    }



    str = strtok(time, ":");



    while(str != NULL)

    {

        memcpy(text[index], str, strlen(str));

        index++;



        str = strtok(NULL, ":");

    }



#if 0

    for(uint8_t i = 0; i < index; i++)

    {

        printf("\r\n->%s", text[i]);

    }

#endif



    char *strMonth[12] =

    {

        "Jan", "Feb", "Mar", "Apr", "May", "Jun",

        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",

    };



    for(uint8_t i = 0; i < 12; i++)

    {

        if(strcmp(text[0], strMonth[i]) == 0)

        {

            month = i + 1;

        }

    }



    RTCCAL_Date->RTCCAL_Date    = atoi(text[1]);

    RTCCAL_Date->RTCCAL_Month   = month;

    RTCCAL_Date->RTCCAL_Year    = atoi(text[2]) - 2000;

    RTCCAL_Date->RTCCAL_WeekDay = RTC_GetWeek(RTCCAL_Date->RTCCAL_Year + 2000,

                                              RTCCAL_Date->RTCCAL_Month,

                                              RTCCAL_Date->RTCCAL_Date);



    RTCCAL_Time->RTCCAL_Hours   = atoi(text[3]);

    RTCCAL_Time->RTCCAL_Minutes = atoi(text[4]);

    RTCCAL_Time->RTCCAL_Seconds = atoi(text[5]);

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void RTC_MultiTimerCallback(MultiTimer *timer, void *userData)

{

    RTCCAL_TimeTypeDef RTCCAL_TimeStructure;

    RTCCAL_DateTypeDef RTCCAL_DateStructure;



    RTCCAL_GetTime(RTCCAL_Format_BIN, &RTCCAL_TimeStructure);

    RTCCAL_GetDate(RTCCAL_Format_BIN, &RTCCAL_DateStructure);



#if ENABLE_LCD

    LCD_DisplayNumber2(0, '0' + (RTCCAL_TimeStructure.RTCCAL_Hours   / 10), 0);

    LCD_DisplayNumber2(1, '0' + (RTCCAL_TimeStructure.RTCCAL_Hours   % 10), 0);

    LCD_DisplayNumber2(2, '0' + (RTCCAL_TimeStructure.RTCCAL_Minutes / 10), 0);

    LCD_DisplayNumber2(3, '0' + (RTCCAL_TimeStructure.RTCCAL_Minutes % 10), 0);

    LCD_DisplayNumber2(4, '0' + (RTCCAL_TimeStructure.RTCCAL_Seconds / 10), 0);

    LCD_DisplayNumber2(5, '0' + (RTCCAL_TimeStructure.RTCCAL_Seconds % 10), 0);

#else

    printf("\r\n%04d-%02d-%02d", RTCCAL_DateStructure.RTCCAL_Year + 2000, RTCCAL_DateStructure.RTCCAL_Month,  RTCCAL_DateStructure.RTCCAL_Date);



    switch(RTCCAL_DateStructure.RTCCAL_WeekDay)

    {

        case 0 : printf(" SUN "); break;

        case 1 : printf(" MON "); break;

        case 2 : printf(" TUE "); break;

        case 3 : printf(" WED "); break;

        case 4 : printf(" THU "); break;

        case 5 : printf(" FRI "); break;

        case 6 : printf(" SAT "); break;

        default: break;

    }



    printf("%02d:%02d:%02d\r\n", RTCCAL_TimeStructure.RTCCAL_Hours, RTCCAL_TimeStructure.RTCCAL_Minutes, RTCCAL_TimeStructure.RTCCAL_Seconds);

#endif



    MultiTimerStart(&RTC_MultiTimer, 500, RTC_MultiTimerCallback, "RTC");

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void RTC_Init(void)

{

    RTCCAL_InitTypeDef RTCCAL_InitStructure;

    RTCCAL_TimeTypeDef RTCCAL_TimeStructure;

    RTCCAL_DateTypeDef RTCCAL_DateStructure;



    RCC_APB1PeriphClockCmd(RCC_APB1ENR_PWR, ENABLE);

    RCC_APB1PeriphClockCmd(RCC_APB1ENR_BKP, ENABLE);

    PWR_BackupAccessCmd(ENABLE);



    RCC_LSEConfig(RCC_LSE_ON);

    while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);



    RCC_APB1PeriphClockCmd(RCC_APB1ENR_RTC, ENABLE);



    RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);

    RCC_RTCCLKCmd(ENABLE);



    RTCCAL_EnterInitMode();



    RTCCAL_WaitForSynchro();



    RTCCAL_StructInit(&RTCCAL_InitStructure);

    RTCCAL_InitStructure.RTCCAL_HourFormat   = RTCCAL_HourFormat_24;

    RTCCAL_InitStructure.RTCCAL_AsynchPrediv = 0x7F;

    RTCCAL_InitStructure.RTCCAL_SynchPrediv  = 0xFF;

    RTCCAL_Init(&RTCCAL_InitStructure);



    RTC_LoadDefault(&RTCCAL_DateStructure, &RTCCAL_TimeStructure);

    RTCCAL_TimeStructure.RTCCAL_H12 = RTCCAL_H12_AM;

    RTCCAL_SetTime(RTCCAL_Format_BIN, &RTCCAL_TimeStructure);

    RTCCAL_SetDate(RTCCAL_Format_BIN, &RTCCAL_DateStructure);



    RTCCAL_WaitForSynchro();



    RTCCAL_ExitInitMode();



    MultiTimerStart(&RTC_MultiTimer, 500, RTC_MultiTimerCallback, "RTC");

}





#endifI2S & DMA & WAV功能实现:

#if ENABLE_I2S





/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

/* Private macro -------------------------------------------------------------*/





/* Private variables ---------------------------------------------------------*/

MultiTimer I2S_MultiTimer;





/* Private variables ---------------------------------------------------------*/

uint8_t  WAV_DataBuffer[2][WAV_BUFFER_SIZE];

uint8_t  WAV_NextIndex = 0;

uint8_t  WAV_PlayEnded = 0;

uint8_t  WAV_PlayState = 0;





/* Private variables ---------------------------------------------------------*/

uint32_t WAV_Offset   = 0;

uint32_t WAV_DataSize = 0;

uint32_t WAV_TxLength = 0;





/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/





/* Exported variables --------------------------------------------------------*/

/* Exported function prototypes ----------------------------------------------*/





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void I2S_MultiTimerCallback(MultiTimer *timer, void *userData)

{

    WAV_PlaySong();



    MultiTimerStart(&I2S_MultiTimer, 5000, I2S_MultiTimerCallback, "I2S");

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void mI2S_Init(void)

{

    GPIO_InitTypeDef GPIO_InitStructure;

    I2S_InitTypeDef  I2S_InitStructure;



    RCC_APB2PeriphClockCmd(RCC_APB2ENR_SPI1, ENABLE);



    I2S_InitStructure.I2S_Mode       = I2S_Mode_MasterTx;

    I2S_InitStructure.I2S_Standard   = I2S_Standard_Phillips;

    I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_16b;

    I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Enable;

    I2S_InitStructure.I2S_AudioFreq  = I2S_AudioFreq_44k;

    I2S_InitStructure.I2S_CPOL       = I2S_CPOL_Low;

    I2S_Init(SPI1, &I2S_InitStructure);



    SPI_DMACmd(SPI1, ENABLE);



    I2S_Cmd(SPI1, ENABLE);



    SPI1->GCTL |= (SPI_GCR_SPIEN | SPI_GCR_MODE | SPI_GCR_TXEN);



    RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOC, ENABLE);



    GPIO_PinAFConfig(GPIOC, GPIO_PinSource4, GPIO_AF_6);

    GPIO_PinAFConfig(GPIOC, GPIO_PinSource5, GPIO_AF_6);

    GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_6);

    GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_6);



    GPIO_StructInit(&GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_4 | GPIO_Pin_5 |

                                    GPIO_Pin_6 | GPIO_Pin_7;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;

    GPIO_Init(GPIOC, &GPIO_InitStructure);



    GPIO_StructInit(&GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_2;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;

    GPIO_Init(GPIOC, &GPIO_InitStructure);



    GPIO_WriteBit(GPIOC, GPIO_Pin_2, Bit_RESET);



    MultiTimerStart(&I2S_MultiTimer, 5000, I2S_MultiTimerCallback, "I2S");

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void I2S_DMA_Transfer(uint16_t *Buffer, uint32_t BufferSize)

{

    DMA_InitTypeDef  DMA_InitStructure;

    NVIC_InitTypeDef NVIC_InitStructure;



    DMA_DeInit(DMA1_Channel1);



    RCC_AHBPeriphClockCmd(RCC_AHBENR_DMA1, ENABLE);



    DMA_StructInit(&DMA_InitStructure);

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(SPI1->TXREG);

    DMA_InitStructure.DMA_MemoryBaseAddr     = (uint32_t)Buffer;

    DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralDST;

    DMA_InitStructure.DMA_BufferSize         = BufferSize;

    DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;

    DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;

    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;

    DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_HalfWord;

    DMA_InitStructure.DMA_Mode               = DMA_Mode_Circular;

    DMA_InitStructure.DMA_Priority           = DMA_Priority_High;

    DMA_InitStructure.DMA_M2M                = DMA_M2M_Disable;

    DMA_InitStructure.DMA_Auto_reload        = DMA_Auto_Reload_Disable;

    DMA_Init(DMA1_Channel1, &DMA_InitStructure);



    if(DMA_InitStructure.DMA_PeripheralBaseAddr == ((uint32_t)(&(SPI1->TXREG))))

    {

        DMA_SetChannelMuxSource(DMA1_Channel1, DMA1_MUX_SPI1_TX);



        if(DMA_GetChannelMuxSource(DMA1_Channel1) != DMA1_MUX_SPI1_TX)

        {

            while(1);

        }

    }



    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;

    NVIC_InitStructure.NVIC_IRQChannelPriority = 0;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);



    DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);

    DMA_ITConfig(DMA1_Channel1, DMA_IT_HT, ENABLE);



    DMA_Cmd(DMA1_Channel1, ENABLE);

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

uint8_t WAV_DecodeFile(WAV_TypeDef *pWav, uint32_t Address)

{

    ChunkRIFF_TypeDef *WAV_RIFF;

    ChunkFMT_TypeDef  *WAV_FMT ;

    ChunkFACT_TypeDef *WAV_FACT;

    ChunkDATA_TypeDef *WAV_DATA;



    uint8_t WAV_HeadBuffer[512];





    SPI_FLASH_FastRead(Address, WAV_HeadBuffer, 512);





    /* 获取RIFF块 */

    WAV_RIFF = (ChunkRIFF_TypeDef *)WAV_HeadBuffer;



    /* 是WAV格式文件 */

    if(WAV_RIFF->Format == 0x45564157)

    {

        /* 获取FMT块 */

        WAV_FMT  = (ChunkFMT_TypeDef *)(WAV_HeadBuffer+12);



        /* 读取FACT块 */

        WAV_FACT = (ChunkFACT_TypeDef *)(WAV_HeadBuffer+12+8+WAV_FMT->ChunkSize);



        if((WAV_FACT->ChunkID == 0x74636166) || (WAV_FACT->ChunkID == 0x5453494C))

        {

            /* 具有FACT/LIST块的时候(未测试) */

            pWav->DataStart=12+8+WAV_FMT->ChunkSize+8+WAV_FACT->ChunkSize;

        }

        else

        {

            pWav->DataStart=12+8+WAV_FMT->ChunkSize;

        }



        /* 读取DATA块 */

        WAV_DATA = (ChunkDATA_TypeDef *)(WAV_HeadBuffer+pWav->DataStart);



        /* 解析成功 */

        if(WAV_DATA->ChunkID == 0x61746164)

        {

            pWav->AudioFormat   = WAV_FMT->AudioFormat;     /* 音频格式 */

            pWav->nChannels     = WAV_FMT->NumOfChannels;   /* 通道数 */

            pWav->SampleRate    = WAV_FMT->SampleRate;      /* 采样率 */

            pWav->BitRate       = WAV_FMT->ByteRate*8;      /* 得到位速 */

            pWav->BlockAlign    = WAV_FMT->BlockAlign;      /* 块对齐 */

            pWav->BitsPerSample = WAV_FMT->BitsPerSample;   /* 位数,16/24/32位 */



            pWav->DataSize      = WAV_DATA->ChunkSize;      /* 数据块大小 */

            pWav->DataStart     = pWav->DataStart+8;        /* 数据流开始的地方 */



            printf("\r\npWav->AudioFormat   : %d", pWav->AudioFormat);

            printf("\r\npWav->nChannels     : %d", pWav->nChannels);

            printf("\r\npWav->SampleRate    : %d", pWav->SampleRate);

            printf("\r\npWav->BitRate       : %d", pWav->BitRate);

            printf("\r\npWav->BlockAlign    : %d", pWav->BlockAlign);

            printf("\r\npWav->BitsPerSample : %d", pWav->BitsPerSample);

            printf("\r\npWav->DataSize      : %d", pWav->DataSize);

            printf("\r\npWav->DataStart     : %d", pWav->DataStart);



            WAV_Offset   = pWav->DataStart + Address;

            WAV_DataSize = pWav->DataSize;

        }

    }



    return 0;

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void WAV_PrepareData(void)

{

    if(WAV_NextIndex == 0)

    {

        SPI_FLASH_FastRead(WAV_Offset + WAV_TxLength, WAV_DataBuffer[0], WAV_BUFFER_SIZE);

    }

    else

    {

        SPI_FLASH_FastRead(WAV_Offset + WAV_TxLength, WAV_DataBuffer[1], WAV_BUFFER_SIZE);

    }



    WAV_TxLength += WAV_BUFFER_SIZE;



    if(WAV_TxLength > WAV_DataSize) WAV_PlayEnded = 1;

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void WAV_PlayHandler(void)

{

    if(WAV_PlayEnded == 0)

    {

        I2S_DMA_Transfer((uint16_t *)&WAV_DataBuffer[WAV_NextIndex][0], (WAV_BUFFER_SIZE / 2));

    }

    else

    {

        DMA_Cmd(DMA1_Channel1,    DISABLE);



        printf("\r\nWAV Play Finish!\r\n");     WAV_PlayState = 0;

    }



    if(WAV_NextIndex == 0) WAV_NextIndex = 1;

    else                   WAV_NextIndex = 0;

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void WAV_PlaySong(void)

{

    WAV_TypeDef WaveFile;



    if(WAV_PlayState == 0)

    {

        if(WAV_DecodeFile(&WaveFile, 0x00000000) == 0)

        {

            if((WaveFile.BitsPerSample == 16) && (WaveFile.nChannels == 2) &&

               (WaveFile.SampleRate  > 44000) && (WaveFile.SampleRate < 48100))

            {

                WAV_NextIndex = 0;

                WAV_PlayEnded = 0;

                WAV_TxLength  = 0;

                WAV_PlayState = 1;



                printf("\r\n");

                printf("\r\nWAV Data Size : %d, Data Start : 0x%08x", WAV_DataSize, WAV_Offset);

                printf("\r\n");



                WAV_PrepareData();

                WAV_PlayHandler();

            }

            else

            {

                printf("\r\nWAV File Format Error!\r\n"); return;

            }

        }

        else

        {

            printf("\r\nNo WAV File!\r\n"); return;

        }

    }

    else

    {

        printf("\r\nThe Song Is Not Over Yet!\r\n");

    }

}





/*******************************************************************************

 * @brief       

 * @param       

 * @retval      

 * @attention   

*******************************************************************************/

void DMA1_Channel1_IRQHandler(void)

{

    if(DMA_GetITStatus(DMA1_IT_TC1) != RESET)

    {

        DMA_ClearITPendingBit(DMA1_IT_TC1);



        WAV_PlayHandler();

    }



    if(DMA_GetITStatus(DMA1_IT_HT1) != RESET)

    {

        DMA_ClearITPendingBit(DMA1_IT_HT1);



        WAV_PrepareData();

    }

}





#endif还有其它等等功能,由于篇幅太长就不这边一一列举出来,大家可以下载最后的软件工程源代码进行学习和研究。
---------------------
作者:xld0932
链接:https://bbs.21ic.com/icview-3263182-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值