51模拟SPI


# 代码

有一些朋友可能需要代码,而不是看我砍大山,先放上完整版的代码。注意 代码是 SPI在方式0,数据在上升沿采样,下降沿发送。
提示:以下是本篇文章正文内容,下面案例仅供参考

#include "reg51.h"

sbit _NSS  =  P2^0;
sbit _SCK  =  P2^1;
sbit _MISO =  P2^2;
sbit _MOSI =  P2^3;

#define 	NSS(STA)   if(STA) _NSS  = 1; else  _NSS  = 0
#define 	SCK(STA)   if(STA) _SCK  = 1; else  _SCK  = 0
#define 	MOSI(STA)  if(STA) _MOSI = 1; else  _MOSI = 0
#define 	READ_MISO  _MOSI
											 
unsigned char i;

//发送数据,默认CPHA = CPOL = 0 大端模式,高位先行,一次发送八位 ,返回读取到的数据  
unsigned char SP_SendData(unsigned char dat)
{
	unsigned char reveDat = 0;
	NSS(0);
	SCK(0);
	for(i = 0; i < 8; i++)
	{			
		  if(dat&0x80) MOSI(1);
		  else         MOSI(0);	
	     SCK(1);    //SPI模式0,下降沿数据发送
	     SCK(0);
		 dat <<= 1;
	}
  	for(i = 0; i < 8; i++)
	{
				SCK(0);
				SCK(1);
				reveDat |= READ_MISO ;
			    reveDat <<= 1;
	}
	NSS(1);
	return reveDat;
}
//数据接收只要发送数据0x00就可以接收到数据了
首先

1、我们的51单片机并没有内置SPI内部外设,所以我们的一切数据的传输需要通过IO口模拟来实现

2、在代码还没开始之前的时候我们需要一点点的SPI通信的基础,知道SPI的基本工作原理和它的时序,只要这两点就足够了(也没其他的了)。

3、SPI的基本工作原理,SPI最初由摩托罗拉公司研发并且流传开来的,关于SPI的历史基本在网上都能搜索得到,这里不再赘述,首先从它按照OSI分层讲,它处于第二层-数据链路层,规定了数据传输的逻辑规则,在物理层它有四个引脚,分别为

引脚功能
NSS从设备选择
MISO主设备输入,从设备输出
MOSI主设备输出,从设备输入
SCK同步时钟

注意的是:我们的SPI传输最少可以只用两线便可以传输数据,如果只有一个从设备可省略NSS(接地),如果对方是显示设备,我们还可以省略掉MISO,当然省略NSS前提是主设备和从设备共地才行。

SPI有主设备模式和从设模式,当然了我们的MCU一般选择为主设备。而我们的其他通信外设默认为从设备,这在我们的开发基本是这样,MISO意思只有一个,那就是我们的主设备输入我们从设备输出,方向是相对的MOSI的意思也是一样,然后是我们的NSS,在我们的协议中非常常见,用来表示我们当前表示的是哪一个设备(反过来讲我们的从设备在当只有NSS为低电平的时候才去接收数据)在我们的多设备通信的时候有用的 ,然后是我们的数据传输的时钟。要通过数据的同步。设备在工作中必须要有一个是主设备。
接下来我们来聊聊SPI的基本通信原理,通信的时序,于OSI第二层-数据链路层。在讲这些之前先解决一个问题,那就是我我们的数据上升沿的问题,按照我们数据发送和接收上升沿和第一二个脉冲,我们的SPI模式可以有四种模式。
CPOL:用来表示SCK的有效状态,为1表示SCK高电平为空闲状态,有效状态就是低电平。
CPHA:为0表示在第一个边沿采样,为1则是数据在第二个边沿采样。

方式状态
方式0CPOL = 0 CPHA = 0
方式1CPOL = 0 CPHA = 1
方式2CPOL = 1 CPHA = 0
方式3CPOL = 1 CPHA = 1

例如:SPI工 作在方式0:那么SCK的空闲状态是低电平,数据采样在第一个边沿,也就是上升沿,而数据的发送则是在下降沿。
注意理解,这里上升沿和下降沿只是相对的,会随着SCK的空闲状态不同而不同,说白了也就是方式不同。
还有一点就是我们的SCK只能由主设备来产生,还有NSS,所以都应该配置为输出

SPI内部原理图:
SPI内部原理图
SSPSR 是SPI的内部移位寄存器,他的主要工作是在SCK发生变化的时候,往SSPBUF里面移入或者移出数据,每次移动数据的大小由Bus-Width和Channel-Width决定。

该图是我们SPI收发数据的时序图,在我们后面也会提到,通过我们代码,并且在Proteus软件仿真中实现。

介绍完了SPI的理论,我们可以就可用代码来实现了,新建一个工程。
4、新建工程,工程目录结构下


一、程序编写

工程目录结构如下
在这里插入图片描述

所有的硬件声明,如下:

sbit _NSS  =  P2^0;
sbit _SCK  =  P2^1;
sbit _MISO =  P2^2;
sbit _MOSI =  P2^3;

sbit kl =  P1^7;

kl是我们做测试,为了方便捕捉SPI时序定义的一个按键控制,按键按下发送交换一次数据。CPHA和CPOL,通信的时候主从机的CPHA和CPOL必须一致。否则数据会发生错误。

