第六章:SPI通信(3线制)(4线制)

1.SPI总线简介

  SPI(serial peripheral interface,串行外围设备接口)总线技术是Motorola公司推出的一种同步串行接口。它用于CPU与各种外围器件进行全双工、同步串行通讯。、

        四条线就可以完成MCU与各种外围器件的通讯,这四条线是:串行时钟线(CSK)、主机输入/从机输出数据线(MISO)、主机输出/从机输入数据线(MOSI)、低电平有效从机选择线CS。

 

例程:DS1302实时时钟

第六章:SPI通信(3线制)(4线制)_第1张图片

    static void Ds1302WriteReg(u8 addr, u8 dat)

/*********************************************************************
* 函 数 名       : Ds1302WriteReg
* 函数功能		 : 向DS1302中地址为addr的寄存器写入数值dat
* 参数列表       : addr - 待写入数值的寄存器地址
				   dat  - 待写入addr寄存器的数值
* 函数输出    	 : 无
*********************************************************************/
static void Ds1302WriteReg(u8 addr, u8 dat)
{
	u8 i = 0;

	CE = 0;
	_nop_();				// 空指令,延时

	SCLK = 0;				// 先将SCLK置低电平
	_nop_();

	CE = 1; 				// CE拉高以使能对DS1302的读写权限
	_nop_();

	for (i=0; i<8; i++)		// 循环逐位发送addr的8个bit,注意低位在前
	{
		DSIO = addr & 0x01;	// 数据从LSB低位开始传送
		addr >>= 1;			// 发完后addr右移一位原来的次低位变成新的低位

		SCLK = 1;			// 拉高SCLK制造一个上升沿,通知DS1302读取数据
		_nop_();			// 延时等待DS1302读取DSIO线上的1位数据

		SCLK = 0;			// 读完后,拉低SCLK为下一个位的传输做准备
		_nop_();
	}
							// 循环结束后1字节的寄存器地址传给DS1302
	for (i=0; i<8; i++)		// 循环写入8位数据,注意低位在前
	{
		DSIO = dat & 0x01;
		dat >>= 1;
		SCLK = 1;			//制造上升沿通知DS1302读取数据
		_nop_();
		SCLK = 0;
		_nop_();	
	}	   					// 循环结束后1字节值成功传给DS1302
		 
	CE = 0;					// 写入完毕拉低CE以禁止对DS1302的读写,防止意外改写事故
	_nop_();
}

 

static u8 Ds1302ReadReg(u8 addr)

第六章:SPI通信(3线制)(4线制)_第2张图片

/*********************************************************************
* 函 数 名       : Ds1302ReadReg
* 函数功能		 : 向DS1302中地址为addr的寄存器写入数值dat
* 参数列表       : addr - 待读出的寄存器的地址
* 函数输出    	 : 读出的寄存器addr的数值
*********************************************************************/
static u8 Ds1302ReadReg(u8 addr)
{
	u8 i = 0, dat = 0, dat1 = 0;

	CE = 0;		  					// CE设置为初始状态
	_nop_();

	SCLK = 0;						// SCLK设置为初始状态
	_nop_();

	CE = 1;							// 拉高CE使能对DS1302的寄存器读写权限
	_nop_();

	for (i=0; i<8; i++)				// 循环发送8bit寄存器地址值
	{
		DSIO = addr & 0x01;			// DS1302的SPI接口从LSB开始发送
		addr >>= 1;

		SCLK = 1;					// 制造上升沿,DS1302在上升沿完成读取动作
		_nop_();

		SCLK = 0;					// 拉低SCLK为下个bit发送做准备
		_nop_();
	}
	
	for (i=0; i<8; i++)				// 循环读取8bit寄存器值数据
	{
		dat1 = DSIO;//从最低位开始接收
		dat = (dat>>1) | (dat1<<7);

		SCLK = 1;
		_nop_();

		SCLK = 0;//DS1302下降沿时,放置数据
		_nop_();
	}

	CE = 0;
	_nop_();	//以下为DS1302复位的稳定时间,必须的。

	SCLK = 1;
	_nop_();

	DSIO = 0;
	_nop_();

	DSIO = 1;
	_nop_();

	return dat;	
}

例程:XPT2046中文手册

第六章:SPI通信(3线制)(4线制)_第3张图片

