大作业——嵌入式系统

flash

wav格式音频数据

wav音频选用的是window开机的经典音乐,通过python代码得到wav格式音频的数据块,采用16进格式保存

大作业——嵌入式系统
import sys

if __name__ == '__main__':

    filepath = 'winxp.wav'

    bin_file = open(filepath, 'rb')

    bin_file.seek(42, 0)

    data = bin_file.read(4)

    size = int().from_bytes(data, byteorder="little", signed=True)

    num = 0

    each_size = 10240
    print(size)

    while size >= each_size:

        file = open('output{:d}.txt'.format(num), 'w')
        sys.stdout = file

        data = bin_file.read(each_size)
        print("size ", 10240)
        for i, index in zip(data, range(1, each_size + 1)):

            if index % 16 == 0:
                print("0x%02x ," % i)
            else:
                print("0x%02x ," % i, end='')

        file.close()
        size -= each_size
        num += 1

    file = open('output{:d}.txt'.format(num), 'w')
    sys.stdout = file
    data = bin_file.read(size)
    print("size ", size)
    for i, index in zip(data, range(1, size + 1)):
        if index % 16 == 0:
            print("0x%02x ," % i)
        else:
            print("0x%02x ," % i, end='')

    file.close()
    bin_file.close()

大作业——嵌入式系统
读取
/**
读取flash
address 读取起始地址
readBuf 读取内容存放位置
size 读取的大小**/
void readFlash(uint32_t address,uint8_t *readBuf,uint16_t size)
{
    uint16_t i;
    uint16_t tmpBuf;
    printf("开始读取flash\n");
    for(i=0;i<size;i+=2)
    {
        tmpBuf=*(__IO uint16_t *)(address+i);
        //低八位
        readBuf[i]=tmpBuf&0xff;
        //高八位
        readBuf[i+1]=tmpBuf>>8;
    }
    printf("读取flash完毕\n");
}
写入
/**
写flash
address 起始地址
data 数据
size 数据大小

**/
void writeFlash(u32 address,u8 *data,u16 size)
{
    FLASH_EraseInitTypeDef FlashSet;
    HAL_StatusTypeDef FlashStatus = HAL_OK;
    u16 tmpbuf;
    u16 i;
    u32 PageError = 0;

    //解锁FLASH
    HAL_FLASH_Unlock();
    //擦除FLASH

    //第一次写入之前调用擦除函数进行擦除,后续无需再调用,否则会吧之前写入的数据擦除掉
    //除非需要覆盖之前的flash

    //初始化FLASH_EraseInitTypeDef
    //擦除方式
    FlashSet.TypeErase = FLASH_TYPEERASE_SECTORS;
    //擦除起始页
    FlashSet.Sector  = 5;
    //擦除结束页
    FlashSet.NbSectors  = 6;
    FlashSet.VoltageRange = FLASH_VOLTAGE_RANGE_3;

    printf("擦除\r\n");
    //调用擦除函数
    HAL_FLASHEx_Erase(&FlashSet, &PageError);
    FlashStatus = FLASH_WaitForLastOperation(1000); //等待上次操作完成

    //对FLASH烧写
    printf("开始写flash\r\n");
    for( i= 0;i< size ;i+=2)
    {
        //把8位转16位,得到半个字节
        //每两个8位,一个当低八位,一个当高八位
        tmpbuf = (*(data + i + 1) << 8) + (*(data + i));
        //写半个字节
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD , address + i , tmpbuf);
    }
    //锁住FLASH
    HAL_FLASH_Lock();
}
数据存储

大作业——嵌入式系统
; flash操作

调用writeFlash函数进行写flash操作,直至完全写入

大作业——嵌入式系统
播放音乐
  • 原理
    I2S(Inter—IC Sound)总线,是飞利浦公司为数字音频设备之间的音频数据传输而制定的一种总线标准,该总线专门用于音频设备之间的音频数据传输。它采用了沿独立的导线传输时钟与数据信号的设计,通过将数据和时钟信号分离,避免了因时差诱发的失真,为用户节省了购买抵抗音频抖动的专业设备的费用

I2S协议及标准介绍(带图)

