9.SPI通信协议

硬件

SPI通信协议由MOSI(主机发送从机接收)、MISO(主机接收从机发送)、SCK(时钟)、SS(片选)线组成,其中MOSI、SCK、SS为主机输出线配置为推挽输出,MISO为主机输入线配置为上拉输入

协议内容

SPI通信协议中SS为从机选中线,置低电平代表选中相应从机,拉低SS时序开始拉高SS时序结束。SPI通信协议传输数据有四种模式。一般用模式0(SCK第一个边沿移入数据(第一个bit)相当于是将SS的下降沿当做第一个边沿移出第一个bit,第二个边沿移出数据(第二个bit)... ,空闲时刻SCK为低电平)。SPI传输数据的核心就是移位模型,一般是向左移高位先行。SPI发送一个字节数据必定会接收一个字节数据,想要接收一个字节数据必须要发送一个字节数据。发送和接收同时进行。

软件spi协议层驱动

#include "stm32f10x.h"                  // Device header

void MySPI_W_SS(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue);
}

void MySPI_W_SCK(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_5, (BitAction)BitValue);
}

void MySPI_W_MOSI(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_7, (BitAction)BitValue);
}

uint8_t MySPI_R_MISO(void)
{
	return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6);
}

//初始化SPI
void MySPI_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
    //GPIO模拟的SS SCK MOSI输出线配置为推挽输出

	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
    //MISO配置为上拉输入
	
	MySPI_W_SS(1);		//SS给高电平默认不选中从机
	MySPI_W_SCK(0);		//SCK给低电平空闲状态下SCK为低电平
}

//开始
void MySPI_Start(void)
{
	MySPI_W_SS(0);
}

//结束
void MySPI_Stop(void)
{
	MySPI_W_SS(1);
}

/*SPI模式0*/
//交换一个字节数据
uint8_t MySPI_SwapByte(uint8_t DataSend)
{
	uint8_t DataReceive;
	uint8_t i = 0;
	for(i = 0; i < 8; i++)
	{
		MySPI_W_MOSI(DataSend & (0x80 >> i));		//SPI模式0在第一个边沿之前就要先移出数据,相当于在SS上升沿时移除第一位数据
		MySPI_W_SCK(1);								//主机控制时钟线产生第一个边沿
		if(MySPI_R_MISO())
		{
			DataReceive |= (0x80 >> i);
		}											//第一个边沿移入数据					
		MySPI_W_SCK(0);								//主机控制时钟线产生第二个边沿,之后在下一个循环开始移出数据,一次循环8次交换一个字节数据
	}
	return DataReceive;
}

硬件SPI协议层驱动

#include "stm32f10x.h"                  // Device header

void MySPI_W_SS(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue);
}
//这里SS片选线依然用软件模拟

//初始化SPI
void MySPI_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
    //开启时钟
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
    //SCK MOSI线由SPI外设操纵,配置为复用推挽输出

	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
    //MOSI配置为上拉输入

	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
    //SS线还是软件模拟配置为推挽输出
	
	SPI_InitTypeDef SPI_InitStructure;
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
    //这三个分别配置SCK时钟的预分频器,和SPI的模式为常用配置选项

	SPI_InitStructure.SPI_CRCPolynomial = 7;
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    //这六个为固定配置一般保持不变

	SPI_Init(SPI1, &SPI_InitStructure);
	
	SPI_Cmd(SPI1, ENABLE);
	
	MySPI_W_SS(1);		//SS给高电平默认不选中从机
}

//开始
void MySPI_Start(void)
{
	MySPI_W_SS(0);
}

//结束
void MySPI_Stop(void)
{
	MySPI_W_SS(1);
}

//交换一个字节数据
uint8_t MySPI_SwapByte(uint8_t DataSend)
{
	while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != SET);    
    //等待TXE标志位

	SPI_I2S_SendData(SPI1, DataSend);                              
	//将待发送的数据放到发送数据寄存器

	while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != SET);   
	//等待RXNE标志位

	return SPI_I2S_ReceiveData(SPI1); 
    //返回接收寄存器中的数据                              
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值