0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

STM32錄音機(jī)設(shè)計(jì)方案 STM32F103C8T6+Keil5設(shè)計(jì)帶 SPI接口顯示屏的錄音機(jī)

DS小龍哥-嵌入式技術(shù) ? 來源:DS小龍哥-嵌入式技術(shù) ? 作者:DS小龍哥-嵌入式技 ? 2022-02-28 13:15 ? 次閱讀

?

一、環(huán)境介紹

MCU: STM32F103C8T6

開發(fā)軟件: Keil5

音頻模塊: VS1053B

錄音文件存儲(chǔ)設(shè)備: SD卡,采用SPI協(xié)議驅(qū)動(dòng)

顯示屏: SPI接口的0.96寸OLED

代碼風(fēng)格: 采用寄存器編程,代碼簡(jiǎn)潔、執(zhí)行效率高、注釋到位、移植方便。

二、功能介紹

這是基于STM32F103C8T6設(shè)計(jì)的錄音機(jī)功能,支持的功能如下:

1. 按下按鍵1啟動(dòng)自動(dòng)錄音,默認(rèn)為5秒錄音一次,錄音完畢自動(dòng)保存在SD指定目錄下。文件名稱采用當(dāng)前時(shí)間命名;音頻文件格式采用WAV格式存儲(chǔ)。

2. 按下按鍵2啟動(dòng)手動(dòng)錄音,按鍵按下之后開始錄音,再次按下結(jié)束錄音,錄音完畢之后,文件也是一樣的保存在SD卡里。

3. SD卡文件系統(tǒng)采用FAT32格式,STM32移植了FATFS開源文件系統(tǒng)對(duì)SD卡進(jìn)行讀寫操作。

4. OLED顯示屏用于顯示當(dāng)前錄音機(jī)的狀態(tài): 空閑、錄音、回放等狀態(tài)。

5. 按下按鍵3,啟動(dòng)自動(dòng)回放功能。自動(dòng)掃描目錄,按順序播放錄音文件。

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

技術(shù)介紹:

1. SD卡采用SPI協(xié)議驅(qū)動(dòng),因?yàn)閷?duì)速度沒有很高要求,SPI協(xié)議已經(jīng)完全滿足;如果要更高的速度,可以采用SDIO協(xié)議。

2. 音頻模塊采用VS1053B,這個(gè)芯片支持IIS和SPI協(xié)議。我這里采用的是SPI協(xié)議驅(qū)動(dòng),SPI比較簡(jiǎn)單,代碼也好移植,可以很方便的移植到其他單片機(jī)上運(yùn)行。VS1053功能比較強(qiáng)大,支持錄音、解碼播放。

3. 文件系統(tǒng)采用的是FATFS文件系統(tǒng),這個(gè)文件系統(tǒng)功能比較完善,使用免費(fèi),支持FAT16、FAT32等格式。底層也比較好適配移植。當(dāng)前,除了FATFS以外,還有很多其他的嵌入式文件系統(tǒng)可以選擇,移植都大同小異。

4. OLED顯示屏是0.96寸的。采用SPI協(xié)議驅(qū)動(dòng),主要是顯示一些狀態(tài),SPI刷屏比較快,這款OLED也支持IIC接口。

5. VS1053模塊上沒有喇叭設(shè)備,可以適應(yīng)耳機(jī)或者音箱聽回放的錄音。

硬件與STM32的接線說明:

OLED顯示屏:
D0----SCK-----PB14
D1----MOSI----PB13
RES—復(fù)位(低電平有效)—PB12
DC---數(shù)據(jù)和命令控制管腳—PB1
CS---片選引腳-----PA7

VS1053:
#define VS1053_DREQ PAin(11) //DREQ 數(shù)據(jù)請(qǐng)求
#define VS1053_RESET PAout(12) //RST 硬件復(fù)位--低電平有效
#define VS1053_XCS PAout(13) //XCS 片選--低電平有效
#define VS1053_XDCS PAout(14) //XDCS 用于數(shù)據(jù)片選、字節(jié)同步
#define VS1053_SCLK PAout(15)
#define VS1053_OUTPUT PBout(3)
#define VS1053_INPUT PBin(4)

SD卡接口:
5V----5V
GND---GND
SPI1_MOSI---PA7
SPI1_MISO---PA6
SPI1_CS---PA4
SPI1_SCK--PA5

三、使用的相關(guān)硬件

STM32F103C8T6系統(tǒng)板:

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

OLED顯示屏:

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

VS1053:

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

SD卡卡槽:

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

四、操作說明

開發(fā)板有一個(gè)復(fù)位鍵和一個(gè)K0按鍵。

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

程序下載:

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

程序支持三種模式:

因?yàn)殚_發(fā)板只有一個(gè)K0按鍵,所以三種模式都是通過一個(gè)按鍵進(jìn)行切換的。

一個(gè)按鍵是通過按下的計(jì)數(shù)方式進(jìn)行切換的,切換的順序是自動(dòng)錄音模式、手動(dòng)錄音模式、回放模式。

