其实各种协议是很重要的,这篇文章就当做我对spi协议的一个整理吧。

必要的spi简介:

https://www.cnblogs.com/zengsf/p/7221207.html?utm_source=itdadao&utm_medium=referral

前几天在网上看到一段关于oled的程序

不过那段程序是用的io口模拟spi来控制oled模块的

我在想stm32本身就有spi为何要用io口来模拟spi协议呢

所以就想自己试着写一写。

首先第一部分是关于stm32的spi引脚:

http://www.eeworld.com.cn/mcu/2015/0615/article_20333.html

SPI1->CS      ------ PA4

SPI1->CLK    ------ PA5 
SPI1->MISO  ------ PA6
SPI1->MOSI  ------ PA7

SPI2->CS      ------ PB12
SPI2->CLK    ------ PB13 
SPI2->MISO  ------ PB14 
SPI2->MOSI  ------ PB15

SPI3->CS      ------ PA15  
SPI3->CLK    ------ PB3 
SPI3->MISO  ------ PB4 
SPI3->MOSI  ------ PB5

对于SPI ,需要打开相关RCC时钟
主模式下
CLK 配置成复用推挽输出
MOSI 配置成复用推挽输出
MISO 配置成富哦那个或带上拉输入
CS若采用硬件则配置成推挽输出,若采用软件模式,则采用普通IO推挽输出即可。

 
根据上面的提示,不如我们就选用spi1吧
http://blog.sina.com.cn/s/blog_66513d610102wv3p.html
知道了引脚,然后我们开始用库函数去配置spi:
spi1的SCLK,MISO,MOSI分别是PA5,PA6,PA7引脚,这几个引脚配置成GPIO_Mode_AF_PP即复用推挽输出。
如果是单主单从,CS引脚可以不配置,都设置成软件模式即可。

引脚配置好了,我们下面进行spi模式的配置。下面的图片仅供参考,具体问题还需具体分析。spi的极性和相位为4中,我们还需要根据实际情况去查看。

配置好了之后,我们就开始写应用了,也就是收发函数,收发函数把数据通过配置好的底层发出去。

对于应用函数,我们应该设置好形参,形参主要是用来保存协议来往的数据的。

这个协议的收发函数有两种(因为这个协议是双工的):读写分开的函数,读写一起的。

读写分开的函数:

void SPI_Ecah_Buffer_Send(u8* pBuffer, u16 NumByteToRead) //发送

{

for(int i = 0; i < NumByteToRead; i++)

{

SPI_Conmunication_SendByte(*pBuffer);

pBuffer++;

}

}

void SPI_Buffer_Receive(u8* pBuffer, u16 NumByteToRead) //接收

{

while (NumByteToRead--)

{

*pBuffer = SPI_Conmunication_SendByte (Dummy_Byte);

pBuffer++;

}

}

 
 
还有一种是读写一体的

void SPI_Ecah_Buffer_Send(u8* str , u8* pBuffer, u16 NumByteToRead)

{

for(int i = 0; i < NumByteToRead; i++)

{

*str = SPI_Conmunication_SendByte(*pBuffer);

pBuffer++;

str++;

}

}

 
 
好了到了这里之后,我们基本上已经把所有的框架写好了,来整理一下用到的库函数
这些函数都是stm32的库里给我的API接口,我们配置好底层之后,就可以用这些函数去编写自己的应用了。
SPI_Cmd(SPI2,ENABLE);//使能SPI外设
void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data); //发送数据函数
uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx) ;//接收数据函数
SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE);//判断数据是否传输完成
 
 
之后我们应该在上面的框架里补充和修正一些细节。
 我们最终的目的还是想让stm32的spi驱动oled,关于oled的细节
https://www.cnblogs.com/wp2312139418/p/5988713.html
上面文章真的很详细。
 

OLED引脚介绍: 这个是oled模块上的几个引脚。我们要把它和spi对应起来。

CS:OLED片选信号

RST:OLED复位端口

DC: 命令/数据选择端口(0:读写命令, 1: 读写数据)

SCLK(D0):串口时钟线

SDIN(D1): 串口数据线

 
 
stm32与OLED屏接口的引脚介绍:

CS————GPIOD3;    spi的片选

RST————GPIOD4;    复位(spi里没有)

DC—————GPIOD5;   表示写数据还是命令。(spi里没有)

D0——————GPIOD6; spi时钟线

D1——————GPIOD7;   spi MOSI,代表oled从这里接收数据,假设单片机是主机,oled屏是从机。

上面接线,蓝色是我推出来的。
 
我们先分析一下上面网友的模拟spi的程序:
不知道为什么,我写到这里的时候,脑子里竟然是老师讲课时的情景,
告诉我,spi有四种模式。我们可以从下面的程序中发现oled适用于哪一种模式。
 
