SPI总线通信——基于STM32MP157A

SPI总线概念

        SPI总线是Motorola首先提出的全双工三线/四线同步串行总线,采用主从模式(Master Slave)架构;支持多从机(slave)模式应用,一般仅支持单主机,多从机。

        时钟由主机控制,在时钟移位脉冲下,数据按位传输,高位在前,低位在后(MSB first)

        SPI接口有2根单向数据线,为全双工 通信,目前应用中的数据速率可达几Mbps的水平,所以,SPI总线被广泛地使用在FLASH、ADC、LCD等设备与MCU间,要求通讯速率较高的场合。

SPI硬件连接

1.SPI接口共有4根信号线,

        分别是:设备选择线(片选线):NSS nsc

                       时钟线:SCK CLK 串行输出数据线:MOSI

                       串行输入数据线:MISO

                       M:master主机 O:output输出 S:slave从机 I:input输入

2.作用:

• (1)MOSI:主器件数据输出,从器件数据输入(M out S in)

• (2)MISO:主器件数据输入,从器件数据输出(M in S out)

• (3)SCLK :时钟信号,由主器件产生

• (4)/SS:从器件使能信号,由主器件控制(片选)

 

 三线制

四线制

通信协议

起始信号: NSS信号由高到低

结束信号:NSS信号由低变高

数据传输:SPI使用MOSI及MISO信号线来传输数据,使用SCK信号线同步数据。MOSI以及

                  MISO数据线在SCK每一个时钟周期内传输一位数据,且数据输入输出是同时进行

                  的。SPI每次数据传输可以8或16位为单位,每次传输的单位数不受限制。

 通信模式

         在SPI操作中,最重要的两项设置是时钟极性(CPOL)以及时钟相位(CPHA)。这两项是主从设备间数据采样的约定方式。

• 时钟极性CPOL:设置时钟空闲时的电平

        当CPOL = 0时,SCK引脚在空闲状态保持低电平

        当CPOL = 1时,SCK引脚在空闲状态保持高电平

• 时钟相位CPHA:设置数据采样时的时钟沿

        当CPHA = 0时,MOSI或MISO数据线上的信号将会在SCK时钟线的奇数边沿被采样

        当CPHA = 1时,MOSI或MISO数据线上的信号将会在SCK时钟线的偶数边沿被采样

 相对应的,在CPOL和CPHA的变化组合中,诞生了2×2种通信模式

通信模式

 

SPI模式CPOLCPHA空闲时SCK时钟采样时刻
0(00)00低电平奇数边沿
1(01)01低电平偶数边沿
2(10)11高电平奇数边沿
3(11)10高电平偶数边沿

分析电路

 

由此可知:

是GPIO章节 

* SPI4_NSS     ---->   PE11
 * SPI4_SCK     ---->   PE12
 * SPI4_MOSI    ---->   PE14
 * SPI4_MISO    ---->   PE13

数码管驱动原理

 

一个a~g分别控制一根数码管的亮灭字母组合控制数码管亮起,比如,数字2,就是abged。将它们转化为二进制,即使我们需要按位调整的代码。

分析芯片手册

翻看芯片手册《M74HC595》

引脚描述

 工作原理

 

 数码管真值表

《STM32MP157-datasheet》的GPIO章节

首先需要RCC给GPIOE使能

这个是RCC章节的

 

其次设置成通用输出模式

 然后设置成推挽输出模式

接着再是低速模式

 最后设置为禁止上下拉

代码实现

数码管数字对应值,最终的结果为:四个数码管会同时从0~9循环

/* 数码管的编码, 先发送低位,再发送高位
 * 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
 * */

头文件

#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__

先根据GPIO章节的分析,写好初始化部分

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();

}

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老K殿下

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值