对User’s guide进行了简单翻译并加上了自己的一些理解。
之前用模拟IO写过SPI,今天来试着学下自带的SPI模块
一、基本
1.1 SPI操作模式
SPI模式中,串行数据将通过多种设备通过一个由master提供的共用的时钟而被接受和发送。一个额外的管脚,UCxSTE,提供传送和发送的使能。
可以设定三个或四个管脚用于SPI数据交换
·UCxSIMO:slave in ,master out
·UCxSOMI:slave out,master in
·UCxCLK:SPI clock
·UCxSTE:slave传送使能
当四个管脚时候允许多个设备共用一个总线,不用于3个管脚模式
1.2 SPI初始化和重置
同UART设定,USCI被PUC或是UCSWRST重置。当配置的时候,首先UCSWRST=1,接着配置端口,然后UCSWRST=0,最终中断使能打开。
1.3主机模式(Master 模式)
不论是主机模式还是从机模式的原理图都十分简单…
1.4从机模式
1.5传送使能和接受使能
主机模式中,当数据写入UCxTXBUF中时,时钟被产生,数据开始传送。
从机模式中,传送发生在主机提供时钟的时候。
SPI在传送被激活的时候接受数据,接受和传送能够同时发生。
1.6时钟控制。
UCxCLK由主机提供,当UCMST=1时,bit CLK被UCxCLK管脚提供。当UCMST=0时,时钟由主机提供(这个时候是从机)。传送的时候还发送和接受都使用同一个时钟,同样的速度。
16位的时钟速率控制寄存器:UCxxBR1和BR0,和UART模式一样。但是这个是bit clkock.调制在SPI模式中不需要。USCI_A中,UCAxMTL应该被清零。
计算公式为:
fbit-clock=fBRCLK/UCBRx
1.7极性与相位
SPI有四种模式,区别是极性与相位,可以简单认为是上沿或下沿时传输或接收数据的区别。
具体了解可以到这个博客https://www.cnblogs.com/shangdawei/p/4752476.html
这个里面讲的十分清楚
我们只需要注意这个里面的UCCKPH UCCKPL,这决定了数据如何传输。在看元件的数据手册的时候,需要观察给的时序图,确定具体如何配置。
1.8中断
中断基本类似于UART,之前写UART时候提到过。
二、寄存器
这个与UART需要配置的寄存器不太一样,但不一样的地方主要在CTL0上。
2.1UCAxCTL0
UCCKPH、UCCKPL,时序配置。
UCMSB:传送时从LSB还是MSB传送
UC7BIT:选择七位数据还是八位数据
UCMST:选择主机还是从机
UCMODEx:三管脚四管脚模式选择
UCSYNC:通信模式,0为异步通信(UART)
1为同步通信(SPI)
这个时候就必须要把其配置为1了
其他的比较简单就不再赘述。
三、代码什么的可以看下例程。
例程也比较简单,可以使用两个430单片机进行SPI通讯实验。
(过几天可能会放一个具体的实例)
/*
MSP430F55xx_uscia0_spi_09
主机模式
主机发送一个数据,从机返回,用LED来表征
*/
#include <msp430.h>
unsigned char MST_Data,SLV_Data;
unsigned char temp;
int main(void)
{
volatile unsigned int i;
WDTCTL = WDTPW+WDTHOLD; // Stop watchdog timer
P1OUT |= 0x02; // Set P1.0 for LED
// Set P1.1 for slave reset
P1DIR |= 0x03; // Set P1.0-2 to output direction
P3SEL |= BIT3+BIT4; // P3.3,4 option select
P2SEL |= BIT7; // P2.7 option select
UCA0CTL1 |= UCSWRST; // **Put state machine in reset**
UCA0CTL0 |= UCMST+UCSYNC+UCCKPL+UCMSB; // 3-pin, 8-bit SPI master
// Clock polarity high, MSB
UCA0CTL1 |= UCSSEL_2; // SMCLK
UCA0BR0 = 0x02; // /2
UCA0BR1 = 0; //
UCA0MCTL = 0; // No modulation
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
UCA0IE |= UCRXIE; // Enable USCI_A0 RX interrupt
P1OUT &= ~0x02; // Now with SPI signals initialized,
P1OUT |= 0x02; // reset slave
for(i=50;i>0;i--); // Wait for slave to initialize
MST_Data = 0x01; // Initialize data values
SLV_Data = 0x00; //
while (!(UCA0IFG&UCTXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = MST_Data; // Transmit first character
__bis_SR_register(LPM0_bits + GIE); // CPU off, enable interrupts
}
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_A0_VECTOR))) USCI_A0_ISR (void)
#else
#error Compiler not supported!
#endif
{
volatile unsigned int i;
switch(__even_in_range(UCA0IV,4))
{
case 0: break; // Vector 0 - no interrupt
case 2: // Vector 2 - RXIFG
while (!(UCA0IFG&UCTXIFG)); // USCI_A0 TX buffer ready?
if (UCA0RXBUF==SLV_Data) // Test for correct character RX'd
P1OUT |= 0x01; // If correct, light LED
else
P1OUT &= ~0x01; // If incorrect, clear LED
MST_Data++; // Increment data
SLV_Data++;
UCA0TXBUF = MST_Data; // Send next value
for(i = 20; i>0; i--); // Add time between transmissions to
// make sure slave can process information
break;
case 4: break; // Vector 4 - TXIFG
default: break;
}
}
//
/*
MSP430F55xx_uscia0_spi_10
从机模式
将主机传来的数据发送回去
*/
#include <msp430.h>
int main(void)
{
WDTCTL = WDTPW+WDTHOLD; // Stop watchdog timer
while(!(P2IN&0x80)); // If clock sig from mstr stays low,
// it is not yet in SPI mode
P3SEL |= BIT3+BIT4; // P3.3,4 option select
P2SEL |= BIT7; // P2.7 option select
UCA0CTL1 |= UCSWRST; // **Put state machine in reset**
UCA0CTL0 |= UCSYNC+UCCKPL+UCMSB; // 3-pin, 8-bit SPI slave,
// Clock polarity high, MSB
UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
UCA0IE |= UCRXIE; // Enable USCI_A0 RX interrupt
__bis_SR_register(LPM4_bits + GIE); // Enter LPM4, enable interrupts
}
// Echo character
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_A0_VECTOR))) USCI_A0_ISR (void)
#else
#error Compiler not supported!
#endif
{
switch(__even_in_range(UCA0IV,4))
{
case 0:break; // Vector 0 - no interrupt
case 2: // Vector 2 - RXIFG
while (!(UCA0IFG&UCTXIFG)); // USCI_A0 TX buffer ready?
UCA0TXBUF = UCA0RXBUF;
break;
case 4:break; // Vector 4 - TXIFG
default: break;
}
}