打印
[STM32]

STM32做从设备,循环读取主设备发送的数据,偶尔出错

[复制链接]
2110|19
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
any012|  楼主 | 2016-5-23 17:25 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 any012 于 2016-5-25 15:42 编辑

主设备发送的是:0x3a05,0x010a,0x0100,0x0000,0x9d76
现在用stm32做为spi的从设备,用到的资源有,定时器,串口1,spi2,dma;
定时器用来做1s基准,每1秒开启一次spi2中断使能,中断函数里判断帧首,帧首正确后接收5个16位数据,然后置个标志位。主函数里等待这个标志位被置位,然后关断中断,并将接收到的数据通过串口发送出来。
DMA是用来不停的将另组5个16位数据通过SPI2发送出去(SPI2接收主设备数据时同时将自身的数据发送出去)。

现在的现象是,
1s定时到。
spirecive[0]: 3a05
spirecive[1]: 10a
spirecive[2]: 100
spirecive[3]: 0
spirecive[4]: 9d76
1s定时到。
spirecive[0]: 3a05
spirecive[1]: 3a05
spirecive[2]: 100
spirecive[3]: 0
spirecive[4]: 9d76
1s定时到。
spirecive[0]: 3a05
spirecive[1]: 10a
spirecive[2]: 100
spirecive[3]: 0
spirecive[4]: 9d76
1s定时到。
spirecive[0]: 3a05
spirecive[1]: 10a
spirecive[2]: 100
spirecive[3]: 0
spirecive[4]: 9d76
1s定时到。

几次中会有一次,连续读取到两个3a05。
不知道是什么原因造成的,忘朋友们指教。

------------------------------------------------------------

SPI2中断部分:
void SPI2_IRQHandler(void)
{
        static u8 spi2Num;
        u16 spi2Temp;
        
        spi2Temp = SPI_I2S_ReceiveData(SPI2);        
        if(spi2Num == 0)
        {
                if(spi2Temp == 0x3a05)
                {
                        spi2RecivBuff[0] = spi2Temp;
                        spi2Num = 1;
                }
        }
        else
        {
                spi2RecivBuff[spi2Num] = spi2Temp;
                if(spi2Num++ > 4)
                {
                        spi2Num = 0;
                        spi2RecivOk = 1;
                }
        }
}

主函数:
int main(void)
{
        Init();
        TIM_Cmd(TIM3, ENABLE);                                                        //¿ªÆô¶¨Ê±Æ÷
        
        while(1)
        {
                if(flag_1ms)
                {
                        flag_1ms = 0;
                        printf("\r\n1s¶¨Ê±µ½¡£");
                        SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_RXNE, ENABLE);
                        while(spi2RecivOk == 0);
                        spi2RecivOk = 0;
                        for(i = 0; i < 5; i++)
                                printf("\r\nspirecive[%d]: %x", i, spi2RecivBuff[i]);
                        SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_RXNE, DISABLE);
                }
        }
}

------------------------20160525------------------

上传下工程文件吧,有兴趣有空闲的朋友,帮忙看下吧。



SPI从模式测试.zip

4.38 MB

相关帖子

沙发
any012|  楼主 | 2016-5-23 17:41 | 只看该作者
虽然感觉也有可能确实是连续收到了0x3a05,不过用示波器观察了一阵子,感觉这5个数据是间隔不远传输过来的。示波器观察基本上没观察到连续的0x3a05。

使用特权

评论回复
板凳
泰山特曲123| | 2016-5-24 13:14 | 只看该作者
用逻辑分析仪!你保证关中断的1s内没有spi数据发送过来?

使用特权

评论回复
地板
any012|  楼主 | 2016-5-24 14:11 | 只看该作者
本帖最后由 any012 于 2016-5-24 14:12 编辑

逻辑分析仪...
没用过,身边也没有...
spi中断优先级高过串口中断高过定时器中断。

void NVIC_Configuration(void)
{
        NVIC_InitTypeDef NVIC_InitStructure;
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
       
        NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
       
        NVIC_InitStructure.NVIC_IRQChannel = SPI2_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
       
        NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
}


使用特权

评论回复
5
ningling_21| | 2016-5-24 16:18 | 只看该作者
any012 发表于 2016-5-24 14:11
逻辑分析仪...
没用过,身边也没有...
spi中断优先级高过串口中断高过定时器中断。

程序分解调试,先调试SPI2数据接收,接收没问题再一步一步加入其它功能

使用特权

评论回复
6
yangxf1217| | 2016-5-24 16:26 | 只看该作者
关注。。。

使用特权

评论回复
7
any012|  楼主 | 2016-5-24 17:00 | 只看该作者
ningling_21 发表于 2016-5-24 16:18
程序分解调试,先调试SPI2数据接收,接收没问题再一步一步加入其它功能