/**
播放欢迎光临提示
从flash读取音频文件

**/
void hello(){
    u8 res;
    //每次读取flash大小
    u32 eachSize=8192;
    //音频文件大小
    u32 fillnum=data_size;
    //flash起始地址
    u32 address=(u32)0x08020000;
    //分配内存
    audiodev.i2sbuf1=mymalloc(SRAMIN,eachSize);
    audiodev.i2sbuf2=mymalloc(SRAMIN,eachSize);
    audiodev.tbuf=mymalloc(SRAMIN,eachSize);

    WM8978_I2S_Cfg(2,0);    //飞利浦标准,16位数据长度
    I2S2_Init(I2S_STANDARD_PHILIPS,I2S_MODE_MASTER_TX,I2S_CPOL_LOW,I2S_DATAFORMAT_16B_EXTENDED);    //飞利浦标准,主机发送,时钟低电平有效,16位扩展帧长度
    I2S2_SampleRate_Set(8000);//设置采样率
    I2S2_TX_DMA_Init(audiodev.i2sbuf1,audiodev.i2sbuf2,eachSize/2); //配置TX DMA
    i2s_tx_callback=wav_i2s_dma_tx_callback;            //回调函数指wav_i2s_dma_callback

    audio_start();
    printf("开始播放\r\n");

    while(1)
    {
        //根据当前剩余数据大小和每次播放数据大小来确定每次读取buf的大小
        if(fillnum>=eachSize){
            fillnum-=eachSize;
        }
        else{
            eachSize=fillnum;
        }

        //读取flash
        readFlash(address,audiodev.i2sbuf1,eachSize);
        readFlash(address,audiodev.i2sbuf2,eachSize);

        //根据当前剩余数据大小和每次播放数据大小来计算读取地址
        if(eachSize!=fillnum){
            address+=eachSize;
        }
        else{
            break;
        }

        while(wavtransferend==0);//等待wav传输完成;
        wavtransferend=0;

        //播放转换完毕的buf
        audiodev.status=1;
        while(1)
        {
            //判断是否播放完当前buf
            if((audiodev.status&0X01)==0)delay_ms(10);
            else break;
        }

    }
    //停止播放
    audio_stop();
    printf("停止播放\r\n");
    myfree(SRAMIN,audiodev.tbuf);   //释放内存
    myfree(SRAMIN,audiodev.i2sbuf1);//释放内存
    myfree(SRAMIN,audiodev.i2sbuf2);//释放内存
}

红外遥控

红外遥控是一种无线、非接触控制技术,具有抗干扰能力强,信息传输可靠,功耗低,成本低,易实现等显著优点,被诸多电子设备特别是家用电器广泛采用,并越来越多的应用到计算机系统中。同类产品的红外线遥控器,可以有相同的遥控频率或编码,而不会出现遥控信号”串门”的情况。红外遥控的编码目前广泛使用的是: NEC ProtocolPWM(脉冲宽度调制)和 Philips RC-5 ProtocolPPM(脉冲位置调制)。这里采用的是 NEC ProtocolPWM协议。

  • NEC协议特征
    (1)8位地址和8位指令长度;
    (2)地址和命令2次传输(确保可靠性)
    (3)PWM脉冲宽度调制,以发射红外载波的占空比代表”0″和”1″;
    (4)载波频率为38Khz;
    (5)位时间为1.125ms或2.25ms。
  • NEC码的位定义
    一个脉冲对应560us的连续载波
    一个逻辑1传输需要2.25ms(560us脉冲+1680us低电平)
    一个逻辑0的传输需要1.125ms(560us脉冲+560us低电平)
    而遥控接收头在收到脉冲的时候为低电平,在没有脉冲的时候为高电平,这样,我们在接收头端收到的信号为: 逻辑1应该是560us低+1680us高,逻辑0应该是560us低+560us高。
  • NEC遥控指令格式
    NEC遥控指令的数据格式为: 同步码头、地址码、地址反码、控制码、控制反码。同步码由一个9ms的低电平和一个4.5ms的高电平组成,地址码、地址反码、控制码、控制反码均是8位数据格式。按照低位在前,高位在后的顺序发送。采用反码是为了增加传输的可靠性(可用于校验)。
代码修改