(1)自動(dòng)錄音模式:按下一次按鍵后,進(jìn)入自動(dòng)錄音模式,自動(dòng)錄音模式下,錄音5秒自動(dòng)退出,退出后自動(dòng)啟動(dòng)播放狀態(tài),就是播放剛才5秒錄制的音頻,播放過程中按下按鍵可以退出播放狀態(tài)。

(2)手動(dòng)錄音模式:第二次按下K0按鍵后,進(jìn)入手動(dòng)錄音模式,手動(dòng)錄音模式下,可以長時(shí)間錄音,如果要結(jié)束錄音,按下K0按鍵即可結(jié)束;結(jié)束后自動(dòng)啟動(dòng)播放狀態(tài),就是播放剛才錄制的音頻,播放過程中按下按鍵可以退出播放狀態(tài)。

(3)回放模式:第三次按下K0按鍵后,進(jìn)入回放模式,自動(dòng)掃描wav目錄,進(jìn)行順序播放音頻文件。

播放過程中可以按下K0按鍵退出回放模式。
每次錄音后的文件是存放在SD卡根目錄下的wav目錄下。
每個(gè)狀態(tài)都會(huì)在OLED顯示屏上顯示
也會(huì)同時(shí)通過串口打印到串口調(diào)試助手終端。

五、SD卡上存放的文件

SD卡上有兩個(gè)目錄:font目錄和wav目錄。
font目錄下存放16x16字庫文件。
wav目錄下存放錄音的音頻文件。

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

六、部分源碼

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

?

6.1 VS1053.c 這是VS1053的驅(qū)動(dòng)代碼

#include "vs1053b.h"	

/*
函數(shù)功能:移植接口--SPI時(shí)序讀寫一個(gè)字節(jié)
函數(shù)參數(shù):data:要寫入的數(shù)據(jù)
返 回 值:讀到的數(shù)據(jù)
*/
u8 VS1053_SPI_ReadWriteByte(u8 tx_data)
{			  	 
	u8 rx_data=0;				 
  u8 i;
  for(i=0;i<8;i++)
	{
		VS1053_SCLK=0;  
		if(tx_data&0x80){VS1053_OUTPUT=1;}
		else {VS1053_OUTPUT=0;}
		tx_data<<=1;	
		VS1053_SCLK=1;
		rx_data<<=1;
		if(VS1053_INPUT)rx_data|=0x01;
	}
	return rx_data; 
}


/*
函數(shù)功能:初始化VS1053的IO口	 
*/
void VS1053_Init(void)
{
	 RCC->APB2ENR|=1<<0;
	 AFIO->MAPR&=~(0x7<<24);  //釋放PA13/14/15
	 AFIO->MAPR|=0x4<<24;
	
	 RCC->APB2ENR|=1<<2;
	 RCC->APB2ENR|=1<<3;
	 
	 GPIOA->CRH&=0x00000FFF;
	 GPIOA->CRH|=0x33338000;
	  
	 GPIOB->CRL&=0xFFF00FFF;
	 GPIOB->CRL|=0x00083000;
	
	 VS1053_SCLK=1;
	 VS1053_XCS=1;
     VS1053_RESET=1;

}	


/*
函數(shù)功能:軟復(fù)位VS10XX
*/
void VS1053_SoftReset(void)
{	 
	u8 retry=0;  				   
	while(VS1053_DREQ==0); 							//等待軟件復(fù)位結(jié)束	   
	VS1053_SPI_ReadWriteByte(0Xff);			//啟動(dòng)傳輸
	retry=0;
	while(VS1053_ReadReg(SPI_MODE)!=0x0800)	// 軟件復(fù)位,新模式  
	{
		VS1053_WriteCmd(SPI_MODE,0x0804);		// 軟件復(fù)位,新模式	    
		DelayMs(2);//等待至少1.35ms 
		if(retry++>100)break; 	  
	}	
	while(VS1053_DREQ==0);//等待軟件復(fù)位結(jié)束	 
	retry=0;
	while(VS1053_ReadReg(SPI_CLOCKF)!=0X9800)//設(shè)置VS10XX的時(shí)鐘,3倍頻 ,1.5xADD 
	{
		VS1053_WriteCmd(SPI_CLOCKF,0X9800);	//設(shè)置VS10XX的時(shí)鐘,3倍頻 ,1.5xADD
		if(retry++>100)break; 	    
	}	 
	DelayMs(20);
} 


/*
函數(shù) 功 能:硬復(fù)位MP3
函數(shù)返回值:1:復(fù)位失敗;0:復(fù)位成功	
*/
u8 VS1053_Reset(void)
{
	u8 retry=0;
	VS1053_RESET=0;
	DelayMs(20);
	VS1053_XDCS=1;//取消數(shù)據(jù)傳輸
	VS1053_XCS=1; //取消數(shù)據(jù)傳輸
	VS1053_RESET=1;	   
	while(VS1053_DREQ==0&&retry<200)//等待DREQ為高
	{
		retry++;
		DelayUs(50);
	}
	DelayMs(20);	
	if(retry>=200)return 1;
	else return 0;	    		 
}


