你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【求助】多个STM32相连的冲突问题

[复制链接]
newton64 提问时间:2018-3-14 14:42 /
本帖最后由 newton64 于 2018-3-14 14:46 编辑

目前架构:
PC下连了两个STM32模块,用STM32的UART通过RS485模块互连。

实现功能:
只是想实现正常通讯(简单读写寄存器),两个STM32烧录同样的东西(除了ID)。
UART使用DMA收发,IDLE中断。
在正常写寄存器后,应答“AAAA”(字符)

问题描述:
    正常时:此时两片的代码都插入了一些printf,从UART2中打印出调试信息,可以清楚看到:电脑发送1号STM32的写命令,1号识别ID进行写操作,2号ID不匹配,不应答。然后1号回复了“AAAA”。重复多次操作无异常。之后同时去掉了两片中的printf,运行变快,也无异常。
    异常时:只去掉1号的printf,保留2号的printf(1号快,2号慢)。进行写操作,第一遍正常,1号完成了写操作(是从点灯看出来的),2号的调试信息表示ID不匹配,不应答。1号回复“AAAA”。但从第二次开始,1号仍然正常工作,但2号收到的数据就不对了。

以下是2号收到正常与异常的数据:
A857A857001F00295732570B040134300100000049884AC4
57A857411F0029A832570B000134305700000004884AC40100000049

我用示波器看了UART线上的数据,是正常的。而二号中断后收到的很奇怪,多出来一些数据,而且头一个“A8”不见了,中间还有错的。

===========================================现象就是这样↑

我非常怀疑是1号回复的"AAAA"被2号收到后影响的。平时两片同时开或关printf,使得两片速度一样,同时接受数据后触发IDLE中断,开始处理,2号早早处理完了,等1号发“AAAA”时,2号是空闲的,可以正常接受一次,做不应答处理。
但当1号快2号慢时,2号还未处理完第一条命令,1号的“AAAA”就来了,这时我感觉就出了问题,但不知道为啥。

我本意是2号处理时,不再接受其它东西,但显然还是有影响的,下面是代码:

_it.c

  1. void USART1_IRQHandler(void)
  2. {
  3.   /* USER CODE BEGIN USART1_IRQn 0 */
  4.     uint32_t temp;
  5.     /*        如果是串叿1中断        */
  6.     if(USART1 == huart1.Instance)
  7.     {        /* 如果是串叿1IDLE中断        */
  8.         if(RESET != __HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE))
  9.         {
  10.             /*        清除中断标志        */
  11.             __HAL_UART_CLEAR_IDLEFLAG(&huart1);
  12.             /*        停止DMA接收        */
  13.             HAL_UART_DMAStop(&huart1);
  14.             /*        获取DMA当前还有多少未填兿        */
  15.             temp = __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
  16.             /*        计算串口接收到的数据个数        */
  17.             Rx_len = BUFFERSIZE - temp;
  18.             recv_end_flag = 1;
  19.         }
  20.     }

  21.   /* USER CODE END USART1_IRQn 0 */
  22.   HAL_UART_IRQHandler(&huart1);
  23.   /* USER CODE BEGIN USART1_IRQn 1 */
  24.   /* USER CODE END USART1_IRQn 1 */
  25. }
复制代码
main.c

main函数中就是普通的循环:

  1. __HAL_UART_CLEAR_FLAG(&huart1, UART_CLEAR_IDLEF | UART_CLEAR_NEF);  
  2.   __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);  /*        使能串口1 IDLE中断        */
  3.     HAL_UART_Receive_DMA(&huart1,pR,BUFFERSIZE);
  4.   /* USER CODE END 2 */

  5.   /* Infinite loop */
  6.   /* USER CODE BEGIN WHILE */
  7.   while (1)
  8.   {
  9.   /* USER CODE END WHILE */

  10.   /* USER CODE BEGIN 3 */
  11.         uartdmaget();
  12.   }
  13.   /* USER CODE END 3 */
