ucos串口通讯模块设计
在嵌入式应用中,使用RTOS的主要原因是为了提高系统的可靠性,其次是提高开发效率、缩短开发周期。uCOS-II是一个占先式实时多任务内核,使用对象是嵌入式系统,对源代码适当裁减,很容易移植到8~32位不同框架的微处理器上。但uCOS-II仅是一个实时内核,它不像其他实时操作系统(如嵌入式Linux)那样提供给用户一些API函数接口。在uCOS-II实时内核下,对外设的访问接口没有统一完善,有很多工作需要用户自己去完成。串口通信是单片机测控系统的重要组成部分,异步串行口是一个比较简单又很具代表性的中断驱动外设。本文以单片机中的串口为例,介绍uCOS—II下编写中断服务程序以及外设驅动程序的一般思路。 1 uCOS-II的中断处理及51系列单片机中断系统分析
uCOS-II中断服务程序(ISR)一般用汇编语言编写。以下是中断服务程序的步骤。
- 保存全部CPU寄存器;调用OSIntEnter()或OSIntNesting(全局变量)直接加1;
- 执行用户代码做中断服务;
- 调用OSIntExit();
- 恢复所有CPU寄存器;
- 执行中断返回指令。
uCOS-II提供两个ISR与内核接口函数;OSIntEnter()和OSIntExit()。OSIntEnter()通知uCOS-II核,中断服务程序开始了。事实上,此函数做的工作是把一个全局变量OSIntNesting加1,此中断嵌套计数器可以确保所有中断处理完成后再做任务调度。另一个接口函数OSIntExit()则通知内核,中断服务已结束。根据相应情况,退回被中断点(可能是一个任务或者是被嵌套的中断服务程序)或由内核作任务调度。
用户编写的ISR必须被安装到某一位置,以便中断发生后,CPU根据相应的中断号运行准确的服务程序。许多实时操作系统都提供了安装和卸载中断服务程序的API接口函数,但uCOS-II内核没有提供类似的接口函数,需要用户在对CPU的移植中自己实现。这些接口函数与具体的硬件环境有关,接下来以51单片机下的中断处理对此详细说明。
51单片机的中断基本过程如下:CPU在每个机器周期的S5P2时刻采样中断标志,而在下一指令周期将对采样的中断进行查询。如果有中断请求,则按照优先级高低的原则进行处理。响应中断时,先置相应的优先级激活触发器于相应位,封锁同级或低级中断,然后根据中断源类别,在硬件控制下,将中断地址压入堆栈,并转向相应的中断向量入口单元。通常在入口单元处放一跳转指令,转向执行中断服务程序.当执行中断返回指令RETI时,把响应中断时所置位的优先级激活触发器清零后,从堆栈中弹出被保护的断点地址,装入程序计数器PC,CPU返回原来被中断处继续执行程序。
在移植的过程中,采用Keil C51作为编译环境。Keil C5l集成C编译和汇编器。中断子程序用汇编语言编写,放到移植uCOS-II后的OS_CPU_A.ASM汇编文件中。下面是以串行口中断为例的移植中断服务子程序代码。
CSEGAT0023H ;串口中断响应入口地址
LJMPSerialISR;转移到串口中断子程序入口地址
RSEG?PR?SeriallSR?OS_CPU_A
SerialISR:
USINGO
CLR EA ;先关中断,以防中断嵌套
PUSHALL ;已定义的压栈宏,用于将
;CPU寄存器的值压入堆栈
LCALL_?OSIntEnter ;监视中断嵌套
LCALL_?Serial ;串口中断服务程序
LCALL_?OSintExlt
SETBEA
POPALL;已定义的出栈宏,将CPU寄存器的值出栈
RETI
2 串口驱动程序
笔者已在5l单片机上成功移植了uCOS-II内核,移植过程在此不再讨论。这里重点分析uC0S—II内核下串口驱动程序编写。
由于串行设备存在外设处理速度和CPU速度不匹配的问题,所以需要一个缓冲区.向串口发送数据时,只要把数据写到缓冲区中,然后由串口逐个取出往外发。从串口接收数据时,往往等收到若干个字节后才需要CPU进行处理,所以这些预收的数据可以先存于缓冲区中。实际上,单片机的异步串口中只有两个相互独立、地址相同的接收、发送缓冲寄存器SBUF。在实际应用中,需要从内存中开辟两个缓冲区,分别为接收缓冲区和发送缓冲区。这里把缓冲区定义为环形队列的数据结构。
uCOS-II内核提供了信号量作为通信和同步的机制,引入数据接收信号量、数据发送信号量分别对缓冲区两端的操作进行同步。串口的操作模式如下:用户任务想写,但缓冲区满时,在信号量上睡眠,让CPU运行别的任务,待ISR从缓冲区读走数据后唤醒此睡眠的任务;同样,用户任务想读,但缓冲区空时,也可以在信号量上睡眠,待外部设备有数据来了再唤醒。由于uCOS-II的信号量提供了超时等待机制,串口当然也具有超时读写能力。
图1是带缓冲区和信号量的串口接收示意图。数据接收信号量初始化为0,表示在环形缓冲区中无数据。
接收中断到来后,ISR从UART的接收缓冲器SBUF中读入接收的字节(②),放入接收缓冲区(③),然后通过接收信号量唤醒用户任务端的读操作(④、①)。在整个过程中,可以查询记录缓冲区中当前字节数的变量值,此变量表明接收缓冲区是否已满。UART收到数据并触发了接收中断,但如果此时缓冲区是满的,那么放弃收到的字符。缓冲区的大小应合理设置,降低数据丢失的可能性,又要避免存储空间的浪费。
图2为带环形缓冲区和超时信号量的串口发送示意图。发送信号量初始值设为发送缓冲区的大小,表示缓冲区已空,并且关闭发送中断。发送数据时,用户任务在信号量上等待(①)。如果发送缓冲区未满,用户任务向发送缓冲区中写入数据(②)。如果写入的是发送缓冲区中的第一个字节,则允许发送中断(②)。然后,发送ISR从发送缓冲区中取出最早写入的字节输出至UART(④),这个操作又触发了下一次的发送中断,如此循环直到发送缓冲区中最后一个字节被取走,重新关闭发送中断。在ISR向UART输出的同时,给信号量发信号(⑤),发送任务据此信号量计数值来了解发送缓冲区中是否有空间。
3 串口通信模块的设计
每个串行端口有两个环状队列缓冲区,同时有两个信号量:一个用来指示接收字节,另一个用来指示发送字节。每个环状缓冲区有以下四个要素:
- 存储数据(INT8U数组);
- 包含环状缓冲区字节数的计数器;
- 环状缓冲区中指向将被放置的下一字节的指针;
- 环状缓冲区中指向被取出的下一字节的指针。
图3是接收数据软件模块的流程图。SerialGetehar()用来获取接收到的数据,如果缓冲区已空时将任务挂起,接收到字节时,任务将被唤醒,同时从串行口接收字节。SerialPutRxChar()用来将接收的字节放到缓冲区中,如果接收缓冲区已满,则该字节被丢弃。当字节插入到缓冲区中,SerialPutRxChar()通知数据接收信号量,使之将数据己到的消息传达给所有等待的任务。为防止挂起应用任务,可以通过调用SceiallsEmPty()去发现环状队列中是否有字节。
图4是发送数据模块的流程图。当需要发送数据给串行端口时,SerialPurChar()等待信号量在初始化发送信号量时应该初始为缓冲区的大小。因此,当缓冲区中没有更多空间时,SerialPutChar()就挂起任务,只要UART再次发送字节,挂起任务就将恢复。SerialGctChar()被中断服务程序调用,如果发送缓冲区至少还有一个字节,Seri-a1GetChar()就返回一个从缓冲区发送的字节。如果缓冲区己空,则SerialGetChar()返回Null,这将使调用停止进一步的发送中断,一直到有数据发送为止。
4 异步串行通信的接口函数
应用任务可以通过如下的几个函数来控制和访问UART:SerialCfgPort()、SerialGetChar()、SerialInit()、SerialIsEmpty()、SerialIsFull()和SerialPutChar()。
SerialCfgPort()用于建立串行端口的特征,在为指定端口调用其他服务前,必须先调用该函数,包括确定波特率、比特数、奇偶校验和停止位等。
SerialGetChar()使应用程序从接收数据的环状缓冲区中取出数据。
SerialInit()用于初始化整个串口软件模块,且必须在该模块提供的其他任何服务前调用。SeriallInit()将环状缓冲区计数器的字节数清零,并初始化每个环状缓冲区的IN和OUT指针,指向数据存储区的开始处。数据接收信号量初始化为0,表示在环状缓冲区无数据。用传送缓冲区大小初始化数据传送信号量,表示缓冲区已空。
SerialIsEmpty()允许应用程序确定是否有字节从串口接收进来。本函数允许在无数据时避免将任务挂起。
SerialIsFull()允许应用程序确定传送环状缓冲区的状态,本函数可以在缓冲区已满时避免将任务挂起。
SerialPutChar()允许应用程序向一个串行端口发送数据。
结 语
该串口通信模块充分利用了实时内核的任务调度功能和信号量机制,系统软件模块化,可读性增强,便于修改和移植,其设计思路和方法可以很好的应用在多种情况下的测控系统中,系统的扩展方便,具有一定的借鉴作用。该串口通信模块已作为某铁路供水远程控制终端的一部分,运行稳定,提高了整个系统的运行效率和实时性。
ucos串口通讯模块设计的更多相关文章
- pyserial库-串口通讯模块
pySerial 封装了串口通讯模块,支持Linux.Windows.BSD(可能支持所有支持POSIX的操作系统),支持Jython(Java)和IconPython(.NET and Mono). ...
- (转载)uCOS-II的嵌入式串口通信模块设计
在嵌入式应用中,使用RTOS的主要原因是为了提高系统的可靠性,其次是提高开发效率.缩短开发周期.uCOS-II是一个占先式实时多任务内核,使用对象是嵌入式系统,对源代码适当裁减,很容易移植到8~32位 ...
- 单片机课程设计——《基于AT89S52单片机和DS1302时钟芯片的电子时钟(可蓝牙校准)》
引言 本设计以AT89S52单片机为控制核心,时钟芯片DS1302提供时钟源,配合LCD1602液晶显示模块,组成基本硬件系统,同时利用HC-05嵌入式蓝牙串口通讯模块,可在手机端进行日期.时间的校准 ...
- CAN总线收发节点设计
CAN总线收发节点设计 写在前面 这是微机接口的一个项目作业. 这段时间一直在宿舍隔离,没办法进行焊接和测试,但原理和代码已经在学习板子上经过验证. 设计目标 CAN在工业现场大量应用,尤其是汽车工业 ...
- Socket聊天程序——初始设计
写在前面: 可能是临近期末了,各种课程设计接踵而来,最近在csdn上看到2个一样问答(问题A,问题B),那就是编写一个基于socket的聊天程序,正好最近刚用socket做了一些事,出于兴趣,自己抽了 ...
- ucos实时操作系统学习笔记——内核结构和任务创建
对于ucos实时操作系统,邵贝贝的那本书已经写得很详细了,我因为之前不深的研究过ucos,所以在这里做一个笔记,写一些个人对该操作系统的理解,仅仅是个人理解,如果有人看到这边随笔有不对的地方,望给我指 ...
- Pyserial操作串口
pySerial 介绍 封装了串口通讯模块,支持Linux.Windows.BSD(可能支持所有支持POSIX的操作系统),支持Jython(Java)和IconPython(.NET and Mon ...
- LPC1768串口使用
Lpc1768内置了四个串口通讯模块,都是异步通讯模块,其中,串口0/2/3是普通串口通讯,串口1与 UART0/2/3 基本相同,只是增加了一个 Modem 接口和 RS-486/EIA-486 模 ...
- 两个HC-05蓝牙模块互相绑定构成无线串口模块
HC-05 嵌入式蓝牙串口通讯模块(以下简称模块)具有两种工作模式:命令响应工作模式和自动连接工作模式,在自动连接工作模式下模块又可分为主(Master).从(Slave)和回环(Loopback)三 ...
随机推荐
- html打造动画【系列2】- 可爱的蛙蛙表情
先感受一下全部表情包: 在开始之前先安利一个知识点:Flex弹性布局 我们一般做水平三列布局都是用的float方法,将每一块浮动显示在同一行.这种方法会导致元素没有原来的高度属性,要用清除浮动来解决空 ...
- Android Viewpager+Fragment实现滑动标签页
ViewPager 结合Fragment实现一个Activity里包含多个可滑动的标签页,每个标签页可以有独立的布局及响应. 主页布局 <?xml version="1.0" ...
- iPhone 应用开发的5个贴士
[编者按]本文作者为来自 Redbytes Software 的开发者 James Richard,主要介绍开发 iPhone 应用过程中大有益处的五个贴士.文章系国内 ITOM 管理平台 OneAP ...
- 第六章 函数、谓词、CASE表达式 6-1 各种各样的函数
一.函数的种类 算术函数 字符串函数 日期函数 转换函数 聚合函数 二.算术函数 + - * / 1.ABS——绝对值 ABS(数值) 绝对值 absolute value ,不考虑数值的符号 ...
- 显示iOS所有系统字体
显示iOS所有系统字体 源码地址: https://github.com/YouXianMing/UI-Component-Collection 效果图: 便于你开发中寻找适合自己的字体, demo中 ...
- Python3.5 执行发邮件Exchangelib(=)
fyl Python发邮件的代码如下: 只需要填写好加粗字体,即可正常使用. from exchangelib import DELEGATE, Account, Credentials, Messa ...
- Python学习---Form拾遗180322
Form操作之错误信息操作 1. 用户发送请求过来 2. for 循环对字段进行正则表达式的验证 fields.clean(value) 3. 自定义clean_字段() 进行名字段值正确性的校验 ...
- 剑指offer 11二进制中1的个数
输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. java版本: public class Solution { public int NumberOf1(int n) { Strin ...
- EntityFramework Code First便捷工具——数据迁移
使用EntityFramework Code First开发,数据迁移是一个不得不提的技术. 在我们的开发过程中,难免需要对模型进行改进,模型改进后,会导致实体集与数据库不一致,当然我们可以通过删除数 ...
- Basestation函数解析(二)
---恢复内容开始--- 这部分从Basestation的RecvDataThread开始,流程为 RecvDataThread->RecvData->Decoder->PostDa ...