现在的程序,只保留了调试用到的部分。
串口用来输出调试信息。
定时器用来做1秒时基,开启SPI中断用。

主设备发送数据挺频繁的,我做的这个从设备不能每次都响应。想做成1秒响应一次:
即1秒时间基准到的时候,开启中断,判断帧首后接收总共5个16位数据后,置个标志位,然后关中断,将接收的数据通过串口发送出来。

主设备每次发送数据必须有响应,故现在暂时用spi2的DMA功能,发送固定数据。

使用特权

评论回复
8
yklstudent| | 2016-5-25 08:47 | 只看该作者
接收数据搞个环形缓冲区,中断接收数据就负责存储数据;
主函数负责处理数据

使用特权

评论回复
9
any012|  楼主 | 2016-5-25 08:49 | 只看该作者
yklstudent 发表于 2016-5-25 08:47
接收数据搞个环形缓冲区,中断接收数据就负责存储数据;
主函数负责处理数据 ...

那么,主函数里如何判断帧首?对缓冲区里的数据一个一个辨别?

使用特权

评论回复
10
yklstudent| | 2016-5-25 09:22 | 只看该作者
这就要看协议了;
比如协议格式
帧头 命令码 功能码 数据长度 数据内容 校验码
先判断缓冲器内数据个数,大于帧头+命令码长度就判断缓冲区内数据是否符合要求,不符合就读出,直到读取到帧头+命令码,然后就继续往下判断读取数据

使用特权

评论回复
11
any012|  楼主 | 2016-5-25 09:40 | 只看该作者
yklstudent 发表于 2016-5-25 09:22
这就要看协议了;
比如协议格式
帧头 命令码 功能码 数据长度 数据内容 校验码

缓冲区不是循环存储的吗?这样应该总是满的吧?难道是处理完一帧信息后清空缓冲区?
感谢回复,回头试试这种方法。

使用特权

评论回复
12
yklstudent| | 2016-5-25 11:21 | 只看该作者
any012 发表于 2016-5-25 09:40
缓冲区不是循环存储的吗?这样应该总是满的吧?难道是处理完一帧信息后清空缓冲区?
感谢回复,回头试试 ...

如果你的缓冲区是循环处理,为了不丢失数据包,你就该确保缓冲区不能存在存满的时候,否则就极易丢失数据包,所以你就该尽可能的提高你的数据处理速度

使用特权

评论回复
13
yklstudent| | 2016-5-25 11:21 | 只看该作者
any012 发表于 2016-5-25 09:40
缓冲区不是循环存储的吗?这样应该总是满的吧?难道是处理完一帧信息后清空缓冲区?
感谢回复,回头试试 ...

如果你的缓冲区是循环处理,为了不丢失数据包,你就该确保缓冲区不能存在存满的时候,否则就极易丢失数据包,所以你就该尽可能的提高你的数据处理速度

使用特权

评论回复
14
yklstudent| | 2016-5-25 11:21 | 只看该作者
any012 发表于 2016-5-25 09:40
缓冲区不是循环存储的吗?这样应该总是满的吧?难道是处理完一帧信息后清空缓冲区?
感谢回复,回头试试 ...

如果你的缓冲区是循环处理,为了不丢失数据包,你就该确保缓冲区不能存在存满的时候,否则就极易丢失数据包,所以你就该尽可能的提高你的数据处理速度

使用特权

评论回复
15
yklstudent| | 2016-5-25 11:21 | 只看该作者
any012 发表于 2016-5-25 09:40
缓冲区不是循环存储的吗?这样应该总是满的吧?难道是处理完一帧信息后清空缓冲区?
感谢回复,回头试试 ...

如果你的缓冲区是循环处理,为了不丢失数据包,你就该确保缓冲区不能存在存满的时候,否则就极易丢失数据包,所以你就该尽可能的提高你的数据处理速度

使用特权

评论回复
16
killer2014| | 2016-5-25 15:03 | 只看该作者
程序配置的问题, 很多条件运行在边界上, 希望再找找看看

使用特权

评论回复
17
any012|  楼主 | 2016-5-25 15:43 | 只看该作者
killer2014 发表于 2016-5-25 15:03
又需要,可以联系我, 帮你解决。

已在顶楼上传工程文件,有空的话,请帮看下。

使用特权

评论回复
18
any012|  楼主 | 2016-6-15 09:25 | 只看该作者
改成下面这样就没事了。主要是进入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]

使用特权

评论回复
19
any012|  楼主 | 2016-12-3 09:00 | 只看该作者
问题的原因是,发送数据太快,没来得及做相应处理。
解决办法,让主设备发送数据的间隔大一点,或尽量精简中断处理部分。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

35

主题

232

帖子

6

粉丝