/*
函數(shù)功能:向VS10XX寫命令
函數(shù)參數(shù):
				address:命令地址
				data   :命令數(shù)據(jù)
*/
void VS1053_WriteCmd(u8 address,u16 data)
{  
	while(VS1053_DREQ==0);	//等待空閑		   	   
	VS1053_XDCS=1; 	 
	VS1053_XCS=0; 	 
	VS1053_SPI_ReadWriteByte(VS_WRITE_COMMAND);//發(fā)送VS10XX的寫命令
	VS1053_SPI_ReadWriteByte(address); 	//地址
	VS1053_SPI_ReadWriteByte(data>>8); 	//發(fā)送高八位
	VS1053_SPI_ReadWriteByte(data);	 		//第八位
	VS1053_XCS=1;            
} 


/*
函數(shù)參數(shù):向VS1053寫數(shù)據(jù)
函數(shù)參數(shù):data:要寫入的數(shù)據(jù)
*/
void VS1053_WriteData(u8 data)
{
	VS1053_XDCS=0;   
	VS1053_SPI_ReadWriteByte(data);
	VS1053_XDCS=1;      
}


/*
函數(shù)功能:讀VS1053的寄存器 
函數(shù)參數(shù):address:寄存器地址
返回值:讀到的值
*/
u16 VS1053_ReadReg(u8 address)
{ 
	u16 temp=0;   	
  while(VS1053_DREQ==0);//非等待空閑狀態(tài)   	
	VS1053_XDCS=1;       
	VS1053_XCS=0;        
	VS1053_SPI_ReadWriteByte(VS_READ_COMMAND);//發(fā)送VS10XX的讀命令
	VS1053_SPI_ReadWriteByte(address);       	//地址
	temp=VS1053_SPI_ReadWriteByte(0xff); 		  //讀取高字節(jié)
	temp=temp<<8;
	temp+=VS1053_SPI_ReadWriteByte(0xff); 		//讀取低字節(jié)
	VS1053_XCS=1;      
   return temp; 
}  


/*
函數(shù)功能:讀取VS1053的RAM
函數(shù)參數(shù):addr:RAM地址
返 回 值:讀到的值
*/
u16 VS1053_ReadRAM(u16 addr) 
{ 
	u16 res;			   	  
 	VS1053_WriteCmd(SPI_WRAMADDR, addr); 
	res=VS1053_ReadReg(SPI_WRAM);  
 	return res;
} 


/*
函數(shù)功能:寫VS1053的RAM
函數(shù)參數(shù):
				addr:RAM地址
				val:要寫入的值 
*/
void VS1053_WriteRAM(u16 addr,u16 val) 
{  		   	  
 	VS1053_WriteCmd(SPI_WRAMADDR,addr);	//寫RAM地址 
	while(VS1053_DREQ==0); 							//等待空閑	   
	VS1053_WriteCmd(SPI_WRAM,val); 			//寫RAM值 
} 


/*
函數(shù)參數(shù):發(fā)送一次音頻數(shù)據(jù),固定為32字節(jié)
返 回 值:0,發(fā)送成功
				  1,本次數(shù)據(jù)未成功發(fā)送   
*/ 
u8 VS1053_SendMusicData(u8* buf)
{
	u8 n;
	if(VS1053_DREQ!=0)  //送數(shù)據(jù)給VS10XX
	{			   	 
		VS1053_XDCS=0;  
    for(n=0;n<32;n++)
		{
			VS1053_SPI_ReadWriteByte(buf[n]);	 			
		}
		VS1053_XDCS=1;     				   
	}else return 1;
	return 0;//成功發(fā)送了
}


/*
函數(shù)參數(shù):發(fā)送一次音頻數(shù)據(jù),固定為32字節(jié)
返 回 值:0,發(fā)送成功
				  1,本次數(shù)據(jù)未成功發(fā)送   
*/ 
void VS1053_SendMusicByte(u8 data)
{
	u8 n;
	while(VS1053_DREQ==0){}	   	 
	VS1053_XDCS=0;  
	VS1053_SPI_ReadWriteByte(data);	 			
	VS1053_XDCS=1;     				   
}


/*
函數(shù)功能:設(shè)定VS1053播放的音量
函數(shù)參數(shù):volx:音量大小(0~254)
*/
void VS1053_SetVol(u8 volx)
{
    u16 volt=0; 			      //暫存音量值
    volt=254-volx;			    //取反一下,得到最大值,表示最大的表示 
	  volt<<=8;
    volt+=254-volx;					//得到音量設(shè)置后大小
    VS1053_WriteCmd(SPI_VOL,volt);//設(shè)音量 
}


/*--------------------------------------錄音功能-----------------------------------------------------*/


