• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

大作业——嵌入式系统

武飞扬头像
天狼溯光者
帮助1

flash

wav格式音频数据

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

import sys

if __name__ == '__main__':
    # wav文件
    filepath = 'winxp.wav'
    # 打开二进制文件
    bin_file = open(filepath, 'rb')
    # 跳到data
    bin_file.seek(42, 0)
    # 读取data大小
    data = bin_file.read(4)
    # 转10进制,小端对齐
    size = int().from_bytes(data, byteorder="little", signed=True)
    # 文件个数
    num = 0
    # 每次写入个数
    each_size = 10240
    print(size)

    # 循环写入 each_size 个字节到 output.txt
    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)):
            # 每 16 个 字节换行一次
            if index % 16 == 0:
                print("0xx ," % i)
            else:
                print("0xx ," % 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("0xx ," % i)
        else:
            print("0xx ," % 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位数据格式。按照低位在前,高位在后的顺序发送。采用反码是为了增加传输的可靠性(可用于校验)。
代码修改

使用定时器设置定时中断去扫描对面通道的值,根据扫描的值进行对应转换得到按键信息。

  1.  
//定时器更新(溢出)中断回调函数
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);
		}				 		     	    
	}
}

学新通
  1.  
//处理红外键盘
//返回值:
//	 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协议及标准介绍

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhhkaakh
系列文章
更多 icon
同类精品
更多 icon
继续加载