数码之家

 找回密码
 立即注册

QQ登录

只需一步,快速开始

微信登录

微信扫一扫,快速登录

搜索
查看: 2399|回复: 3

[STM] STM32学习记录SPI总线

[复制链接]
发表于 2021-3-12 16:46:26 | 显示全部楼层 |阅读模式

爱科技、爱创意、爱折腾、爱极致,我们都是技术控

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

x
前几天写了SPI的程序,还是那样,用别人的改,记忆不深刻,今天基本又忘的差不多了
所以,又大体的看了一遍,又有些收获
SPI是串行总线的一种,有点类似232,但是232是靠双方频率同步通信,SPI是单方频率控制


SPI 一共有三根线,一根 MOSI,一根 SCK,一根 MISO
MOSI    MOSI又称 SI,是 master outputslaver input(主出从入)的缩写

MISO    与MOSI相反,主入从出

SCK      时钟,也就是脉冲信号,就是高低电平变换


大概讲解一下,单片机是主器件,它提供频率变换时钟,被控制的芯片叫从器件,没有时钟,属于被动控制
相当于雇主拿个小皮鞭,cpu是雇主,从器件是奴隶,雇主拿皮鞭抽一下奴隶,相当于cpu给从器件一个时钟脉冲
奴隶被打叫了一声,相当于传递给雇主一个信号,这样,抽一下,叫一声,抽一下,叫一声,抽是MOSI发送的,叫是MISO接收的,他们是同步的
抽8下,叫8声,就完成一个字节的信息交换。 整个过程是双向的,就是我抽他就叫,写入信息同时必须得到信息
那么只写入,就把得到的信息丢掉就可以了,如果想得到信息,就得写入同样长度的没用的信息来换要读取的信息
大概就是这个原理


void SPIx_Init(void)
{
  SPI_InitTypeDef  SPI_InitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;
  /* Enable SPI1 and GPIOA clocks */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);        //IO的时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);          //SPI1总线时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);      
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);        //端口复用的时钟      
     /* Configure SPI1 pins: NSS, SCK, MISO and MOSI */
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;   //这3个IO就是硬件已经定义好的,找到就行,改不了的
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);   
        //SPI1 NSS
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;                          //这个是片选信号,多个SPI器件时使用
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOC, &GPIO_InitStructure);

        /* SPI1 configuration */
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //SPI1设置为两线全双工
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;     //设置SPI1为主模式
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //SPI发送接收8位帧结构
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;       //串行时钟在不操作时,时钟为高电平
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;      //第二个时钟沿开始采样数据
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;       //NSS信号由软件(使用SSI位)管理
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //定义波特率预分频的值:波特率预分频值为8
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;    //数据传输从MSB位开始
  SPI_InitStructure.SPI_CRCPolynomial = 7;              //CRC值计算的多项式
  SPI_Init(SPI1, &SPI_InitStructure);
  SPI_Cmd(SPI1, ENABLE);  /* Enable SPI1  */                                                                                         //使能SPI1外设
}  
写入与读取库函数里的
static void SPI_Write_Byte(u8 byte)
{  
  //时序同发生字节一样,只是不返回读取的字节
  while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);  /* Loop while DR register in not emplty */
  SPI_I2S_SendData(SPI2, byte);/* Send byte through the SPI2 peripheral */
  
  while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);  /* Wait to receive a byte */
  SPI_I2S_ReceiveData(SPI2);  /* Return the byte read from the SPI bus */
}

static u8 SPI_Read_Byte(void)
{  
  //等待发送信号寄存器为非空,然后发送一个字节到spi总线上
  while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
  SPI_I2S_SendData(SPI2, 0x00);
  //等待接收信号寄存器为非空,然后从spi总线上接收一个字节
  while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);  /* Wait to receive a byte */
  return SPI_I2S_ReceiveData(SPI2);/* Return the byte read from the SPI bus */
}

用IO模拟SPI总线
  for(i=8;i;i--)
  {
     SCK_OFF();   //时钟先拉低
    if(value&0x80)MOSI_ON();   //从要发送的数据value高位开始,是1MOSI_ON,是0MOSI_OFF
    else MOSI_OFF();
    Delay();           //延时
    value<<=1;    //把要发送的数据左移一位为下次发送做准备
    SCK_ON();     //时钟拉高,此时器件开始读取信号
    T<<=1;        
    T|=MISO_IN;  //把返回位读出来放最后一位
    Delay();
}
   SCK_OFF();
return;
} 循环8次,完成一字节交换

打赏

参与人数 1家元 +20 收起 理由
家睦 + 20

查看全部打赏

发表于 2021-3-15 12:36:03 | 显示全部楼层
硬件SPI+DMA, 必要时加中断,飞起的感觉
回复 支持 反对

使用道具 举报

发表于 2021-3-16 14:28:30 | 显示全部楼层
inthsunshine 发表于 2021-3-15 12:36
硬件SPI+DMA, 必要时加中断,飞起的感觉

大婶说说什么时候是 “必要时”    中断加在哪里

最好是贴些代码给讲解下 :handshake:
回复 支持 反对

使用道具 举报

发表于 2021-3-17 09:35:25 | 显示全部楼层
茶壹杯 发表于 2021-3-16 14:28
大婶说说什么时候是 “必要时”    中断加在哪里

最好是贴些代码给讲解下  ...

有兴趣自己研究一下,不难,看起来你目前还没必要用上:titter:
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册 微信登录

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2025-8-27 08:12 , Processed in 0.171600 second(s), 14 queries , Redis On.

Powered by Discuz!

© 2006-2025 MyDigit.Net

快速回复 返回顶部 返回列表