/*
函數(shù)功能:vs10xx裝載patch
函數(shù)參數(shù):
				patch:patch首地址
				len  :patch長度
*/
void VS1053_LoadPatch(u16 *patch,u16 len) 
{
	u16 i; 
	u16 addr, n, val; 	  			   
	for(i=0;iriff.ChunkID=0X46464952;	//"RIFF"
	wavhead->riff.ChunkSize=0;				//還未確定,最后需要計(jì)算
	wavhead->riff.Format=0X45564157; 	//"WAVE"
	wavhead->fmt.ChunkID=0X20746D66; 	//"fmt "
	wavhead->fmt.ChunkSize=16; 				//大小為16個(gè)字節(jié)
	wavhead->fmt.AudioFormat=0X01; 		//0X01,表示PCM;0X01,表示IMA ADPCM
 	wavhead->fmt.NumOfChannels=1;			//單聲道
 	wavhead->fmt.SampleRate=8000;			//8Khz采樣率 采樣速率
 	wavhead->fmt.ByteRate=wavhead->fmt.SampleRate*2;//16位,即2個(gè)字節(jié)
 	wavhead->fmt.BlockAlign=2;				//塊大小,2個(gè)字節(jié)為一個(gè)塊
 	wavhead->fmt.BitsPerSample=16;		//16位PCM
  wavhead->data.ChunkID=0X61746164;	//"data"
 	wavhead->data.ChunkSize=0;				//數(shù)據(jù)大小,還需要計(jì)算  
}

//VS1053的WAV錄音有bug,這個(gè)plugin可以修正這個(gè)問題 							    
const u16 VS1053_WavPlugin[40]=/* Compressed plugin */ 
{ 
		0x0007, 0x0001, 0x8010, 0x0006, 0x001c, 0x3e12, 0xb817, 0x3e14, /* 0 */ 
		0xf812, 0x3e01, 0xb811, 0x0007, 0x9717, 0x0020, 0xffd2, 0x0030, /* 8 */ 
		0x11d1, 0x3111, 0x8024, 0x3704, 0xc024, 0x3b81, 0x8024, 0x3101, /* 10 */ 
		0x8024, 0x3b81, 0x8024, 0x3f04, 0xc024, 0x2808, 0x4800, 0x36f1, /* 18 */ 
		0x9811, 0x0007, 0x0001, 0x8028, 0x0006, 0x0002, 0x2a00, 0x040e,  
}; 


/*
函數(shù)功能:激活PCM 錄音模式
函數(shù)參數(shù):
				agc:0,自動(dòng)增益
        1024相當(dāng)于1倍
        512相當(dāng)于0.5倍
        最大值65535=64倍		  
*/
void VS1053_RecoderInit(u16 agc)
{
	//如果是IMA ADPCM,采樣率計(jì)算公式如下:
 	//采樣率=CLKI/256*d;	
	//假設(shè)d=0,并2倍頻,外部晶振為12.288M.那么Fc=(2*12288000)/256*6=16Khz
	//如果是線性PCM,采樣率直接就寫采樣值 
  VS1053_WriteCmd(SPI_BASS,0x0000);    
 	VS1053_WriteCmd(SPI_AICTRL0,8000);	//設(shè)置采樣率,設(shè)置為8Khz
 	VS1053_WriteCmd(SPI_AICTRL1,agc);		//設(shè)置增益,0,自動(dòng)增益.1024相當(dāng)于1倍,512相當(dāng)于0.5倍,最大值65535=64倍	
 	VS1053_WriteCmd(SPI_AICTRL2,0);		  //設(shè)置增益最大值,0,代表最大值65536=64X
 	VS1053_WriteCmd(SPI_AICTRL3,6);		  //左通道(MIC單聲道輸入)
	VS1053_WriteCmd(SPI_CLOCKF,0X2000);	//設(shè)置VS10XX的時(shí)鐘,MULT:2倍頻;ADD:不允許;CLK:12.288Mhz
	VS1053_WriteCmd(SPI_MODE,0x1804);		//MIC,錄音激活    
 	DelayMs(5);					//等待至少1.35ms 
 	VS1053_LoadPatch((u16*)VS1053_WavPlugin,40);//VS1053的WAV錄音需要patch
}

;)>
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

6.2 SD.c 這是SD卡的驅(qū)動(dòng)代碼

#include "sdcard.h"			   
static u8  SD_Type=0;  //存放SD卡的類型

/*
函數(shù)功能:SD卡底層接口,通過SPI時(shí)序向SD卡讀寫一個(gè)字節(jié)
函數(shù)參數(shù):data是要寫入的數(shù)據(jù)
返 回 值:讀到的數(shù)據(jù)
*/
u8 SDCardReadWriteOneByte(u8 DataTx)
{		 
    u16 cnt=0;				 
    while((SPI1->SR&1<<1)==0)		 //等待發(fā)送區(qū)空--等待發(fā)送緩沖為空	
    {
      cnt++;
      if(cnt>=65530)return 0; 	  //超時(shí)退出  u16=2個(gè)字節(jié)
    }	
    SPI1->DR=DataTx;	 	  		      //發(fā)送一個(gè)byte 
    cnt=0;
    while((SPI1->SR&1<<0)==0) 		//等待接收完一個(gè)byte   
    {
      cnt++;
      if(cnt>=65530)return 0;	   //超時(shí)退出
    }	  						    
    return SPI1->DR;          		//返回收到的數(shù)據(jù)
}


