打印
[PIC32/SAM]

PIC32 SPI简介(主/从模式)

[复制链接]
1044|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wiba|  楼主 | 2019-7-25 12:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
SPI串行同步接口(有时钟脉冲)

串行外设接口(Serial Peripheral Interface,SPI)模块是用于同外部外设和其他单片机器件进行

通信的同步串行接口。这些外设可以是串行EEPROM、移位寄存器、显示驱动器和模数转换器

(ADC)或音频编解码器。


SPIx 串行接口由以下四个引脚组成:(可由引脚的映射确定四个引脚)

• SDIx:串行数据输入

• SDOx:串行数据输出

• SCKx:移位时钟输入或输出

• SSx:低动态功耗从选择或帧同步I/O 脉冲


使用特权

评论回复
沙发
wiba|  楼主 | 2019-7-25 12:03 | 只看该作者
主模式下SPI 模块的工作原理如下所述:



一句话概括:数据由用户写入SPIxbuf然后装入SPIXTXB发送缓冲区移入移位寄存器SPIxSR,仅当存在待发送数据时波特发生器才产生对应数据位模式的时钟脉冲,一个脉冲一个数据位同步从移位寄存器SPIxSR发送至数据输出引脚SDOX。

1. 一旦模块设置为主模式工作并使能,待发送数据就会写入SPIxBUF 寄存器。

SPITBE 位(SPIxSTAT<3>)清零。

2. SPIxTXB 的内容移入移位寄存器SPIxSR (见图23-8),且模块将SPITBE 位清零。

3. 一组8/16/32 个时钟脉冲将8/16/32 位发送数据从SPIxSR 移出到SDOx 引脚,同时将

SDIx 引脚的数据移入SPIxSR。

4. 当传输结束时,将发生以下事件:

a) 中断标志位SPIxRXIF 置1。通过将中断允许位SPIxRXIE 置1 来允许SPI 中断。

SPIxRXIF 标志不会被硬件自动清零。

b) 此外,当正在进行的发送和接收操作结束时, SPIxSR 的内容将移入SPIxRXB。

c) 模块将SPIRBF 位(SPIxSTAT<0>)置1,指示接收缓冲区已满。一旦用户代码读取了

SPIxBUF,硬件就会将SPIRBF 位清零。在增强型缓冲模式下, SPIRBE 位(SPIxSTAT<5>)

会在SPIxRXB FIFO 缓冲区全空时置1,在不全空时清零。

5. 当SPI 模块需要将数据从SPIxSR 传输到SPIxRXB 时,如果SPIRBF 位置1 (接收缓冲
区满),模块会将SPIROV 位(SPIxSTAT<6>)置1,指示产生了溢出条件。
6. 只要SPITBE 位(SPIxSTAT<3>)置1,用户软件就可以在任何时候将待发送数据写入
SPIxBUF。写操作可以与SPIxSR移出先前写入的数据同时发生,因此可以允许连续发送。
在增强型缓冲模式下,SPITBF 位(SPIxSTAT<1>)会在SPIxTXB FIFO 缓冲区全满时置
1, 在不全满时清零。
SPITBE:SPI 发送缓冲区空状态位(1)(empty)
1 = 发送缓冲区SPIxTXB 为空
0 = 发送缓冲区SPIxTXB 非空
当SPI 将数据从SPIxTXB 传输到SPIxSR 时,该位由硬件自动置1。
当通过写SPIxBUF 装入SPIxTXB 时,该位由硬件自动清零。
SPITBF:SPI 发送缓冲区满状态位(1)(full)
1 = 发送尚未开始, SPIxTXB 为满
0 = 发送缓冲区未满
标准缓冲模式:
当内核通过写SPIxBUF 存储单元装入SPIxTXB 时,该位由硬件自动置1。
当SPI 模块将数据从SPIxTXB 传输到SPIxSR 时,该位由硬件自动清零。
增强型缓冲模式:
当FIFO 中没有可用空间时置1。

