OpenEdv-开源电子网

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

SPI从设备接收固定数组,接收出错。

[复制链接]

9

主题

50

帖子

0

精华

初级会员

Rank: 2

积分
128
金钱
128
注册时间
2014-5-28
在线时间
16 小时
发表于 2016-6-8 13:39:06 | 显示全部楼层 |阅读模式
1金钱
本帖最后由 any_014 于 2016-6-8 13:55 编辑

主设备发送的是:0x3a05,0x010a,0100,0000,9d76
stm32作为从设备,中断接收。
因为程序总是调不通,就精简程序。
spi中断接收数据放到个数组里,接收够30个时,置个标志位。
主函数里判断这个标志位,置位时,串口输出这三十个数据。输出结束后,清标志位,开始继续往这个数组里存spi接收的数据。

以下为串口输出数据,总是有错误的。用示波器观察MOSI和SCLK波形,观察了一段很长的数据,主设备发送的就是一开始说的那5个数据,没有错位或漏发。

SPI从模式测试V1_0.zip (2.88 MB, 下载次数: 83)

最佳答案

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

void SPI2_IRQHandler(void) { static u16 spi2Temp; static u8 n; spi2Temp = SPI_I2S_ReceiveData(SPI2); if(spi2RecvTempOk == 0) spi2RecvTemp[n] = spi2Temp; if(n++ > 29) { n = 0; spi2RecvTempOk = 1; } } 你只是关了spi2RecvTempOk ,程序会不停的执行 if(n++ > 29) 所以n在 spi2RecvTe ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

22

主题

751

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1605
金钱
1605
注册时间
2015-6-10
在线时间
222 小时
发表于 2016-6-8 13:39:07 | 显示全部楼层
void SPI2_IRQHandler(void)
{
        static u16 spi2Temp;
        static u8 n;
        spi2Temp = SPI_I2S_ReceiveData(SPI2);
        if(spi2RecvTempOk == 0)
                spi2RecvTemp[n] = spi2Temp;

        if(n++ > 29)
        {
                n = 0;
                spi2RecvTempOk = 1;
        }
}


你只是关了spi2RecvTempOk ,程序会不停的执行 if(n++ > 29)
所以n在  spi2RecvTempOk =1后是一个不确定的数

void SPI2_IRQHandler(void)
{
        static u16 spi2Temp;
        static u8 n;
        spi2Temp = SPI_I2S_ReceiveData(SPI2);
        if(spi2RecvTempOk == 0)
                spi2RecvTemp[n++] = spi2Temp;

        if(n > 29)
        {
                n = 0;
                spi2RecvTempOk = 1;
        }
}

回复

使用道具 举报

17

主题

237

帖子

0

精华

高级会员

Rank: 4

积分
925
金钱
925
注册时间
2012-2-27
在线时间
393 小时
发表于 2016-6-8 13:47:31 | 显示全部楼层
贴代码,要不然怎么看
回复

使用道具 举报

9

主题

50

帖子

0

精华

初级会员

Rank: 2

积分
128
金钱
128
注册时间
2014-5-28
在线时间
16 小时
 楼主| 发表于 2016-6-8 13:49:57 | 显示全部楼层
本帖最后由 any_014 于 2016-6-8 13:52 编辑
k-ad 发表于 2016-6-8 13:47
贴代码,要不然怎么看
感谢回复。

主循环:
[mw_shl_code=applescript,true]while(1)
        {
                if(spi2RecvTempOk)
                {
                        
                        printf("\r\n");
                        for(i = 0; i < 30; i++)
                        {        
                                if((spi2RecvTemp & 0xFF00) == 0x3a00)
                                        printf("\r\n\r\nspi2RecvTemp[%d]:%04x", i, spi2RecvTemp);
                                else
                                        printf("\r\nspi2RecvTemp[%d]:%04x", i, spi2RecvTemp);
                        }
                        spi2RecvTempOk = 0;
                }
        }[/mw_shl_code]

spi2中断部分:
[mw_shl_code=applescript,true]void SPI2_IRQHandler(void)
{
        static u16 spi2Temp;
        static u8 n;
        spi2Temp = SPI_I2S_ReceiveData(SPI2);
        if(spi2RecvTempOk == 0)
                spi2RecvTemp[n] = spi2Temp;

        if(n++ > 29)
        {
                n = 0;
                spi2RecvTempOk = 1;
        }
}
[/mw_shl_code]

spi初始化部分:
[mw_shl_code=applescript,true]void SPI2_Init(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        SPI_InitTypeDef SPI_InitStructure;
        
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
        
        GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_14;                                //PB14 - SPI2_MISO
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
        
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;//PB13 - SPI2_SCK, PB15 - SPI2_MOSI
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
        
        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
        SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
        SPI_InitStructure.SPI_NSS =SPI_NSS_Soft;
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
        SPI_InitStructure.SPI_CRCPolynomial = 7;
        SPI_Init(SPI2, &SPI_InitStructure);
        
        SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_RXNE, ENABLE);
        SPI_Cmd(SPI2, ENABLE);
}[/mw_shl_code]
回复

使用道具 举报

9

主题

50

帖子

0

精华

初级会员

Rank: 2

积分
128
金钱
128
注册时间
2014-5-28
在线时间
16 小时
 楼主| 发表于 2016-6-8 14:17:38 | 显示全部楼层