/*
函數(shù)功能:底層SD卡接口初始化
SPI1接口---SD卡接線原理
5V----5V
GND---GND
SPI1_MOSI---PA7
SPI1_MISO---PA6
SPI1_CS---PA4
SPI1_SCK--PA5
*/
void SDCardSpiInit(void)
{
  /*1. 開啟時(shí)鐘*/
 	RCC->APB2ENR|=1<<2;		    //使能PORTA時(shí)鐘
  
  /*2. 配置GPIO口模式*/
  GPIOA->CRL&=0x0000FFFF;
  GPIOA->CRL|=0xB8B30000;
  
  /*3. 上拉*/
  GPIOA->ODR|=1<<4;
	
		/*SPI1基本配置*/
	RCC->APB2ENR|=1<<12;    //開啟SPI1時(shí)鐘
	RCC->APB2RSTR|=1<<12;
	RCC->APB2RSTR&=~(1<<12);
	
	SPI1->CR1=0X0; 		//清空寄存器
	SPI1->CR1|=0<<15; //選擇“雙線雙向”模式
	SPI1->CR1|=0<<11; //使用8位數(shù)據(jù)幀格式進(jìn)行發(fā)送/接收;
	SPI1->CR1|=0<<10; //全雙工(發(fā)送和接收);
	SPI1->CR1|=1<<9;  //啟用軟件從設(shè)備管理
	SPI1->CR1|=1<<8;  //NSS
	SPI1->CR1|=0<<7;  //幀格式,先發(fā)送高位
	SPI1->CR1|=0x0<<3;//當(dāng)總線頻率為36MHZ時(shí),SPI速度為18MHZ,高速。
	SPI1->CR1|=1<<2;  //配置為主設(shè)備
	SPI1->CR1|=1<<1;  //空閑狀態(tài)時(shí), SCK保持高電平。
	SPI1->CR1|=1<<0;  //數(shù)據(jù)采樣從第二個(gè)時(shí)鐘邊沿開始。
	SPI1->CR1|=1<<6;  //開啟SPI設(shè)備。
}

/*
函數(shù)功能:取消選擇,釋放SPI總線
*/
void SDCardCancelCS(void)
{
	SDCARD_CS=1;
 	SDCardReadWriteOneByte(0xff);//提供額外的8個(gè)時(shí)鐘
}


/*
函數(shù) 功 能:選擇sd卡,并且等待卡準(zhǔn)備OK
函數(shù)返回值:0,成功;1,失敗;
*/
u8 SDCardSelectCS(void)
{
	SDCARD_CS=0;
	if(SDCardWaitBusy()==0)return 0;//等待成功
	SDCardCancelCS();
	return 1;//等待失敗
}


/*
函數(shù) 功 能:等待卡準(zhǔn)備好
函數(shù)返回值:0,準(zhǔn)備好了;其他,錯(cuò)誤代碼
*/
u8 SDCardWaitBusy(void)
{
	u32 t=0;
	do
	{
		if(SDCardReadWriteOneByte(0XFF)==0XFF)return 0;//OK
		t++;		  
	}while(t<0xFFFFFF);//等待 
	return 1;
}


/*
函數(shù)功能:等待SD卡回應(yīng)
函數(shù)參數(shù):
					Response:要得到的回應(yīng)值
返 回 值:
					0,成功得到了該回應(yīng)值
					其他,得到回應(yīng)值失敗
*/
u8 SDCardGetAck(u8 Response)
{
	u16 Count=0xFFFF;//等待次數(shù)	   						  
	while((SDCardReadWriteOneByte(0XFF)!=Response)&&Count)Count--;//等待得到準(zhǔn)確的回應(yīng)  	  
	if(Count==0)return SDCard_RESPONSE_FAILURE;//得到回應(yīng)失敗   
	else return SDCard_RESPONSE_NO_ERROR;//正確回應(yīng)
}


/*
函數(shù)功能:從sd卡讀取一個(gè)數(shù)據(jù)包的內(nèi)容
函數(shù)參數(shù):
				buf:數(shù)據(jù)緩存區(qū)
				len:要讀取的數(shù)據(jù)長度.
返回值:
			0,成功;其他,失敗;	
*/
u8 SDCardRecvData(u8*buf,u16 len)
{			  	  
	if(SDCardGetAck(0xFE))return 1;//等待SD卡發(fā)回?cái)?shù)據(jù)起始令牌0xFE
    while(len--)//開始接收數(shù)據(jù)
    {
        *buf=SDCardReadWriteOneByte(0xFF);
        buf++;
    }
    //下面是2個(gè)偽CRC(dummy CRC)
    SDCardReadWriteOneByte(0xFF);
    SDCardReadWriteOneByte(0xFF);									  					    
    return 0;//讀取成功
}


/*
函數(shù)功能:向sd卡寫入一個(gè)數(shù)據(jù)包的內(nèi)容 512字節(jié)
函數(shù)參數(shù):
					buf 數(shù)據(jù)緩存區(qū)
					cmd 指令
返 回 值:0表示成功;其他值表示失敗;
*/
u8 SDCardSendData(u8*buf,u8 cmd)
{	
	u16 t;		  	  
	if(SDCardWaitBusy())return 1;  //等待準(zhǔn)備失效
	SDCardReadWriteOneByte(cmd);
	if(cmd!=0XFD)//不是結(jié)束指令
	{
		for(t=0;t<512;t++)SDCardReadWriteOneByte(buf[t]);//提高速度,減少函數(shù)傳參時(shí)間
	    SDCardReadWriteOneByte(0xFF); //忽略crc
	    SDCardReadWriteOneByte(0xFF);
		  t=SDCardReadWriteOneByte(0xFF); //接收響應(yīng)
		if((t&0x1F)!=0x05)return 2;   //響應(yīng)錯(cuò)誤									  					    
	}						 									  					    
    return 0;//寫入成功
}



