Novel reader designed based on STM32 (page turning, font switching, color switching, voice broadcasting)

Posted by dstantdog3 on Wed, 12 Jan 2022 05:51:01 +0100

1, Environment introduction

Trolley main control MCU: STM32F103ZET6

STM32 program development IDE: keil5

STM32 program style: developed in register mode, complete annotations, high execution efficiency and convenient transplantation

The hardware includes: a STM32F103ZET6 system board, a 2.8-inch TFT resistance touch screen, an SD card slot (SPI interface), and an SD card (storing word library and novel files)

Project complete source code download address: https://download.csdn.net/download/xiaolong1126626497/19628524

2, Function introduction

This is a novel reader designed based on ST32F103ZET6. Although there is still a lot of difference in practicability and function for real novel reader products, the technology designed here is the most valuable for STM32 and MCU development engineers who have just started.

Therefore, the novel reader of this article is mainly used as an introductory training project for embedded MCU engineers, curriculum design for college students, etc. The purpose is not to use the novel reader, but to take the novel reader as an example to learn relevant technologies: SD card, serial communication, SPI communication, 8080 timing, touch screen calibration principle, use of FATFS file system, use of voice broadcast module, etc.

The reader supports the basic functions of a conventional novel Reader:

1. It supports selecting the specified novel for viewing and reading, which can be switched through the button on the touch screen.

2. Support switching font size

3. Support switching font color and background color

4. The title bar displays the name of the novel file viewed by the current reader

5. Support page turning, previous page and next page

6. It supports automatic voice reading, and its voice is close to that of normal real people. It is very powerful.

There are two voice schemes: (1) Yu Yin syn6658 (2) IFLYTEK SYN5152. These two chips communicate through serial port, and the programming is very simple.

Introduction to internal programming ideas:

The font of the novel reader is stored on the SD card. The SD card uses the card slot of SPI interface to connect with STM32. STM32 cooperates with FATFS file system to operate the files on the SD card; In order to improve the access efficiency, the font file on the SD card will be copied to the on-board W25Q64 chip at the first power on. The novel file is still stored on the SD card. Each time the page is turned, the text file is obtained from the SD card and rendered to the LCD display.

The display screen is a 2.8-inch resistive touch screen, the driving chip is ILI9341 (compatible: 93259328), and the LCD pin wiring is compatible with the 2.8-inch LCD display screen of punctual atom; The driving chip of the resistance screen is XPT2046, which is a very common combination. This XPT2046 is an ADC chip. Finally, to complete the coordinate point positioning on the touch screen, you need to write your own calibration algorithm for conversion. ILI9341 driver chip supports 8080 timing operation, which can be driven by IO analog mode or STM32 FSMC interface. STM32 enhanced version supports FSMC function. Other chips without FSMC interface can be driven by analog 8080 timing. The effect is the same, but the efficiency is poor, and high-speed screen brushing cannot be realized. As long as high-speed screen brushing is not carried out, there is no problem in making do with it.

3, Introduction to the hardware used (all bought on Taobao)

3.1 STM32F103ZET6 minimum system board

This is the hardware details bought on Taobao. You can use either development board or LCD. The programming ideas are the same.

The onboard resources of the development board are as follows: CPU: STM32F103ZET6,LQFP144,FLASH: 512K,SRAM: 64K; Extended SPI FLASH: W25Q32, 8M bytes; 1 power indicator; 2 status indicators; An EEPROM chip, 24C02, with a capacity of 256 bytes (Note: the labels of different places of origin are different, but they are all 24C02 chips, which are correct after testing) 1 photosensitive sensor; 1 wireless module interface, which can be connected to NRF24L01/RFID/CC01 module; 1 channel CAN interface, using TJA1050 chip; 1 channel 485 interface, using SP485 chip; 1 standard 2.4/2.8/3.5/4.3/7 inch LCD interface, supporting touch screen; A USB serial port, which can be used for program download and code debugging (USMART debugging); 1 USB SLAVE interface for USB communication; 1 reset button; 2 independent keys; 1 SD card holder for connecting SD card; 1 RTC backup battery base; 1 standard JTAG/SWD simulation download and debugging interface; 1 circuit from 5V to 3.3V; All 144 pins of the chip are led out to facilitate external expansion experiment; 1 power switch to switch USB power supply;