复制代码
uartdmaget这个函数处理所有东西:
  1. void uartdmaget(void)
  2. {
  3.     if(recv_end_flag ==1)
  4.     {
  5.         memset(LocalBuff,0,sizeof(LocalBuff));
  6.         memcpy(LocalBuff,ReceiveBuff,sizeof(ReceiveBuff));
  7.         Local_len = Rx_len;
  8.          
  9.         if(Local_len>=21)    //只对完整命令译码,否则会出错
  10.         {
  11.             if(decode()==1)
  12.             {
  13.                 opcode();
  14.             }
  15.         }   
  16.          
  17.         /*        清空接收缓存匿        */
  18.         for(int i = 0; i < Rx_len ; i++)
  19.                 ReceiveBuff[i]=0;
  20.          
  21.         /*        接收数据长度清零        */
  22.         Rx_len=0;
  23.         recv_end_flag=0;
  24.          
  25.         /*        开启下次接收        */
  26.         HAL_UART_Receive_DMA(&huart1,pR,BUFFERSIZE);
  27.     }
  28. }
复制代码
我刚接触STM32不久,对DMA和中断的用法不是很熟,不知道为什么上次没处理的数据会影响下次,或者是我没有完全关闭DMA的接收或是没清缓存?请大牛指点我的问题所在,谢谢!
收藏 评论15 发布时间:2018-3-14 14:42

举报

15个回答
wenyangzeng 回答时间:2018-3-14 16:08:39
本帖最后由 wenyangzeng 于 2018-3-14 16:10 编辑
newton64 发表于 2018-3-14 15:55
您好,感谢您的回复

如我文中提到,我将每台从机设计成了接收数据后返回应答指令“AAAA”,主机收到这个 ...

那个AAAA应该是从机给主机的应答,我不明白“第二台从机收到“AAAA”后好像发生了异常。”是怎么回事?
你应该每次发送完就清空从机的接收缓冲区,以免把上次的信息当成本次的信息

评分

参与人数 1ST金币 +1 收起 理由
newton64 + 1 很给力!

查看全部评分

wenyangzeng 回答时间:2018-3-14 15:39:43
RS485通讯进程由主机调度,主机必须等某台从机完全发送完数据后才能请求另一台丛机发送数据。你应该在每台从机发送完数据后给主机一个结束标志应答信号,主机接收到应答信号后才能请求另外从机发送。

评分

参与人数 1蝴蝶豆 +3 收起 理由
zero99 + 3

查看全部评分

newton64 回答时间:2018-3-14 15:55:04
wenyangzeng 发表于 2018-3-14 15:39
RS485通讯进程由主机调度,主机必须等某台从机完全发送完数据后才能请求另一台丛机发送数据。你应该在每台 ...

您好,感谢您的回复

如我文中提到,我将每台从机设计成了接收数据后返回应答指令“AAAA”,主机收到这个后才会对第二个从机进行操作。
但是现在的问题是,第二台从机收到“AAAA”后好像发生了异常。看上去似乎是将“AAAA”收进了缓冲区,在正常命令到来时,和“AAAA”拼在了一起处理。

上面只是我的猜测,请您根据我的代码帮忙看看有没有可能是这样的。 谢谢
蚁族 回答时间:2018-3-14 16:12:40
你的电路是怎么接的,UART的串口发送输出引脚是输出模式,是不是发送端口的冲突了!

评分

参与人数 1蝴蝶豆 +2 收起 理由
zero99 + 2

查看全部评分

uwyciw100 回答时间:2018-3-14 16:25:20
newton64 发表于 2018-3-14 15:55
您好,感谢您的回复

如我文中提到,我将每台从机设计成了接收数据后返回应答指令“AAAA”,主机收到这个 ...

如果你将PC和两个单片机连到一条总线上,那么单片机A发的“AAA”是能够被单片机B收到的。在这种情况下,单片机的程序是需要做些处理,来判断它所收到的“AAA”是另一个单片机发的,还是PC发的。如果处理不了这个,通信是无法正常进行的。

评分

参与人数 1蝴蝶豆 +3 收起 理由
zero99 + 3

查看全部评分

newton64 回答时间:2018-3-14 16:32:03
wenyangzeng 发表于 2018-3-14 16:08
那个AAAA应该是从机给主机的应答,我不明白“第二台从机收到“AAAA”后好像发生了异常。”是怎么回事?
你 ...

首先,感谢您的回复

对对!就是这个!我也觉得问题出在我没清从机,但我刚接触不知道怎么清,能赐教么?谢谢

我使用DMA接收,虽然中断里我关了DMA,但好像还是会从UART缓存进来垃圾,从而被当做第二次的数据。

请问我是不是该在中断里也关闭UART呢?还是只要清UART缓存就行了,请问函数是什么呢?
newton64 回答时间:2018-3-14 16:34:17
yizushijie 发表于 2018-3-14 16:12
你的电路是怎么接的,UART的串口发送输出引脚是输出模式,是不是发送端口的冲突了! ...

