Stm32的io口模拟spi例程分析

接口/总线/驱动

1114人已加入

描述

  SPCE061A的I/O端口,对某一位的设定包括以下3个基本项:数据向量Data、属性向量Attribution和方向控制向量Direction。3个端口内每个对应的位组合在一起,形成一个控制字,用来定义相应I/O口位的输入输出状态和方式。例如,假设需要IOA0是下拉输入管脚,则相应的Data、Attribution和Direction的值均被置为“0”。如果需要IOA1是带唤醒功能的悬浮式输入管脚,则Data、Attribution和Direction的值被置为“010”。A口和B口的Data、Attribution和Direction的设定值均在不同的寄存器里,用户在进行I/O口设置时要特别注意这一点。

  在STM32F105和STM32F107互连型系列微控制器之前,意法半导体已经推出STM32基本型系列、增强型系列、USB基本型系列、互补型系列;新系列产品沿用增强型系列的72MHz处理频率。内存包括64KB到256KB闪存和 20KB到64KB嵌入式SRAM。新系列采用LQFP64、LQFP100和LFBGA100三种封装,不同的封装保持引脚排列一致性,结合STM32平台的设计理念,开发人员通过选择产品可重新优化功能、存储器、性能和引脚数量,以最小的硬件变化来满足个性化的应用需求。

  以下是硬件电路图,主芯片为stm32rbt6.

  

  贴上代码

  void SPI_FLASH_Init1(void)//io初始化配置

  {

  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_9;//CS CLK

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_Init(GPIOC, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 ;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //MOSI要用模拟输入

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_Init(GPIOC, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//MISO

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_Init(GPIOA, &GPIO_InitStructure);

  //关键在读取函数

  //包括读取和发送

  u8 SPIx_FLASH_SendByte(u8 byte)

  {

  uint8_t i;

  u8 Temp=0x00;

  unsigned char SDI;

  for (i = 0; i 《 8; i++)

  {

  GPIO_SetBits(GPIOC, GPIO_Pin_9);//sclk = 0;//先将时钟拉高

  if (byte&0x80)

  {

  GPIO_SetBits(GPIOC, GPIO_Pin_7); // //SO=1

  }

  else

  {

  GPIO_ResetBits(GPIOC, GPIO_Pin_7);// //SO=0

  }

  byte 《《= 1;

  GPIO_ResetBits(GPIOC, GPIO_Pin_9);// //sclk = 1; 拉低时钟

  SDI = GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_8);//判断si是否有输入

  Temp《《=1;

  if(SDI) //读到1时

  {

  Temp++; //置1 即向右移动一位同时加1 因上边有《《=1

  }

  GPIO_SetBits(GPIOC, GPIO_Pin_9);//sclk = 0;// 拉高时钟

  }

  return Temp; //返回读到miso输入的值

  }

  }

  //下面是以读写spi flash为例具体的实现

  //此函数中 时钟机时序很重要。Cs在读写中只能出现一次,不能在sendwrite

  //读写里边有,被调用时还出现,就肯定不行了。

  //其它函数宏定义

  #define BUFFER_1_WRITE 0x84 // buffer 1 write

  #define BUFFER_2_WRITE 0x87 // buffer 2 write

  #define BUFFER_1_READ 0x54 // buffer 1 read (change to 0xD4 for SPI mode 0,3)

  #define BUFFER_2_READ 0x56 // buffer 2 read (change to 0xD6 for SPI mode 0,3)

  #define B1_TO_PAGE_WITH_ERASE 0x83 // buffer 1 to main memory page program with built-in erase

  #define B2_TO_PAGE_WITH_ERASE 0x86 // buffer 2 to main memory page program with built-in erase

  #define B1_TO_PAGE_WITHOUT_ERASE 0x88 // buffer 1 to main memory page program without built-in erase

  #define B2_TO_PAGE_WITHOUT_ERASE 0x89 // buffer 2 to main memory page program without built-in erase

  #define PAGE_PROG_THROUGH_B1 0x82 // main memory page program through buffer 1

  #define PAGE_PROG_THROUGH_B2 0x85 // main memory page program through buffer 2

  #define AUTO_PAGE_REWRITE_THROUGH_B1 0x58 // auto page rewrite through buffer 1

  #define AUTO_PAGE_REWRITE_THROUGH_B2 0x59 // auto page rewrite through buffer 2

  #define PAGE_TO_B1_COMP 0x60 // main memory page compare to buffer 1

  #define PAGE_TO_B2_COMP 0x61 // main memory page compare to buffer 2

  #define PAGE_TO_B1_XFER 0x53 // main memory page to buffer 1 transfer

  #define PAGE_TO_B2_XFER 0x55 // main memory page to buffer 2 transfer

  #define STATUS_REGISTER 0x57

  #define MAIN_MEMORY_PAGE_READ 0x52 // main memory page read (change to 0xD2 for SPI mode 0,3)

  #define PAGE_ERASE 0x81 // erase a 264 byte page

  #define BULK_ERASE 0x50 // erase 8 pages

  #define WIP_Flag 0x80

  #define Dummy_Byte 0xA5

  AT45DB系列的读写函数

  void AT45xxReadx(uint32_t Num,uint32_t PageAddr, uint32_t ByteAddr, uint8_t *

  Data, uint32_t ByteNum)

  {

  SPIx_FLASH_PageToBuffer2(Num,PageAddr);

  SPIx_FLASH_Buffer2Read(Num,Data, ByteAddr, ByteNum);

  }

  写函数

  void AT45xxWritex(uint32_t Num,uint32_t PageAddr, uint32_t ByteAddr, u8 *Data

  , uint32_t ByteNum)

  {

  uint32_t i;

  u8 aa[100];

  if((ByteNum 《= (528 - ByteAddr))&&(ByteNum 》 0))

  {

  SPIx_FLASH_WaitForWriteEnd(Num);

  // while(!(Rat45_status()& 0x80 )); //判断是否忙

  SPIx_FLASH_CS_LOW(Num);

  SPIx_FLASH_SendByte(Num,0x82);

  // SPIx_ReadWriteByte(0x82);

  // SPIx_ReadWriteByte((uint8_t)(PageAddr》》6));

  // SPIx_ReadWriteByte((uint8_t)((PageAddr《《2)|(ByteAddr》》8)));

  // SPIx_ReadWriteByte((uint8_t)ByteAddr);

  SPIx_FLASH_SendByte(Num,(uint8_t)(PageAddr》》6));

  SPIx_FLASH_SendByte(Num,(uint8_t)((PageAddr《《2)|(ByteAddr》》8)));

  SPIx_FLASH_SendByte(Num,(uint8_t)ByteAddr);

  for(i = 0; i 《 ByteNum; i++)

  {

  SPIx_FLASH_SendByte(Num,Data[i]);

  // SPIx_ReadWriteByte(Data[i]);

  // SPIx_FLASH_SendByte(Num,Data[i]);

  }

  SPIx_FLASH_CS_HIGH(Num);

  }

  }

  void SPIx_FLASH_WaitForWriteEnd(uint32_t Num)

  {

  unsigned char FLASH_Status = 0;

  SPIx_FLASH_CS_LOW(Num);

  SPIx_FLASH_SendByte(Num,STATUS_REGISTER);

  do

  {

  FLASH_Status = SPIx_FLASH_SendByte(Num,Dummy_Byte);

  }

  while ((FLASH_Status & WIP_Flag) == RESET);

  SPIx_FLASH_CS_HIGH(Num);

  }

  void SPIx_FLASH_Buffer2Read(uint32_t Num,u8* pBuffer, u32 ReadAddr, u16

  NumByteToRead)

  {

  SPIx_FLASH_WaitForWriteEnd(Num);

  // while(!(Rat45_status()& 0x80 )); //判断是否忙

  SPIx_FLASH_CS_LOW(Num);

  SPIx_FLASH_SendByte(Num,BUFFER_2_READ);

  SPIx_FLASH_SendByte(Num,Dummy_Byte);

  SPIx_FLASH_SendByte(Num,(ReadAddr& 0xFF00) 》》 8);

  SPIx_FLASH_SendByte(Num,ReadAddr & 0xFF);

  SPIx_FLASH_SendByte(Num,Dummy_Byte);//

  while (NumByteToRead--)

  {

  *pBuffer = SPIx_FLASH_SendByte(Num,Dummy_Byte);

  pBuffer++;

  }

  SPIx_FLASH_CS_HIGH(Num);

  }

  void SPIx_FLASH_CS_LOW(uint32_t Num)

  {

  switch(Num)

  {

  case 0: GPIO_ResetBits(GPIOB, GPIO_Pin_12); break;

  case 1: GPIO_ResetBits(GPIOA, GPIO_Pin_8); break; //U6

  case 2: GPIO_ResetBits(GPIOA, GPIO_Pin_7); break; //U7

  case 3: GPIO_ResetBits(GPIOA, GPIO_Pin_3); break; //U8

  case 4: GPIO_ResetBits(GPIOC, GPIO_Pin_3); break; //U9

  default:break;

  }

  }

  void SPIx_FLASH_CS_HIGH(uint32_t Num)

  {

  switch(Num)

  {

  case 0: GPIO_SetBits(GPIOB, GPIO_Pin_12); break;

  case 1: GPIO_SetBits(GPIOA, GPIO_Pin_8); break; //U6

  case 2: GPIO_SetBits(GPIOA, GPIO_Pin_7); break; //U7

  case 3: GPIO_SetBits(GPIOA, GPIO_Pin_3); break; //U8

  case 4: GPIO_SetBits(GPIOC, GPIO_Pin_3); break; //U9

  default:break;

  }

  }

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
评论(0)
发评论
武汉王公 2018-01-12
0 回复 举报
楼主:资料很好!解释很详细。对3线式SPI的LTC2400I芯片的操作能否修改后使用呢?谢谢你!武汉王公 收起回复

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分