3.2 SD card slot

3.3 SYN6658 speech synthesis chip

Functional features: • the chip supports the synthesis of any Chinese text, and can adopt four coding methods: GB2312, GBK, BIG5 and Unicode; • the chip has the function of text intelligent analysis and processing, which can analyze the text in common formats such as numerical value, telephone number, time and date, scale symbol, etc; • the chip can automatically analyze the text, identify the pronunciation of polyphonic words in the text and synthesize the correct pronunciation; • the chip can realize 10 levels of digital volume control, making the volume larger and wider; • 77 sound prompts and 14 chord music are integrated in the chip; • provide 6 Chinese speakers, including two men, two women, one effector and one girl voice; • support a variety of text control tags to improve the accuracy of text processing; • support a variety of control commands, including: synthesis, stop, pause synthesis, continue synthesis, change baud rate, etc; • support multiple ways to query the working status of the chip; • two communication modes: the chip supports UART and SPI; • the chip supports Power Down mode. The chip can enter the Power Down mode by using the control command; • communication baud rate supported by the chip: 4800bps, 9600bps, 57600bps, 115200bps; • all indicators of the chip meet the application in outdoor harsh environment;

Application scope: • on board information terminal voice broadcasting, on-board dispatching and on-board navigation • parking charge system / guidance system • bus stop announcer and attendance machine • mobile phones, landlines • queuing machine, cashier and toll machine • vending machines, information machines, POS machines • intelligent instruments, weather warning machines, intelligent transformers • smart toys, smart watches • electric bicycle • voice e-book, color screen story book, voice electronic dictionary, voice electronic tour guide • short message broadcast, news broadcast • electronic maps

4, Operating instructions

4.1 program download

The development board supports Jlink download and serial port download.

4.2 screen operation instructions

Currently implemented functions: 1. Novel page turning: it supports clicking the touch screen button to turn the next page 2. Change the novel: click the touch screen button "next" to switch the novel. 3. Change color: click the touch screen button "color adjustment" to switch colors, and 12 font colors are supported. 4. Change font: click the touch screen button "font adjustment" to switch fonts. At present, two fonts (16x16 24x24) are supported.

Idea Description: FATFS file system is transplanted in the program. Font files and novel files are stored on the SD card. The novel files in the SD card are read and displayed through the file system.

During the operation, the serial port debugging assistant will also synchronize the output information.

4.3 calibration instructions

The first time you use it, you need to calibrate the screen, otherwise the touch screen will not respond.

If the screen is not sensitive, it can be forced to calibrate. Press the key K2 and then press the reset key to force calibration.

Click the four red circles on the screen in turn.

4.4 documents stored on SD card

There are two directories on the SD card: font directory and txt directory.

Font Directory: store font library files. There are two font libraries.

txt Directory: store novel files, built-in 3 novels.

5, Core code

The code is written in Keil5, which can be downloaded, compiled, tested and learned.

Project complete source code download address: https://download.csdn.net/download/xiaolong1126626497/19628524

5.1 main.c main function code

#include "stm32f10x.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include <string.h>
#include <stdio.h>
#include "iic.h"
#include "at24c08.h"
#include "w25q64.h"
#include "nt35310_lcd.h"
#include "xpt2046.h"
#include "sdcard.h"
#Include "FF. H" / / header file of FatFs file system

//Update font --- read font from SD card to W25Q64
void FontUpdate_to_W25Q64();
    
FATFS fatfs; //File system registration workspace required