/*    SPI写数据/命令
 *    Mode :O:写命令   1:写数据
 *    data :数据/命令
 *
*/
void SPI_Write(char data, int Mode)
{    
    int i = 0;
    if(Mode)                   //这个是用来区分命令,还是数据的。
    {
        OLED_DC(1);        //DC引脚输入高,表示写数据
    }
    else
    {
        OLED_DC(0);        //DC引脚输入低,表示写命令
    }
    OLED_CS(0);            //CS引脚输入低,片选使能   这里符合spi协议,低电平是选中。
    for(i = 0; i < 8; i++)     //从这句话,我们能判断出,这个spi协议是,8位的, spi分为8帧和16帧
    {
        OLED_D0(0);        //D0引脚输入低
        if(data & 0x80)      //判断传输的数据最高位为1还是0   从这里判断是先传输高位, spi协议有先传高位或先传低位。
        {
            OLED_D1(1);    //D1引脚输入高 
        }
        else
        {
            OLED_D1(0);    //D1引脚输入低
        }
        OLED_D0(1);        //D1引脚输入高    //先准备好数据,然后在让时钟有一个上升沿,也就是上升沿的时候读取数据。
        data <<= 1;        //将数据左移一位
    }
    OLED_DC(0);            //DC引脚输入低
    OLED_CS(1);            //CS引脚输入高,片选失能,  //这个可能是为了防止干扰,
}
 
所以呢。我们要把io口改一下:
 
 OLED屏与stm32接口的引脚介绍:

CS————GPIOD3;    spi的片选

RST————GPIOD4;    复位(spi里没有)

DC—————GPIOD5;   表示写数据还是命令。(spi里没有)

D0——————GPIOD6; spi时钟线

D1——————GPIOD7;   spi MOSI,代表oled从这里接收数据,假设单片机是主机,oled屏是从机。

 
 把上面的一层关系,修改成下面这样:
单片机                        -----oled屏幕

SPI1->CS      ------ PA4----CS

SPI1->CLK    ------ PA5 ----D0
SPI1->MISO  ------ PA6-----D1

SPI1->MOSI  ------ PA7

                             PB1-----RST
                             PB2-----DC
 
 之后,就是spi配置的修正:
也就是上面提到的这个图片:

第一个是全双工,其实没有必要,因为oled屏好像不会返回数据给stm32

第二行是从机,我感觉单片机应该还是主机的好

第三个8帧,这个应该不用改

第四个,这个应该也是低电平,空闲时刻D0 ,,,,,,候选项:SPI_CPOL_High(=1)和SPI_CPOL_Low ( =0)

第五个,感觉应该是第一个跳变沿被采集,,,,,,, 候选项:SPI_CPHA_1Edge (=0) 和SPI_CPHA_2Edge(=1)

第六个,cs片选引脚为软件模式

第七个, 这个是波特率,分频为8,可以但是这个时钟默认应该是36M的。

第八个,这个的确是先传高字节

第九个,这个是CRC校验,实际上是这个赋值是7是没有意义的,至于为什么?

https://blog.csdn.net/kobesdu/article/details/50972273

SPI_CRCPolynomial :这是 SPI 的 CRC 校验中的多项式,若我们使用 CRC 校验
时,就使用这个成员的参数(多项式)来计算 CRC 的值。由于本实验的 Flash 不支持 CRC
校验,所以我们向这个结构体成员赋值为7 实际上是没有意义的。
配置完这些结构体成员后,我们要调用SPI_Init() 函数把这些参数写入寄存器中,实现
SPI 的初始化,然后调用

 
 之后我们把引脚线改一下,然后把spi配置改一下,
然后程序要改
void SPI_Write(char data, int Mode) ,这个函数我们就不再用了。
然后需要重新写一个,用SPI_Conmunication_SendByte(*pBuffer);
这个库函数写一个,按照oled的操作规则写一个应用函数,看来是协议
包含着协议呀,
 
这个我晚上回去测试一下,看看能不能用。
不过改来改去似乎没有觉得有多么简单,也许调用库函数对于移植和后期的维护是很方便的吧。
 
改一下函数:
/*    SPI写数据/命令
 *    Mode :O:写命令   1:写数据
 *    data :数据/命令
 *
*/
void SPI_Write(char data, int Mode)
{    
    int i = 0;
    if(Mode)                   //这个是用来区分命令,还是数据的。
    {
        OLED_DC(1);        //DC引脚输入高,表示写数据
    }
    else
    {
        OLED_DC(0);        //DC引脚输入低,表示写命令
    }
    OLED_CS(0);            //CS引脚输入低,片选使能   这里符合spi协议,低电平是选中。
   SPI_Conmunication_SendByte(data);  //这个是协议部分,不知道这样可以不可以。
    OLED_DC(0);            //DC引脚输入低
    OLED_CS(1);            //CS引脚输入高,片选失能,  //这个可能是为了防止干扰,
}
 
 
先整理一下网友的程序。
然后把我的程序改进去试一下。
 
