STM32利用SPI读写SD卡的程序详解

发布者:epsilon15最新更新时间:2018-08-21 来源: eefocus关键字:STM32  SPI  读写SD卡 手机看文章 扫描二维码
随时随地手机看文章

关于SD卡的基础知识这里不做过多陈述,如果有对这方面感兴趣的朋友可以直接百度一下,有很多讲SD卡的文章,这里主要是针对SD卡的读写程序实现做一些详细说明。



SD卡的读写驱动程序是运用FATFS的基础,学了FATFS就可以在SD卡上创建文件夹及文件了。








我们先从main文件了解一下程序的执行流程

int main(void)

{

  u16 i; 

  USART1_Config();

  for(i=0;i<1536;i++)

     send_data[i]='D';

  switch(SD_Init())

  {

  case 0: 

  USART1_Puts("\r\nSD Card Init Success!\r\n");

break;

  case 1:  

        USART1_Puts("Time Out!\n");

        break;

  case 99: 

        USART1_Puts("No Card!\n");

        break;

  default: USART1_Puts("unknown err\n");

  break;

  }

  SD_WriteSingleBlock(30,send_data);

  SD_ReadSingleBlock(30,receive_data);

  if(Buffercmp(send_data,receive_data,512))

  {

    USART1_Puts("\r\n single read and write success \r\n");

  //USART1_Puts(receive_data);

  }

  SD_WriteMultiBlock(50,send_data,3);

  SD_ReadMultiBlock(50,receive_data,3);

  if(Buffercmp(send_data,receive_data,1536))

  {

USART1_Puts("\r\n multi read and write success \r\n");

//USART1_Puts(receive_data);

  }

  while(1);

}

这里程序流程比较简单:


1)配置串口,用作程序的调试输出


2)填充将要给SD卡写入数据的数组send_data。


3)初始化SD卡,根据返回SD_Init()返回值确定SD卡初始化是否完成。


4)单块读写实验,并比对读写出的数据是否相同。


5)多块读写实验,并比对读写出的数据是否相同。


下面我们开始对main函数中涉及到的用户函数的层层调用详细说明




SD初始化函数SD_Init()


为使程序更简洁,故只对SD卡进行检测,放弃对MMC卡的支持(此种卡市面上已几乎不再使用,本人手上也没有这种卡,所以写出驱动程序,也没有硬件进行检测是否可用)。


下面程序是部分对SD2.0卡检测的代码,完整代码中还有对1.0版本SD卡的初始化,可下载完整代码查看。


u8 SD_Init(void)

