OpenEdv-开源电子网

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

求一个STM8作为SPI从机的程序,求指导。。

[复制链接]

2

主题

12

帖子

0

精华

新手上路

积分
41
金钱
41
注册时间
2014-11-20
在线时间
0 小时
发表于 2014-11-27 20:40:20 | 显示全部楼层 |阅读模式
5金钱
目前在做一个项目,需要双机通信,主机STM32F407,从机STM8F103,正在头痛从机SPI的问题。

主要是CS脚和中断的处理比较晕,参考了一下附件中风驰的SPI从机程序, 他定义的SPI_CS在PE6,但是没有在PE的中断服务函数里看到任何内容,反而在SPI_IRQ里执行,不太理解怎么放PE6就好了?
或者说这就是硬件NSS的中断服务?


STM8-SLAVE_SPI.zip

348.21 KB, 下载次数: 2370

最佳答案

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

void SPI_Slave_Configuration(void) { SPI_CR1    = 0;     SPI_CR2    = 0;     SPI_ICR    = 0;     SPI_SR     = 0x02;     SPI_CRCPR  = 0x07; PE_DDR = 0;//PE5输入,上拉 NSS PC_DDR&n ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

65

帖子

0

精华

初级会员

Rank: 2

积分
127
金钱
127
注册时间
2014-10-31
在线时间
8 小时
发表于 2014-11-27 20:40:21 | 显示全部楼层
void SPI_Slave_Configuration(void)
{
SPI_CR1    = 0;
    SPI_CR2    = 0;
    SPI_ICR    = 0;
    SPI_SR     = 0x02;
    SPI_CRCPR  = 0x07;
PE_DDR = 0;//PE5输入,上拉 NSS
PC_DDR &= 0x9F;//5(SCK).6(mosi)输入 7(miso)输出
PC_DDR |= 0x80;// 5.6输入 7输出
   PC_CR1 &= 0x9F;
PC_CR1 |= 0x80;
SPI_CR1 = 0x02;//从模式,先发高位,空闲是CLK为高,采样第一个开始,时钟/8
SPI_CR2 = 0x02;//软件从模式
SPI_ICR = 0X40;//接收完成中断
SPI_CR1 |= 0x40;
}
#pragma vector= SPI_RXNE_vector  
 __interrupt void SPI_RCN( void )
{   
    uint8_t data_buffer;
data_buffer = SPI_DR;
t_sleep = 10; 
 
    if((spi_cnt == 0)&&((data_buffer == 0xef)||(data_buffer == 0x7e)))

    spi_head = 1;
}
if(spi_head)
{
    RxBuf[spi_cnt] = data_buffer;
    spi_cnt  += 1;
    ....
}
SPI_DR = 0;
}
我用的是STM8S005K6,希望对你有用,从机通讯没有问题,已经在产品上用起来了,用的是IAR4.22;
SS要定义为软件从模式,只要是它为低,不管是主机拉的还是自己拉的,SCK时钟过来都可以接收到数据
回复

使用道具 举报

2

主题

12

帖子

0

精华

新手上路

积分
41
金钱
41
注册时间
2014-11-20
在线时间
0 小时
 楼主| 发表于 2014-11-27 20:40:21 | 显示全部楼层
这里我按照自己的想法稍微做了一点点的改动就测试成功了,接下来可以加上判断条件来有目的地返回数据。

先上一份我修改成库函数版本的程序吧。