我的电路是每个STM32模块外都串了RS485模块,是自动流控制的。用示波器量出错的单片机的UART端,数据都对,感觉就像有人说的,我没清缓存?
newton64 回答时间:2018-3-14 16:36:37
uwyciw100 发表于 2018-3-14 16:25
如果你将PC和两个单片机连到一条总线上,那么单片机A发的“AAA”是能够被单片机B收到的。在这种情况下, ...

您好,感谢您的回复

我本意是单片机会处理,比如会识别ID,AAAA如果正常处理肯定过不了ID那一关,就扔掉了。但是现在好像是在单片机B忙的时候来了AAAA,这样就没法正常触发中断处理了,而是被存在了缓存中?没扔?这是我猜的,然后和下一个正常数据合并了?
wenyangzeng 回答时间:2018-3-14 16:49:53
newton64 发表于 2018-3-14 16:32
首先,感谢您的回复

对对!就是这个!我也觉得问题出在我没清从机,但我刚接触不知道怎么清,能赐教么? ...

uart不应该关闭,假设接收缓冲区是:Rx_buf[100],
for(i=0;i<100;i++)Rx_Buf=0;
这个谁都会清空,对吧?
newton64 回答时间:2018-3-14 17:00:49
wenyangzeng 发表于 2018-3-14 16:49
uart不应该关闭,假设接收缓冲区是:Rx_buf[100],
for(i=0;i

感谢您的回复,

您说的我理解了,不过是这样,诸如您说的那个自己写的缓存我也有,我每次也都会清空。错误是发生在用指令从硬件把数据读到缓存时,数据就已经不对了。

HAL_UART_Receive_DMA(&huart1,pR,BUFFERSIZE);

我用的DMA,所以这句里的pR就是我指向缓存的指针。

#define BUFFERSIZE 80                                
uint32_t ReceiveBuff[BUFFERSIZE];        //接收缓冲匿
uint8_t *pR=(uint8_t *)&ReceiveBuff[0];
(这里的8位32位的原因是因为我用CRC32,所以就转了一下)

也就是说当数据到ReceiveBuff的时候数据就已经错了,我其实是有个疑问:是不是有个硬件缓存在UART端口,我看不见,它会接收垃圾信息和我这次的有用信息合并,然后当我读操作时,会一并读到缓存里,从而我看到的数据就错了?
wenyangzeng 回答时间:2018-3-14 17:02:16
本帖最后由 wenyangzeng 于 2018-3-14 17:03 编辑
newton64 发表于 2018-3-14 17:00
感谢您的回复,

您说的我理解了,不过是这样,诸如您说的那个自己写的缓存我也有,我每次也都会清空。错 ...

让ReceiveBuff[xx]=0x00其实这个USART接收不用DMA好像更容易数据处理
newton64 回答时间:2018-3-14 17:08:20
wenyangzeng 发表于 2018-3-14 17:02
让ReceiveBuff[xx]=0x00其实这个USART接收不用DMA好像更容易数据处理

谢谢回复,

我里面也有这样一段:

/*        清空接收缓存匿        */
                for(int i = 0; i < Rx_len ; i++)
                                ReceiveBuff=0;

用来清这个缓存。
但如我说的,第二次的数据来的时候,进ReceiveBuff后就不对了,进之前我可以肯定里面是全0的。

确实也许不用DMA会简单很多,但我目前这个不太方便改了,而且感觉是一些新手错误,毕竟我刚接触这个。可能我描述的不够清楚,您有任何质疑我都很乐意详述,谢谢。
wenyangzeng 回答时间:2018-3-14 17:57:07
newton64 发表于 2018-3-14 17:08
谢谢回复,

我里面也有这样一段:

数组!数组!数组!!
ReceiveBuff[i++]=0;而非ReceiveBuff=0;
newton64 回答时间:2018-3-14 18:29:48
wenyangzeng 发表于 2018-3-14 17:57
数组!数组!数组!!
ReceiveBuff=0;而非ReceiveBuff=0;

/*        清空接收缓存匿        */
                for(int i = 0; i < Rx_len ; i++)
                                ReceiveBuff=0;

额 是这么写的 怎么写帖子里就那样了呢

  1. /*        清空接收缓存匿        */
  2.                 for(int i = 0; i < Rx_len ; i++)
  3.                                 ReceiveBuff[i]=0;
复制代码
12下一页

所属标签

相似问题

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版