CKE:SPI 时钟边沿选择位(edge)
1 = 串行输出数据在时钟从工作状态转变为空闲状态时变化(见CKP 位)
0 = 串行输出数据在时钟从空闲状态转变为工作状态时变化(见CKP 位)
CKP:时钟极性选择位(polarity)
1 = 空闲状态时时钟信号为高电平;工作状态时为低电平
0 = 空闲状态时时钟信号为低电平;工作状态时为高电平


使用特权

评论回复
板凳
wiba|  楼主 | 2019-7-25 12:04 | 只看该作者
当仅当移位寄存器SPIXSR有待发送数据时,产生时钟脉冲,由CKP决定时钟空闲极性,由
CKE决定数据发送的时钟沿。
例如8位数据模式,产生8个时钟脉冲,每个时钟脉冲发送一位数据,实现同步发送数据。传输完一条数据后产生中断SPIxRXIF(在SPIxBUF 接收缓冲区中汇集新数据时,将会发生该事件。)

使用特权

评论回复
地板
wiba|  楼主 | 2019-7-25 12:04 | 只看该作者
1 主模式工作
要将SPI 模块设置为主模式工作,请执行以下步骤:
1. 禁止相应IECx 寄存器中的SPI 中断。              mSPI1TXIntEnable(0);//发送完成中断
2. 通过清零ON 位停止并复位SPI 模块。             SPI1CON=0;     //清零15位
3. 清除接收缓冲区。                               rData=SPI1BUF; //读取SPI缓冲区数据后清零
4. 如果使用标准缓冲模式,则将ENHBUF 位(SPIxCON<16>)清零,如果使用增强型缓冲
模式,则将它置1。                                SPI1CONCLR=0X10000;
5. 如果不希望使用SPI 中断,则跳过此步骤并继续步骤5。否则,需要执行以下附加步骤:
a) 清零相应IFSx 寄存器中的SPIx 中断标志/ 事件。
b) 在相应的IPCx 寄存器中写入SPIx 中断优先级位和子优先级位。
c) 将相应IECx 寄存器中的SPIx 中断允许位置1。
6. 写入波特率发生器寄存器SPIxBRG。
7. 清零SPIROV 位(SPIxSTAT<6>)。
8. 将所需的设置写入SPIxCON 寄存器,且MSTEN (SPIxCON<5>) = 1。
9. 通过将ON 位(SPIxCON<15>)置1 使能SPI 工作。
10. 将待发送数据写入SPIxBUF 寄存器。发送(和接收)在数据写入SPIxBUF 寄存器时立即
开始。

使用特权

评论回复
5
wiba|  楼主 | 2019-7-25 12:04 | 只看该作者
一. 配置引脚映射(由实际所需引脚情况决定)             
PPSOutput(2, RPB8, SDO2); 或RPB8Rbits.RPB8R=0B0100;  
PPSInput(2,SDI2,RPB13); 或 SDI2bits.SDI2=0B0011;
二. 初始化SPI
用库函数SpiChnOpen(SpiChannel chn, SpiOpenFlags oFlags, unsigned int srcClkDiv);
SPIChannel 通道1、2即SPI1/SPI2,
SpiOpenFlags开启的配置(见库函数SPI.h) 附一
例如SpiOpenFlags oFlags = SPI_OPEN_MSTEN | SPI_OPEN_CKP_HIGH | SPI_OPEN_MODE8 | SPI_OPEN_ON;
主模式,时钟空闲时高电位,8位数据模式,开启SPI。其他默认0
srcClkDi    波特对外设时钟的分频,从而决定发送数据时钟脉冲速度
FSCK=FPB/(2*(SPIxBRG+1))       BRG为9位寄存器(0—511)        FSCK(FPB/2—FPB/1024)

使用特权

