完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
前言
在STM32常用串口协议实现与其它外设交互数据,发送数据简单,但是如何方便快捷的处理通过串口接收到的数据并没那么简单。在STM32中,USART发送接收有三种方式:轮询,中断,DMA。其中轮询的方式过于笨拙,一般本人不会选择这种方式,下文中将从中断方式,IDLE+DMA方式进行介绍,以及如何对循环数组中的数据提取当次接收的数据。 一、中断方式 发送方式: HAL_UART_Transmit(&huart1, (uint8_t*)"testrn", 7, 0xFFFF); 调用此函数即可输出字符串 接收方式: HAL_UART_Receive_IT(&huart1, data_rec, 10); 使用此函数后,即可当串口收到数据后便往data_rec数组里存数据,存了10个数据以后,会自动调用回调函数 void HAL_UART_RxCpltCallback(UART_HandleTypeDef* huart) 在此函数中,即可对存入的10个数据统一进行处理。这种方式勉强能实现功能,但是谈不上方便,缺点如下: 首先HAL_UART_Receive_IT函数是一次性的,在传递10个数据以后便不再传了,需要循环调用该函数才能一直传数据,这种方式对于我这种懒人来说属实难受; 另外,只有当传递完10个数据才能通过回调函数进行处理,那么对于不定长的数据岂不是很不友好? 每次来一个字符就进一次中断,会占用一部分CPU的资源 为了解决上述痛点,引入下面这种解决方案 二、空闲中断+DMA 空闲中断(IDLE)简单来说,就是检测到接收数据后,在数据总线上的一个字节时间内,没有接收到数据触发空闲中断。RXNE置位一次,空闲总线就检测一次!另外为了减少误进入串口空闲中断,串口RX的IO管脚一定设置成Pull-up<上拉模式>。 __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//使能空闲中断 DMA就不做详细介绍了,它的作用就是不断的将串口接收到的数据转移到内存中(程序中定义存数据的数组),将其配置为循环模式,则可以初始化一次,就拥有一个永久的搬运工了。当一帧数据搬完以后,空闲中断就会触发,此时代码中就可以去对数组中的数据进行处理了。 HAL_UART_Receive_DMA(&huart1, data_rec, 10);//告诉DMA传送地址及数据长度 上面介绍了IDLE和DMA相互配合的逻辑,下面介绍如何对数据进行提取。因为不同帧的数据都在同一个数组中,如何分开它们是一个问题。首先得知道DMA搬运的效果是怎么样的,利用stlink的在线仿真,能看到数据从数组的头开始存放,一直到末尾,然后多余的数据将会从头继续存放,覆盖掉原先的数据,如此往复,类似于一个循环数组。 为了定位本次帧在数组中的起始位置和终止位置,需要用到函数 __HAL_DMA_GET_COUNTER() 1 此函数可以获得经过此次数据传递后,该数组还剩余多少空间,比如第一次传了4个数据,那么此函数返回值即为10-4=6,第二次传了3个数据,那么此函数返回值为10-3-4=3,第三次传了3个数据,理论上是10-3-3-4=0;然而此函数返回值为10,这是需要注意的地方,空的同时也是满! 基于上述的描述,提取当次帧的函数如下: void USER_UART_IDLECallback(UART_HandleTypeDef *huart) { static uint8_t pre_index,now_index = 0; now_index = length - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx); //当前指向的位置 Ble_DataProcess(pre_index,now_index); pre_index = now_index; } void Ble_DataProcess(uint8_t pre_index,uint8_t now_index) { uint8_t i,j,temp_index = 0; if(now_index <= pre_index) { temp_index = now_index + length; } else{ temp_index = now_index; } j=0; for(i=0;i temp[j] = 0; j++; } j=0; for(i=pre_index;i temp[j] = data_rec[i%length]; j++; } HAL_UART_Transmit(&huart1, temp, length, 0xFFFF); } 大家稍微看一下应该能理清里面逻辑。 最后提一下串口DMA的发送方式 HAL_UART_Receive_DMA(); 使用此函数发送数据出现一个问题:不能连续使用此函数进行数据发送,自己理解的原因大概是第一个DMA在传送数据的并没有传完,而第二个DMA数据发送请求就到了,因此第二个DMA传送函数便无法执行。解决办法:可以延时一段时间;也可以加个while循环,当判断第一个DMA传送数据完成后才跳出。 个人更倾向于直接用HAL_UART_Transmit(),毕竟人懒,就喜欢代码写的少的,哈哈哈。 总结 以后再遇到关于串口接收不定长数据的情形时就可采用上述方法,如果理解有困难或者想知道在STM32CubeMX中的相关配置,可以点击这里下载完整工程代码 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1763 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1617 浏览 1 评论
1059 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
723 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1670 浏览 2 评论
1933浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
726浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
566浏览 3评论
592浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
550浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-21 10:15 , Processed in 0.655730 second(s), Total 47, Slave 41 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号