“我报名参加金石计划1期应战——分割10万奖池,这是我的第10篇文章,点击查看活动详情”
运用篇-在STM32L051上运用RT-Thread 第四篇,巧妙的运用信号量处理串口通讯。
前言
在上一篇文章,咱们完结了温湿度驱动移植,依据咱们开端的根本规划思路,还有必需求完结的无线模块串口通讯,本文就来移植一下无线模块的串口通讯驱动。
再次阐明一下,本运用篇重点在于了解在 RT-Thread 上的规划思路 以及 在小内存芯片上的注意事项,所以根底的驱动代码的完结并不会具体的分析阐明,可是博主在把本系列更新完今后会把最终的整个项目上传,所以实在想看驱动完结的朋友到时分也能够去下载。
本 RT-Thread 专栏记载的开发环境:
RT-Thread记载(一、RT-Thread 版别、RT-Thread Studio开发环境 及 合作CubeMX开发快速上手)
RT-Thread记载(二、RT-Thread内核发动流程 — 发动文件和源码分析)
RT-Thread 内核篇系列博文链接:
RT-Thread记载(三、RT-Thread 线程操作函数及线程办理与FreeRTOS的比较)
RT-Thread记载(四、RT-Thread 时钟节拍和软件定时器)
RT-Thread记载(五、RT-Thread 临界区维护)
RT-Thread记载(六、IPC机制之信号量、互斥量和事情集)
RT-Thread记载(七、IPC机制之邮箱、音讯队列)
RT-Thread记载(八、了解 RT-Thread 内存办理)
RT-Thread记载(九、RT-Thread 中止处理与阶段小结)
在STM32L051C8 上运用 RT-Thread 运用篇系列博文衔接:
RT-Thread 运用篇 — 在STM32L051上运用 RT-Thread (一、无线温湿度传感器 之 新建项目)
RT-Thread 运用篇 — 在STM32L051上运用 RT-Thread (二、无线温湿度传感器 之 CubeMX配置)
RT-Thread 运用篇 — 在STM32L051上运用 RT-Thread (三、无线温湿度传感器 之 I2C通讯)
一、规划思路阐明
咱们STM32L051C8与无线模块通讯的串口是LPUART1
(对应 pin to pin 的STM32F103C8 是串口3),运用的是中止方法接纳,所以当时在CubeMX 设置的时分咱们就需求使能中止。
STM32串口中止接纳是很根底问题,本文的目的不在于阐明STM32怎样进行串口通讯,所以并不会具体阐述怎样运用串口接纳,咱们只做简略阐明:
关于STM32 的串口接纳中止,咱们一般会使能UART_IT_RXNE
或许UART_IT_IDLE
。
简略阐明一下,假如串口收到一个字节就会发生RXNE
中止,假如接纳完结一帧数据,就会发生IDLE
中止。
依据我自己运用的经验,这个 IDLE
中止所谓的一帧数据,是 stm32 内部本身依据自己主频,波特率等一些参数作为判别依据,本质上也是认为在多长的时刻内没有收到新的数据就当成一帧。
再依据曾经的运用经验和测验,我运用的无线通讯模块给 STM32 发送一帧数据,会触发两次IDLE
中止,这个具体也没有深究,由于本身无线通讯模块也是靠自己的单片机内核发送数据,或许模块内部有点特别处理,通过这个问题我也发现IDLE
不是万能的一帧数据,在遇到一些特别模块的时分也会有问题。当然,在我运用的其他设备,一切串口通讯的传感器上,运用IDLE
作为一帧数据接纳完结的判别都是没问题的。
当时的测验博文:STM32L051测验 (五、Enocean模块串口通讯问题)
所以,尽管咱们本次模块接纳的是不定长度,可是咱们这儿仍是不运用IDLE
作为一帧数据的判别,咱们只运用RXNE
中止。
为了更加直观的了解咱们的规划思路,我也不准备运用 DMA 通方法。
综上,本次运用的规划思路是:只使能RXNE
中止,当接纳到第一个字节,开释一个信号量。
另外一边,串口接纳线程一直在等候这个信号量,假如获取到信号量,等候必定时刻(等候必定时刻是为了确保接纳到完好的一帧数据,一般便是几个ms),然后进行数据处理。
发送数据的话就简略,写好驱动,组包发送即可。
为了接纳数据,咱们需求界说个全局变量数组作为缓冲区。
后来在实际运用的时分这个思路略微修正了一下,由于每次发生中止,都会发送一次信号量,那么一帧数据有多少个字节,就会发送多少个信号量,那么等候信号量的线程就会不停的获取到信号量,那么咱们怎样来处理?且看下文……
二、驱动移植
由于博主运用的Enocean模块并不是通用干流的通讯模块,是公司需求运用的,考虑到各种问题,也不方便把模块具体的介绍一遍,可是这并不影响我阐明程序的移植和串口的运用思路,我们不需求在意内部的具体完结,只要理解我在 STM32L051C8 上 RT-Thread 是怎样处理串口数据的即可。
首要咱们把需求保存接纳数据的数组界说一下:
这个全局数据可是直接占用了一大块 RAM 空间,enoncean_buff多大就占用多大,可是这是没有办法的!
然后依据上一篇文章的阐明,咱们直接把.c 和.h文件拷贝到咱们的 mydrivers 目录下:
编译一下看看:
其中,上面的警告提示咱们还需求完结1个函数,便是串口发送数据的函数,咱们也移植过来,加在CubMX串口驱动文件中:
完结好这些根本上整体上没问题了,然后需求做一些移植过来代码的细节修正,细节修正这儿就不逐个阐明,咱们运用一个典型的当地举个比方。裸机中,除了中止一切的操作都是先后进行的,所以有许多延时函数是干等,在运用 RT-Thread 的时分这些函数都得去掉,比方
三、信号量的处理
信号量的处理算得上本文的重点了,原本咱们在 RT-Thread Nano 上运用串口通讯,完全能够依照裸机的方法来,界说全局变量然后线程轮询接纳函数,可是这儿我仍是想着没有音讯的时分线程轮询完全是浪费资源,我得发挥操作系统的优势。 至少做到,只要音讯来的时分线程才会唤醒去履行,其他时分都是阻塞状态。
尽管信号量处理的方法并不是最优的,当然也是本着测验的原则,来尝试一下。
再次注意,咱们在本运用第一篇就阐明过,只能运用静态初始化的方法创建目标,信号量也不例外,测验时分还在这儿出错了。 = =!
3.1 开释信号量
首要初始化信号量,中止呼应函数中做根本的处理:
注意,有一个HAL库的根本运用问题,什么时分才会调用HAL_UART_RxCpltCallback
中处理,咱们用户的处理能够在原始的中止向量表对应的函数LPUART1_IRQHandler
中处理,也能够在上图的HAL_UART_RxCpltCallback
中处理。
同时,数据处理的方法要注意,标志着缓冲数组个数的 Enocean_Data是否需求先++,也是需求注意。
这些其实是STM32 HAL库运用的根本知识,在下面《4.2 串口通讯细节问题》会有阐明。
假如在LPUART1_IRQHandler
中处理也能够,数据处理是放在HAL_UART_IRQHandler(&hlpuart1);
前面仍是后面也是有考究的:
3.2 获取信号量
考虑到内存不行,不想再新建线程作为数据接纳处理了,直接把数据接纳处理放在主函数线程里面,这儿给出根本的结构:
其实两句代码便是本文核心结构~ ~
四、根本测验
咱们先测验根本的接纳函数移植是否正常,然后再测验发送函数。
4.1 接纳测验
完结上面的进程,咱们基于上面的结构,应该是能够用起来了,比方开端的上电需求读取通讯模块的ID,得到ID今后发送一次无线报文,完结的代码如下:
成果如下:
在解决了上图所说的ID读取反常问题之后(就在下面《4.2 串口通讯细节问题》,这是STM32 HAL库的运用问题),咱们再增加一些结构代码:
看下测验成果,上电ID读取正确,按键线程正常,接纳报文也正常:
4.2 串口通讯细节问题
具体问题描绘:
上面的第一次的ID读取截图有问题,查看了一段时刻,后来发现接纳额数据与实际的有一位的差别,然后解决了这个问题,在接纳数据的时分仍是发现每次接纳数据会丢掉第一个字节。
这是STM32 HAL库根本运用导致的,由于博主开端直接运用程序移植,有些细节的当地没有第一时刻发现。
其实最根本的原因在于,串口敞开之时是怎样使能中止接纳的!
是用__HAL_UART_ENABLE_IT
宏界说使能中止
仍是HAL_UART_Receive_IT
这个函数使能中止?
这是STM32的根底运用问题,复制的分析调整进程这儿就省略了,我只把最终的结论和运用方法阐明一下,其实运用HAL_UART_Receive_IT
内部会调用__HAL_UART_ENABLE_IT
。
__HAL_UART_ENABLE_IT
先来说说运用__HAL_UART_ENABLE_IT
的状况,正确的流程图如下:
这是一种功率比较高的方法,运用__HAL_UART_ENABLE_IT
使能无法进入HAL_UART_RxCpltCallback
函数(有问题请指出),所以咱们得在LPUART1_IRQHandler
进行数据处理。
HAL_UART_Receive_IT
一般运用方法
假如串口初始化今后就运用函数HAL_UART_Receive_IT
敞开接纳中止,大部分网络文章教程阐明运用流程如下图:
其他方法阐明一
当然,咱们的数据处理能够不在HAL_UART_RxCpltCallback
函数中,也能够学习上面在LPUART1_IRQHandler
中处理,比方:
上面图中的注意事项,原因是由于HAL_UART_IRQHandler(&hlpuart1);
处理进程会封闭一些中止,之后才调用HAL_UART_RxCpltCallback
,咱们在HAL_UART_RxCpltCallback
最终的函数HAL_UART_Receive_IT
又会重新翻开,所以能够正常走流程。
假如咱们在LPUART1_IRQHandler
中处理,在履行 HAL_UART_IRQHandler(&hlpuart1);
的时分会封闭中止,假如在此之后不再次使能,就无法持续呼应下次中止了!
其他方法阐明二
开端运用函数HAL_UART_Receive_IT
敞开接纳中止,其他当地运用完全和运用__HAL_UART_ENABLE_IT
的状况相同也是能够的:
至于原因,是在HAL_UART_Receive_IT
函数最终会使能RXNE
中止,就和运用__HAL_UART_ENABLE_IT
是相同的:
两种方法都能够完结串口中止处理,然后两种方法结合也是能够的,可是并不建议,除非你完全了解HAL库的内部完结方法,你完全知道自己在做什么!
4.3 发送测验
发送测验其实在咱们前面发送学习报文现已得到过验证了,能够正常的发送学习报文表明发送功用没有问题。
咱们这儿要做的便是把温湿度的数据封包至无线报文中发送出去,这儿发送函数的话按理来说也能够新建一个线程专门处理,收到特定的信号量进行发送,可是考虑到内存问题并且咱们本运用功用比较简略,所以咱们直接在温湿度读取线程里面进行,曾经是读取了数据打印出来,现在是封包至无线协议通过报文发送出去。
发送操作直接放在温湿度读取线程里面进行处理:
测验成果正常,如图:
还好我把发送功用加入到温湿度读取的线程中,并不需求增加线程栈空间就能够正常运转。
通过上面的折腾,在串口细节处理上花了不少的时刻,不过好在结局还算圆满,接纳和发送都测验正常!
五、时刻关注占RAM巨细
串口的运用咱们并没有新建线程,可是由于串口需求缓存区和与串口处理相关的一些全局变量,还有信号量也需求占用RAM空间,所咱们的内存占用又变大了。
那么仍是老样子,今天测验完结今后和曾经占用空间的比照图上一下:
串口通讯的流程完结完后,程序运转时分需求占用 RAM的巨细: 7416 字节,咱们的芯片 RAM:8192字节。
结语
本文咱们运用信号量完结了串口通讯,尽管也不是复杂的进程,仍是遇到了不少的问题,使得原本昨天能够完结的博文,不得不晚一天,在根本的 STM32 串口通讯问题上画了一些时刻调试,移植尽管能够省去大部分工作,可是细节问题不容忽视。
本次测验,也算是让自己再次总结了一下STM32 HAL库中的串口中止接纳方法。然后信号量接纳的方法居然和自己考虑的相同完美的完结接纳一帧数据,仍是有点小惊喜的!
其实本次运用篇到这儿现已算是完结了一个单品传感器了,完毕? 既然是运用篇,那么当初计划的功用仍是得完善一下,比方,按键操作,短按长按的动作,至少把按键驱动移植完。定时器,运用定时器作为传感器收集的时刻机制,那么下一篇就决定了,按键驱动移植,假如顺利把简略的定时器也顺带加上~ ~!
没想到本次测验比上一篇还累 = =! 持续期望小伙伴多多支撑,多多指教!
好了,本文就到这,谢谢我们!