定时器用于设置定时中断扫描对方频道的值,并根据扫描值进行相应的转换得到密钥信息。

[En]

The timer is used to set the timing interrupt to scan the value of the opposite channel, and the key information is obtained by corresponding conversion according to the scanned value.

//定时器更新(溢出)中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
 if(htim->Instance==TIM1){
        if(RmtSta&0x80)//上次有数据被接收到了
        {
            RmtSta&=~0X10;                      //取消上升沿已经被捕获标记
            if((RmtSta&0X0F)==0X00)RmtSta|=1<<6;//标记已经完成一次按键的键值信息采集
            if((RmtSta&0X0F)<14)RmtSta++;
            else
            {
                RmtSta&=~(1<<7);//清空引导标识
                RmtSta&=0XF0;   //清空计数器
            }
        }

 }
}

//定时器输入捕获中断回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//捕获中断发生时执行
{
 if(htim->Instance==TIM1)
{

    if(RDATA)//上升沿捕获
    {
        TIM_RESET_CAPTUREPOLARITY(&TIM1_Handler,TIM_CHANNEL_1);   //一定要先清除原来的设置!!
        TIM_SET_CAPTUREPOLARITY(&TIM1_Handler,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);//CC1P=1 设置为下降沿捕获
        __HAL_TIM_SET_COUNTER(&TIM1_Handler,0);  //清空定时器值
            RmtSta|=0X10;                   //标记上升沿已经被捕获
    }else //下降沿捕获
    {
        Dval=HAL_TIM_ReadCapturedValue(&TIM1_Handler,TIM_CHANNEL_1);//读取CCR1也可以清CC1IF标志位
        TIM_RESET_CAPTUREPOLARITY(&TIM1_Handler,TIM_CHANNEL_1);   //一定要先清除原来的设置!!
        TIM_SET_CAPTUREPOLARITY(&TIM1_Handler,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);//配置TIM5通道1上升沿捕获
        if(RmtSta&0X10)                 //完成一次高电平捕获
        {
            if(RmtSta&0X80)//接收到了引导码
            {

                if(Dval>300&&Dval<800)          //560为标准值,560us
                {
                    RmtRec<<=1; //左移一位.
                    RmtRec|=0;  //接收到0
                }else if(Dval>1400&&Dval<1800)  //1680为标准值,1680us
                {
                    RmtRec<<=1; //左移一位.
                    RmtRec|=1;  //接收到1
                }else if(Dval>2200&&Dval<2600)  //得到按键键值增加的信息 2500为标准值2.5ms
                {
                    RmtCnt++;       //按键次数增加1次
                    RmtSta&=0XF0;   //清空计时器
                }
                }else if(Dval>4200&&Dval<4700)      //4500为标准值4.5ms
                {
                    RmtSta|=1<<7;   //标记成功接收到了引导码
                    RmtCnt=0;       //清除按键次数计数器
                }
            }

        RmtSta&=~(1<<4);
        }
    }
}

//处理红外键盘
//返回值:
//   0,没有任何按键按下
//其他,按下的按键键值.

u8 Remote_Scan(void)
{
    u8 sta=0;
    u8 t1,t2;
    if(RmtSta&(1<<6))//得到一个按键的所有信息了
    {
        t1=RmtRec>>24;          //得到地址码
        t2=(RmtRec>>16)&0xff;   //得到地址反码
        if((t1==(u8)~t2)&&t1==REMOTE_ID)//检验遥控识别码(ID)及地址
        {
            t1=RmtRec>>8;
            t2=RmtRec;
            if(t1==(u8)~t2)sta=t1;//键值正确
        }
        if((sta==0)||((RmtSta&0X80)==0))//按键数据错误/遥控已经没有按下了
        {
            RmtSta&=~(1<<6);//清除接收到有效按键标识
            RmtCnt=0;       //清除按键次数计数器
        }
    }
    return sta;
}

参考

  1. STM32F407ZET6音乐播放器
  2. 基于stm32的红外遥控
  3. I2S协议及标准介绍

Original: https://blog.csdn.net/m0_51120713/article/details/122500909
Author: 天狼溯光者
Title: 大作业——嵌入式系统

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/498296/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球