OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5535|回复: 12

SPI双机通信问题

[复制链接]

2

主题

9

帖子

0

精华

初级会员

Rank: 2

积分
64
金钱
64
注册时间
2016-6-1
在线时间
13 小时
发表于 2016-6-1 12:11:18 | 显示全部楼层 |阅读模式
1金钱
我最近在做SPI双机通信的程序,在这个过程中,遇到很多的问题,主要是从机接收不到信息,我现在把程序传上去,希望能够得到大家的帮助。

usart_spi.zip

6.44 MB, 下载次数: 365

最佳答案

查看完整内容[请看2#楼]

论坛有SPI双机例程,自己找到,参考,改。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2016-6-1 12:11:19 | 显示全部楼层
论坛有SPI双机例程,自己找到,参考,改。
回复

使用道具 举报

0

主题

183

帖子

0

精华

高级会员

Rank: 4

积分
684
金钱
684
注册时间
2016-1-27
在线时间
184 小时
发表于 2016-6-1 12:44:55 | 显示全部楼层
你把遇到的问题、现象好好整理描述一下吧,这样没法帮你的
回复

使用道具 举报

10

主题

254

帖子

0

精华

高级会员

Rank: 4

积分
594
金钱
594
注册时间
2015-10-17
在线时间
145 小时
发表于 2016-6-1 15:02:30 | 显示全部楼层
又是谁能帮我改代码,谁能帮我纠错,一天天的只想指望别人,劝你还是去干点别的吧。
开着单片机翱翔在天空
回复

使用道具 举报

58

主题

6296

帖子

1

精华

资深版主

Rank: 8Rank: 8

积分
11603
金钱
11603
注册时间
2014-4-1
在线时间
1327 小时
发表于 2016-6-1 15:20:25 | 显示全部楼层

注意提问的技巧。

大家一般喜欢回答概念性、方向性的问题,
从程序代码里找错误,对任何人都是费脑子的事,大神也不例外。


回复

使用道具 举报

2

主题

9

帖子

0

精华

初级会员

Rank: 2

积分
64
金钱
64
注册时间
2016-6-1
在线时间
13 小时
 楼主| 发表于 2016-6-1 15:45:25 | 显示全部楼层
不吃鱼的老鼠 发表于 2016-6-1 12:44
你把遇到的问题、现象好好整理描述一下吧,这样没法帮你的

我现在遇到的现象是,SPI从机接收到的不是0x00就是0xff。我的从机接收用的是中断,然后从机的配置和主机的配置完全相同,主机每隔100ms发送一次数据,然后从机把接收到的数据用串口发送到PC。
主机的SPI配置函数:
//以下是SPI模块的初始化代码,配置成主机模式       
//SPI口初始化
//这里针是对SPI1的初始化
SPI_InitTypeDef  SPI_InitStructure;

void SPI1_Init(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
  
        RCC_APB2PeriphClockCmd(        RCC_APB2Periph_GPIOA|RCC_APB2Periph_SPI1, ENABLE );       

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);

        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
        SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//设置SPI工作模式:设置为主SPI
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//设置SPI的数据大小:SPI发送接收8位帧结构
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//选择了串行时钟的稳态:时钟悬空高
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//数据捕获于第二个时钟沿
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;//定义波特率预分频的值:波特率预分频值为2
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
        SPI_InitStructure.SPI_CRCPolynomial = 7;//CRC值计算的多项式
        SPI_Init(SPI1, &SPI_InitStructure);//根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器

        SPI_Cmd(SPI1, ENABLE); //使能SPI外设               

        SPI1_ReadWriteByte(0xff);//启动传输
}

//SPI 速度设置函数
//SpeedSet:
//SPI_BaudRatePrescaler_2   2分频   (SPI 36M@sys 72M)
//SPI_BaudRatePrescaler_8   8分频   (SPI 9M@sys 72M)
//SPI_BaudRatePrescaler_16  16分频  (SPI 4.5M@sys 72M)
//SPI_BaudRatePrescaler_256 256分频 (SPI 281.25K@sys 72M)
void SPI1_SetSpeed(u8 SpeedSet)
{
        SPI_InitStructure.SPI_BaudRatePrescaler = SpeedSet ;
  SPI_Init(SPI1, &SPI_InitStructure);
        SPI_Cmd(SPI1,ENABLE);
}