评论回复
6
wiba|  楼主 | 2019-7-25 12:05 | 只看该作者
2 从模式工作
要将SPI 模块设置为从工作模式,请执行以下步骤:
1. 如果使用中断,禁止相应IECx 寄存器中的SPI 中断。
2. 通过清零ON 位,停止并复位SPI 模块。
3. 清除接收缓冲区。
4. 如果使用标准缓冲模式,则将ENHBUF 位(SPIxCON<16>)清零,如果使用增强型缓冲
模式,则将它置1。
5. 如果要使用中断,则需要执行以下附加步骤:
a) 清零相应IFSx 寄存器中的SPIx 中断标志/ 事件。
b) 在相应的IPCx 寄存器中写入SPIx 中断优先级位和子优先级位。
c) 将相应IECx 寄存器中的SPIx 中断允许位置1。
6. 清零SPIROV 位(SPIxSTAT<6>)。
7. 将所需的设置写入SPIxCON 寄存器,且MSTEN (SPIxCON<5>) = 0。
8. 通过将ON 位(SPIxCON<15>)置1 使能SPI 工作。
9. 发送(及接收)会在主器件提供串行时钟时立即开始。
在从模式下,当SCKx引脚上出现外部时钟脉冲时开始发送和接收数据。CKP位(SPIxCON<6>)
和CKE 位(SPIxCON<8>)决定数据在时钟的哪个边沿发送。

使用特权

评论回复
7
wiba|  楼主 | 2019-7-25 12:05 | 只看该作者
一. 配置引脚映射(由实际所需引脚情况决定)             
PPSOutput(2, RPB8, SDO2); 或RPB8Rbits.RPB8R=0B0100;  
PPSInput(2,SDI2,RPB13); 或 SDI2bits.SDI2=0B0011;
二. 初始化SPI
用库函数SpiChnOpen(SpiChannel chn, SpiOpenFlags oFlags, unsigned int srcClkDiv);
SPIChannel 通道1、2即SPI1/SPI2,
SpiOpenFlags开启的配置(见库函数SPI.h)
例如
SpiOpenFlags  oFlags =
SPI_OPEN_SLVEN | SPI_OPEN_SSEN | SPI_OPEN_CKP_HIGH | SPI_OPEN_MODE8 | SPI_OPEN_ON;
从模式,从选择使能SSx 引脚用于从模式,时钟空闲时高电位,8位数据模式,开启SPI。其他默认0
srcClkDi    波特对外设时钟的分频,从而决定发送数据时钟脉冲速度
FSCK=FPB/(2*(SPIxBRG+1))       BRG为9位寄存器(0—511)        FSCK(FPB/2—FPB/1024)

 

使用特权

评论回复
8
wiba|  楼主 | 2019-7-25 12:05 | 只看该作者
从模式下提供了以下附加特性:
• 从选择同步
SSx 引脚允许同步从模式。如果SSEN 位(SPIxCON<7>)置1,则仅当SSx 引脚被驱动
为低电平时,才能使能从模式下的发送和接收。要使SSx 引脚用作输入,就不能驱动端口输
出或其他外设输出。如果SSEN 位置1 且SSx 引脚被驱动为高电平, SDOx 引脚将不再被
驱动并且将变为三态,即使模块在发送过程中也是如此。下次SSx 引脚被驱动为低电平时,
将使用SPIxTXB 寄存器中保存的数据重新尝试进行被中止的发送。如果SSEN 位未置1,则
SSx 引脚不影响从模式下模块的工作。

• SPITBE 状态标志的操作
SPITBE 位(SPIxSTAT<3>)的功能在从工作模式下有所不同。以下介绍了各种从工作模式
设置下的SPITBE 功能:
- 如果SSEN (SPIxCON<7>)清零,当用户代码将数据装入SPIxBUF 时, SPITBE 清
零。它在模块将SPIxTXB 中的数据传输到SPIxSR 时置1。这与主模式下SPITBE 位的
功能类似。
- 如果SSEN 置1,当用户代码将数据装入SPIxBUF 时,SPITBE 清零。但是,它只有在
SPIx 模块完成数据发送时才被置1。当SSx 引脚变为高电平时,发送将被中止,但是可
能在稍后重新尝试发送。因此,每个数据字都保存在SPIxTXB 中,直到所有位都被发
送到接收器中。

其他模式:音频解码模式,帧模式详见数据手册

使用特权