{

  u16 i;

  u8 r1;

  u16 retry;

  u8 buff[6];

  SPI_ControlLine();

  //SD卡初始化时时钟不能超过400KHz

  SPI_SetSpeed(SPI_SPEED_LOW);

  //CS为低电平,片选置低,选中SD卡

  SD_CS_ENABLE();

  //纯延时,等待SD卡上电稳定

  for(i=0;i<0xf00;i++);

  //先产生至少74个脉冲,让SD卡初始化完成

  for(i=0;i<10;i++)

  {

   //参数可随便写,经过10次循环,产生80个脉冲

   SPI_ReadWriteByte(0xff);

  }

//-----------------SD卡复位到idle状态----------------

//循环发送CMD0,直到SD卡返回0x01,进入idle状态

//超时则直接退出

 retry=0;

 do

  {

  //发送CMD0,CRC为0x95

  r1=SD_SendCommand(CMD0,0,0x95);

  retry++;

  }

  while((r1!=0x01)&&(retry<200));

  //跳出循环后,检查跳出原因,

  if(retry==200) //说明已超时

  {

    return 1;

  }

  //如果未超时,说明SD卡复位到idle结束

  //发送CMD8命令,获取SD卡的版本信息

  r1=SD_SendCommand(CMD8,0x1aa,0x87);

  //下面是SD2.0卡的初始化

  if(r1==0x01)

 {

    // V2.0的卡,CMD8命令后会传回4字节的数据,要跳过再结束本命令

    buff[0] = SPI_ReadWriteByte(0xFF);  

    buff[1] = SPI_ReadWriteByte(0xFF);  

    buff[2] = SPI_ReadWriteByte(0xFF);  

    buff[3] = SPI_ReadWriteByte(0xFF);      

    SD_CS_DISABLE();

    //多发8个时钟  

    SPI_ReadWriteByte(0xFF);  

    retry = 0;

    //发卡初始化指令CMD55+ACMD41

    do

    {

      r1 = SD_SendCommand(CMD55, 0, 0);

      //应返回0x01

      if(r1!=0x01)

      return r1;   

      r1 = SD_SendCommand(ACMD41, 0x40000000, 1);

      retry++;

      if(retry>200)

      return r1; 

    }

    while(r1!=0);

    //初始化指令发送完成,接下来获取OCR信息   

    //----------鉴别SD2.0卡版本开始-----------

    //读OCR指令

    r1 = SD_SendCommand_NoDeassert(CMD58, 0, 0);

    //如果命令没有返回正确应答,直接退出,返回应答

    if(r1!=0x00)  

    return r1;    

    //应答正确后,会回传4字节OCR信息

    buff[0] = SPI_ReadWriteByte(0xFF);

    buff[1] = SPI_ReadWriteByte(0xFF); 

    buff[2] = SPI_ReadWriteByte(0xFF); 

    buff[3] = SPI_ReadWriteByte(0xFF);

    //OCR接收完成,片选置高

    SD_CS_DISABLE();

    SPI_ReadWriteByte(0xFF);

    //检查接收到的OCR中的bit30位(CSS),确定其为SD2.0还是SDHC

    //CCS=1:SDHC   CCS=0:SD2.0

    if(buff[0]&0x40)

    {

      SD_Type = SD_TYPE_V2HC;

    }    

    else

    {

      SD_Type = SD_TYPE_V2;

    }    

    //-----------鉴别SD2.0卡版本结束----------- 

    SPI_SetSpeed(1); //设置SPI为高速模式

 }

}

以上函数是根据SD卡的发送和响应时序进行编写的。


1)程序中配置好SPI模式和引脚后,需要先将SPI的速度设为低速,SD卡初始化时SCK时钟信号不能大于400KHz,初始化结束后再设为高速模式,这里对SPI的模式配置不在赘述,可参考SPI读写FLASH文章的相关内容。


2)将片选信号拉低,选中SD卡,上电后,需要等待至少74个时钟,使SD卡上电稳定。


3)向SD卡发送CMD0指令,SD卡如果返回0x01,说明SD卡已复位到idle状态。


4)向SD卡发送CMD8指令,SD卡如果返回0x01,说明SD卡是2.0或SDHC卡。




SPI读写一字节数据


在这里,先介绍一个相对底层的函数。


SPI操作SD卡时,发送和接收是同步的,所以发送和接收数据使用同一个函数。


在发送数据时,并不关心函数的返回值;


在接收数据时,可以发送并无实际意义的字节(如0xFF)作为函数的参数。


u8  SPI_ReadWriteByte(u8 TxData)

{

   while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==RESET);

   SPI_I2S_SendData(SPI1,TxData);

   while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)==RESET);

   return SPI_I2S_ReceiveData(SPI1);

}

这个函数在所有主机与SD卡通信的函数中都会被调用到。






从SD卡中读回指定长度的数据


在SD卡读写试验中,我们会遇到很多需要读取SD卡各个寄存器数据的情况。


SD卡返回的数据长度并不都相同,所以需要一个函数来实现这个功能。


函数中多次调用了读写一字节数据的函数SPI_ReadWriteByte。


这个功能由函数 u8 SD_ReceiveData()来实现。


u8 SD_ReceiveData(u8 *data, u16 len, u8 release)

