OpenEdv-开源电子网

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

前段时间在做两块STM32通过SPI主从通讯,现在基本解决了通讯问题,就是还有点小瑕疵,现在写下来分享下

[复制链接]

11

主题

40

帖子

0

精华

初级会员

Rank: 2

积分
129
金钱
129
注册时间
2014-11-9
在线时间
5 小时
发表于 2015-11-9 18:26:20 | 显示全部楼层 |阅读模式
对于两块STM32通过SPI通讯,在网上看到有资料说是有bug缺陷,具体什么缺陷我不太清楚,前段时间我在做这方面项目,也发帖咨询过不少人,经过一个多星期测试,总算可以通讯成功,而且通讯数据不会出错了。
废话不说进入正题:
我们要实现SPI主从通讯一定要用片选(具体怎么用下面有介绍),而且两块开发板一定要共地,不然就呵呵了,我也不知道原因。我们从主机开始:
SPI初始化函数:
[mw_shl_code=c,true]void SPI1_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );//PORTB时钟使能 RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1, ENABLE );//SPI1时钟使能 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //PB13/14/15复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7); //PB13/14/15上拉 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA GPIO_SetBits(GPIOA,GPIO_Pin_3); SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置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_32; //定义波特率预分频的值:波特率预分频值为4 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始,高位在前 SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式 SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_Init(SPI1, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器 SPI_Cmd(SPI1, ENABLE); //使能SPI外设 // SPI1_ReadWriteByte(0xff);//启动传输,这句一定去掉,加了会错位 } [/mw_shl_code]
其实吃实话大家都差不多,下面是收发函数:跟原子哥的一样,我就不说了,
我们主要来看主函数:
[mw_shl_code=c,true]int main(void) { u16 i=0,number=0; u8 datatemp[SIZE]; u32 FLASH_SIZE; u8 rx=0; delay_init(); //延时函数初始化 NVIC_Configuration(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 uart_init(9600); //串口初始化为9600 LED_Init(); //LED端口初始化 LCD_Init(); KEY_Init(); SPI1_Init(); POINT_COLOR=RED;//设置字体为红色 LCD_ShowString(60,50,200,16,16,"WarShip STM32"); LCD_ShowString(60,70,200,16,16,"SPI TEST"); LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK"); LCD_ShowString(60,110,200,16,16,"2012/9/11"); LCD_ShowString(60,130,200,16,16,"LoopBack Mode"); LCD_ShowString(60,150,200,16,16,"KEY0:Send WK_UP:Mode");//显示提示信息 LCD_ShowString(60,170,200,16,16,"Count:"); //显示当前计数值 LCD_ShowString(60,190,200,16,16,"Send Data:"); //提示发送的数据 LCD_ShowString(60,250,200,16,16,"Receive Data:"); //提示接收到的数据 while(1) //检测不到W25Q64 { number=KEY_Scan(0); if(number==1) { LED1=0; while(1) { for(key=0;key<9;key++) { GPIO_ResetBits(GPIOA,GPIO_Pin_3); rx=SPI1_ReadWriteByte(key); GPIO_SetBits(GPIOA,GPIO_Pin_3); LCD_ShowxNum(60+2*32,210,rx,3,16,0X80); delay_ms(1000); } } } } }[/mw_shl_code]
我主要解释第一个while(1)循环里面的函数,首先我们加一个按键: [mw_shl_code=c,true]number=KEY_Scan(0);当按键按下时,我们进入SPI发送程序,其中LED1用来显示程序进去了,[/mw_shl_code] [mw_shl_code=c,true]在发送函数里面,我们的SPI主机依次发送0-8的数据,一秒发送一次,不断循环发送,现在大家看下[/mw_shl_code] [mw_shl_code=c,true]第二个while(1)循环,是不是有个 [mw_shl_code=c,true]GPIO_ResetBits(GPIOA,GPIO_Pin_3);这是我用来做片选的,当我们要进入发送的时候,首先通过这个片选[/mw_shl_code] [mw_shl_code=c,true]告诉我们的从机我要开始发送了,然后发送,发送完后拉高,不断这样发送,这个[/mw_shl_code] [mw_shl_code=c,true] [mw_shl_code=c,true]LCD_ShowxNum(60+2*32,210,rx,3,16,0X80);[/mw_shl_code] 用来显示主机收的从机发送的数据,主机大概就这样[/mw_shl_code] [mw_shl_code=c,true]现在大家看看从机的主函数:[/mw_shl_code] [mw_shl_code=c,true]
[mw_shl_code=c,true] while(1) //检测不到W25Q64 { number=GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3); if(!number) { key = SPI2_ReadWriteByte(++tx); LCD_ShowxNum(60+2*32,210,key,3,16,0X80); } }[/mw_shl_code]

用一个number来读取片选信号,当片选选中时,就进去执行
[/mw_shl_code] [mw_shl_code=c,true] [mw_shl_code=c,true] key = SPI2_ReadWriteByte(++tx);同时发送数据给主机,[/mw_shl_code] [mw_shl_code=c,true]这样就可以正确的通讯了,大家注意当给两块板烧完程序后要先开主机,是主机,主机重要的说三遍[/mw_shl_code] [mw_shl_code=c,true]然后开从机,最后按下主机开始按钮,就是那个key(0),就可以开始通讯,然后大家可以根据自己的需求改,大家有啥好的想法请大家提出来,这个是初级版本,在随后我会继续发布,看能不能改进下代码。[/mw_shl_code] [mw_shl_code=c,true]这是我上传的包,keil4的,欢迎大家测试。[/mw_shl_code]
[/mw_shl_code] [/mw_shl_code]


        

spi主从全双工收发,先开主机.rar

5.94 MB, 下载次数: 6408

加油,奋斗
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

5

主题

163

帖子

0

精华

高级会员

Rank: 4

积分
615
金钱
615
注册时间
2011-11-7
在线时间
180 小时
发表于 2015-11-9 18:58:45 | 显示全部楼层
回复 支持 反对

使用道具 举报

15

主题

786

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3223
金钱
3223
注册时间
2015-7-26
在线时间
811 小时
发表于 2015-11-9 21:00:02 | 显示全部楼层
谢谢分享!!
我的博客:http://blog.csdn.net/itdo_just
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165538
金钱
165538
注册时间
2010-12-1
在线时间
2117 小时
发表于 2015-11-9 22:33:06 | 显示全部楼层
谢谢分享!!
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

3

主题

11

帖子

0

精华

初级会员

Rank: 2

积分
139
金钱
139
注册时间
2017-3-26
在线时间
52 小时
发表于 2017-3-26 22:47:05 | 显示全部楼层
你的程序好像是双机同时发送,但是接收数据那部分处理好像是没有,为什么主机上SPI_ReadWrite()的发送在屏幕上显示的都是255,从机SPI_ReadWrite()都显示0,你的实验现象是怎么样
回复 支持 反对

使用道具 举报

12

主题

53

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
246
金钱
246
注册时间
2015-1-28
在线时间
50 小时
发表于 2018-1-5 11:24:41 | 显示全部楼层
马猴一洒哥 发表于 2017-3-26 22:47
你的程序好像是双机同时发送,但是接收数据那部分处理好像是没有,为什么主机上SPI_ReadWrite()的发送在屏 ...

我的现象和你相同,这个程序用不了
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-15 16:07

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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