评论回复
9
wiba|  楼主 | 2019-7-25 12:05 | 只看该作者
中断
SPI 模块能够产生一些中断,以反映在数据通信期间发生的事件。它可以产生以下类型的中断:
• 接收数据可用中断通过SPI1RXIF 和SPI2RXIF 指示。在SPIxBUF 接收缓冲区中汇集新数据
时,将会发生该事件。
• 发送缓冲区为空,中断通过SPI1TXIF 和SPI2TXIF 指示。在SPIxBUF 发送缓冲区中有可用空
间,可以写入新数据时,将会发生该事件。
• 错误中断通过SPI1EIF 和SPI2EIF 指示。 当SPIxBUF 接收缓冲区存在溢出条件(即,汇集
了新的接收数据,但前一个数据尚未被读取)、当发送缓冲区数据不足或发生FRMERR 事
件时,将会发生该事件。
bit 3-2 STXISEL<1:0>:SPI 发送缓冲区为空的中断模式位(1,3)
11 = SPIxTXIF 在缓冲区未满(具有一个或多个空元素)时置1
10 = SPIxTXIF 在缓冲区有一半或更多元素为空时置1
01 = SPIxTXIF 在缓冲区全空时置1
00 = SPIxTXIF 在最后一个传输数据移出SPISR 并且发送操作完成时置1
bit 1-0 RTXISEL<1:0>:SPI 接收缓冲区为满的中断模式位(1,3)
11 = SPIxRXIF 在缓冲区全满时置1
10 = SPIxRXIF 在缓冲区有一半或更多元素不为空时置1
01 = SPIxRXIF 在缓冲区不为空时置1
00 = SPIxRXIF 在接收缓冲区中的最后一个字被读取(即,缓冲区为空)时置1

使用特权

评论回复
10
wiba|  楼主 | 2019-7-25 12:06 | 只看该作者
例1

点亮数码管

#include
#pragma config FPLLIDIV = DIV_2         // PLL Input Divider (2x Divider)
#pragma config FPLLMUL = MUL_24         // PLL Multiplier (24x Multiplier)
#pragma config FPLLODIV = DIV_2         // System PLL Output Clock Divider (PLL Divide by 2)
#pragma config FNOSC = FRCPLL           // Oscillator Selection Bits (Fast RC Osc with PLL)
#pragma config JTAGEN = OFF             // JTAG Enable (JTAG Disabled)
#pragma config FWDTEN = OFF             // Watchdog Timer Enable (WDT Disabled (SWDTEN Bit Controls))
char   Led[]={0x42, 0xf3, 0x86, 0xa2, 0x33, 0x2a, 0x0a, 0xf2, 0x02, 0x22, 0x40, 0xf1, 0x84, 0xa0, 0x31, 0x28, 0x08, 0xf0, 0x00, 0x20, 0x1e, 0x0e, 0x0f, 0xbf, 0x23, 0x9b, 0x8b};
//led字库

void spiout(char image[],int len)
{
    int i;
PORTClearBits(IOPORT_B, BIT_9);
    for (i = 0; i < len; i++)
        {
            SpiChnPutC(2, image[i]);
        }
for(i=0;i<60;i++);  //等待数据存储成功
PORTSetBits(IOPORT_B, BIT_9);  //锁存数据显示
}
int main()
{
PPSOutput(2, RPB8, SDO2);
//输出针脚组2中,查表将针脚RPB8,作为数据输出2口SDO2.实际连线也是如此
    SpiOpenFlags oFlags = SPI_OPEN_MSTEN | SPI_OPEN_CKP_HIGH | SPI_OPEN_MODE8 | SPI_OPEN_ON;//作为主机,时钟脉冲空闲时高电位,8位数据模式,SPI使能
    SpiChnOpen(2, oFlags, 6);//打开通道2即SDO2,配置SPI,分频fpbDiv(2~1024).波特率BR=Fpb/fpbDiv
    PORTSetPinsDigitalOut(IOPORT_B, BIT_9);//外部移位寄存器数据锁存,1锁存,0开放
//    SPI2CONCLR=(1<<15);    SPI2CONCLR=0X8000;  多种操作
    spiout(Led,4);
}

使用特权

