一、SPI概念
1.SPI总线是Motorola首先提出的全双工三线/四线同步串行总线
2.采用主从模式(MasterSlave)架构;支持多slave模式应用
3.一般仅支持单Master,多从机
4.时钟由Master控制,在时钟移位脉冲下,数据按位传输,高位在前,低位在后(MSB first)
5.SPI接口有2根单向数据线,为全双工通信,目前应用中的数据速率可达几Mbps的水平
6.SPI总线被广泛地使用在FLASH、ADC、LCD等设备与MCU间,要求通讯速率较高的场合
7.本次实验:SOC<----SPI---->数码管
二、SPI硬件连接
1.SPI接口共有4根信号线,
分别是:设备选择线(片选线):NSS nsc
时钟线:SCK CLK
串行输出数据线:MOSI
串行输入数据线:MISO
M:master主机 O:output输出 S:slave从机 I:input输入
2.作用:
• (1)MOSI:主器件数据输出,从器件数据输入
• (2)MISO:主器件数据输入,从器件数据输出
• (3)SCLK :时钟信号,由主器件产生
• (4)/SS:从器件使能信号,由主器件控制(片选)
2.1 四线制
2.2 三线制
三、SPI总线通信协议
四、SPI总线通信模式
五、IIC总线和SPI总线对比总结
IIC总线和SPI总线对比:
1.相同点
1>采用串行、同步总线
2>都采用的是TTL电平,传输的距离和使用场景类似
3>都采用主从模式
2.不同点:
1>IIC总线是半双工,SPI总线是全双工
2>IIC总线有应答机制,SPI总线无应答机制
3>IIC总线通过从机地址选择和哪一个从机进行通信,SPI总线通过片选线选择和哪一个从机进行通信
4>SPI总线如果有10个硬件设备,那就需要有10个片选线,比较浪费硬件资源
5>IIC总线通信协议是通过SCL高低电平决定读写,SPI总线通过时钟极性和时钟相位决定读写
6>IIC总线是高低电平进行数据传输,SPI总线是边沿触发,边沿采样
六、电路图
七、分析芯片手册
7.1 芯片框图
7.2 引脚描述
7.3 工作原理
7.4 真值表
主函数:
#include "spi.h"
extern void printf(const char *fmt, ...);
void delay_ms(unsigned int ms)
{
int i, j;
for (i = 0; i < ms; i++)
for (j = 0; j < 1800; j++)
;
}
extern char buffer[LEN];
unsigned char num[10] = {0xFC, 0x60, 0xDA, 0xF2, 0x66, 0xB6, 0xBE, 0xE0, 0xFE, 0xF6};
int main()
{
unsigned int i;
si7006_init();
SPI_init();
while(1)
{
//让4位数码管都同时显示0-9,每隔1s中切换一次
for (i = 0; i < 10; i++)
{
// 先发送数码管的位,在发送数码管的段
SPI_write(0xF0); // 发送数码管的位
SPI_write(num[i]); // 发送数码管的段
// 将移位寄存器中的数据存到索存寄存器中,让片选线产生一个上升沿
NSS_OUTPUT_L();
delay_ms(1);
NSS_OUTPUT_H();
delay_ms(1000); // 1s切换一次显示的数据
}
#endif
}
return 0;
}
SPI.C:
#include "spi.h"
// 通过GPIO引脚模拟SPI总线的通信协议
/* SPI4_NSS ----> PE11
* SPI4_SCK ----> PE12
* SPI4_MOSI ----> PE14
* SPI4_MISO ----> PE13
* */
/* 数码管的编码,不带小数点, 先发送低位,在发送高位
* A B C D E F G DP
* 1 1 1 1 1 1 0 0 0xFC 0
* 0 1 1 0 0 0 0 0 0x60 1
* 1 1 0 1 1 0 1 0 0xDA 2
* 1 1 1 1 0 0 1 0 0xF2 3
* 0 1 1 0 0 1 1 0 0x66 4
* 1 0 1 1 0 1 1 0 0xB6 5
* 1 0 1 1 1 1 1 0 0xBE 6
* 1 1 1 0 0 0 0 0 0xE0 7
* 1 1 1 1 1 1 1 0 0xFE 8
* 1 1 1 1 0 1 1 0 0xF6 9
* 0 0 0 1 1 0 1 0 0x1A
*
* 如果需要显示小数点,需要在以上数据的基础之上加1即可
* */
void delay_us1(unsigned int us)
{
int i,j;
for(i = 0; i < us;i++)
for (j = 0; j < 1;j++);
}
void SPI_init(void)
{
RCC->MP_AHB4ENSETR |= (0x1 << 4);
// MOSI PE14
GPIOE->MODER &= (~(0x3 << 28));
GPIOE->MODER |= (0x1 << 28);
GPIOE->OTYPER &= (~(0x1 << 14));
GPIOE->OSPEEDR &= (~(0x3 << 28));
// GPIOE->OSPEEDR |= (0x2 << 28);
GPIOE->PUPDR &= (~(0x3 << 28));
// MISO PE13
GPIOE->MODER &= (~(0x3 << 26));
GPIOE->OSPEEDR &= (~(0x3 << 26));
// GPIOE->OSPEEDR |= (0x2 << 26);
GPIOE->PUPDR &= (~(0x3 << 26));
// SCK PE12
GPIOE->MODER &= (~(0x3 << 24));
GPIOE->MODER |= (0x1 << 24);
GPIOE->OTYPER &= (~(0x1 << 12));
GPIOE->OSPEEDR &= (~(0x3 << 24));
// GPIOE->OSPEEDR |= (0x2 << 24);
GPIOE->PUPDR &= (~(0x3 << 24));
// NSS PE11
GPIOE->MODER &= (~(0x3 << 22));
GPIOE->MODER |= (0x1 << 22);
GPIOE->OTYPER &= (~(0x1 << 11));
GPIOE->OSPEEDR &= (~(0x3 << 22));
// GPIOE->OSPEEDR |= (0x2 << 22);
GPIOE->PUPDR &= (~(0x3 << 22));
NSS_OUTPUT_L(); // 595芯片的锁存引脚拉低
SCK_OUTPUT_L(); // SPI的时钟线拉低
}
void SPI_write(unsigned char dat)
{
unsigned char i;
for(i = 0; i < 8; i++)
{
if(dat & 0x01) // 由于数码管的编码格式,因此需要先发低位,再发高位。
{
MOSI_OUTPUT_H(); // MOSI线写高
} else {
MOSI_OUTPUT_L(); // MOSI线写低
}
dat >>= 1;
// 时钟线从低电平到高电平的变化时,MOSI数据线上的数据
// 被写到595芯片的移位寄存器中
SCK_OUTPUT_L(); // SCK拉低
delay_us1(10);
SCK_OUTPUT_H(); // SCK拉高
delay_us1(10);
}
//NSS_OUTPUT_L();
//NSS_OUTPUT_H();
}
SPI.h:
#ifndef __SPI_H__
#define __SPI_H__
#include "stm32mp1xx_gpio.h"
#include "stm32mp1xx_rcc.h"
// MOSI对应的引脚输出高低电平的信号
#define MOSI_OUTPUT_H() do{GPIOE->ODR |= (0x1 << 14);}while(0)
#define MOSI_OUTPUT_L() do{GPIOE->ODR &= (~(0x1 << 14));}while(0)
// 对应595芯片的锁存引脚输出高低电平
#define NSS_OUTPUT_H() do{GPIOE->ODR |= (0x1 << 11);}while(0)
#define NSS_OUTPUT_L() do{GPIOE->ODR &= (~(0x1 << 11));}while(0)
// 时钟信号对应的引脚输出高低电平
#define SCK_OUTPUT_H() do{GPIOE->ODR |= (0x1 << 12);}while(0)
#define SCK_OUTPUT_L() do{GPIOE->ODR &= (~(0x1 << 12));}while(0)
/*
* 函数功能: SPI初始化函数,推挽输出,高速,禁止上拉和下拉
* 函数参数:无
* 函数返回值:无
*/
void SPI_init(void);
/*
* 函数功能:SPI发送数据的函数
* 函数参数:dat : 要发送的数据
* 函数返回值:无
*
*/
void SPI_write(unsigned char dat);
#endif // __SPI_H__