{

   u16 retry;

   u8 r1;

   //启动一次传输

   SD_CS_ENABLE();

   retry = 0;   

   do

   {

      r1 = SPI_ReadWriteByte(0xFF);

      retry++;

      if(retry>4000)  //4000次等待后没有应答,退出报错(可多试几次)

   {

   SD_CS_DISABLE();

   return 1;

   }

}

  //等待SD卡发回数据起始令牌0xFE

  while(r1 != 0xFE);

  //跳出循环后,开始接收数据

  while(len--)

  {

   *data = SPI_ReadWriteByte(0xFF);

   data++;

  }

  //发送2个伪CRC

  SPI_ReadWriteByte(0xFF);

  SPI_ReadWriteByte(0xFF);

  //按需释放总线

  if(release == RELEASE)

  {

    SD_CS_DISABLE();

    SPI_ReadWriteByte(0xFF);

  }  

  return 0;

}

此函数有3个输入参数:


u8 * data为保存读回数据的变量


len为需要保存的的数据个数


release 为当程序结束后是否释放总线的标志。




给SD卡发送命令


在初始化函数中,我们需要做的最多的就是给SD卡发送各种命令以及接收各种响应,从而判断卡片的类型,操作条件等相关信息。


一个命令包括6个段:



给SD卡发送命令的程序有2个。


区别为一个发送完命令后失能片选,一个为发送完命令不失能片选(后续还有数据传回)。


u8  SD_SendCommand(u8 cmd,u32 arg,u8 crc)

{

   unsigned char r1;

   unsigned int Retry = 0;

   SD_CS_DISABLE();

   //发送8个时钟,提高兼容性

   SPI_ReadWriteByte(0xff);

   //选中SD卡

   SD_CS_ENABLE();

   /*按照SD卡的命令序列开始发送命令 */

   //cmd参数的第二位为传输位,数值为1,所以或0x40  

   SPI_ReadWriteByte(cmd | 0x40);    

   //参数段第24-31位数据[31..24]

   SPI_ReadWriteByte((u8)(arg >> 24));

   //参数段第16-23位数据[23..16]

   SPI_ReadWriteByte((u8)(arg >> 16));

   //参数段第8-15位数据[15..8]

   SPI_ReadWriteByte((u8)(arg >> 8));

   //参数段第0-7位数据[7..0]

   SPI_ReadWriteByte((u8)arg);    

   SPI_ReadWriteByte(crc);

   //等待响应或超时退出

   while((r1 = SPI_ReadWriteByte(0xFF))==0xFF)

   {

     Retry++;

     if(Retry > 800) break; //超时次数

   }   

   //关闭片选

   SD_CS_DISABLE();

   //在总线上额外发送8个时钟,让SD卡完成剩下的工作

   SPI_ReadWriteByte(0xFF);

   //返回状态值

   return r1;

}



u8 SD_SendCommand_NoDeassert(u8 cmd, u32 arg,u8 crc)

{

   unsigned char r1;

   unsigned int Retry = 0;

   SD_CS_DISABLE();

   //发送8个时钟,提高兼容性

   SPI_ReadWriteByte(0xff);

   //选中SD卡

   SD_CS_ENABLE();

   /* 按照SD卡的命令序列开始发送命令 */

   SPI_ReadWriteByte(cmd | 0x40);                      

   SPI_ReadWriteByte((u8)(arg >> 24));

   SPI_ReadWriteByte((u8)(arg >> 16));

   SPI_ReadWriteByte((u8)(arg >> 8));

   SPI_ReadWriteByte((u8)arg);    

   SPI_ReadWriteByte(crc);

   //等待响应或超时退出

   while((r1 = SPI_ReadWriteByte(0xFF))==0xFF)

   {

      Retry++;

      if(Retry > 800)break; 

    }

    return r1;

}

以上两个函数就是根据SD卡在SPI模式下发送指令的时序编写的




取CID寄存器数据


u8 SD_GetCID(u8 *cid_data)

{

   u8 r1;

   //发CMD10命令,读取CID信息

   r1 = SD_SendCommand(CMD10, 0, 0xFF);

   if(r1 != 0x00)

   return r1;   //响应错误,退出 

   //接收16个字节的数据

   SD_ReceiveData(cid_data, 16, RELEASE);  

   return 0;

}

以上程序源码相对比较简单,发送了CMD10读取CID寄存器命令后,如果相应正确,即开始进入接收数据环节,这里SD_ReceiveData函数中第二个参数输入16,即表示回传128位的CID数据。




获取SD卡容量信息