评论回复
11
wiba|  楼主 | 2019-7-25 12:06 | 只看该作者
数码管说明
所用芯片74HC595内部有8位移位寄存器和一个存储器,移位寄存器和存储寄存器具有独立的时钟信号,数据在移位寄存器时钟信号SHCP的上升沿输入,在存储寄存器时钟信号STCP的上升沿进入到存储寄存器中去,移位寄存器有一个串行移位输入DS、一个串行输出Q7’和一个异步的低电平复位MR,由于PIC32MX的输入/输出端口的输出高电平为电压3.3V,不能直接驱动5V供电的芯片74HC595,采用了的二极管与上拉电阻构成的电平转换匹配电路,电路简单可靠成本低。
当SDO脚接收到PIC32MX的SPI输出的一个低电平信号时,二极管导通,此时OUT1为一个低电平信号;当SDO脚接收到一个高电平信号时,二极管的OUT1端经过上拉电阻连接到5V,以输出高于4V以上的高电平信号,从而实现电平转换的匹配功能。

 

当需要使用多个七段数码管显示时,可进行如下处理:各个74HC595共用SHCP与STCP时钟信号,前一级74HC595的Q7’依次接到下一级74HC595的DS。



当数据全部移入所有74HC595的移位寄存器时,所有74HC595的移位寄存器都已经更新后,利用SLCK信号将数据全部移入锁存到存储寄存器,从而实现LED显示信号的锁存与显示。

使用特权