本帖最后由 any_014 于 2016-6-8 14:18 编辑
止天 发表于 2016-6-8 14:11
void SPI2_IRQHandler(void)
{
        static u16 spi2Temp;

厉害,一下就看出来了...

我原来是有其他问题。感觉spi接收数据判断帧首时,总是接收两遍,解决不了于是就精简程序。结果还是有问题。按您说的修改了下,将n>29这部分放到上个if语句的循环里,没事了。

我把接收一帧的判断程序稍整理下,再上传过来。您能再帮分析下原因吗?
回复

使用道具 举报

9

主题

50

帖子

0

精华

初级会员

Rank: 2

积分
128
金钱
128
注册时间
2014-5-28
在线时间
16 小时
 楼主| 发表于 2016-6-13 10:26:10 | 显示全部楼层
本帖最后由 any_014 于 2016-6-13 11:56 编辑

现在显示改成这样,主函数里,检测1m标志位,到的话,开SPI2的接收中断,然后等待spi2RecvOk标志置位,spi2RecOk标志应该在spi2接收中断里被置位。标志位被置位后,关spi2中断,然后将接收到的数,通过串口打印出来。

问题是,接收正确,1s串口输出一次接受的数据。但是,用示波器观测,每接收到数据,MISO管脚都有数据发出。按我的设想,应该是打开接收中断时,MISO才会发送输出。

用示波器观测了下波形,MISO一直在发送3a05。感觉,即使关掉SPI2的接收中断,SPI2的发送缓器里的数据也在保存着并一直在发送。
又或者说,中断没关掉?不对,关闭中断这条语句应该执行了,因为串口输出数据语句放在其后,每1秒都会正常输出的。

[mw_shl_code=c,true]if(flag_1ms)        
{
    flag_1ms = 0;
    printf("\r\n1s时间到\r\n");
    SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_RXNE, ENABLE);
    while(spi2RecvOk == 0);
    SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_RXNE, DISABLE);
    printf("\r\nSPI2 recive sucess");
    for(i = 0; i < 5; i++)
        printf("\r\nspi2RecvBuff[%d]: %04x", i, spi2RecvBuff);
    spi2RecvNum = 0;
    spi2RecvOk = 0;
}                [/mw_shl_code]
回复

使用道具 举报

9

主题

50

帖子

0

精华

初级会员

Rank: 2

积分
128
金钱
128
注册时间
2014-5-28
在线时间
16 小时
 楼主| 发表于 2016-6-13 10:50:48 | 显示全部楼层
本帖最后由 any_014 于 2016-6-13 10:54 编辑

尝试不打开/关断SPI2中断,而是打开/关断SPI2使能功能。
结果,上电后,串口打印了四五帧数据后,就不再输出数据了。
感觉像是一直处于SPI2接收中断状态,而进不到主循环里,从而无法关断SPI2了。

[mw_shl_code=c,true]if(flag_1ms)        
{
    flag_1ms = 0;
    printf("\r\n1s时间到\r\n");
    SPI_Cmd(SPI2, ENABLE);
    while(spi2RecvOk == 0);
    SPI_Cmd(SPI2, DISABLE);
    printf("\r\nSPI2 recive sucess");
    for(i = 0; i < 5; i++)
        printf("\r\nspi2RecvBuff[%d]: %04x", i, spi2RecvBuff);
    spi2RecvNum = 0;
    spi2RecvOk = 0;
}[/mw_shl_code]

回复

使用道具 举报

9

主题

50

帖子

0

精华

初级会员

Rank: 2

积分
128
金钱
128
注册时间
2014-5-28
在线时间
16 小时
 楼主| 发表于 2016-6-15 09:23:25 | 显示全部楼层
止天 发表于 2016-6-8 13:39
void SPI2_IRQHandler(void)
{
        static u16 spi2Temp;

改成下面这样就没事了。主要是进入SPI中断后,SPI发送数据尽量靠前一点。也不知道为什么会这样。
在接收完帧首以后的中断处理里,就是else语句,需要将SPI发送语句放在紧靠else语句的位置。
这样的话,原来想只用spi2RecvNum这个变量控制接收和发送的数据位,现在不那么好实现了,于是又加了个变量spi2SendNum。

[mw_shl_code=c,true]void SPI2_IRQHandler(void)
{
        static u8 n;
        static u16 spi2Temp;
        spi2Temp = SPI_I2S_ReceiveData(SPI2);
       
        if(spi2RecvOk == 0)
        {
                if(spi2RecvNum == 0)
                {
                        if((spi2Temp & 0xff00)== 0x3a00)
                        {
                                SPI_I2S_SendData(SPI2, spi2SendBuff[1]);
                                spi2RecvBuff[0] = spi2Temp;
                                spi2RecvNum = 1;
                                spi2SendNum = 2;                               
                        }
                }
                else
                {
                        SPI_I2S_SendData(SPI2, spi2SendBuff[spi2SendNum]);
                        spi2RecvBuff[spi2RecvNum] = spi2Temp;
                        spi2RecvNum++;
                        if(spi2RecvNum > 4)
                                spi2RecvOk = 1;
                        spi2SendNum += 1;
                        spi2SendNum %= 5;
                }
        }       
}[/mw_shl_code]
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-13 23:30

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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