/*
函數(shù)功能:向SD卡發(fā)送一個(gè)命令
函數(shù)參數(shù):
				u8 cmd   命令 
				u32 arg  命令參數(shù)
				u8 crc   crc校驗(yàn)值	
返回值:SD卡返回的響應(yīng)
*/												  
u8 SendSDCardCmd(u8 cmd, u32 arg, u8 crc)
{
	u8 r1;	
	u8 Retry=0; 
		
	SDCardCancelCS();               //取消上次片選
	if(SDCardSelectCS())return 0XFF;//片選失效 
	//發(fā)送數(shù)據(jù)
	SDCardReadWriteOneByte(cmd | 0x40);//分別寫入命令
	SDCardReadWriteOneByte(arg >> 24);
	SDCardReadWriteOneByte(arg >> 16);
	SDCardReadWriteOneByte(arg >> 8);
	SDCardReadWriteOneByte(arg);	  
	SDCardReadWriteOneByte(crc); 
	if(cmd==SDCard_CMD12)SDCardReadWriteOneByte(0xff);//Skip a stuff byte when stop reading
	Retry=0X1F;
	do
	{
		r1=SDCardReadWriteOneByte(0xFF);
	}while((r1&0X80) && Retry--);	  //等待響應(yīng),或超時(shí)退出
   return r1;	//返回狀態(tài)值
}	



/*
函數(shù)功能:獲取SD卡的CID信息,包括制造商信息
函數(shù)參數(shù):u8 *cid_data(存放CID的內(nèi)存,至少16Byte)	  
返 回 值:
					0:成功,1:錯(cuò)誤				
*/
u8 GetSDCardCISDCardOutnfo(u8 *cid_data)
{
    u8 r1;	   
    //發(fā)SDCard_CMD10命令,讀CID
    r1=SendSDCardCmd(SDCard_CMD10,0,0x01);
    if(r1==0x00)
	  {
			r1=SDCardRecvData(cid_data,16);//接收16個(gè)字節(jié)的數(shù)據(jù)	 
    }
	SDCardCancelCS();//取消片選
	if(r1)return 1;
	else return 0;
}	


/*
函數(shù)說明:
					獲取SD卡的CSD信息,包括容量和速度信息
函數(shù)參數(shù):
					u8 *cid_data(存放CID的內(nèi)存,至少16Byte)	    
返 回 值:
					0:成功,1:錯(cuò)誤	
*/
u8 GetSDCardCSSDCardOutnfo(u8 *csd_data)
{
	u8 r1;	 
	r1=SendSDCardCmd(SDCard_CMD9,0,0x01);    //發(fā)SDCard_CMD9命令,讀CSD
	if(r1==0)
	{
		r1=SDCardRecvData(csd_data, 16);//接收16個(gè)字節(jié)的數(shù)據(jù) 
	}
	SDCardCancelCS();//取消片選
	if(r1)return 1;
	else return 0;
}  


/*
函數(shù)功能:獲取SD卡的總扇區(qū)數(shù)(扇區(qū)數(shù))   
返 回 值:
				0表示容量檢測(cè)出錯(cuò),其他值表示SD卡的容量(扇區(qū)數(shù)/512字節(jié))
說   明:
				每扇區(qū)的字節(jié)數(shù)必為512字節(jié),如果不是512字節(jié),則初始化不能通過.	
*/
u32 GetSDCardSectorCount(void)
{
    u8 csd[16];
    u32 Capacity;  
	  u16 csize;  					    
    if(GetSDCardCSSDCardOutnfo(csd)!=0) return 0;	//取CSD信息,如果期間出錯(cuò),返回0
    if((csd[0]&0xC0)==0x40)  //SDHC卡,按照下面方式計(jì)算
    {	
			csize = csd[9] + ((u16)csd[8] << 8) + 1;
			Capacity = (u32)csize << 10;//得到扇區(qū)數(shù)	 		   
    }
    return Capacity;
}