SD卡容量的信息主要是通过查询CSD寄存器的一些相关数据,并根据数据手册进行计算得出的。


该函数虽然较为复杂,但可先精读SPI操作SD卡的理论知识篇,看懂程序的算法为何是这样实现的,也就容易理解程序的编写原理了。


u32 SD_GetCapacity(void)

{

    u8 csd[16];

    u32 Capacity;

    u8 r1;

    u16 i;

    u16 temp;

    //取CSD信息,如果出错,返回0

    if(SD_GetCSD(csd)!=0)

    return 0;    

    //如果是CSD寄存器是2.0版本,按下面方式计算

    if((csd[0]&0xC0)==0x40)

    {  

       Capacity=((u32)csd[8])<<8;

       Capacity+=(u32)csd[9]+1;  

       Capacity = (Capacity)*1024; //得到扇区数

       Capacity*=512; //得到字节数   

    }

    else //CSD寄存器是1.0版本

   {    

       i = csd[6]&0x03;

       i<<=8;

       i += csd[7];

       i<<=2;

       i += ((csd[8]&0xc0)>>6);

       r1 = csd[9]&0x03;

       r1<<=1;

       r1 += ((csd[10]&0x80)>>7);  

       r1+=2;

       temp = 1;

       while(r1)

       {

        temp*=2;

         r1--;

       }

   Capacity = ((u32)(i+1))*((u32)temp);  

   i = csd[5]&0x0f;

   temp = 1;

   while(i)

   {

      temp*=2;

      i--;

   }

   //最终结果

   Capacity *= (u32)temp;

   //字节为单位  

  }

   return (u32)Capacity;

}

此函数计算出来的容量是Kbyte,结果除以1024就是Mbyte,再除以1024就是GByte。


2G的卡,结果可能是1.8G,8G的卡结果可能是7.6G,代表用户可用容量。




读单块block和读多块block


SD卡读单块和多块的命令分别为CMD17和CMD18,他们的参数即要读的区域的开始地址。


因为考虑到一般SD卡的读写要求地址对齐,所以一般我们都将地址转为块,并以扇区(块)(512Byte)为单位进行读写,比如读扇区0参数就为0,读扇区1参数就为1<<9(即地址512),读扇区2参数就为2<<9(即地址1024),依此类推。


读单块:


u8 SD_ReadSingleBlock(u32 sector, u8 *buffer)

{

  u8 r1;

  //高速模式

  SPI_SetSpeed(SPI_SPEED_HIGH);

  if(SD_Type!=SD_TYPE_V2HC) //如果不是SDHC卡

  {

    sector = sector<<9; //512*sector即物理扇区的边界对其地址

  }

   r1 = SD_SendCommand(CMD17, sector, 1); //发送CMD17 读命令

   if(r1 != 0x00) return r1;    

   r1 = SD_ReceiveData(buffer, 512, RELEASE); //一个扇区为512字节

   if(r1 != 0)

     return r1;   //读数据出错

   else 

     return 0; //读取正确,返回0

}

读多块:


u8 SD_ReadMultiBlock(u32 sector, u8 *buffer, u8 count)

{

  u8 r1;  

  SPI_SetSpeed(SPI_SPEED_HIGH);

  if(SD_Type != SD_TYPE_V2HC)

  {

    sector = sector<<9;

  } 

  r1 = SD_SendCommand(CMD18, sector, 1); //读多块命令

  if(r1 != 0x00) return r1;  

  do //开始接收数据 

  {

    if(SD_ReceiveData(buffer, 512, NO_RELEASE) != 0x00)

    {

        break;

    }

    buffer += 512;

       } while(--count);  

  

  SD_SendCommand(CMD12, 0, 1); //全部传输完成,发送停止命令

  SD_CS_DISABLE(); //释放总线

  SPI_ReadWriteByte(0xFF);    

  if(count != 0)

    return count;   //如果没有传完,返回剩余个数

  else 

    return 0;

}



写单块和写多块


SD卡用CMD24和CMD25来写单块和多块,参数的定义和读操作是一样的。


忙检测:SD卡写入数据并自编程时,数据线上读到0x00表示SD卡正忙,当读到0xff表示写操作完成。