PS:发现用软件判断CS,是比较慢的,数据会后移不少,放在中断里直接置标志位比较快捷。能用硬件NSS就还是用上吧,从机模式下很好用,基本不出错。
[mw_shl_code=c,true]u8 RxBuf[10]; u8 spi_cnt=0; main(void) { ...... SPI_SLAVE_Init(); SPI_SLAVE_SendByte(0x12);//SPI首字节0x12,作为从机标识 __enable_interrupt(); ...... } void SPI_SLAVE_Init(void) { SPI_DeInit(); /* 初始化SPI , 从机和主机的相位有效沿一定要一致*/ SPI_Init(SPI_FIRSTBIT_MSB, SPI_BAUDRATEPRESCALER_2,SPI_MODE_SLAVE,\ SPI_CLOCKPOLARITY_LOW, SPI_CLOCKPHASE_1EDGE, \ SPI_DATADIRECTION_2LINES_FULLDUPLEX, SPI_NSS_SOFT, 0x07); SPI_ITConfig(SPI_IT_RXNE,ENABLE); SPI_NSSInternalSoftwareCmd(DISABLE);//产生SSI从机信号,也可放在外部中断里来使能从机中断 SPI_Cmd(ENABLE); } u8 SPI_SLAVE_SendByte(u8 byte)//把while判断非空标志全部去掉,不然等待时间太长会错帧,判断等待交给主机做 { /* Loop while DR register in not emplty */ // while (SPI_GetFlagStatus( SPI_FLAG_TXE) == RESET); /* Send byte through the SPI1 peripheral */ SPI_SendData(byte); /* Wait to receive a byte */ // while (SPI_GetFlagStatus(SPI_FLAG_RXNE) == RESET); /* Return the byte read from the SPI bus */ return SPI_ReceiveData(); } //SPI从机中断 INTERRUPT_HANDLER(SPI_IRQHandler, 10) { /* In order to detect unexpected events during development, it is recommended to set a breakpoint on the following instruction. */ uint8_t Rx_byte,spi_head; // if(GPIO_ReadInputPin(GPIOD, GPIO_PIN_3)==0)//确认CS脚拉低的这个判断太慢了,总是出错,另谋他法吧! // { Rx_byte = SPI_SLAVE_SendByte(0x36);//设置下一个字节,同时读回主机当前CLK下的字节 if((spi_cnt == 0)&&((Rx_byte == 0xef)||(Rx_byte == 0x7e))) //首字为0xef或者0x7e,就认为是有效包 { spi_head = 1; } if(spi_head) //在有效包内的话就将读回的字节放入数组 { RxBuf[spi_cnt] = Rx_byte; //注意,首字会在这个数组里 spi_cnt += 1; //地址+1 } if(spi_cnt==10) //包满归零 { spi_head=0; spi_cnt=0; SPI_SLAVE_SendByte(0x12);//设置下一轮发送的首字节0x12 } // } } [/mw_shl_code]

回复

使用道具 举报

557

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165051
金钱
165051
注册时间
2010-12-1
在线时间
2103 小时
发表于 2014-11-27 20:49:14 | 显示全部楼层
帮顶。。。。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

2

主题

12

帖子

0

精华

新手上路

积分
41
金钱
41
注册时间
2014-11-20
在线时间
0 小时
 楼主| 发表于 2014-11-28 15:43:36 | 显示全部楼层
回复【3楼】brook_z:
---------------------------------
非常感谢你提供的程序和思路!

不过
#pragma vector= SPI_RXNE_vector 
这个定义的是什么?
好像STM8里面只有一个SPI中断向量(10)吧。。
回复

使用道具 举报

3

主题

65

帖子

0

精华

初级会员

Rank: 2

积分
127
金钱
127
注册时间
2014-10-31
在线时间
8 小时
发表于 2014-12-1 08:58:51 | 显示全部楼层
#pragma vector= SPI_RXNE_vector   
 __interrupt void SPI_RCN( void ) 
与INTERRUPT_HANDLER(SPI_IRQHandler, 10)
意思是一样的,只是当时你我空间不够就没有用库函数,为什么还要软件判断CS呢,从机SPI应该不用的吧,
回复

使用道具 举报

2

主题

12

帖子

0

精华

新手上路

积分
41
金钱
41
注册时间
2014-11-20
在线时间
0 小时
 楼主| 发表于 2014-12-2 19:31:00 | 显示全部楼层
回复【6楼】brook_z:
---------------------------------
对对,发现了。
判断CS的作用是舍弃头尾的数据包进行帧对齐。我这个案子是突发传输,很容易和STM8的I2C传输就重叠了,就尽量缩短时间吧。不过就算我这么做,还是经常出错。硬件NSS就好用的多。
回复

使用道具 举报

1

主题

6

帖子

0

精华

新手上路

积分
39
金钱
39
注册时间
2014-5-5
在线时间
2 小时
发表于 2015-8-1 13:39:55 | 显示全部楼层
楼主,你好。现在我的一个项目也需要用到stm32f407做master,stm8做slave。方便把你的程序给我参考一下吗?1224532706@qq.com。多谢了。
keep hungry,keep foolish。
回复

使用道具 举报

12

主题

126

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
281
金钱
281
注册时间
2013-1-5
在线时间
22 小时
发表于 2015-12-20 13:56:33 | 显示全部楼层
单纯的做从机应该就不用返回数据了吧,直接在中断中接收就OK吧?
天道酬勤
回复

使用道具 举报

12

主题

126

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
281
金钱
281
注册时间
2013-1-5
在线时间
22 小时
发表于 2015-12-20 14:00:23 | 显示全部楼层
回复【3楼】brook_z:
---------------------------------
  if((spi_cnt == 0)&&((data_buffer == 0xef)||(data_buffer == 0x7e))) 
这个语句后半部分是做的协议吗?
data_buffer == 0x7e或是0xef
天道酬勤
回复

使用道具 举报

12

主题

126

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
281
金钱
281
注册时间
2013-1-5
在线时间
22 小时
发表于 2015-12-23 12:48:31 | 显示全部楼层
回复【5楼】wz18th:
-----------------------------
楼主在主机中,SPI发送字节之间加延时没?
天道酬勤
回复

使用道具 举报

12

主题

126

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
281
金钱
281
注册时间
2013-1-5
在线时间
22 小时
发表于 2015-12-23 12:49:39 | 显示全部楼层
回复【7楼】wz18th:
---------------------------------
硬件NSS是在主从机初始化的时候都配置为硬件吗
天道酬勤
回复

使用道具 举报

0

主题

8

帖子

0

精华

初级会员

Rank: 2

积分
142
金钱
142
注册时间
2014-12-27
在线时间
17 小时
发表于 2016-7-15 14:33:48 | 显示全部楼层
楼主:从机STM8S用NSS用硬件模式,由主机发送NSS,不能接收到数据,但是用软件模式就可以这是为什么呀
void APP_SPI_Init(void)
{
     SPI_DeInit();
     SPI_Init( SPI_FIRSTBIT_MSB,
              SPI_BAUDRATEPRESCALER_2,
              SPI_MODE_SLAVE, SPI_CLOCKPOLARITY_HIGH,
              SPI_CLOCKPHASE_2EDGE,
              SPI_DATADIRECTION_2LINES_FULLDUPLEX,
              SPI_NSS_SOFT, 7);
        SPI_ITConfig(SPI_IT_RXNE, ENABLE);
    SPI_NSSInternalSoftwareCmd(DISABLE);       
        SPI_Cmd(ENABLE);
        SPI_SendData(SPI_SendBuffer[0]);
}
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2024-7-1 04:35

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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