Stm32的io口模拟spi例程分析

发布者:二进制游侠最新更新时间:2015-09-21 来源: eefocus关键字:Stm32  io口  模拟spi 手机看文章 扫描二维码
随时随地手机看文章
以下是硬件电路图,主芯片为stm32rbt6.

1.jpg

 

贴上代码

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;
   }
}

关键字:Stm32  io口  模拟spi 引用地址:Stm32的io口模拟spi例程分析

上一篇:Stm32矩阵键盘扫描程序分析
下一篇:基于stm32的精确延时利用系统滴答systick

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

STM32 PWM功能在关闭时GPIO电平不确定的情况
  刚开始接触STM32,遇到一个项目中出现在产品调试中出现在关闭PWM输出时,GPIO电平有不确定的情况。在网上查阅资料发现大神们是这样解释的:PWM在一个脉冲没有结束时关闭输出,会导致GPIO电平不确定。   解决方法:1、在关闭PWM输出时随即将相应GPIO强制为低(这个高/低看各人的需要)   tiM_Cmd(TIM3 ,DISABLE);//关闭PWM输出   TIM_ForcedOC1Config(TIM3, TIM_ForcedAction_InActive);//将PWM输出强制为低   2、在下次打开PWM时使用下面的函数   /*因前面使用PWM强制输出为低,此处需要重新打开PWM输出*/   TI
[单片机]
STM32单片机学习总结之------位操作
储备知识: 与(&)运算 0&0=0,0&1=0,1&0=0,1&1=1 非(~)运算 在二进制中1变0,0变1 或(|)运算 0|0=0,0|1=1,1|0=1,1|1=1 异或(^)运算,同为假,异为真 0^0=0 0^1=1 1^0=1 1^1=0 学习内容: 库函数的实现涉及到不少位操作,下面为几个常用的位操作方法,可以排除阅读代码的障碍。 char型只占一个字节,取值范围为-128 ~ +127 1、将char型变量a的第七位(bit6)清0,其它位不变。 2、同理,将变量a的第七位(bit6)置1,其它位不变的方法如下 3、将变量a的第七位(bit6)取反,其它位不变。 学习总结: 以上
[单片机]
<font color='red'>STM32</font>单片机学习总结之------位操作
关于STM32的几种输入模式以及外部中断的配置
最近做毕业设计,需要用按键来触发外部中断。实验的时候是正常的,但是换了个核心板以及用上自己做的PCB电路板后,出现了一些问题。问题如下: 要求:将连接按键的IO口配置为上拉输入,按键一端接IO口,一端接地,即当按键按下后,该IO口会产生一个下降沿,触发下降沿中断。 问题:将相应的IO口配置好后,测了引脚的的电压,并不是3.3V左右,而是0.1V左右。于是猜想: 1. 外围电路对IO口产生了影响。 2. STM32内部上拉能力较弱,一次只能上拉一个IO口。 于是开始从这两个想法着手解决。首先第一个,很容易就排除了。将外围电路撤掉,我用的是杜邦线,直接拔掉测量引脚上的电压,依然是0.1V左右,于是第1个猜想排除。 第二个,查看万能
[单片机]
STM32 USART的使用
SECTION 1 调试STM32串口过程中发现一个奇怪的问题,初始化串口1口,使能串口发送完成中断后,立刻就进入了发送完成中断。 仔细的查阅了STM32手册中的串口部分的介绍: 以下是字符发送的配置过程,注意第6点,在设置USART_CR1中的TE位时,会发送一个空闲帧作为第一次数据发送,所以即便你执行了USART_ClearFlag(USART1, USART_FLAG_TC); (这个函数肯定在空闲帧数据发送完成前执行),所以当空闲帧发送完后,就进入发送完成中断。 配置步骤: 1. 通过在USART_CR1寄存器上置位UE位来激活USART 2. 编程USART_CR1的M位来定义字长。 3. 在USAR
[单片机]
STM32之通用定时器计数器模式
#include stm32f10x.h /* RCC时钟配置 */ void RCC_config() { ErrorStatus HSEStartUpStatus; /* RCC寄存器设置为默认配置 */ RCC_DeInit(); /* 打开外部高速时钟 */ RCC_HSEConfig(RCC_HSE_ON); /* 等待外部高速时钟稳定 */ HSEStartUpStatus = RCC_WaitForHSEStartUp(); if(HSEStartUpStatus == SUCCESS) { /* 设置HCLK = SYSCLK */ RCC_HCLKConfig(RCC_SYSCLK_Div1); /
[单片机]
50.待机唤醒实验
一。STM32低功耗模式讲解 有些设备比如可穿戴设备对功耗的要求非常高,比如手表,我在看时间或者获取数据的时候就需要正常的执行, 但有的时候比如晚上或有时候不需要使用它,但我们并不需要关机,可以通过低功耗模式让它更加省电,就延长了它的使用时间。 1. 睡眠模式: 内核停止,但是它的外设比如中断管理NVIC,系统的时钟Systick仍在运行。 2. 停止模式:比睡眠模式更加低功耗,所有的时钟都停止,但是1.8V的内核电源还在工作,但是其他的时钟比如 PLL,HIS和HSE RC振荡器功能全部禁止了。 寄存器和SRAM的内容保留。 3. 待机模式:功耗更低,内核1.8V的电源关闭,只
[单片机]
50.待机唤醒实验
STM32入门系列-位带操作介绍
向大家介绍 STM32F1 的位带操作,让 STM32 的位操作和 51 单片机的位操作一样简单。 位带操作 在学习 51 单片机的时候就使用过位操作,通过关键字 sbit 对单片机 IO 口进行位定义。但是 STM32 没有这样的关键字,而是通过访问位带别名区来实现。即将每个比特位膨胀成一个 32 位字,当访问这些字的时候就达到了访问比特的目的。比方说 BSRR 寄存器有 32 个位,那么可以映射到 32 个地址上,当我们去访问这 32 个地址就达到访问 32 个比特的目的。 STM32F1 中有两个区域支持位带操作,一个是 SRAM 区的最低 1MB 范围,一个是片内外设区的最低 1MB 范围(APB1、APB2、
[单片机]
<font color='red'>STM32</font>入门系列-位带操作介绍
STM32上的SDRAM硬件电路设计
SDRAM简介 SDRAM(synchronous dynamic random-access memory)即同步动态随机存取内存。在介绍SDRAM前,我们先了解下DRAM(Dynamic random-access memory),DRAR中文译为动态随机存取内存,也叫动态随机存取器,为什么叫动态随机存取器,原因是它的实现原理跟静态存储器SRAM不一样,DRAM是在芯片里集成很多个阵列的电容,DRAM存储二进制数据0和1就是通过给这些阵充放电荷实现。一个简单的单个DRAM存储单元示例图如下图所示。 单个DRAM单元实现电容充放电原理 电容C用来存储电荷,信号WRITE 1、WRITE 0控制开关晶体管Q1和Q2给电容充电和
[单片机]
<font color='red'>STM32</font>上的SDRAM硬件电路设计
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

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