本帖最后由 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
- void USART1_IRQHandler(void)
- {
- /* USER CODE BEGIN USART1_IRQn 0 */
- uint32_t temp;
- /* 如果是串叿1中断 */
- if(USART1 == huart1.Instance)
- { /* 如果是串叿1IDLE中断 */
- if(RESET != __HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE))
- {
- /* 清除中断标志 */
- __HAL_UART_CLEAR_IDLEFLAG(&huart1);
- /* 停止DMA接收 */
- HAL_UART_DMAStop(&huart1);
- /* 获取DMA当前还有多少未填兿 */
- temp = __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
- /* 计算串口接收到的数据个数 */
- Rx_len = BUFFERSIZE - temp;
- recv_end_flag = 1;
- }
- }
-
- /* USER CODE END USART1_IRQn 0 */
- HAL_UART_IRQHandler(&huart1);
- /* USER CODE BEGIN USART1_IRQn 1 */
- /* USER CODE END USART1_IRQn 1 */
- }
复制代码 main.c
main函数中就是普通的循环:
- __HAL_UART_CLEAR_FLAG(&huart1, UART_CLEAR_IDLEF | UART_CLEAR_NEF);
- __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); /* 使能串口1 IDLE中断 */
- HAL_UART_Receive_DMA(&huart1,pR,BUFFERSIZE);
- /* USER CODE END 2 */
-
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- /* USER CODE END WHILE */
-
- /* USER CODE BEGIN 3 */
- uartdmaget();
- }
- /* USER CODE END 3 */
复制代码 uartdmaget这个函数处理所有东西:
- void uartdmaget(void)
- {
- if(recv_end_flag ==1)
- {
- memset(LocalBuff,0,sizeof(LocalBuff));
- memcpy(LocalBuff,ReceiveBuff,sizeof(ReceiveBuff));
- Local_len = Rx_len;
-
- if(Local_len>=21) //只对完整命令译码,否则会出错
- {
- if(decode()==1)
- {
- opcode();
- }
- }
-
- /* 清空接收缓存匿 */
- for(int i = 0; i < Rx_len ; i++)
- ReceiveBuff[i]=0;
-
- /* 接收数据长度清零 */
- Rx_len=0;
- recv_end_flag=0;
-
- /* 开启下次接收 */
- HAL_UART_Receive_DMA(&huart1,pR,BUFFERSIZE);
- }
- }
复制代码 我刚接触STM32不久,对DMA和中断的用法不是很熟,不知道为什么上次没处理的数据会影响下次,或者是我没有完全关闭DMA的接收或是没清缓存?请大牛指点我的问题所在,谢谢!
|
那个AAAA应该是从机给主机的应答,我不明白“第二台从机收到“AAAA”后好像发生了异常。”是怎么回事?
你应该每次发送完就清空从机的接收缓冲区,以免把上次的信息当成本次的信息
评分
查看全部评分
评分
查看全部评分
您好,感谢您的回复
如我文中提到,我将每台从机设计成了接收数据后返回应答指令“AAAA”,主机收到这个后才会对第二个从机进行操作。
但是现在的问题是,第二台从机收到“AAAA”后好像发生了异常。看上去似乎是将“AAAA”收进了缓冲区,在正常命令到来时,和“AAAA”拼在了一起处理。
上面只是我的猜测,请您根据我的代码帮忙看看有没有可能是这样的。 谢谢
评分
查看全部评分
如果你将PC和两个单片机连到一条总线上,那么单片机A发的“AAA”是能够被单片机B收到的。在这种情况下,单片机的程序是需要做些处理,来判断它所收到的“AAA”是另一个单片机发的,还是PC发的。如果处理不了这个,通信是无法正常进行的。
评分
查看全部评分
首先,感谢您的回复
对对!就是这个!我也觉得问题出在我没清从机,但我刚接触不知道怎么清,能赐教么?谢谢
我使用DMA接收,虽然中断里我关了DMA,但好像还是会从UART缓存进来垃圾,从而被当做第二次的数据。
请问我是不是该在中断里也关闭UART呢?还是只要清UART缓存就行了,请问函数是什么呢?
我的电路是每个STM32模块外都串了RS485模块,是自动流控制的。用示波器量出错的单片机的UART端,数据都对,感觉就像有人说的,我没清缓存?
您好,感谢您的回复
我本意是单片机会处理,比如会识别ID,AAAA如果正常处理肯定过不了ID那一关,就扔掉了。但是现在好像是在单片机B忙的时候来了AAAA,这样就没法正常触发中断处理了,而是被存在了缓存中?没扔?这是我猜的,然后和下一个正常数据合并了?
uart不应该关闭,假设接收缓冲区是:Rx_buf[100],
for(i=0;i<100;i++)Rx_Buf=0;
这个谁都会清空,对吧?
感谢您的回复,
您说的我理解了,不过是这样,诸如您说的那个自己写的缓存我也有,我每次也都会清空。错误是发生在用指令从硬件把数据读到缓存时,数据就已经不对了。
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端口,我看不见,它会接收垃圾信息和我这次的有用信息合并,然后当我读操作时,会一并读到缓存里,从而我看到的数据就错了?
让ReceiveBuff[xx]=0x00其实这个USART接收不用DMA好像更容易数据处理
谢谢回复,
我里面也有这样一段:
/* 清空接收缓存匿 */
for(int i = 0; i < Rx_len ; i++)
ReceiveBuff=0;
用来清这个缓存。
但如我说的,第二次的数据来的时候,进ReceiveBuff后就不对了,进之前我可以肯定里面是全0的。
确实也许不用DMA会简单很多,但我目前这个不太方便改了,而且感觉是一些新手错误,毕竟我刚接触这个。可能我描述的不够清楚,您有任何质疑我都很乐意详述,谢谢。
数组!数组!数组!!
ReceiveBuff[i++]=0;而非ReceiveBuff=0;
/* 清空接收缓存匿 */
for(int i = 0; i < Rx_len ; i++)
ReceiveBuff=0;
额 是这么写的 怎么写帖子里就那样了呢