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

[复制链接]
2497|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中断部分:
  1. void SPI2_IRQHandler(void)
  2. {
  3.         static u8 spi2Num;
  4.         u16 spi2Temp;
  5.         
  6.         spi2Temp = SPI_I2S_ReceiveData(SPI2);        
  7.         if(spi2Num == 0)
  8.         {
  9.                 if(spi2Temp == 0x3a05)
  10.                 {
  11.                         spi2RecivBuff[0] = spi2Temp;
  12.                         spi2Num = 1;
  13.                 }
  14.         }
  15.         else
  16.         {
  17.                 spi2RecivBuff[spi2Num] = spi2Temp;
  18.                 if(spi2Num++ > 4)
  19.                 {
  20.                         spi2Num = 0;
  21.                         spi2RecivOk = 1;
  22.                 }
  23.         }
  24. }

主函数:
  1. int main(void)
  2. {
  3.         Init();
  4.         TIM_Cmd(TIM3, ENABLE);                                                        //¿ªÆô¶¨Ê±Æ÷
  5.         
  6.         while(1)
  7.         {
  8.                 if(flag_1ms)
  9.                 {
  10.                         flag_1ms = 0;
  11.                         printf("\r\n1s¶¨Ê±µ½¡£");
  12.                         SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_RXNE, ENABLE);
  13.                         while(spi2RecivOk == 0);
  14.                         spi2RecivOk = 0;
  15.                         for(i = 0; i < 5; i++)
  16.                                 printf("\r\nspirecive[%d]: %x", i, spi2RecivBuff[i]);
  17.                         SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_RXNE, DISABLE);
  18.                 }
  19.         }
  20. }

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

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



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| 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中断优先级高过串口中断高过定时器中断。

  1. void NVIC_Configuration(void)
  2. {
  3.         NVIC_InitTypeDef NVIC_InitStructure;
  4.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  5.        
  6.         NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  7.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
  8.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
  9.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  10.         NVIC_Init(&NVIC_InitStructure);
  11.        
  12.         NVIC_InitStructure.NVIC_IRQChannel = SPI2_IRQn;
  13.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  14.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
  15.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  16.         NVIC_Init(&NVIC_InitStructure);
  17.        
  18.         NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
  19.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  20.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
  21.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  22.         NVIC_Init(&NVIC_InitStructure);
  23. }


ningling_21 发表于 2016-5-24 16:18 | 显示全部楼层
any012 发表于 2016-5-24 14:11
逻辑分析仪...
没用过,身边也没有...
spi中断优先级高过串口中断高过定时器中断。

程序分解调试,先调试SPI2数据接收,接收没问题再一步一步加入其它功能
yangxf1217 发表于 2016-5-24 16:26 | 显示全部楼层
关注。。。
 楼主| any012 发表于 2016-5-24 17:00 | 显示全部楼层
ningling_21 发表于 2016-5-24 16:18
程序分解调试,先调试SPI2数据接收,接收没问题再一步一步加入其它功能

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

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

主设备每次发送数据必须有响应,故现在暂时用spi2的DMA功能,发送固定数据。
yklstudent 发表于 2016-5-25 08:47 | 显示全部楼层
接收数据搞个环形缓冲区,中断接收数据就负责存储数据;
主函数负责处理数据
 楼主| any012 发表于 2016-5-25 08:49 | 显示全部楼层
yklstudent 发表于 2016-5-25 08:47
接收数据搞个环形缓冲区,中断接收数据就负责存储数据;
主函数负责处理数据 ...

那么,主函数里如何判断帧首?对缓冲区里的数据一个一个辨别?
yklstudent 发表于 2016-5-25 09:22 | 显示全部楼层
这就要看协议了;
比如协议格式
帧头 命令码 功能码 数据长度 数据内容 校验码
先判断缓冲器内数据个数,大于帧头+命令码长度就判断缓冲区内数据是否符合要求,不符合就读出,直到读取到帧头+命令码,然后就继续往下判断读取数据
 楼主| any012 发表于 2016-5-25 09:40 | 显示全部楼层
yklstudent 发表于 2016-5-25 09:22
这就要看协议了;
比如协议格式
帧头 命令码 功能码 数据长度 数据内容 校验码

缓冲区不是循环存储的吗?这样应该总是满的吧?难道是处理完一帧信息后清空缓冲区?
感谢回复,回头试试这种方法。
yklstudent 发表于 2016-5-25 11:21 | 显示全部楼层
any012 发表于 2016-5-25 09:40
缓冲区不是循环存储的吗?这样应该总是满的吧?难道是处理完一帧信息后清空缓冲区?
感谢回复,回头试试 ...

如果你的缓冲区是循环处理,为了不丢失数据包,你就该确保缓冲区不能存在存满的时候,否则就极易丢失数据包,所以你就该尽可能的提高你的数据处理速度
yklstudent 发表于 2016-5-25 11:21 | 显示全部楼层
any012 发表于 2016-5-25 09:40
缓冲区不是循环存储的吗?这样应该总是满的吧?难道是处理完一帧信息后清空缓冲区?
感谢回复,回头试试 ...

如果你的缓冲区是循环处理,为了不丢失数据包,你就该确保缓冲区不能存在存满的时候,否则就极易丢失数据包,所以你就该尽可能的提高你的数据处理速度
yklstudent 发表于 2016-5-25 11:21 | 显示全部楼层
any012 发表于 2016-5-25 09:40
缓冲区不是循环存储的吗?这样应该总是满的吧?难道是处理完一帧信息后清空缓冲区?
感谢回复,回头试试 ...

如果你的缓冲区是循环处理,为了不丢失数据包,你就该确保缓冲区不能存在存满的时候,否则就极易丢失数据包,所以你就该尽可能的提高你的数据处理速度
yklstudent 发表于 2016-5-25 11:21 | 显示全部楼层
any012 发表于 2016-5-25 09:40
缓冲区不是循环存储的吗?这样应该总是满的吧?难道是处理完一帧信息后清空缓冲区?
感谢回复,回头试试 ...

如果你的缓冲区是循环处理,为了不丢失数据包,你就该确保缓冲区不能存在存满的时候,否则就极易丢失数据包,所以你就该尽可能的提高你的数据处理速度
killer2014 发表于 2016-5-25 15:03 | 显示全部楼层
程序配置的问题, 很多条件运行在边界上, 希望再找找看看
 楼主| any012 发表于 2016-5-25 15:43 | 显示全部楼层
killer2014 发表于 2016-5-25 15:03
又需要,可以联系我, 帮你解决。

已在顶楼上传工程文件,有空的话,请帮看下。
 楼主| 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]
 楼主| any012 发表于 2016-12-3 09:00 | 显示全部楼层
问题的原因是,发送数据太快,没来得及做相应处理。
解决办法,让主设备发送数据的间隔大一点,或尽量精简中断处理部分。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

35

主题

232

帖子

6

粉丝
快速回复 在线客服 返回列表 返回顶部