u8 SD_WaitReady(void)

{

  u8 r1;

  u16 retry=0;

  do

  {

    r1 = SPI_ReadWriteByte(0xFF);

    retry++;

    if(retry==0xfffe)

    return 1; 

  }while(r1!=0xFF); 

    return 0;

}



写单块流程:


1.发送CMD24,收到0x00表示成功


2.发送若干时钟


3.发送写单块开始字节0xFE


4.发送512个字节数据


5.发送2字节CRC(可以均为0xff)


6.连续读直到读到XXX00101表示数据写入成功


7.继续读进行忙检测(读到0x00表示SD卡正忙),当读到0xff表示写操作完成


u8 SD_WriteSingleBlock(u32 sector, const u8 *data)

{

  u8 r1;

  u16 i;

  16 retry;

        //高速模式

  SPI_SetSpeed(SPI_SPEED_HIGH);

//如果不是SDHC卡,将sector地址转为byte地址

        if(SD_Type!=SD_TYPE_V2HC)

  {

      sector = sector<<9;

  }

//写扇区指令

        r1 = SD_SendCommand(CMD24, sector, 0x00);

  if(r1 != 0x00)

  {

//应答错误,直接返回

    return r1;  

  }

//开始准备数据传输

        SD_CS_ENABLE();

  //先发3个空数据,等待SD卡准备好

  SPI_ReadWriteByte(0xff);

  SPI_ReadWriteByte(0xff);

  SPI_ReadWriteByte(0xff);

  //放起始令牌0xFE

        SPI_ReadWriteByte(0xFE);

        //发一个sector数据

  for(i=0;i<512;i++)

  {

      SPI_ReadWriteByte(*data++);

  }

  //发送2个伪CRC校验

  SPI_ReadWriteByte(0xff);

  SPI_ReadWriteByte(0xff);

  //等待SD卡应答

  r1 = SPI_ReadWriteByte(0xff);

//如果为0x05说明数据写入成功

  if((r1&0x1F)!=0x05)

  {

      SD_CS_DISABLE();

      return r1;

  }

    //等待操作完成

  retry = 0;

        //卡自编程时,数据线被拉低

  while(!SPI_ReadWriteByte(0xff))

  {

      retry++;

      if(retry>65534)        //如果长时间没有写入完成,退出报错

      {

        SD_CS_DISABLE();

        return 1;           //写入超时,返回1

      }

  }

        //写入完成,片选置1

  SD_CS_DISABLE();

  SPI_ReadWriteByte(0xff);

        return 0;

}





写多块流程:


1.发送CMD25,收到0x00表示成功


2.发送若干时钟


3.发送写多块开始字节0xFC


4.发送512字节数据


5.发送两个CRC(可以均为0xff)


6.连续读直到读到XXX00101表示数据写入成功


7.继续读进行忙检测,直到读到0xFF表示写操作完成


8.如果想读下一扇区重复2-7步骤


9.发送写多块停止字节0xFD来停止写操作


10.进行忙检测直到读到0xFF


u8 SD_WriteMultiBlock(u32 sector, const u8 *data, u8 count)

