大作业——嵌入式系统
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)总线,是飞利浦公司为数字音频设备之间的音频数据传输而制定的一种总线标准,该总线专门用于音频设备之间的音频数据传输。它采用了沿独立的导线传输时钟与数据信号的设计,通过将数据和时钟信号分离,避免了因时差诱发的失真,为用户节省了购买抵抗音频抖动的专业设备的费用
/**
播放欢迎光临提示
从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 Protocol
的PWM
(脉冲宽度调制)和Philips RC-5 Protocol
的PPM
(脉冲位置调制)。这里采用的是NEC Protocol
的PWM
协议。
- 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位数据格式。按照低位在前,高位在后的顺序发送。采用反码是为了增加传输的可靠性(可用于校验)。
代码修改
使用定时器设置定时中断去扫描对面通道的值,根据扫描的值进行对应转换得到按键信息。
//定时器更新(溢出)中断回调函数
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;
}
参考
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhhkaakh
系列文章
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
微信运动停用后别人还能看到步数吗
PHP中文网 07-22