1, Environment introduction
MCU: STM32F103C8T6
Development software: Keil5
Audio module: VS1053B
Recording file storage device: SD card, driven by SPI protocol
Display: 0.96 inch OLED with SPI interface
Code style: register programming is adopted, with simple code, high execution efficiency, in place annotation and convenient transplantation.
Download address of complete source code of the project (you can compile and run the test after downloading): https://download.csdn.net/download/xiaolong1126626497/19520781
2, Function introduction
This is a recorder function designed based on STM32F103C8T6. The supported functions are as follows:
1. Press key 1 to start automatic recording. The default is recording once every 5 seconds. After recording, it will be automatically saved in the directory specified by SD. The file name shall be named at the current time; The audio file format is stored in WAV format.
2. Press key 2 to start manual recording. After pressing the key, start recording, and press again to end recording. After recording, the file is also saved in the SD card.
3. SD card file system adopts FAT32 format. STM32 transplants FATFS open source file system to read and write SD card.
4. OLED display screen is used to display the status of the current recorder: idle, recording, playback, etc.
5. Press key 3 to start the automatic playback function. Automatically scan the directory and play the recording files in order.


Technical introduction:
1. The SD card is driven by SPI protocol. Because there is no high requirement for speed, SPI protocol has been fully met; If you want higher speed, you can use SDIO protocol.
2. The audio module adopts VS1053B, which supports IIS and SPI protocols. I use SPI protocol driver here. SPI is relatively simple, and the code is easy to transplant. It can be easily transplanted to other MCU. VS1053 is powerful and supports recording, decoding and playback.
3. The file system adopts FATFS file system, which has perfect functions and is free of charge, and supports FAT16, FAT32 and other formats. The bottom layer is also better adapted for transplantation. At present, in addition to FATFS, there are many other embedded file systems to choose from, and the transplantation is similar.
4. The OLED display is 0.96 inch. Driven by SPI protocol, it mainly displays some states. SPI swipes the screen faster. This OLED also supports IIC interface.
5. There is no speaker device on the vs1053 module, which can be used to listen to the playback recording with headphones or speakers.
Wiring description between hardware and STM32:
OLED display: D0----SCK-----PB14 D1----MOSI----PB13 RES - reset (active at low level) - PB12 DC --- data and command control pin - PB1 CS --- chip selection pin ----- PA7
VS1053: #define VS1053_ Dreq pain (11) / / dreq data request #define VS1053_ Reset paout (12) / / RST hardware reset - active low level #define VS1053_ XCS paout (13) / / XCS chip selection - active low level #define VS1053_ Xdcs paout (14) / / xdcs is used for data slice selection and byte synchronization #define VS1053_SCLK PAout(15) #define VS1053_OUTPUT PBout(3) #define VS1053_INPUT PBin(4)
SD card interface: 5V----5V GND---GND SPI1_MOSI---PA7 SPI1_MISO---PA6 SPI1_CS---PA4 SPI1_SCK--PA5
3, Relevant hardware used
STM32F103C8T6 system board:

OLED display:

VS1053:

SD card slot:

4, Operating instructions
The development board has a reset key and a K0 key.

Program download:

The program supports three modes:
Because the development board has only one K0 key, the three modes are switched through one key.
One key is switched by pressing the counting mode. The switching sequence is automatic recording mode, manual recording mode and playback mode.
(1) Automatic recording mode: press the key once to enter the automatic recording mode. In the automatic recording mode, the recording will exit automatically after 5 seconds. After exiting, the playback state will be started automatically, that is, to play the audio recorded for just 5 seconds. During playback, press the key to exit the playback state.
(2) Manual recording mode: after pressing the K0 key for the second time, enter the manual recording mode. In the manual recording mode, you can record for a long time. If you want to end the recording, press the K0 key to end it; Automatically start the playback state after the end, that is, play the audio just recorded. During playback, press the key to exit the playback state.
(3) Playback mode: after pressing the K0 key for the third time, enter the playback mode, automatically scan the wav directory and play audio files in sequence.
During playback, you can press K0 key to exit playback mode. The files recorded each time are stored in the wav directory under the root directory of the SD card. Each status is displayed on the OLED display It will also be printed to the serial port debugging assistant terminal through the serial port.
5, Files stored on SD card
There are two directories on the SD card: font directory and wav directory. Font: 16x16 font library files are stored in the directory. wav directory to store recorded audio files.



6, Partial source code

6.1 VS1053.c this is the driver code of vs1053
#include "vs1053b.h" /* Function function: porting interface -- SPI sequential reading and writing a byte Function parameter: data: data to be written Return value: read data */ 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; } /* Function: initialize the IO port of VS1053 */ void VS1053_Init(void) { RCC->APB2ENR|=1<<0; AFIO->MAPR&=~(0x7<<24); //Release 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; } /* VS10XX function: soft reset */ void VS1053_SoftReset(void) { u8 retry=0; while(VS1053_DREQ==0); //Wait for software reset to end VS1053_SPI_ReadWriteByte(0Xff); //Start transmission retry=0; while(VS1053_ReadReg(SPI_MODE)!=0x0800) // Software reset, new mode { VS1053_WriteCmd(SPI_MODE,0x0804); // Software reset, new mode DelayMs(2);//Wait at least 1.35ms if(retry++>100)break; } while(VS1053_DREQ==0);//Wait for software reset to end retry=0; while(VS1053_ReadReg(SPI_CLOCKF)!=0X9800)//Set the clock of VS10XX, triple frequency, 1.5xADD { VS1053_WriteCmd(SPI_CLOCKF,0X9800); //Set the clock of VS10XX, triple frequency, 1.5xADD if(retry++>100)break; } DelayMs(20); } /* MP3 function: hard reset Function return value: 1: reset failed; 0: reset succeeded */ u8 VS1053_Reset(void) { u8 retry=0; VS1053_RESET=0; DelayMs(20); VS1053_XDCS=1;//Cancel data transfer VS1053_XCS=1; //Cancel data transfer VS1053_RESET=1; while(VS1053_DREQ==0&&retry<200)//Wait for DREQ to be high { retry++; DelayUs(50); } DelayMs(20); if(retry>=200)return 1; else return 0; } /* Function: write command to VS10XX Function parameters: address:Command address data :Command data */ void VS1053_WriteCmd(u8 address,u16 data) { while(VS1053_DREQ==0); //Waiting idle VS1053_XDCS=1; VS1053_XCS=0; VS1053_SPI_ReadWriteByte(VS_WRITE_COMMAND);//Send VS10XX write command VS1053_SPI_ReadWriteByte(address); //address VS1053_SPI_ReadWriteByte(data>>8); //Send high eight bits VS1053_SPI_ReadWriteByte(data); //Eighth place VS1053_XCS=1; } /* Function parameter: write data to VS1053 Function parameter: data: data to be written */ void VS1053_WriteData(u8 data) { VS1053_XDCS=0; VS1053_SPI_ReadWriteByte(data); VS1053_XDCS=1; } /* Function: read VS1053 register Function parameter: Address: register address Return value: read value */ u16 VS1053_ReadReg(u8 address) { u16 temp=0; while(VS1053_DREQ==0);//Non waiting idle state VS1053_XDCS=1; VS1053_XCS=0; VS1053_SPI_ReadWriteByte(VS_READ_COMMAND);//Send VS10XX read command VS1053_SPI_ReadWriteByte(address); //address temp=VS1053_SPI_ReadWriteByte(0xff); //Read high byte temp=temp<<8; temp+=VS1053_SPI_ReadWriteByte(0xff); //Read low byte VS1053_XCS=1; return temp; } /* Function: read the RAM of VS1053 Function parameter: addr: RAM address Return value: read value */ u16 VS1053_ReadRAM(u16 addr) { u16 res; VS1053_WriteCmd(SPI_WRAMADDR, addr); res=VS1053_ReadReg(SPI_WRAM); return res; } /* Function: write VS1053 RAM Function parameters: addr: RAM address val:Value to write */ void VS1053_WriteRAM(u16 addr,u16 val) { VS1053_WriteCmd(SPI_WRAMADDR,addr); //Write RAM address while(VS1053_DREQ==0); //Waiting idle VS1053_WriteCmd(SPI_WRAM,val); //Write RAM value } /* Function parameter: send audio data once, fixed to 32 bytes Return value: 0, sent successfully 1,The data was not sent successfully */ u8 VS1053_SendMusicData(u8* buf) { u8 n; if(VS1053_DREQ!=0) //Send data to VS10XX { VS1053_XDCS=0; for(n=0;n<32;n++) { VS1053_SPI_ReadWriteByte(buf[n]); } VS1053_XDCS=1; }else return 1; return 0;//Successfully sent } /* Function parameter: send audio data once, fixed to 32 bytes Return value: 0, sent successfully 1,The data was not sent successfully */ void VS1053_SendMusicByte(u8 data) { u8 n; while(VS1053_DREQ==0){} VS1053_XDCS=0; VS1053_SPI_ReadWriteByte(data); VS1053_XDCS=1; } /* Function: set the volume of VS1053 playback Function parameter: volx: Volume (0 ~ 254) */ void VS1053_SetVol(u8 volx) { u16 volt=0; //Temporary volume value volt=254-volx; //Take the inverse to get the maximum value, which represents the maximum representation volt<<=8; volt+=254-volx; //Get the volume after setting VS1053_WriteCmd(SPI_VOL,volt);//Set volume } /*--------------------------------------Recording function-----------------------------------------------------*/ /* Function: vs10xx load patch Function parameters: patch: patch First address len : patch length */ void VS1053_LoadPatch(u16 *patch,u16 len) { u16 i; u16 addr, n, val; for(i=0;i<len;) { addr = patch[i++]; n = patch[i++]; if(n & 0x8000U) //RLE run, replicate n samples { n &= 0x7FFF; val = patch[i++]; while(n--)VS1053_WriteCmd(addr, val); } else //copy run, copy n sample { while(n--) { val = patch[i++]; VS1053_WriteCmd(addr, val); } } } } /* Function parameter: initialize WAV header */ void VS1053_RecoderWavInit(__WaveHeader* wavhead) //Initialize WAV header { wavhead->riff.ChunkID=0X46464952; //"RIFF" wavhead->riff.ChunkSize=0; //It has not been determined yet. Finally, it needs to be calculated wavhead->riff.Format=0X45564157; //"WAVE" wavhead->fmt.ChunkID=0X20746D66; //"fmt " wavhead->fmt.ChunkSize=16; //The size is 16 bytes wavhead->fmt.AudioFormat=0X01; //0X01, indicating PCM;0X01 indicates IMA ADPCM wavhead->fmt.NumOfChannels=1; //Mono wavhead->fmt.SampleRate=8000; //8Khz sampling rate wavhead->fmt.ByteRate=wavhead->fmt.SampleRate*2;//16 bits, i.e. 2 bytes wavhead->fmt.BlockAlign=2; //Block size, 2 bytes as a block wavhead->fmt.BitsPerSample=16; //16 bit PCM wavhead->data.ChunkID=0X61746164; //"data" wavhead->data.ChunkSize=0; //The data size also needs to be calculated } //There is a bug in the WAV recording of VS1053. This plugin can correct this problem 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, }; /* Function: activate PCM recording mode Function parameters: agc:0,automatic gain 1024 Equivalent to 1 time 512 Equivalent to 0.5x Maximum 65535 = 64 times */ void VS1053_RecoderInit(u16 agc) { //In case of IMA ADPCM, the sampling rate is calculated as follows: //Sampling rate = CLKI/256*d; //Assuming d=0 and frequency doubling, the external crystal oscillator is 12.288M Then Fc=(2*12288000)/256*6=16Khz //In the case of linear PCM, the sampling rate directly writes the sampling value VS1053_WriteCmd(SPI_BASS,0x0000); VS1053_WriteCmd(SPI_AICTRL0,8000); //Set the sampling rate to 8Khz VS1053_WriteCmd(SPI_AICTRL1,agc); //Set gain, 0, automatic gain. 1024 is equivalent to 1 times, 512 is equivalent to 0.5 times, and the maximum value is 65535 = 64 times VS1053_WriteCmd(SPI_AICTRL2,0); //Set the maximum gain value, 0, representing the maximum value 65536=64X VS1053_WriteCmd(SPI_AICTRL3,6); //Left channel (MIC mono input) VS1053_WriteCmd(SPI_CLOCKF,0X2000); //Set the clock of VS10XX, mult: double frequency; ADD: not allowed; CLK:12.288Mhz VS1053_WriteCmd(SPI_MODE,0x1804); //MIC, recording activation DelayMs(5); //Wait at least 1.35ms VS1053_LoadPatch((u16*)VS1053_WavPlugin,40);//patch is required for WAV recording of VS1053 }
6.2 SD.c this is the SD card driver code
#include "sdcard.h" static u8 SD_Type=0; //Type of SD card /* Function function: the SD card bottom interface reads and writes a byte to the SD card through SPI timing Function parameter: data is the data to be written Return value: read data */ u8 SDCardReadWriteOneByte(u8 DataTx) { u16 cnt=0; while((SPI1->SR&1<<1)==0) //The waiting to send buffer is empty -- the waiting to send buffer is empty { cnt++; if(cnt>=65530)return 0; //Timeout exit u16=2 bytes } SPI1->DR=DataTx; //Send a byte cnt=0; while((SPI1->SR&1<<0)==0) //Wait for a byte to be received { cnt++; if(cnt>=65530)return 0; //Timeout exit } return SPI1->DR; //Return received data } /* Function function: initialization of underlying SD card interface SPI1 Interface -- SD card wiring principle 5V----5V GND---GND SPI1_MOSI---PA7 SPI1_MISO---PA6 SPI1_CS---PA4 SPI1_SCK--PA5 */ void SDCardSpiInit(void) { /*1. Turn on the clock*/ RCC->APB2ENR|=1<<2; //Enable PORTA clock /*2. Configure GPIO port mode*/ GPIOA->CRL&=0x0000FFFF; GPIOA->CRL|=0xB8B30000; /*3. Pull up*/ GPIOA->ODR|=1<<4; /*SPI1 Basic configuration*/ RCC->APB2ENR|=1<<12; //Turn on SPI1 clock RCC->APB2RSTR|=1<<12; RCC->APB2RSTR&=~(1<<12); SPI1->CR1=0X0; //Clear register SPI1->CR1|=0<<15; //Select double line bidirectional mode SPI1->CR1|=0<<11; //Transmit / receive using 8-bit data frame format; SPI1->CR1|=0<<10; //Full duplex (transmit and receive); SPI1->CR1|=1<<9; //Enable software slave device management SPI1->CR1|=1<<8; //NSS SPI1->CR1|=0<<7; //Frame format, send the high bit first SPI1->CR1|=0x0<<3;//When the bus frequency is 36MHZ, the SPI speed is 18MHZ, high speed. SPI1->CR1|=1<<2; //Configure master device SPI1->CR1|=1<<1; //When idle, SCK remains high. SPI1->CR1|=1<<0; //Data sampling starts at the edge of the second clock. SPI1->CR1|=1<<6; //Turn on the SPI device. } /* Function function: deselect and release SPI bus */ void SDCardCancelCS(void) { SDCARD_CS=1; SDCardReadWriteOneByte(0xff);//Provide additional 8 clocks } /* Function function: select sd card and wait for the card to be ready for OK Function return value: 0, successful; 1. Failure; */ u8 SDCardSelectCS(void) { SDCARD_CS=0; if(SDCardWaitBusy()==0)return 0;//Wait for success SDCardCancelCS(); return 1;//Wait failed } /* Function: wait for the card to be ready Function return value: 0, ready; Other, error code */ u8 SDCardWaitBusy(void) { u32 t=0; do { if(SDCardReadWriteOneByte(0XFF)==0XFF)return 0;//OK t++; }while(t<0xFFFFFF);//wait for return 1; } /* Function function: wait for SD card response Function parameters: Response:Response value to get Return value: 0,The response value was obtained successfully Other, failed to get response value */ u8 SDCardGetAck(u8 Response) { u16 Count=0xFFFF;//Waiting times while((SDCardReadWriteOneByte(0XFF)!=Response)&&Count)Count--;//Waiting for an accurate response if(Count==0)return SDCard_RESPONSE_FAILURE;//Failed to get response else return SDCard_RESPONSE_NO_ERROR;//Correct response } /* Function: read the contents of a data packet from sd card Function parameters: buf:Data buffer len:The length of data to be read Return value: 0,success; Others, failure; */ u8 SDCardRecvData(u8*buf,u16 len) { if(SDCardGetAck(0xFE))return 1;//Wait for the SD card to send back the data start token 0xFE while(len--)//Start receiving data { *buf=SDCardReadWriteOneByte(0xFF); buf++; } //Here are 2 dummy CRC s SDCardReadWriteOneByte(0xFF); SDCardReadWriteOneByte(0xFF); return 0;//Read successful } /* Function: write 512 bytes of a data packet to sd card Function parameters: buf Data buffer cmd instructions Return value: 0 indicates success; Other values indicate failure; */ u8 SDCardSendData(u8*buf,u8 cmd) { u16 t; if(SDCardWaitBusy())return 1; //Waiting for preparation to fail SDCardReadWriteOneByte(cmd); if(cmd!=0XFD)//Not an end instruction { for(t=0;t<512;t++)SDCardReadWriteOneByte(buf[t]);//Improve speed and reduce function parameter transfer time SDCardReadWriteOneByte(0xFF); //Ignore crc SDCardReadWriteOneByte(0xFF); t=SDCardReadWriteOneByte(0xFF); //Receive response if((t&0x1F)!=0x05)return 2; //Response error } return 0;//Write successful } /* Function function: Send a command to SD card Function parameters: u8 cmd command u32 arg Command parameters u8 crc crc Check value Return value: the response returned by the SD card */ u8 SendSDCardCmd(u8 cmd, u32 arg, u8 crc) { u8 r1; u8 Retry=0; SDCardCancelCS(); //Cancel last selection if(SDCardSelectCS())return 0XFF;//Film selection failure //send data SDCardReadWriteOneByte(cmd | 0x40);//Write command separately 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--); //Wait for a response, or exit timeout return r1; //Return status value } /* Function: obtain CID information of SD card, including manufacturer information Function parameter: U8 * CID_ Data (memory for storing CID, at least 16Byte) Return value: 0: Success, 1: error */ u8 GetSDCardCISDCardOutnfo(u8 *cid_data) { u8 r1; //Send SDCard_CMD10 command, read CID r1=SendSDCardCmd(SDCard_CMD10,0,0x01); if(r1==0x00) { r1=SDCardRecvData(cid_data,16);//Receive 16 bytes of data } SDCardCancelCS();//Cancel film selection if(r1)return 1; else return 0; } /* Function Description: Obtain CSD information of SD card, including capacity and speed information Function parameters: u8 *cid_data(Memory for storing CID (at least 16Byte) Return value: 0: Success, 1: error */ u8 GetSDCardCSSDCardOutnfo(u8 *csd_data) { u8 r1; r1=SendSDCardCmd(SDCard_CMD9,0,0x01); //Send SDCard_CMD9 command, read CSD if(r1==0) { r1=SDCardRecvData(csd_data, 16);//Receive 16 bytes of data } SDCardCancelCS();//Cancel film selection if(r1)return 1; else return 0; } /* Function function: get the total number of sectors of SD card (number of sectors) Return value: 0 Indicates an error in capacity detection. Other values indicate the capacity of the SD card (number of sectors / 512 bytes) explain: The number of bytes per sector must be 512 bytes. If it is not 512 bytes, initialization cannot pass */ u32 GetSDCardSectorCount(void) { u8 csd[16]; u32 Capacity; u16 csize; if(GetSDCardCSSDCardOutnfo(csd)!=0) return 0; //Get CSD information. If there is an error during the, return 0 if((csd[0]&0xC0)==0x40) //SDHC card, calculated as follows { csize = csd[9] + ((u16)csd[8] << 8) + 1; Capacity = (u32)csize << 10;//Get the number of sectors } return Capacity; } /* Function: initialize SD card Return value: non-0 indicates initialization failure! */ u8 SDCardDeviceInit(void) { u8 r1; // Store the return value of SD card u16 retry; // Used for timeout counting u8 buf[4]; u16 i; SDCardSpiInit(); //Initialize the underlying IO port for(i=0;i<10;i++)SDCardReadWriteOneByte(0XFF); //Send a minimum of 74 pulses retry=20; do { r1=SendSDCardCmd(SDCard_CMD0,0,0x95);//Enter IDLE state }while((r1!=0X01) && retry--); SD_Type=0; //Default no card 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) //Does the card support 2.7~3.6V { retry=0XFFFE; do { SendSDCardCmd(SDCard_CMD55,0,0X01); //Send SDCard_CMD55 r1=SendSDCardCmd(SDCard_CMD41,0x40000000,0X01);//Send SDCard_CMD41 }while(r1&&retry--); if(retry&&SendSDCardCmd(SDCard_CMD58,0,0X01)==0)//Identify SD2 0 card version start { for(i=0;i<4;i++)buf[i]=SDCardReadWriteOneByte(0XFF);//Get OCR value if(buf[0]&0x40)SD_Type=SDCard_TYPE_V2HC; //Check CCS else SD_Type=SDCard_TYPE_V2; } } } } SDCardCancelCS(); //Cancel film selection if(SD_Type)return 0; //0 returned after successful initialization else if(r1)return r1; //Return value error value return 0xaa; //Other errors } /* Function: read SD card Function parameters: buf:Data buffer sector:a sector cnt:sector number Return value: 0,ok;Others, failed explain: SD The size of one sector of the card is 512 bytes */ u8 SDCardReadData(u8*buf,u32 sector,u32 cnt) { u8 r1; if(SD_Type!=SDCard_TYPE_V2HC)sector<<=9;//Convert to byte address if(cnt==1) { r1=SendSDCardCmd(SDCard_CMD17,sector,0X01);//Read command if(r1==0) //Command sent successfully { r1=SDCardRecvData(buf,512); //Receive 512 bytes } }else { r1=SendSDCardCmd(SDCard_CMD18,sector,0X01);//Continuous read command do { r1=SDCardRecvData(buf,512);//Receive 512 bytes buf+=512; }while(--cnt && r1==0); SendSDCardCmd(SDCard_CMD12,0,0X01); //Send stop command } SDCardCancelCS();//Cancel film selection return r1;// } /* Function: write data to SD card Function parameters: buf:Data buffer sector:starting sector cnt:sector number Return value: 0,ok;Others, failed explain: SD The size of one sector of the card is 512 bytes */ u8 SDCardWriteData(u8*buf,u32 sector,u32 cnt) { u8 r1; if(SD_Type!=SDCard_TYPE_V2HC)sector *= 512;//Convert to byte address if(cnt==1) { r1=SendSDCardCmd(SDCard_CMD24,sector,0X01);//Read command if(r1==0)//Command sent successfully { r1=SDCardSendData(buf,0xFE);//Write 512 bytes } } else { if(SD_Type!=SDCard_TYPE_MMC) { SendSDCardCmd(SDCard_CMD55,0,0X01); SendSDCardCmd(SDCard_CMD23,cnt,0X01);//Send instructions } r1=SendSDCardCmd(SDCard_CMD25,sector,0X01);//Continuous read command if(r1==0) { do { r1=SDCardSendData(buf,0xFC);//Receive 512 bytes buf+=512; }while(--cnt && r1==0); r1=SDCardSendData(0,0xFD);//Receive 512 bytes } } SDCardCancelCS();//Cancel film selection return r1;// }