{

  u8 r1;

  u16 i;  

  SPI_SetSpeed(SPI_SPEED_HIGH); 

  if(SD_Type != SD_TYPE_V2HC)

        {

       sector = sector<<9;

        }

  if(SD_Type != SD_TYPE_MMC) 

        {

     //启用ACMD23指令使能预擦除

        r1 = SD_SendCommand(ACMD23, count, 0x01);  

        }  

        //写多块指令CMD25

        r1 = SD_SendCommand(CMD25, sector, 0x01);

        //应答不正确,直接返回

  if(r1 != 0x00) return r1;

//开始准备数据传输

  SD_CS_ENABLE();

//放3个空数据让SD卡准备好

SPI_ReadWriteByte(0xff);

  SPI_ReadWriteByte(0xff); 

        SPI_ReadWriteByte(0xff);   

  //下面是N个sector循环写入的部分

  do

  {

       //放起始令牌0xFC,表明是多块写入

         SPI_ReadWriteByte(0xFC);  

         //发1个sector的数据

         for(i=0;i<512;i++)

         {

        SPI_ReadWriteByte(*data++);

         }

         //发2个伪CRC

   SPI_ReadWriteByte(0xff);

       SPI_ReadWriteByte(0xff);

            //等待SD卡回应

         r1 = SPI_ReadWriteByte(0xff);

   //0x05表示数据写入成功

         if((r1&0x1F)!=0x05)

         {

        SD_CS_DISABLE();    

        return r1;

         }

            //检测SD卡忙信号

         if(SD_WaitReady()==1)

        {

        SD_CS_DISABLE();    //长时间写入未完成,退出

        return 1;

        }   

       } 

       while(--count);

       //发送传输结束令牌0xFD

       SPI_ReadWriteByte(0xFD);

       //等待准备好   

       if(SD_WaitReady())

       {

           SD_CS_DISABLE();

           return 1;  

        }

       //写入完成,片选置1

       SD_CS_DISABLE();

       SPI_ReadWriteByte(0xff);

       //返回count值,如果写完,则count=0,否则count=未写完的sector数  

       return count;   

}

SD卡的基本读写程序就是这些,编写的思路就是由最底层的SPI 读写一字节数据的程序作为基本程序,然后根据SD卡不同时序进行相应的组合。


想细致研究STM32的SPI在这个例程中的配置还是需要下载源码仔细阅读的。


掌握了这个例程的读写SD卡的函数原理,下一步就可以着手运用到FATFS文件系统了。


关键字:STM32  SPI  读写SD卡 引用地址:STM32利用SPI读写SD卡的程序详解

上一篇:stm32f4基于spi用fatfs读写SD卡的实现
下一篇:STM32+FATFS文件系统连续在同一个txt文件里写入内容

推荐阅读最新更新时间:2024-03-16 16:11