第六章:SPI通信(3线制)(4线制)_第4张图片

/*********************************************************************
* 函 数 名       : SpiWrite
* 函数功能		 : 按照SPI时序发送1byte数据出去
* 参数列表       : dat - 待发送的1字节数据
* 函数输出    	 : 无
*********************************************************************/
static void SpiWrite(u8 dat)
{
	u8 i = 0;

	for (i=0; i<8; i++)
	{
		DIN = dat >> 7;  	// 查时序图可知XPT2046的SPI从MSB开始发送
		dat <<= 1;
		CLK = 0;			
		CLK = 1;			// 数据在CLK的上升沿被XPT2046接收
	}
}

/*********************************************************************
* 函 数 名       : SpiRead8
* 函数功能		 : 按照SPI时序接收8位AD值
* 参数列表       : 无
* 函数输出    	 : 返回从XPT2046内部读取到的8位AD值
*********************************************************************/
static u8 SpiRead8(void)
{
	u8 i = 0, dat = 0;

	CLK = 0;
	for (i=0; i<8; i++)			// 循环接收8位数据
	{
		dat <<= 1;				// XPT2046的SPI读取也是从MSB开始的

		CLK = 1;
		CLK = 0;

		dat |= DOUT;			// 读取到最低位,然后借助左移走向高位
	}

	return dat;	
}


/*********************************************************************
* 函 数 名       : SpiRead12
* 函数功能		 : 按照SPI时序接收12位AD值
* 参数列表       : 无
* 函数输出    	 : 返回从XPT2046内部读取到的12位AD值
*********************************************************************/
static u16 SpiRead12(void)
{
	u16 i = 0, dat = 0;

	CLK = 0;
	for (i=0; i<12; i++)		// 循环接收12位数据
	{
		dat <<= 1;				// XPT2046的SPI读取也是从MSB开始的

		CLK = 1;
		CLK = 0;

		dat |= DOUT;			// 读取到最低位,然后借助左移走向高位
	}

	return dat;	
}

/*********************************************************************
* 函 数 名       : ReadAdValue8
* 函数功能		 : 按照给定cmd从XPT2046中读取相应通道的8位AD值
* 参数列表       : 无
* 函数输出    	 : 返回从XPT2046内部读取到的8位AD值
*********************************************************************/
u8 ReadAdValue8(u8 cmd)
{
	u8 i = 0;
	u8 val = 0;

	CLK = 0;
	CS  = 0;
	SpiWrite(cmd);
	for (i=6; i>0; i--); 	// 延时一段给XPT2046内部去做AD转换

	CLK = 1;	  			// 发送一个时钟周期,清除BUSY
	_nop_();
	_nop_();

	CLK = 0;
	_nop_();
	_nop_();

	val = SpiRead8();
	CS = 1;

	return val;	
}


/*********************************************************************
* 函 数 名       : ReadAdValue12
* 函数功能		 : 按照给定cmd从XPT2046中读取相应通道的12位AD值
* 参数列表       : 无
* 函数输出    	 : 返回从XPT2046内部读取到的12位AD值
*********************************************************************/
u16 ReadAdValue12(u8 cmd)
{
	u8 i = 0;
	u16 val = 0;

	CLK = 0;
	CS  = 0;
	SpiWrite(cmd);
	for (i=6; i>0; i--); 	// 延时一段给XPT2046内部去做AD转换

	CLK = 1;	  			// 发送一个时钟周期,清除BUSY
	_nop_();
	_nop_();

	CLK = 0;
	_nop_();
	_nop_();

	val = SpiRead12();
	CS = 1;

	return val;	
}

推荐链接:

https://blog.csdn.net/gogomusic/article/details/54783969

 

 

总结写命令或写数据的位操作。

// Send------------(lsb-msb)

DSIO = ADDR & 0X01;
ADDR >>= 1;

       ------------(msb-lsb)
DSIO =     ADDR >> 7;
ADDR <<= 1; 

// rx  ------------(lsb msb)
addr1 = DSIO;
addr = (addr >> 1) | (addr1 << 7);

       ------------(Msb Lsb)
addr <<= 1;
//CLK CHEG
addr |= DSIO;
 

你可能感兴趣的:(第六章:SPI通信(3线制)(4线制))