/*
函數(shù)功能: 初始化SD卡
返 回 值: 非0表示初始化失敗!
*/
u8 SDCardDeviceInit(void)
{
  u8 r1;      // 存放SD卡的返回值
  u16 retry;  // 用來進(jìn)行超時(shí)計(jì)數(shù)
  u8 buf[4];  
	u16 i;
	SDCardSpiInit();		//初始化底層IO口
	
 	for(i=0;i<10;i++)SDCardReadWriteOneByte(0XFF); //發(fā)送最少74個(gè)脈沖
	retry=20;
	do
	{
		r1=SendSDCardCmd(SDCard_CMD0,0,0x95);//進(jìn)入IDLE狀態(tài) 閑置
	}while((r1!=0X01) && retry--);
 	SD_Type=0;   //默認(rèn)無卡
	if(r1==0X01)
	{
		if(SendSDCardCmd(SDCard_CMD8,0x1AA,0x87)==1)  //SD V2.0
		{
			for(i=0;i<4;i++)buf[i]=SDCardReadWriteOneByte(0XFF);
			if(buf[2]==0X01&&buf[3]==0XAA)    //卡是否支持2.7~3.6V
			{
				retry=0XFFFE;
				do
				{
					SendSDCardCmd(SDCard_CMD55,0,0X01);	    //發(fā)送SDCard_CMD55
					r1=SendSDCardCmd(SDCard_CMD41,0x40000000,0X01);//發(fā)送SDCard_CMD41
				}while(r1&&retry--);
				if(retry&&SendSDCardCmd(SDCard_CMD58,0,0X01)==0)//鑒別SD2.0卡版本開始
				{
					for(i=0;i<4;i++)buf[i]=SDCardReadWriteOneByte(0XFF);//得到OCR值
					if(buf[0]&0x40)SD_Type=SDCard_TYPE_V2HC;    //檢查CCS
					else SD_Type=SDCard_TYPE_V2;   
				}
			}
		}
	}
	SDCardCancelCS();       //取消片選
	if(SD_Type)return 0;  //初始化成功返回0
	else if(r1)return r1; //返回值錯(cuò)誤值	   
	return 0xaa;          //其他錯(cuò)誤
}


/*
函數(shù)功能:讀SD卡
函數(shù)參數(shù):
				buf:數(shù)據(jù)緩存區(qū)
				sector:扇區(qū)
				cnt:扇區(qū)數(shù)
返回值:
				0,ok;其他,失敗.
說  明:
				SD卡一個(gè)扇區(qū)大小512字節(jié)
*/
u8 SDCardReadData(u8*buf,u32 sector,u32 cnt)
{
	u8 r1;
	if(SD_Type!=SDCard_TYPE_V2HC)sector<<=9;//轉(zhuǎn)換為字節(jié)地址
	if(cnt==1)
	{
		r1=SendSDCardCmd(SDCard_CMD17,sector,0X01);//讀命令
		if(r1==0)												  //指令發(fā)送成功
		{
			r1=SDCardRecvData(buf,512);			//接收512個(gè)字節(jié)	   
		}
	}else
	{
		r1=SendSDCardCmd(SDCard_CMD18,sector,0X01);//連續(xù)讀命令
		do
		{
			r1=SDCardRecvData(buf,512);//接收512個(gè)字節(jié)	 
			buf+=512;  
		}while(--cnt && r1==0); 	
		SendSDCardCmd(SDCard_CMD12,0,0X01);	//發(fā)送停止命令
	}   
	SDCardCancelCS();//取消片選
	return r1;//
}

/*
函數(shù)功能:向SD卡寫數(shù)據(jù)
函數(shù)參數(shù):
				buf:數(shù)據(jù)緩存區(qū)
				sector:起始扇區(qū)
				cnt:扇區(qū)數(shù)
返回值:
				0,ok;其他,失敗.
說  明:
				SD卡一個(gè)扇區(qū)大小512字節(jié)
*/
u8 SDCardWriteData(u8*buf,u32 sector,u32 cnt)
{
	u8 r1;
	if(SD_Type!=SDCard_TYPE_V2HC)sector *= 512;//轉(zhuǎn)換為字節(jié)地址
	if(cnt==1)
	{
		r1=SendSDCardCmd(SDCard_CMD24,sector,0X01);//讀命令
		if(r1==0)//指令發(fā)送成功
		{
			r1=SDCardSendData(buf,0xFE);//寫512個(gè)字節(jié)	   
		}
	}
	else
	{
		if(SD_Type!=SDCard_TYPE_MMC)
		{
			SendSDCardCmd(SDCard_CMD55,0,0X01);	
			SendSDCardCmd(SDCard_CMD23,cnt,0X01);//發(fā)送指令	
		}
 		r1=SendSDCardCmd(SDCard_CMD25,sector,0X01);//連續(xù)讀命令
		if(r1==0)
		{
			do
			{
				r1=SDCardSendData(buf,0xFC);//接收512個(gè)字節(jié)	 
				buf+=512;  
			}while(--cnt && r1==0);
			r1=SDCardSendData(0,0xFD);//接收512個(gè)字節(jié) 
		}
	}   
	SDCardCancelCS();//取消片選
	return r1;//
}	
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 接口
    +關(guān)注

    關(guān)注

    33

    文章

    8449

    瀏覽量

    150726
  • STM32
    +關(guān)注

    關(guān)注

    2264

    文章

    10854

    瀏覽量

    354305
  • SPI
    SPI
    +關(guān)注

    關(guān)注

    17

    文章

    1688

    瀏覽量

    91215
  • 錄音機(jī)
    +關(guān)注

    關(guān)注

    3

    文章

    79

    瀏覽量

    38463
  • keil5
    +關(guān)注

    關(guān)注

    6

    文章

    44

    瀏覽量

    20626
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    藍(lán)光影音MP3錄音機(jī)

    本帖最后由 gk320830 于 2015-3-8 10:01 編輯 藍(lán)光影音MP3錄音機(jī)藍(lán)光影音MP3錄音機(jī)
    發(fā)表于 08-26 17:06

    基于單片機(jī)的智能錄音機(jī)設(shè)計(jì)

    本帖最后由 eehome 于 2013-1-5 09:44 編輯 基于單片機(jī)的智能錄音機(jī)設(shè)計(jì)
    發(fā)表于 08-17 15:39

    求一種基于STM32H743的錄音機(jī)調(diào)試方案

    怎樣去設(shè)計(jì)一種基于STM32H743的錄音機(jī)硬件部分?怎樣對(duì)基于STM32H743的錄音機(jī)軟件部分進(jìn)行調(diào)試?
    發(fā)表于 11-19 07:04

    如何對(duì)錄音機(jī)進(jìn)行調(diào)試?

    如何對(duì)錄音機(jī)進(jìn)行調(diào)試?
    發(fā)表于 11-22 06:51

    STM32F407錄音機(jī)實(shí)現(xiàn)的相關(guān)資料推薦

    STM32F407錄音機(jī)實(shí)現(xiàn)1**. 開發(fā)平臺(tái)**MCU 型號(hào):STM32F407VET6NAND Flash : MX30LF2G音頻Codec: AK45562. 接口描述****
    發(fā)表于 01-07 06:13

    盒式錄音機(jī)修理技術(shù)

    1 盒式錄音機(jī)結(jié)構(gòu) 2錄音機(jī)電磁互換原理 3盒式錄音機(jī)電路 4 修理技術(shù) .....
    發(fā)表于 09-15 16:47 ?182次下載

    錄音機(jī)遙控顯示電路

    錄音機(jī)遙控顯示電路
    發(fā)表于 02-05 15:40 ?844次閱讀
    <b class='flag-5'>錄音機(jī)</b>遙控<b class='flag-5'>顯示</b>電路

    盒式錄音機(jī)錄放磁頭更換技巧

    盒式錄音機(jī)錄放磁頭更換技巧
    發(fā)表于 09-03 14:45 ?7235次閱讀
    盒式<b class='flag-5'>錄音機(jī)</b>錄放磁頭更換技巧

    巧洗錄音機(jī)磁頭

    巧洗錄音機(jī)磁頭 使用時(shí)間長了,收錄機(jī)的磁頭積滿了污垢,影響錄音、
    發(fā)表于 09-03 14:57 ?3670次閱讀

    數(shù)碼錄音筆與傳統(tǒng)錄音機(jī)的不同

    數(shù)碼錄音筆與傳統(tǒng)錄音機(jī)的不同
    發(fā)表于 12-22 11:19 ?1042次閱讀

    盒式錄音機(jī)的自動(dòng)斷電電路

    在盒式錄音機(jī)上加裝如圖185所示電路,當(dāng)錄音機(jī)倒帶、錄放結(jié)束時(shí),以及發(fā)生軋帶故障時(shí),能自動(dòng)切斷電機(jī)
    發(fā)表于 07-29 21:52 ?1521次閱讀
    盒式<b class='flag-5'>錄音機(jī)</b>的自動(dòng)斷電電路

    錄音機(jī)兼用于對(duì)講通話電路圖

    一臺(tái)具有錄音監(jiān)聽功能的錄音機(jī)(大多數(shù)錄音機(jī)都有),處于錄音狀態(tài)時(shí),外接話筒插孔接收到音頻信號(hào)的同時(shí),監(jiān)聽插孔也會(huì)輸出同一音頻信號(hào)。利用錄音機(jī)
    發(fā)表于 08-20 20:42 ?1176次閱讀
    <b class='flag-5'>錄音機(jī)</b>兼用于對(duì)講通話電路圖

    (網(wǎng)盤)關(guān)于SDRAM和錄音機(jī)等FPGA視頻

    (網(wǎng)盤)關(guān)于SDRAM和錄音機(jī)等FPGA視頻(android嵌入式開發(fā)教程)-關(guān)于SDRAM和錄音機(jī)等FPGA視頻,一步一步的講解,真的很詳細(xì),適合大家自學(xué)研究。
    發(fā)表于 08-04 12:21 ?15次下載
    (網(wǎng)盤)關(guān)于SDRAM和<b class='flag-5'>錄音機(jī)</b>等FPGA視頻

    基于STM32錄音機(jī)設(shè)計(jì)(STM32F103+VS1053B)

    基于STM32錄音機(jī)設(shè)計(jì)(STM32F103+VS1053B)
    發(fā)表于 11-23 18:06 ?120次下載
    基于<b class='flag-5'>STM32</b>的<b class='flag-5'>錄音機(jī)設(shè)</b>計(jì)(<b class='flag-5'>STM32F103</b>+VS1053B)

    SONY雙卡磁帶錄音機(jī)維修圖冊(cè)

    SONY雙卡磁帶錄音機(jī)維修圖冊(cè)
    發(fā)表于 01-17 15:05 ?117次下載