请选择 进入手机版 | 继续访问电脑版
快捷导航
5 190

STM32 SPI写入/读取数据M25PE80

李腾杰 于 2017-12-3 17:52 发表在 [技术分享] [复制链接]
本帖最后由 李腾杰 于 2017-12-5 09:31 编辑

STM32 拥有SPI功能,而我们所使用的开发板中SPI1接口  已经连接到了M25P80的flash芯片上。
现通过SPI将"hello world"写入到flash中,并读出来,用串口(USART1)打印出来

基本流程:配置SPI,USART,GPIO等寄存器
                发送擦除指令
                发送写入指令
                在USART中断中读取数据并发送

原理图(往下=_=):



代码实现:
  1. //配置SPI寄存器
  2. void Ini(void)
  3. {
  4.         //LED 配置
  5.         。。。
  6.         //USART1配置
  7.         。。。

  8.         //SPI
  9.         SPI_InitTypeDef SPI_InitStructure;

  10.         //GPIO:
  11.         //PA5  PA6  PA7    复用推挽输出

  12.         //PB2   推挽输出

  13.         //SPI属性
  14.         //通信方式双线全双工
  15.         SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;            
  16.         //主SPI  主机模式                     
  17.         SPI_InitStructure.SPI_Mode = SPI_Mode_Master;        
  18.         //发送接收8位帧结构                                                      
  19.         SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                                                            
  20.         //空闲时为高电平 时钟极性
  21.         SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;                                                                  
  22.         //第二个条边沿开始采集数据 时钟相位
  23.         SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;                                                              
  24.         //NSS有软件控制
  25.         SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                                                                        
  26.         //预分屏256
  27.         SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;                        
  28.          //数据传输从MSB开始(高位数据在前)   
  29.         SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                                                           
  30.          //CRC值计算的多项式
  31.         SPI_InitStructure.SPI_CRCPolynomial=7;
  32.                                                                        
  33.         SPI_Init(SPI1, &SPI_InitStructure);
  34.         SPI_Cmd(SPI1, ENABLE);
  35.         
  36. }



  37. //基本函数:

  38. //SPI发送到FLASH函数  、 SPI读取函数
  39. static u8 SPI_FLASH_SendByte(u8 cmd)
  40. {   
  41.     while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);        // Wait for SPI1 Tx buffer empty 等待SPI通道发送完毕
  42.     SPI_I2S_SendData(SPI1,cmd);                                                                  // Send SPI1 data

  43.     while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);     //Wait for SPI1 data reception  等待SPI通道接收完毕
  44.     return SPI_I2S_ReceiveData(SPI1);                                                           // Read SPI1 received data
  45. }


  46. //FLASH 操作函数:

  47. //写入函数
  48. void SPI_Flash_Write(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
  49. {
  50.     SPI_FLASH_WriteEnable();                                                              //发送使能指令 0x06
  51.     GPIO_WriteBit(GPIOB, GPIO_Pin_2,Bit_RESET);                              //片选设为低电平  开启SPI1工作

  52.     SPI_FLASH_SendByte(0x02);                                                          //发送页写入指令
  53.     SPI_FLASH_SendByte((WriteAddr&0xFF0000)>>16);                   //按字节发送写入的地址  为0x000000(第一片扇区)
  54.     SPI_FLASH_SendByte((WriteAddr&0xFF00)>>8);
  55.     SPI_FLASH_SendByte((WriteAddr&0xFF));
  56.    
  57.     while (NumByteToWrite--)
  58.     {
  59.            SPI_FLASH_SendByte(*pBuffer);                                            //发送一字节数据
  60.            pBuffer++;                                                                            //Buffer指向下一个要写入的数据
  61.     }
  62.    
  63.     GPIO_WriteBit(GPIOB, GPIO_Pin_2,Bit_SET);                                //片选设为高电平 关闭SPI1         注意:必须拉倒高电平  FLASH才会开始工作
  64.     SPI_FLASH_WaitForWriteEnd();                                                    //注意:必须等待FLASH内工作完成  在进行下一步     发送0x05查看状态
  65. }

  66. //擦除函数
  67. void SPI_FLASH_SectorErase(u32 SectorAddr)
  68. {
  69.     SPI_FLASH_WriteEnable();                                                          //使能
  70.     GPIO_WriteBit(GPIOB, GPIO_Pin_2,Bit_RESET);                          //片选设为低电平

  71.     SPI_FLASH_SendByte(0xD8);                                                     // 发送扇区擦除指令
  72.     SPI_FLASH_SendByte((SectorAddr & 0xFF0000)>>16);
  73.     SPI_FLASH_SendByte((SectorAddr & 0xFF00)>>8);
  74.     SPI_FLASH_SendByte(SectorAddr & 0xFF);
  75.    
  76.     GPIO_WriteBit(GPIOB, GPIO_Pin_2,Bit_SET);                             //设置片选为高电平,取消选择SPI FLASH
  77.     SPI_FLASH_WaitForWriteEnd();                                                //等待FLASH操作完成
  78. }

  79. //读取函数
  80. void SPI_Flash_Write(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)
  81. {
  82.     GPIO_WriteBit(GPIOB, GPIO_Pin_2,Bit_RESET);                        //片选设为低电平
  83.     SPI_FLASH_SendByte(0x03);   

  84.     SPI_FLASH_SendByte((ReadAddr&0xFF0000)>>16);
  85.     SPI_FLASH_SendByte((ReadAddr&0xFF00)>>8);
  86.     SPI_FLASH_SendByte((ReadAddr&0xFF));

  87.     while (NumByteToRead--)      
  88.     {
  89.         *pBuffer = SPI_FLASH_SendByte(0xA5);                            // 读取字节内容
  90.         pBuffer++;
  91.     }

  92.     GPIO_WriteBit(GPIOB,GPIO_Pin_2,Bit_SET);   
  93. }


  94. //main
  95. int main(void)
  96. {

  97.     Ini();
  98.     初始化。。。

  99.     SPI_FLASH_SectorErase(ADD);                                                 //擦除函数
  100.     LED1_ON;

  101.     Sys_DelaynMs(20);

  102.     SPI_Flash_Write(sendData,ADD,SIZE);                                     //写入函数
  103.     LED0_ON;

  104.     while(1);
  105. }


  106. //串口1 中断服务程序
  107. //通过串口中断  读取FLASH数据  发送出来  串口接收数据则读数据打印
  108. void USART1_IRQHandler(void)      //串口1 中断服务程序
  109. {
  110.       。。。

  111.       SPI_Flash_Read(sendData,ADD,SIZE);

  112.       。。。
  113. }
复制代码
基本步骤

注意:每次通过SPI发送数据之前,因配置问题,空闲时间,NSS为高,要将PB2(NSS信号)拉低,使其有效,再进行发送指令,等待发送指令完毕,将其拉高(这时FLASH才会开始工作)。
          在SPI发送指令的时候,要等待SPI通道的操作完毕
          在FLASH擦除、写入的时候  要等待FLASH中操作完成(通过获取FLASH的状态)  再进行下一步操作
          0xA5是一个无意义的指令 发这条指令是为了生成FLASH芯片需要的时钟(读取字节内容操作时可以发送此指令)
          擦除成功时,扇区内所有位均为1  即每个字节的内容均为 "FF"
          每次写操作前 必须擦除

此代码运行结果现象为:
LED1亮:擦除完成
LED0亮:写入完成
通过串口发送任意一个数据,串口上打印 “helloworld”

运行结果如下图:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
Connecting & Messaging from Any.

共 5 个关于本帖的回复 最后回复于 2018-1-11 17:43

anymsg_renzong 版主 发表于 2017-12-3 19:02:44 | 显示全部楼层
这么厉害 这么多代码
Connecting & Messaging from Any.
举报 使用道具
李腾杰 中级会员 发表于 2017-12-3 19:06:49 | 显示全部楼层
anymsg_renzong 发表于 2017-12-3 19:02
这么厉害 这么多代码

没有 没有  大佬面前  不敢放肆
Connecting & Messaging from Any.
举报 使用道具
chinmel 版主 发表于 2017-12-4 01:20:28 from Mobile | 显示全部楼层
代码规范 谢谢
Connecting & Messaging from Any.
举报 使用道具
小亮 中级会员 发表于 2018-1-11 17:42:42 | 显示全部楼层
厉害了大佬

点评

李腾杰 不要水贴  详情 回复 发表于 2018-1-11 17:43
Connecting & Messaging from Any.
举报 使用道具
李腾杰 中级会员 发表于 2018-1-11 17:43:17 | 显示全部楼层

不要水贴
Connecting & Messaging from Any.
举报 使用道具
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

推荐板块

精彩推荐

热门排行

明星用户

手机版|小黑屋|AnyMSG ( ©AnyMSG 2009 - 2017 · ICP备16009991号 )

GMT+8, 2018-10-21 11:17