u16 select_color[]={WHITE,BLACK,BLUE,RED,YELLOW,BROWN,BRRED,GRAY,DARKBLUE,LIGHTBLUE,GRAYBLUE,LIGHTGREEN};
u8 read_text_buf[4096+1];
int main()
{  
    u32 x;u32 y;u32 size=16;u8 *p;
    u8 color_select_cnt=0; //12
    FIL text_file;
    u16 br=0;
    u8 r_data=10;
    u32 read_cnt=0;
    DIR dir;
    FRESULT res; 
    FILINFO fno; //Store read file information
    char *abs_path=NULL;  
    char path[]="0:/txt";
	u32 cnt=0;
	USART_X_Init(USART1,72,115200);
    
    NT35310_LcdInit();
	NT35310_Clear(WHITE);
    
	IIC_Init(); //IIC bus initialization
	W25Q64_Init(); //Initialize W25Q64
	
	TOUCH_Init(); 	 //Touch screen initialization
	TOUCH_CheckXY(); //Touch screen calibration procedure
	
    RCC->APB2ENR|=1<<5;
    GPIOD->CRH&=0xFF0FFFFF;
    GPIOD->CRH|=0x00300000;
    while(SDCardDeviceInit()!=0)
    {
        printf("SDCard_DeviceInit error.\r\n");
        PDout(13)=!PDout(13);
        delay_ms(100);
    }
    
	f_mount(&fatfs,"0:",0); //Workspace for registering file systems

    //Design interface
    LCD_color_1=RED;
    LCD_color_2=LIGHTBLUE;
	NT35310_DisplayString(16,0,16,"be based on STM32 Novel reader design based on");
    NT35310_DrawLine(0,16,239,16,DARKBLUE);
    
    //Draw keys
    NT35310_DrawRectangle(0,319-80,239,319,RED);
    NT35310_DrawLine(0,319-40,239,319-40,DARKBLUE);
    NT35310_DrawLine(239/2,319-80,239/2,319,DARKBLUE);
    
    LCD_color_2=WHITE;
    NT35310_DisplayString(32,319-70,16,"next page");
    NT35310_DisplayString(239/2+32,319-70,16,"Next book");
    NT35310_DisplayString(32,319-30,16,"Font adjustment");
    NT35310_DisplayString(239/2+32,319-30,16,"Color adjustment");
    
     /*1. Open Directory*/    
    res=f_opendir(&dir,path);
    if(res!=FR_OK)return res;
    
    res=f_readdir(&dir,&fno);
    printf("File name: %s,file size: %ld byte\r\n",fno.fname,fno.fsize);
    
    LCD_color_1=BLACK;
    NT35310_DisplayString(0,17,16,fno.fname);
    
    if(abs_path)
    {
         free(abs_path);
         abs_path=NULL;
    }
    
    //Length of the name of the file to be stored
    abs_path=malloc(strlen(path)+strlen(fno.fname)+1);
    
    strcpy(abs_path,path);
    strcat(abs_path,"/");
    strcat(abs_path,fno.fname);

    printf("abs_path=%s\n",abs_path);
    

    NT35310_DisplayString(0,17+16,16,"Volume 1\
For the first time, Zhen Shiyin dreamily knew the spirit, and Jia Yu was pregnant with a girl in the dust of the village\
This is also the first time to open the book. Author Ziyun: because I had a dream, I hid the truth,\
    And borrow the theory of "channeling", write this<<Stone record>>Not a book. So it's called "Zhen Shiyin".\
    But what's in the book and who? He said again: "today, I am busy and accomplish nothing. I suddenly miss all the women of that day,\
    One by one, after careful examination, I feel that my actions and knowledge are all above me. How can I be a man, sincere not like that skirt hairpin?");
    
	while(1)
    {
        if(TOUCH_PEN==0) //Judge whether the touch screen is pressed
        {
            //Judge whether the XY coordinate is read
            if(TOUCH_ReadXY())
            {	
               // printf("x=%d,y=%d\r\n",touch_info.x,touch_info.y);

                //Judgment range
                if((touch_info.x>=0 && touch_info.x<=239/2)&&
                (touch_info.y>=319-80 && touch_info.y<=319-40))
                {
                    LCD_color_2=BLUE;
                    //fill color
                    NT35310_Fill(0+1,319-80+1,239/2-1,319-40-1,BLUE);
                    //display string
                    NT35310_DisplayString(32,319-70,16,"next page");
                    
                    //Wait for the touch screen to release
                    while(TOUCH_PEN==0){}
                    
                    //Fill color - clear screen
                    NT35310_Fill(0,18+16,239,319-80-1,WHITE);
                        
                    LCD_color_2=WHITE;
                    if(read_cnt>=br)
                    {
                        read_cnt=0;
                    }
                    if(read_cnt==0)
                    {
                        if(br!=4096)
                        {
                            res=f_open(&text_file,(const TCHAR*)abs_path,FA_READ);//Open file	 
                            if(res!=0)
                            {
                                printf("%s File open failed!\r\n",abs_path);	
                                return 1;  //File open failed
                            }        
                            printf("%s File opened successfully!\n",abs_path);	
                        }
                      //Execute code                        
                        res=f_read(&text_file,read_text_buf,4096,(UINT*)&br);//Read 4096 bytes
                        read_text_buf[br]='\0';
                        printf("br=%d\r\n",br);
                        if(br!=4096)
                        {
                            f_close(&text_file);
                        }
                    }
                   
                    //font size
                    
                    x=0;     //Coordinate starting position
                    y=17+16; //Coordinate starting position
                    p=read_text_buf+read_cnt;
                    while(*p!='\0')
                    {
                            if(*p>0x80) //Judge whether it is Chinese - coding rules start from 0X8140
                            {
                                    read_cnt+=2;
                                    if(x+size>239)
                                    {
                                            x=0; //Horizontal sitting return 0
                                            y+=size; //Line feed
                                            if(y+size>=319-80-1)break;
                                    }
                                    NT35310_DisplayGBKData(x,y,size,p);//Show a Chinese
                                    x+=size;
                                    p+=2; //Offset by two bytes
                            }
                            else if(*p>=' ' && *p<='~')  //Common ASCII codes
                            {
                                    read_cnt+=1;
                                    if(x+size/2>239)
                                    {
                                            x=0; //Horizontal sitting return 0
                                            y+=size; //Line feed
                                            if(y+size>=319-80-1)break;
                                    }
                                    if(size==16)
                                    {
                                        //Display English letters
                                        NT35310_DisplayData(x,y,size/2,size,(u8*)ASCII_8_16[*p-' ']);
                                    }
                                    else if(size==24)
                                    {
                                        //Display English letters
                                        NT35310_DisplayData(x,y,size/2,size,(u8*)asc2_2412[*p-' ']);
                                    }
                                   
                                    p+=1;
                                    x+=size/2;
                            }
                            else if(*p=='\n')
                            {
                                    x=0;
                                    y+=size;
                                    p+=1; //Offset pointer
                                    read_cnt+=1;
                                    if(y+size>=319-80-1)break;
                            }
                            else 
                            {
                                    read_cnt+=1;
                                    p+=1; //Offset pointer
                            }
                    }
                        
                    //fill color
                    NT35310_Fill(0+1,319-80+1,239/2-1,319-40-1,WHITE);
                    LCD_color_2=WHITE;
                    //display string
                    NT35310_DisplayString(32,319-70,16,"next page");   
                }
 
                 //Judgment range
                if((touch_info.x>=239/2 && touch_info.x<=239)&&
                (touch_info.y>=319-80 && touch_info.y<=319-40))
                {
                    LCD_color_2=BLUE;
                    //fill color
                    NT35310_Fill(239/2+1,319-80+1,239-1,319-40-1,BLUE);
                    //display string
                    NT35310_DisplayString(239/2+32,319-70,16,"Next book");
                    
                    //Wait for the touch screen to release
                    while(TOUCH_PEN==0){}
                    LCD_color_2=WHITE;
                    
                     //Close the original file
                    f_close(&text_file);
                        
                    //Trigger new page
                    read_cnt=0;
                    br=0;
                    //Execute code                        
                    res=f_readdir(&dir,&fno);
                    if(fno.fname[0] == 0 || res!=0)
                    {
                        /*3. Close directory*/
                        f_closedir(&dir);
                        
                         /*1. Open Directory*/    
                        res=f_opendir(&dir,path);
                        if(res!=FR_OK)return res;
                        
                        res=f_readdir(&dir,&fno);
                    }
                        
                    printf("File name: %s,file size: %ld byte\r\n",fno.fname,fno.fsize);
                    
                    LCD_color_1=BLACK;
                    NT35310_DisplayString(0,17,16,fno.fname);
                    
                    if(abs_path)
                    {
                         free(abs_path);
                         abs_path=NULL;
                    }
                    //Length of the name of the file to be stored
                    abs_path=malloc(strlen(path)+strlen(fno.fname)+1);
                    
                    strcpy(abs_path,path);
                    strcat(abs_path,"/");
                    strcat(abs_path,fno.fname);

                    printf("abs_path=%s\n",abs_path);
                        
                    //fill color
                    NT35310_Fill(239/2+1,319-80+1,239-1,319-40-1,WHITE);
                    
                    //display string
                    NT35310_DisplayString(239/2+32,319-70,16,"Next book");   
                }
                
                //Judgment range
                if((touch_info.x>=0 && touch_info.x<=239/2)&&
                (touch_info.y>=319-40 && touch_info.y<=319))
                {
                    LCD_color_2=BLUE;
                    //fill color
                    NT35310_Fill(0+1,319-40+1,239/2-1,319-1,BLUE);
                    //display string
                     NT35310_DisplayString(32,319-30,16,"Font adjustment");
                    
                    //Wait for the touch screen to release
                    while(TOUCH_PEN==0){}
                    
                     if(size==16)size=24;
                     else size=16;
                        
                    //Execute code                        
                        
                    //fill color
                    NT35310_Fill(0+1,319-40+1,239/2-1,319-1,WHITE);
                    LCD_color_2=WHITE;
                    //display string
                     NT35310_DisplayString(32,319-30,16,"Font adjustment");   
                }
                
                
                 //Judgment range
                if((touch_info.x>=239/2 && touch_info.x<=239)&&
                (touch_info.y>=319-40 && touch_info.y<=319))
                {
                    LCD_color_2=BLUE;
                    //fill color
                    NT35310_Fill(239/2+1,319-40+1,239-1,319-1,BLUE);
                    //display string
                    NT35310_DisplayString(239/2+32,319-30,16,"Color adjustment");
                    
                    //Wait for the touch screen to release
                    while(TOUCH_PEN==0){}
                    
                    //Execute code  
                    //Foreground font color Toggle
                    LCD_color_1=select_color[color_select_cnt++];                      
                    if(color_select_cnt>=12)
                    {
                        color_select_cnt=0;
                    }
                       
                    //fill color
                    NT35310_Fill(239/2+1,319-40+1,239-1,319-1,WHITE);
                    LCD_color_2=WHITE;
                    //display string
                    NT35310_DisplayString(239/2+32,319-30,16,"Color adjustment");   
                }
            }	
        }
    }
}

u32 gbk32_32_addr=1024*0;
u8 font_buffer[4096];

//Update font --- read font from SD card to W25Q64
void FontUpdate_to_W25Q64()
{
    u32 w_cnt=0;
	FILINFO fno;
	FIL fp;
	UINT br,res;
    /*1. Open font*/
	f_open(&fp,"0:/font/gbk16.DZK",FA_READ);
	
	/*2. Cyclic read font updated to W25Q64*/
	f_stat("0:/font/gbk16.DZK",&fno);
	printf("File size:%d\r\n",fno.fsize);
	while(1)
	{
		 /*3. Read font file*/
		 res=f_read(&fp,font_buffer,4096,&br);
		 /*4. Write to W25Q64*/
		 W25Q64_WriteData(gbk32_32_addr,br,font_buffer);
		 gbk32_32_addr+=br;
		 w_cnt+=br;
		 printf("font16:%.f%%\r\n",(w_cnt*1.0/fno.fsize)*100);
		
		 /*5. Determine whether the file ends*/
		 if(res!=FR_OK||br!=4096)break;
	}
	/*6. Close font file*/
	f_close(&fp);
}

5.2 sdcard. C 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
 Note: timing is the second rising edge to collect data
*/
u8 SDCardReadWriteOneByte(u8 DataTx)
{		 
  u8 DataRx;				 
  u8 i;
  for(i=0;i<8;i++)
	{
		SDCardSCLK(0);  
		if(DataTx&0x80){SDCardOut(1);}
		else {SDCardOut(0);}
		DataTx<<=1; 
		SDCardSCLK(1);//The second rising edge collects data
		DataRx<<=1;
		if(SDCardInput)DataRx|=0x01;
	}
	return DataRx;
}

/*
Function function: initialization of underlying SD card interface

SPI interfaces of this program are as follows:
PC11  Film selection SDCardCS
PC12  Clock SDCardSCLK
PD2   Output SPI_MOSI -- master output slave input
PC8   Input SPI_MISO -- master input and slave output
*/
void SDCardSpiInit(void)
{
 	RCC->APB2ENR|=1<<5;		    //Enable PORTD clock
	RCC->APB2ENR|=1<<4;		    //Enable PORTC clock
	
	GPIOD->CRL&=0XFFFFF0FF; 
	GPIOD->CRL|=0X00000300;	  //PD2	    
	GPIOD->ODR|=1<<2;    	    //PD2

	GPIOC->CRH&=0XFFF00FF0;   
	GPIOC->CRH|=0X00033008;
	
	GPIOC->ODR|=0X3<<11;
	GPIOC->ODR|=1<<8;
	SDCardCS(1);
}


/*
Function function: deselect and release SPI bus
*/
void SDCardCancelCS(void)
{
	SDCardCS(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)
{
	SDCardCS(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;  
    u8 n;
	  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)	        //V2.00 card. If it is an SDHC card, calculate as follows
    {	
			csize = csd[9] + ((u16)csd[8] << 8) + 1;
			Capacity = (u32)csize << 10;//Get the number of sectors	 		   
    }
		else//V1.XX's card 
    {	
			n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
			csize = (csd[8] >> 6) + ((u16)csd[7] << 2) + ((u16)(csd[6] & 3) << 10) + 1;
			Capacity= (u32)csize << (n - 9);//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);	//Get trailing return value of R7 resp
			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;   
				}
			}
		}
		else//SD V1.x/ MMC	V3
		{
			SendSDCardCmd(SDCard_CMD55,0,0X01);		//Send SDCard_CMD55
			r1=SendSDCardCmd(SDCard_CMD41,0,0X01);	//Send SDCard_CMD41
			if(r1<=1)
			{		
				SD_Type=SDCard_TYPE_V1;
				retry=0XFFFE;
				do //Wait to exit IDLE mode
				{
					SendSDCardCmd(SDCard_CMD55,0,0X01);	//Send SDCard_CMD55
					r1=SendSDCardCmd(SDCard_CMD41,0,0X01);//Send SDCard_CMD41
				}while(r1&&retry--);
			}
			else//MMC card does not support SDCard_CMD55+SDCard_CMD41 identification
			{
				SD_Type=SDCard_TYPE_MMC;//MMC V3
				retry=0XFFFE;
				do //Wait to exit IDLE mode
				{											    
					r1=SendSDCardCmd(SDCard_CMD1,0,0X01);//Send SDCard_CMD1
				}while(r1&&retry--);  
			}
			if(retry==0||SendSDCardCmd(SDCard_CMD13,512,0X01)!=0)SD_Type=SDCard_TYPE_ERR;//Wrong card
		}
	}
	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;//
}