大能苗 发表于 2012-8-30 17:28:00

SPI主从机通信问题-为毛接收少一位?

   写了一个SPI通信的程序,主机发送数字0-9给从机,从机收到后再将一数字发送给主机,在proteus里仿真试过了,主机接收到从机的数据总是少一位,不知为毛,请高手指点。

主机程序:
#include <iom16v.h>

unsigned char led = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};

char data=0;

void delay_s(unsigned char n)                     //---->us延时函数10us 误差0.46us
{
unsigned char i,j;
while(n--)
{
    for(i=256;i>0;i--)
        for(j=256;j>0;j--);                                 //1时钟周期
}
}
//时钟周期62.5ns

void SPI_MasterInit(void)
{
      PORTB=PORTB|0xf8;
      /* 设置MOSI 和SCK 为输出,其他为输入 */
      DDRB = (1<<DDB5)|(1<<DDB4)|(~(1<<DDB6))|(1<<DDB7)|(~(1<<DDB3));
      /* 使能SPI 主机模式,设置时钟速率为fck/16 */
      SPCR = (1<<SPE)|(1<<MSTR)|(0<<DORD)|(0<<SPR1)|(1<<SPR0);
}
voidSPI_MasterTransmit(char cData)
{
         char temp;
      PORTB &= (~(1<<PB4));             //nss选通
                /* 启动数据传输 */
      SPDR = cData;
      /* 等待传输结束 */
      while((SPSR & (1<<SPIF)) == 0);
                temp = SPSR;
                temp = SPDR;
                PORTB |= (1<<PB4);                //nss关闭
}


char SPI_MasterReceive(void)
{
      char temp;
                /* 等待接收结束 */
                while(!(PINB & 0x08));
               
      SPDR = 0xFF;
                PORTB &= (~(1<<PB4));             //nss选通
      while(!(SPSR & (1<<SPIF)));
                PORTB |= (1<<PB4);                //nss关闭
               
                /* 返回数据 */
                temp = SPSR;
                temp = SPDR;
                return temp;
}



void datashift(void)
{
      data++;
                if(data>=10) data = 0;
}


void main(void)
{
      char i=0;
      SPI_MasterInit();
      DDRD = 0x01;
                PORTD = 0x01;
               
      DDRC = 0xFF;
      while(1)
      {
                        
               
                SPI_MasterTransmit(data);
                                delay_s(10);
                               
                                PORTC = led;
                delay_s(50);
                               
                i=SPI_MasterReceive();
                               
                                PORTC = led;
                delay_s(50);
                               
                                datashift();


      }
}

从机程序:
#include <iom16v.h>
#include <macros.h>

unsigned char led = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};

void delay_s(unsigned char n)                     //---->us延时函数10us 误差0.46us
{
unsigned char i;
while(n--)
{
    for(i=256;i>0;i--)
        for(i=256;i>0;i--);                                 //1时钟周期
}
}
//时钟周期62.5ns

void SPI_SlaveInit(void)
{
      PORTB=PORTB|0b11110000;
      /* 设置MISO 为输出,其他为输入 */
      DDRB = (1<<DDB6)|(~(1<<DDB4))|(~(1<<DDB5))|(~(1<<DDB7))|(1<<DDB3);
      /* 使能 SPI */
      SPCR = (1<<SPE)|(0<<SPR1)|(1<<SPR0)|(0<<DORD);
      SPSR = 0x00;                                     //(1<<SPIF)|(1<<WCOL);
}
char SPI_SlaveReceive(void)
{
         char temp;
      /* 等待接收结束 */
      while((SPSR & (1<<SPIF)) == 0);
                temp = SPSR;
                temp = SPDR;
      /* 返回数据 */
      return temp;
               
}


voidSPI_SlaveTransmit(char cData)
{
      char temp;
                /* 启动数据传输 */
      SPDR = cData;
                PORTB |= 0x08;
      /* 等待传输结束 */
      while((SPSR & (1<<SPIF)) == 0);
                PORTB &= 0xF7;
                temp = SPSR;
                temp = SPDR;
}



void main(void)
{
      char i;
                SPI_SlaveInit();
      DDRC = 0xFF;
                DDRD = 0x01;
                PORTD = 0x01;
      while(1)
      {       i = SPI_SlaveReceive();
                        PORTC = led;
                               
                SPI_SlaveTransmit(0x03);
                                SPDR = 0;
                                if(i>=10) i=0;
                               

      }
}

proteus仿真电路:

(从机返回的是0x03,但显示的是1)

proteus仿真波形:

(可以看到MISO输出的波形滞后一位)

nazily215 发表于 2012-8-30 18:11:42

十有八九都是相位沒處理好,不看程序了

大能苗 发表于 2012-8-31 08:33:44

发送和接收都是上升沿采样,下降沿锁存(CPOL=0,CPHA=0).

大能苗 发表于 2012-8-31 09:26:29

nazily215 发表于 2012-8-30 18:11 static/image/common/back.gif
十有八九都是相位沒處理好,不看程序了

问题发现,把原主机程序SPI_MasterReceive里的(1)(2)两句互换结果即为正确的。但是还不理解,之前仿真度的数据显示,发送是LSB,主机收到的数据总是缺少最低一位,这不就是说主机接收滞后从机发送一个周期么,但我(1)(2)据互换不是更延后了主机相对从机的之后么?(从机不是从ss选中开始发送,主机是从SPDR写数据开始么?)

char SPI_MasterReceive(void)
{
      char temp;
                /* 等待接收结束 */
                while(!(PINB & 0x08));
               
                PORTB &= (~(1<<PB4));             //nss选通 (1)
                SPDR = 0xFF;                                          (2)
      while(!(SPSR & (1<<SPIF)));
                PORTB |= (1<<PB4);                //nss关闭
               
                /* 返回数据 */
                temp = SPSR;
                temp = SPDR;
                return temp;
}
页: [1]
查看完整版本: SPI主从机通信问题-为毛接收少一位?