搜索
bottom↓
回复: 3

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

[复制链接]

出0入0汤圆

发表于 2012-8-30 17:28:00 | 显示全部楼层 |阅读模式
   写了一个SPI通信的程序,主机发送数字0-9给从机,从机收到后再将一数字发送给主机,在proteus里仿真试过了,主机接收到从机的数据总是少一位,不知为毛,请高手指点。

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

unsigned char led[10] = {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);
}
void  SPI_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[data];
                delay_s(50);
                               
                i=SPI_MasterReceive();
                               
                                PORTC = led;
                delay_s(50);
                               
                                datashift();


        }
}

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

unsigned char led[10] = {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;
               
}


void  SPI_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输出的波形滞后一位)

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2012-8-30 18:11:42 | 显示全部楼层
十有八九都是相位沒處理好,不看程序了

出0入0汤圆

 楼主| 发表于 2012-8-31 08:33:44 | 显示全部楼层
发送和接收都是上升沿采样,下降沿锁存(CPOL=0,CPHA=0).

出0入0汤圆

 楼主| 发表于 2012-8-31 09:26:29 | 显示全部楼层
nazily215 发表于 2012-8-30 18:11
十有八九都是相位沒處理好,不看程序了

问题发现,把原主机程序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;
}
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-16 07:59

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表