stm32中的stm32f10x.h的作用
1、依据stm32的类型(主要是flash的大小),定义各种中断向量表的顺序; 2、定义数据类型 3、定义MCU外设相关的结构体: 4、定义外设在FLASH中的地址: 5、进行外设寄存器的位定义
[单片机]
<font color='red'>stm32</font>中的stm32f10x.h的作用
关于STM32 SPI NSS问题的探讨
对于STM32的SPI ,Reference Manual中是给出的schematic如下: 按照标准的SPI协议,当SPI被配置为主机模式后,通过SPI对从设备进行操作时,其NSS应该自动置低,从而选中(使能)从设备;一旦不对从设备进行操作,NSS立刻置为高。 但是,我在实际调试过程中却发现:STM32 SPI NSS无法自动实现跳变。 一旦SPI初始化完成并使能SPI,NSS立刻置低,然后保持不变。 这个问题一直无法解决,直到我在ST官方论坛上看到国外有些技术人员也在讨论这个问题,他们得出的结论是:STM32 SPI NSS无法自动跳变。 RichardE Post
[单片机]
关于<font color='red'>STM32</font> <font color='red'>SPI</font> NSS问题的探讨
基于STM32、FreeRTOS 实现硬件看门狗+软件看门狗监测多任务的方法
我们都知道硬件看门狗的目的:是用来监测系统,防止系统死机,并在死机的情况下使系统复位重启。 在RTOS操作系统中,如果任务(线程)较多,出现高优先级任务长时间占用CPU资源,低优先级任务长时间得不到执行这种想象,那么我们的系统就是具有Bug的系统。 如上描述,假如我们的线程没有死机,只是长时间得不到执行。在这种异常情况下,我们又不希望系统复位,只希望执行特定代码,那我们该如何来避免这种问题呢? Ⅰ关于看门狗 硬件看门狗:利用一个定时器计数电路,其定时输出连接到电路的复位端,程序在一定时间范围内对定时“喂狗”。 因此程序正常工作时,定时器总不能溢出,也就不能产生复位信号。如果程序出现故障,不在定时周期内喂狗,就使得看门
[单片机]
基于<font color='red'>STM32</font>、FreeRTOS 实现硬件看门狗+软件看门狗监测多任务的方法
基于STM32的智能参数测试仪的设计方案
产品检测是生产厂家和用户都关心的问题。在产品生产过程中,检测是必不可少的一部分,有的还是工艺过程的一道工序。电磁继电器是电力系统以及其他电气控制系统中常用的开关元件,它们的可靠性是电力系统和其他电气控制系统可靠运行的重要保证,因此,必须对继电器的特性参数进行准确的测试。电磁继电器的电气参数主要有线圈电阻、触点接触电阻、吸合电压、释放电压、吸合时间、释放时间等。这些参数对研究继电器可靠性、动态性能具有重要意义,是保证其质量特性的重要参数。 1 系统总体架构 1.1 系统硬件结构 系统硬件主要包括UART 串口通信模块、JTAG 接口模块、测试结果显示模块、检测程序存储模块FLASH、检测电路模块以及SRAM 模块。系统总体硬件结构框
[电源管理]
基于<font color='red'>STM32</font>的智能参数测试仪的设计方案
Keil STM32工程环境搭建
ST官方提供了一套操作STM32各种外围设备的库,使用该库可以快速的搭建STM32工程,简化工作。 一、【安装STM32库】 将下载后的stm32f10x_stdperiph_lib.zip解压后得到三个文件夹分别是: Libraries 、 Project 、 Utilities 将这3个目录复制到 Keil uVision4 的安装目录,和目录中的文件覆盖合并。 二、【新建工程】 1、打开 Keil uVision4 ,在Project菜单中选择新建工程,选择工程要保存的位置,在弹出的“Select Device for target”的对话框中选择使用的STM32单片机的型号如“STM32F103C8”,点确定,然后
[单片机]
stm32专题十一:USART(二)结构框图
USART的结构框图 引脚: TX RX 发送和接收 SW-_RX 用于智能卡模式(很少用) IRDA_OUT IRDA_IN 红外通信数据的输出和输入 nRTS nCTS 硬件流控,很少用 SCLK 同步时钟(同步模式下使用) USART的引脚分配如下表,注意,只有USART1挂载到APB2高速总线上,其他的串口都是在APB1总线。 数据寄存器:USART_DR,是一个对应两个寄存器(USART_TDR和USART_RDR),寄存器的低9位 位数据有效,由USART_CR1的M位设置,当M = 0时,表示8个数据位(最常用),M = 1时表示9个数据位(很少用)。因为有两个寄存器,所以TX和RX可
[单片机]
<font color='red'>stm32</font>专题十一:USART(二)结构框图
STM32 IIC详解】stm32 IIC从机模式(中断方式收发数据)
1、IIC简介 第二节代码会用到该部分内容,对于IIC来说,从机是不能主动发送数据的,开始条件都是由主机生成。 1.1、主机发送数据流程 1) 主机在检测到总线为“空闲状态”(即 SDA、SCL 线均为高电平)时,发送一个启动信号“S”,开始一次通信的开始 2) 主机接着发送一个命令字节。该字节由 7 位的外围器件地址和 1 位读写控制位 R/W组成(此时 R/W=0) 3) 相对应的从机收到命令字节后向主机回馈应答信号 ACK(ACK=0) 4) 主机收到从机的应答信号后开始发送第一个字节的数据 5) 从机收到数据后返回一个应答信号 ACK 6) 主
[单片机]
PIC单片机与串行闪存的SPI接口设计
(冀科双实科技有限公司,石家庄 050081) 引 言 PIC单片机以性能稳定、品种众多等特点在工业控制、仪器仪表、家电、通信等领域得到广泛应用。虽然很多型号自身集成了存储器,但在很多情况下难以满足系统对大容量存储的要求,需要外扩非易失性的存储器。与并行Flash存储器相比,串行Flash存储器占用MCU引脚少,体积小,易于扩展,接线简单,工作可靠,故而越来越多地应用在各类电子产品和工业测控系统中。本文主要讨论PIC16F877A单片机与串行闪存M25P16之间的SPI通信,在要求大容量数据存储且MCU引脚资源有限的情况下具有实用价值。 1 SPI工作原理 SPI(Serial Periphe
[网络通信]
PIC单片机与串行闪存的<font color='red'>SPI</font>接口设计
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved