嵌入式系统:SPI

一、SPI

在这里插入图片描述


(一)SPI协议

1.通信方式

(1)同步串行

(2)全双工


2.电路连接
在这里插入图片描述
(1)NSS:从机选择引脚(低电平有效)

(2)SCK:同步时钟信号引脚

(3)MOSI:主发从收,主机发送数据引脚

(4)MISO:主收从发,主机接收数据引脚


3.数据传输时序:由于SPI的灵活性,共有四种工作时序

(1)时钟的极性与相位

  • 时钟极性(CPOL):总线空闲时的电平状态
    • CPOL = 1,总线空闲时为高电平
    • CPOL = 0,总线空闲时为低电平
  • 时钟相位(CPHA):信号采集跳变沿选择
    • CPHA = 1,在第二个跳变沿数据被采样
    • CPHA = 0,在第一个跳变沿数据被采样

(2)工作模式(不需实际硬背,根据时钟的相位和极性可推出)
在这里插入图片描述

  • CPOL = 1,CPHA = 0,时钟下降沿发送数据,上升沿接收数据
  • CPOL = 0,CPHA = 0,时钟上升沿发送数据,下降沿接收数据

在这里插入图片描述

  • CPOL = 1,CPHA = 1,时钟上升沿发送数据,下降沿接收数据
  • CPOL = 0,CPHA = 1,时钟下降沿发送数据,上升沿接收数据

(二)数据读写流程

1.从机选择

2.读写数据(全双工,写数据的同时读数据,一个时钟周期)


(三)编程

1.编程流程

(1)GPIO复用为SPI模式(硬件SPI)

(2)SPI功能配置

  • 波特率(时钟频率)
  • 工作模式选择(主从模式 + 四种方式)
  • 数据格式(MSB/LSB)
  • 数据位数(8bit/16bit)

(3)SPI模式使能

(4)SPI中断配置

  • 中断源
  • 中断优先级
  • 中断使能

(5)数据收发

  • 查询模式
  • 中断模式
  • DMA模式

2.编程实例

(1)寄存器版本

#include "msp.h"
#include "driverlib.h"

void main()
{
	WDTCTL = WDTPW + WDTHOLD;
	
	//GPIO复用为SPI
	P1->SEL0 |= (BIT4 | BIT5 | BIT6 | BIT7);
	P1->SEL1 &=~(BIT4 | BIT5 | BIT6 | BIT7);
	

	EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_SWRST;
	
	//时钟源选择:3MHz
	EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_SSEL__SMCLK;
	//传输速率:500KHz
	EUSCI_B0->BRW = 6;
	
	//SPI(四线)、主机、高位优先
	EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_MODE_2 | EUSCI_B_CTLW0_MST | EUSCI_B_CTLW0_MSB;
	
	//时钟极性1,时钟相位1(第四种模式:空闲时为高电平,上升沿有效)
	EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_CKPL | EUSCI_B_CTLW0_CKPH;
	
	EUSCI_B0->CTLW0 &=~EUSCI_B_CTLW0_SWRST;
	
	//清除接收中断标志位
	EUSCI_B0->IFG &=~EUSCI_B_IFG_RXIFG0;
	
	//接收中断使能
	EUSCI_B0->IE |= EUSCI_B_IE_RXIE0;
	
	//选择从机
	EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_STEM;

	//发送数据
	EUSCI_B0->TXBUF = 0xAA;

	while(1);
}

uint8_t recvData = 0;
void EUSCIB0_IRQHandler(void)
{
	//接收中断
	if(EUSCI_B0->IFG & EUSCI_B_IFG_RXIFG0)
	{
		//清除接收中断标志位
		EUSCI_B0->IFG &=~EUSCI_B_IFG_RXIFG0;
		
		//接收数据
		recvData = EUSCI_B0->RXBUF;
	}
}

(2)库函数版本

#include "msp.h"
#include "driverlib.h"

void main()
{
	/* Halting WDT  */
    WDT_A_holdTimer();
	
	/* Selecting P1.5 P1.6 and P1.7 in SPI mode */
    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1, GPIO_PIN4 | GPIO_PIN5 | GPIO_PIN6 | GPIO_PIN7, GPIO_PRIMARY_MODULE_FUNCTION);
	
	/* Configuring SPI in 4wire master mode */
	eUSCI_SPI_MasterConfig spiMasterConfig;
	
	spiMasterConfig.selectClockSource		= EUSCI_B_SPI_CLOCKSOURCE_SMCLK;
	spiMasterConfig.clockSourceFrequency	= 3000000;
	spiMasterConfig.desiredSpiClock			= 500000;
	spiMasterConfig.spiMode					= EUSCI_SPI_4PIN_UCxSTE_ACTIVE_LOW;
	spiMasterConfig.clockPolarity			= EUSCI_B_SPI_CLOCKPOLARITY_INACTIVITY_HIGH;
	spiMasterConfig.clockPhase				= EUSCI_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXT;
	spiMasterConfig.msbFirst				= EUSCI_B_SPI_MSB_FIRST;
	
	SPI_initMaster(EUSCI_B0_BASE, &spiMasterConfig);
	
	/* Enable SPI module */
	SPI_enableModule(EUSCI_B0_BASE);
	
	/* Enabling interrupts */
    SPI_enableInterrupt(EUSCI_B0_BASE, EUSCI_SPI_RECEIVE_INTERRUPT);
	
	//选择从机
	SPI_selectFourPinFunctionality(EUSCI_B0_BASE,EUSCI_SPI_ENABLE_SIGNAL_FOR_4WIRE_SLAVE);
	
	
	/* Polling to see if the TX buffer is ready */
    while (!(SPI_getInterruptStatus(EUSCI_B0_BASE,EUSCI_SPI_TRANSMIT_INTERRUPT)));

    /* Transmitting data to slave */
    SPI_transmitData(EUSCI_B0_BASE, 0xAA);

	while(1);
}

uint8_t recvData = 0;
void EUSCIB0_IRQHandler(void)
{
	uint32_t status = SPI_getEnabledInterruptStatus(EUSCI_B0_BASE);
	
    if(status & EUSCI_SPI_RECEIVE_INTERRUPT)
    {
    	//Clear Receive Interrupt Flag
    	SPI_clearInterruptFlag(EUSCI_B0_BASE,EUSCI_SPI_RECEIVE_INTERRUPT);
        /* USCI_B0 TX buffer ready? */
        while (!(SPI_getInterruptStatus(EUSCI_B0_BASE, EUSCI_SPI_TRANSMIT_INTERRUPT)));

        recvData = SPI_receiveData(EUSCI_B0_BASE);
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值