//SPIx 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
u8 SPI1_ReadWriteByte(u8 TxData)
{               
        u8 retry=0;                                        
        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
        {
                retry++;
                if(retry>200)
                        return 0;
        }                          
        SPI_I2S_SendData(SPI1, TxData);//通过外设SPIx发送一个数据
        retry=0;

        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)//检查指定的SPI标志位设置与否:接受缓存非空标志位
        {
                retry++;
                if(retry>200)
                        return 0;
        }                                                              
        return SPI_I2S_ReceiveData(SPI1);//返回通过SPIx最近接收的数据                                            
}
主机的主函数:
int main(void)
{       
        NVIC_Configuration();//NVIC初始化
        delay_init();//延时函数初始化
        Uart1_Init(9600);//串口1初始化,波特率9600
        LED_Init();//初始化与LED连接的硬件接口
        SPI1_Init();//SPI1初始化
        SPI1_SetSpeed(SPI_BaudRatePrescaler_2);//SPI速度两分频
        while(1)
        {
                SPI1_ReadWriteByte(0x22);
                delay_ms(100);
  }
}
从机的SPI配置函数:
SPI_InitTypeDef  SPI_InitStructure;

void SPI1_Init(void)
{
        NVIC_InitTypeDef NVIC_InitStructure;
        GPIO_InitTypeDef GPIO_InitStructure;
  
        RCC_APB2PeriphClockCmd(        RCC_APB2Periph_GPIOA|RCC_APB2Periph_SPI1, ENABLE );       

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);

        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
        SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;//设置SPI工作模式:设置为从SPI
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//设置SPI的数据大小:SPI发送接收8位帧结构
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//选择了串行时钟的稳态:时钟悬空高
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//数据捕获于第二个时钟沿
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;//定义波特率预分频的值:波特率预分频值为2
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
        SPI_InitStructure.SPI_CRCPolynomial = 7;//CRC值计算的多项式
        SPI_Init(SPI1, &SPI_InitStructure);//根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器

        NVIC_InitStructure.NVIC_IRQChannel = SPI1_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
       
        SPI1->CR2|=1<<6;//接收缓冲区非空中断使能
       
        SPI_I2S_ITConfig(SPI1,SPI_I2S_IT_RXNE,ENABLE);

  SPI_Cmd(SPI1, ENABLE); //使能SPI外设  
}   

//SPI 速度设置函数
//SpeedSet:
//SPI_BaudRatePrescaler_2   2分频   (SPI 36M@sys 72M)
//SPI_BaudRatePrescaler_8   8分频   (SPI 9M@sys 72M)
//SPI_BaudRatePrescaler_16  16分频  (SPI 4.5M@sys 72M)
//SPI_BaudRatePrescaler_256 256分频 (SPI 281.25K@sys 72M)

void SPI1_SetSpeed(u8 SpeedSet)
{
        SPI_InitStructure.SPI_BaudRatePrescaler = SpeedSet;
  SPI_Init(SPI1, &SPI_InitStructure);
        SPI_Cmd(SPI1,ENABLE);
}

//SPIx 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
u8 SPI1_ReadWriteByte(u8 TxData)
{               
        u8 retry=0;                                        
        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
        {
                retry++;
                if(retry>200)
                        return 0;
        }                          
        SPI_I2S_SendData(SPI1, TxData); //通过外设SPIx发送一个数据
        retry=0;

        while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)//检查指定的SPI标志位设置与否:接受缓存非空标志位
        {
                retry++;
                if(retry>200)
                        return 0;
        }                                                              
        return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据                                            
}

u8 Slave_Temp = 0;

