一、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);
}
}
版权声明:本文为weixin_45366970原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。