#define 	NSS(STA)   if(STA) _NSS  = 1; else  _NSS  = 0
#define 	SCK(STA)   if(STA) _SCK  = 1; else  _SCK  = 0
#define 	MOSI(STA)  if(STA) _MOSI = 1; else  _MOSI = 0
#define 	READ_MISO  _MOSI

为什么要写成这样,有原因的,方便代码移植,给读者看32的IO控制一般写法就明白了

#define MOUDLE_RST(uo)  if(uo) __PORT_A -> BSRR   = _nRST_GPIO_Pin;     \
											 else    __PORT_A -> BRR   = _nRST_GPIO_Pin;   
											
#define MOUDLE_CS(uo)  if(uo)  __PORT_A -> BSRR   = _CS_GPIO_Pin;     \
											 else    __PORT_A -> BRR   = _CS_GPIO_Pin;

下面我们继续来看代码实现,在51中模拟SPI:
收发代码如下(示例):

//发送数据,默认CPHA = CPOL = 0 大端模式,高位先行,一次发送八位 ,返回读取到的数据  
unsigned char SP_SendData(unsigned char dat)
{
	unsigned char reveDat = 0;
	
	NSS(0);
	SCK(0);
		
	for(i = 0; i < 8; i++)
	{			
			if(dat&0x80) MOSI(1);
		  else         MOSI(0);	
	   SCK(1);
	   SCK(0);
		 dat <<= 1;
	}
	for(i = 0; i < 8; i++)
	{
				SCK(0);
				SCK(1);
				reveDat |= READ_MISO ;
			reveDat <<= 1;
	}
	NSS(1);
	return reveDat;
}
unsigned char SP_ReveData()
{
	return SP_SendData(0x00);
}

首先初始化SPI的工作模式,其实就是赋值CPHA和CPOL,CPOL表示我们始终在空闲的时候的状态,本来是想好的,但是后面没用上,具体是不能传递变量到宏定义,有解决办法,也很简单,后期实现。还有一个注意的地方是我们的发送模式高位在前,用 &0x80来得到最高位,在发送完之后左移一位,下次发送次高位。还有一点十分重要的是,我们51没有硬件SPI支持的Buff 所以可以看到我发送了一位马上有读取一位,如果从机也是模拟SPI的话,我这样做没有错,但是一般支持SPI的会把待发送数据预备到SPI的缓冲区中,等待我们发送完八位数据之后的读取数据时钟,其实我在写的时候也考虑到这些,后来想通了,基本支持SPI的都是硬件SPI所以不需要担心,我们只需要关注从机SPI模式就行了。

二、仿真结果

实验仿真结果:
在这里插入图片描述
发送0xA5,收到0xFF,第二个是我读到的数据,因为是一个模拟仿真器,他没有发送过数据,所以读到都是高电平为0xFF,时序不是很标准,但也能说明问题,好的 我们继续。

void main()
{
	my_TFTInit();	
	while(1)
	{
		Lcd_Clear(BLUE);
		Lcd_Clear(YELLOW);
   //	showImage();
	}
}

初始化SPI、初始化TFT,然后在while循环中不断的黄蓝刷屏,现象如下:
SPI的TFT测试效果图

现象:证明我们写的SPI通信代码是没有问题的。但是我在实际使用的过程中,发现了一个问题,51的刷新的速度很慢了,肉眼可见的速度在不停的替换每一个像素的颜颜色,大概刷新一屏的时间是半分钟到一分钟左右。
TFT屏是240*320的屏幕。所以我们万不得已不要去刷新整个屏幕。

好的,本篇博文就到这里,如果你有什么问题、疑问,欢迎在下方评论区留言讨论哦。

  • 13
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
51单片机是一种常用的单片机芯片,具有广泛的应用场景。要配置51单片机模拟SPI(Serial Peripheral Interface)接口,首先需要了解SPI工作原理和配置方法。 SPI是一种基于主从设备之间的全双工通信协议。在配置51单片机模拟SPI接口时,需要设置主从设备的角色、时钟频率、数据位宽、数据传输模式等参数。 首先,设置主从设备的角色。在51单片机中,可以将其中一个IO口配置为片选(SS)引脚,用来区分主从设备。当片选引脚为低电平时,为从设备;当片选引脚为高电平时,为主设备。 其次,设置时钟频率。在51单片机中,可以通过配置时钟模式(CPOL和CPHA)来确定时钟的工作方式。CPOL用于设置时钟的空闲电平,CPHA用于设置时钟的上升沿或下降沿为数据采样边沿。根据具体需要,可以选择合适的时钟模式。 然后,设置数据位宽。在51单片机中,可以通过设置数据寄存器的位宽来确定每次数据传输的位数。一般情况下,常用的位宽为8位,但也可以根据实际需求进行调整。 最后,设置数据传输模式。在51单片机中,可以通过配置工作模式(主模式或从模式)来确定数据传输的方式。在主模式下,可以通过控制时钟引脚和数据引脚来进行数据传输;在从模式下,可以通过配置中断或轮询的方式接收主设备的指令。 综上所述,配置51单片机模拟SPI接口需要设置主从设备的角色、时钟频率、数据位宽、数据传输模式等参数。通过合理配置这些参数,可以实现51单片机与其他设备之间的数据交互。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值