评论回复
12
wiba|  楼主 | 2019-7-25 12:06 | 只看该作者
附一

 typedef enum
{
    // master opening mode  主
   SPI_OPEN_MSTEN =        _SPIxCON_MASK_(MSTEN_MASK), // set the Master mode
   SPI_OPEN_SMP_END =      _SPIxCON_MASK_(SMP_MASK),   // Master Sample Phase for the input bit at the end of the data out time. Otherwise data is sampled in the middle.
   SPI_OPEN_MSSEN =        _SPIxCON_MASK_(MSSEN_MASK), // enable the driving of the Slave Select (SS) output pin by the Master
   SPI_OPEN_MSSEN_HIGH =   _SPIxCON_MASK_(FRMPOL_MASK),    // Master driven SS output active high. Otherwise low.

   // slave opening mode   从
   SPI_OPEN_SLVEN =        0,              // set the Slave mode
   SPI_OPEN_SSEN =         _SPIxCON_MASK_(SSEN_MASK),  // enable the SS input pin.

    SPI_OPEN_MCLKSEL =   _SPIxCON_MASK_(MCLKSEL_MASK),
 
   // clocking opening mode   时钟
   SPI_OPEN_CKP_HIGH = _SPIxCON_MASK_(CKP_MASK),  // set the clock polarity to (idle-high, active-low). Otherwise is (idle-low, active-high).
   SPI_OPEN_CKE_REV  = _SPIxCON_MASK_(CKE_MASK), // set the Clock Edge reversed: transmit from active to idle. Otherwise transmit when clock goes from idle to active

   // data characters opening mode    数据
   SPI_OPEN_MODE8 =        0,              // set 8 bits/char
   SPI_OPEN_MODE16 =       _SPIxCON_MASK_(MODE16_MASK),    // set 16 bits/char
   SPI_OPEN_MODE32 =       _SPIxCON_MASK_(MODE32_MASK),    // set 32 bits/char

   // framed mode opening mode  帧高级
   SPI_OPEN_FRMEN =        _SPIxCON_MASK_(FRMEN_MASK), // Enable the Framed SPI support. Otherwise the Framed SPI is disabled.
   SPI_OPEN_FSP_IN =       _SPIxCON_MASK_(FRMSYNC_MASK),   // Frame Sync Pulse (FSP) direction set to input (Frame Slave).
                                        // Otherwise the FSP is output and the SPI channel operates as a Frame Master.
   SPI_OPEN_FSP_HIGH =     _SPIxCON_MASK_(FRMPOL_MASK),    // FSP polarity set active high. Otherwise the FSP is active low.
   SPI_OPEN_FSP_CLK1 =     _SPIxCON_MASK_(SPIFE_MASK), // Set the FSP to coincide with the 1st bit clock.
                                        // Otherwise the FSP precedes the 1st bit clock
   SPI_OPEN_FSP_WIDE =     _SPIxCON_MASK_(FRMSYPW_MASK),   // set the FSP one character wide. Otherwise the FSP is one clock wide.

   SPI_OPEN_FRM_CNT1 =     (0 << _SPIxCON_MASK_(FRMCNT_POSITION)), // set the number of characters per frame (Frame Counter) to 1 (default)
   SPI_OPEN_FRM_CNT2 =     (1 << _SPIxCON_MASK_(FRMCNT_POSITION)), // set the Frame Counter to 2
   SPI_OPEN_FRM_CNT4 =     (2 << _SPIxCON_MASK_(FRMCNT_POSITION)), // set the Frame Counter to 4
    SPI_OPEN_FRM_CNT8 =     (3 << _SPIxCON_MASK_(FRMCNT_POSITION)), // set the Frame Counter to 8
   SPI_OPEN_FRM_CNT16 =    (4 << _SPIxCON_MASK_(FRMCNT_POSITION)), // set the Frame Counter to 16
   SPI_OPEN_FRM_CNT32 =    (5 << _SPIxCON_MASK_(FRMCNT_POSITION)), // set the Frame Counter to 32

   // enhanced buffer (FIFO) opening mode 增强型缓存及中断模式
   SPI_OPEN_ENHBUF =       _SPIxCON_MASK_(ENHBUF_MASK),    // enable the enhanced buffer mode

   SPI_OPEN_TBE_NOT_FULL =   (3 << _SPIxCON_MASK_(STXISEL_POSITION)),    // Tx Buffer event issued when Tx buffer not full (at least one slot empty)
   SPI_OPEN_TBE_HALF_EMPTY = (2 << _SPIxCON_MASK_(STXISEL_POSITION)),    // Tx Buffer event issued when Tx buffer >= 1/2 empty
   SPI_OPEN_TBE_EMPTY =      (1 << _SPIxCON_MASK_(STXISEL_POSITION)),    // Tx Buffer event issued when Tx buffer completely empty
   SPI_OPEN_TBE_SR_EMPTY =   (0 << _SPIxCON_MASK_(STXISEL_POSITION)),    // Tx Buffer event issued when the last character is shifted out of the internal Shift Register
                                            // and the transmit is complete

   SPI_OPEN_RBF_FULL =      (3 << _SPIxCON_MASK_(SRXISEL_POSITION)),    // Rx Buffer event issued when RX buffer is full
   SPI_OPEN_RBF_HALF_FULL = (2 << _SPIxCON_MASK_(SRXISEL_POSITION)),    // Rx Buffer event issued when RX buffer is >= 1/2 full
   SPI_OPEN_RBF_NOT_EMPTY = (1 << _SPIxCON_MASK_(SRXISEL_POSITION)),    // Rx Buffer event issued when RX buffer is not empty
   SPI_OPEN_RBF_EMPTY =     (0 << _SPIxCON_MASK_(SRXISEL_POSITION)),    // Rx Buffer event issued when RX buffer is empty (the last character in the buffer is read).

   // general opening mode   常用
   SPI_OPEN_DISSDO = _SPIxCON_MASK_(DISSDO_MASK), // disable the usage of the SDO pin by the SPI
   SPI_OPEN_DISSDI = _SPIxCON_MASK_(DISSDI_MASK), // disable the usage of the SDI pin by the SPI
   SPI_OPEN_SIDL =   _SPIxCON_MASK_(SIDL_MASK  ), // enable the Halt in the CPU Idle mode. Otherwise the SPI will be still active when the CPU is in Idle mode.
   SPI_OPEN_ON =     _SPIxCON_MASK_(ON_MASK    ), // turn ON the SPI (not used in SpiChnOpen)
}SpiOpenFlags;  // open flags that can be used with SpiChnOpen. Defined in the processor header file.

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

77

主题

3305

帖子

3

粉丝