void SPI1_IRQHandler(void)
{
        if((SPI1->SR&1<<0)==1)
        {
                SPI_I2S_ClearITPendingBit(SPI1,SPI_I2S_IT_RXNE);
                Slave_Temp = SPI1_ReadWriteByte(0xff);
        }
}
从机的主函数:
int main(void)
{       
        NVIC_Configuration();//NVIC初始化
        delay_init();//延时函数初始化
        Uart1_Init(9600);//串口1初始化,波特率9600
        SPI1_Init();//SPI1初始化
        SPI1_SetSpeed(SPI_BaudRatePrescaler_2);//SPI速度两分频
        LED_Init();//初始化与LED连接的硬件接口
        while(1)
        {
                printf("Slave_Temp = %x\r\n",Slave_Temp);
  }
}
回复

使用道具 举报

2

主题

9

帖子

0

精华

初级会员

Rank: 2

积分
64
金钱
64
注册时间
2016-6-1
在线时间
13 小时
 楼主| 发表于 2016-6-1 15:48:28 | 显示全部楼层
xuande 发表于 2016-6-1 15:20
注意提问的技巧。

大家一般喜欢回答概念性、方向性的问题,

像SPI这种通信协议,说起来简单。但是在用的时候就是出一点点差错的话,都有可能导致接收错误或者无法传输。所以这个也没有啥概念性或者方向性的问题。
回复

使用道具 举报

2

主题

9

帖子

0

精华

初级会员

Rank: 2

积分
64
金钱
64
注册时间
2016-6-1
在线时间
13 小时
 楼主| 发表于 2016-6-1 15:52:42 | 显示全部楼层
原_子_哥门徒 发表于 2016-6-1 15:02
又是谁能帮我改代码,谁能帮我纠错,一天天的只想指望别人,劝你还是去干点别的吧。

你应该很牛逼啊。
回复

使用道具 举报

2

主题

9

帖子

0

精华

初级会员

Rank: 2

积分
64
金钱
64
注册时间
2016-6-1
在线时间
13 小时
 楼主| 发表于 2016-6-1 21:08:05 | 显示全部楼层
正点原子 发表于 2016-6-1 12:11
论坛有SPI双机例程,自己找到,参考,改。

谢谢原子哥。
回复

使用道具 举报

0

主题

183

帖子

0

精华

高级会员

Rank: 4

积分
684
金钱
684
注册时间
2016-1-27
在线时间
184 小时
发表于 2016-6-2 09:23:26 | 显示全部楼层
machicheng 发表于 2016-6-1 15:45
我现在遇到的现象是,SPI从机接收到的不是0x00就是0xff。我的从机接收用的是中断,然后从机的配置和主机 ...

查错的时候能借助工具尽量借助工具,示波器,逻辑分析仪,硬仿真都可以,问题会一目了然
你的程序看看有没有进中断
回复

使用道具 举报

2

主题

9

帖子

0

精华

初级会员

Rank: 2

积分
64
金钱
64
注册时间
2016-6-1
在线时间
13 小时
 楼主| 发表于 2016-6-2 15:51:27 | 显示全部楼层
不吃鱼的老鼠 发表于 2016-6-2 09:23
查错的时候能借助工具尽量借助工具,示波器,逻辑分析仪,硬仿真都可以,问题会一目了然
你的程序看看有 ...

谢谢哈,调试好了。坑啊,原来是以前用的板子坏了。今天换了两个新的板子,重新下载进去数据完全正确。
回复

使用道具 举报

2

主题

9

帖子

0

精华

初级会员

Rank: 2

积分
64
金钱
64
注册时间
2016-6-1
在线时间
13 小时
 楼主| 发表于 2016-6-2 16:41:48 | 显示全部楼层
程序是正确的,我在调试的时候是板子本身的硬件出现问题。
回复

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
11
金钱
11
注册时间
2017-4-11
在线时间
1 小时
发表于 2017-4-11 08:48:39 | 显示全部楼层
楼主,你的代码可否移植到STM8S103上使用呢?小白问。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-8-22 05:36

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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