见我的另一篇博客:oled的一套stm32实验。

oled stm32的spi的更多相关文章

  1. STM32 F4 SPI Accelerometer

    STM32 F4 SPI Accelerometer

  2. STM32的SPI口的DMA读写[原创www.cnblogs.com/helesheng]

    SPI是我最常用的接口之一,连接管脚仅为4根:在常见的芯片间通信方式中,速度远优于UART.I2C等其他接口.STM32的SPI口的同步时钟最快可到PCLK的二分之一,单个字节或字的通信时间都在us以 ...

  3. FPGA作为从机与STM32进行SPI协议通信---Verilog实现 [转]

    一.SPI协议简要介绍 SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口.SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用 ...

  4. STM32的SPI问题。

    问题描述: 之前一直使用的单片机是LPC2109,对其SPI很熟悉.基本就是原本拿来稍作修改就用.由于某种原因需要使用STM32,然后设备的驱动是之前写好的,只修改了一些硬件控制端口,由于硬件驱动使用 ...

  5. stm32之SPI通信协议

    SPI (Serial Peripheral interface),顾名思义就是串行外围设备接口.SPI是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为P ...

  6. FPGA作为从机与STM32进行SPI协议通信---Verilog实现

    一.SPI协议简要介绍 SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口.SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用 ...

  7. STM32之spi管理模式

    1)sip管理模式分为:硬件管理和软件管理:主要由NSS .SSI.SSM决定: NSS是芯片上一个实实在在的引脚,SSI和SSM是SPI_CR1控制器里的的位. 值得注意的是:NSS分外部引脚和内部 ...

  8. STM32 HAL SPI读取MPU6500的设备ID异常

    1.问题背景 近前,使用STM32F4 HAL库的SPI读取MPU6500出现异常. 现象:读取ID失败,返回0,以为硬件焊接问题,各种排查,最后为了示波器测试方便,把读取ID的函数放到While(1 ...

  9. STM32之SPI时钟相位选择

    SPI的时钟模式分为四种,由SPI_CR1寄存器的两位CPOL,CPHA组合选择. CPOL 如果为1,则时钟的空闲电平为高电平:CPOL 如果为0,则时钟的空闲电平为低电平.空闲电平影响不大. CP ...

随机推荐

  1. jquery正则匹配URL地址

    JQuery代码: var regexp = /((http|ftp|https|file):\/\/([\w\-]+\.)+[\w\-]+(\/[\w\u4e00-\u9fa5\-\.\/?\@\% ...

  2. SQL char字段类型排序

    我是做的ACCESS时候需要对字段的值进行排序,字段格式是char类型的,但是存的值是数字.现在需要对该字段进行排序. 通过查找,找到以下两种方法,记录下来. 1. 你可以转换成int型再排序 sel ...

  3. 【原生JS组件】javascript 运动框架

    大家都知道JQuerry有animate方法来给DOM元素进行运动,CSS3中也有transition.transform来进行运动.而使用原生的Javascript来控制元素运动,须要写非常多运动的 ...

  4. 使用PHP来压缩CSS文件

    这里将介绍使用PHP以一种简便的方式来压缩你的CSS文件.这种方法不需要命名你的.css文件和.php文件. 当前有许多方法需要将.css文件重命名成.php文件,然后在所有PHP文件中放置压缩代码. ...

  5. 智课雅思词汇---三、aud和auto和bene是什么意思

    智课雅思词汇---三.aud和auto和bene是什么意思 一.总结 一句话总结:aud:听 auto:自己,self bene:good,well 1.anthropo是什么意思? anthropo ...

  6. 3.Maven之(三)Maven插件

    转自:https://yq.aliyun.com/ziliao/312162 Maven本质上是一个插件框架,它的核心并不执行任何具体的构建任务,所有这些任务都交给插件来完成,像编译是通过maven- ...

  7. js对数组进行操作

    1.数组的创建 var arrayObj = new Array(); //创建一个数组 var arrayObj = new Array([size]); //创建一个数组并指定长度,注意不是上限, ...

  8. 120.VS调试技巧

    设置断点调试 在一行代码的左侧点击即可设置断点,按F5(调试->开始调试)即可运行到第一个端点处暂停 逐语句调试 按F11(调试->逐语句)即可开始一步一步执行 逐过程调试 按F10(调试 ...

  9. 62.C++文件操作list实现内存检索,实现两千万数据秒查

    1 #include <iostream> #include <fstream> #include <cstdlib> #include <string> ...

  10. Ubuntu下SVN服务器安装和配置

    一.SVN安装1.安装包$ sudo apt-get install subversion 2.添加svn管理用户及subversion组#添加用户$ sudo adduser  svnuser#添加 ...