精华内容
下载资源
问答
  • QML 信号信号处理器程序

    千次阅读 多人点赞 2017-03-07 19:42:49
    信号和槽作为 Qt 的核心机制,在 Qt 编程中有着广泛的应用。同样,QML 也继承了这样的特性 - 信号和...当一个信号被发射时,相应的信号处理程序就会被调用,在处理程序中放置逻辑(例如:脚本或其他操作)以允许组件

    简述

    信号和槽作为 Qt 的核心机制,在 Qt 编程中有着广泛的应用。同样,QML 也继承了这样的特性 - 信号和信号处理程序 ,只不过叫法上略有不同。

    • 信号:来自 QML 对象的通知。
    • 信号处理程序:由信号触发的表达式(或函数),也被称为 Qt C++ 中的“槽”。

    信号是事件,信号通过信号处理程序来响应。当一个信号被发射时,相应的信号处理程序就会被调用,在处理程序中放置逻辑(例如:脚本或其他操作)以允许组件响应事件。

    | 版权声明:一去、二三里,未经博主允许不得转载。

    使用信号处理程序接收信号

    信号是来自对象的通知,表示发生了某些事件(例如:鼠标已点击、属性已更改、动画已启动/停止)。每当特定信号被发射时,若要接收通知:

    • 对象定义应声明一个名 on<Signal> 的信号处理程序,其中 <Signal> 是信号的名称,首字母大写。
    • 信号处理程序必须在发出信号的对象定义中声明,并且处理程序应包含调用时要执行的 JavaScript 代码块。

    例如,MouseArea 类型有一个 clicked 信号,无论何时在该区域内单击鼠标都会发出该信号。由于信号名称是 clicked,所以接收该信号的信号处理程序应命名为 onClicked

    下面的示例中,每当鼠标区域被点击时,onClicked 处理程序就会被调用,为 Rectangle 分配一个随机颜色:

    import QtQuick 2.3
    
    Rectangle {
        id: rect
        width: 100; height: 100
    
        MouseArea {
            anchors.fill: parent
            onClicked: {  // 鼠标单击
                rect.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1);
            }
        }
    }

    查看 MouseArea 文档,可以看到 clicked 信号发出时带有一个名为 mouse 的参数,这是一个 MouseEvent 对象,包含了有关鼠标单击事件的很多详细信息,可以在 onClicked 处理程序中引用该名称来访问此参数。

    例如,MouseEvent 类型有 x 和 y 坐标,这使我们可以打印出鼠标点击的确切位置:

    import QtQuick 2.3
    
    Rectangle {
        id: rect
        width: 100; height: 100
    
        MouseArea {
            anchors.fill: parent
            onClicked: {  // 鼠标单击
                rect.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1);
    
                // 访问 mouse 参数
                console.log("Clicked mouse at", mouse.x, mouse.y)
            }
        }
    }

    属性改变信号处理程序

    当 QML 属性值发生改变时,将自动发出信号。这种类型的信号是属性改变信号,对应的处理程序为属性改变信号处理程序。

    • 属性改变信号处理程序以 on<Property>Changed 的形式写入,<Property> 是属性的名称,首字母大写。

    例如,MouseArea 类型具有 pressed 属性,要在该属性改变时接收通知,需要编写名为 onPressedChanged 的信号处理程序:

    import QtQuick 2.3
    
    Rectangle {
        id: rect
        width: 100; height: 100
    
        MouseArea {
            anchors.fill: parent
            onPressedChanged: {  // 鼠标按下/释放
                console.log("Mouse area is pressed?", pressed)
            }
        }
    }

    尽管 MouseArea 文档中没有记录名为 onPressedChanged 的信号处理程序,但是因为存在 pressed 属性,所以它也被隐式地提供了。

    使用 Connections 类型

    QtQuick 模块提供了 Connections 类型,用于连接到任意对象的信号。Connections 的优点是:

    • 可以在发射信号的对象外部访问该信号

    例如,上述示例中的 onClicked 处理程序可以由根 Rectangle 接收,只需要将其放置在一个 Connections 对象中,并指定 target 为 mouseArea:

    import QtQuick 2.3
    
    Rectangle {
        id: rect
        width: 100; height: 100
    
        MouseArea {
            id: mouseArea
            anchors.fill: parent
        }
    
        Connections {
            target: mouseArea
            onClicked: {
                rect.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1);
            }
        }
    }

    附加信号处理程序

    附加信号处理程序所接收的信号来自附加类型,而非声明处理程序的对象。

    附加,也称为额外。可以简单理解为:对象本身或其基类没有的属性和信号,需要通过外部(附加类型)提供。

    要引用附加属性和处理程序,可以使用以下语法形式:

    • <AttachingType>.<propertyName>
    • <AttachingType>.on<SignalName>

    例如,下面的 Item 可以通过附加类型 Keys 来访问其附加属性和附加信号处理程序:

    import QtQuick 2.3
    
    Item {
        width: 100; height: 100
    
        focus: true
        Keys.enabled: true
        Keys.onReturnPressed: console.log("Return key was pressed")  // 按下回车键,打印 log 信息
    }

    enabled 是 Keys 的一个属性,为其赋值为 true(默认值是 true,这里主要用于说明如何使用附加类型的属性),表明启用键盘处理。

    由于 Keys 提供了 returnPressed 信号,所以可以通过 onReturnPressed 来引用相应的附加信号处理程序。

    类似的附加类型还有很多,例如:Component,它有一个 onCompleted 附加信号处理程序,通常用于在创建完成后执行某些 JavaScript 代码:

    import QtQuick 2.3
    
    Rectangle {
        width: 200; height: 200
        color: Qt.rgba(Qt.random(), Qt.random(), Qt.random(), 1)
    
        Component.onCompleted: {
            console.log("The rectangle's color is", color)
        }
    }

    onCompleted 处理程序没有响应来自 Rectangle 类型的 completed 信号。相反,Component 对象由 QML 引擎自动附加到 Rectangle 对象,当对象完全创建时,引擎发出 completed 信号,从而触发 Component.onCompleted 信号处理程序。

    附加信号处理程序允许向对象通知有意义的特定信号。如果没有为某个特定对象注册信号,那么就不能接收相应的通知,附加信号处理机制使得对象能够接收特定的信号而无需这些额外的处理。

    自定义信号

    当自定义类型不可避免,当现有信号无法满足,这时,最好的方法就是自定义信号。

    可以通过 signal 关键字来添加自定义信号,语法如下:

    signal <name>[([<type> <parameter name>[, ...]])]

    例如,下面声明了三个自定义信号:

    import QtQuick 2.3
    
    Item {
        signal clicked
        signal hovered()
        signal actionPerformed(string action, var actionResult)
    }

    如果信号没有参数,括号“()” 是可选的;倘若有参数,那么必须声明参数的类型(正如上述 actionPerformed 信号中的 string 和 var 一样)。

    要发射信号,可以将其作为方法来调用。任何相关的信号处理程序将在发出信号时被调用,处理程序可以使用定义的信号参数名称来访问相应的参数。

    例如,假设下面的代码被定义在一个名为 SquareButton.qml 的文件中,根 Rectangle 对象有一个 activated 信号。当子 MouseArea 被点击时,它会以鼠标点击的坐标发出 parent 的 activated 信号:

    // SquareButton.qml
    Rectangle {
        id: root
    
        signal activated(real xPosition, real yPosition)
    
        property int side: 100
        width: side; height: side
    
        MouseArea {
            anchors.fill: parent
            onPressed: root.activated(mouse.x, mouse.y)
        }
    }

    然后,SquareButton 的任何对象都可以使用 onActivated 信号处理程序连接到 activated 信号:

    // myapplication.qml
    SquareButton {
        onActivated: console.log("Activated at " + xPosition + "," + yPosition)
    }

    信号到方法/信号的连接

    大部分情况下,通过信号处理程序接收信号就足够了,然而,要将信号连接至多个方法/信号,这对于信号处理程序来说是不可能的(因为信号处理程序的命名必须唯一)。

    在 Qt C++ 中,信号与槽的连接方式使用的是 QObject::connect()。相应地,在 QML 中,signal 对象也有一个 connect() 方法,用于将信号连接到一个方法或另一信号。当信号连接到方法时,无论信号何时发出,该方法都将被自动调用。有了这种机制,可以通过方法来接收信号,而无需使用信号处理器。

    所以呢,相对于信号处理程序来说,connect() 更加灵活:

    • 可以将信号连接至多个方法/信号

    此外,当将信号连接到动态创建的对象时,connect() 方法也很有用。

    信号到方法的连接

    下面,使用 connect() 方法将 messageReceived 信号连接到两个方法:

    import QtQuick 2.3
    
    Rectangle {
        id: relay
    
        signal messageReceived(string message, string qq)
    
        Component.onCompleted: {
            relay.messageReceived.connect(sendToLiLei)  // 连接信号和方法
            relay.messageReceived.connect(sendToHanMeimei)  // 连接信号和方法
            relay.messageReceived("Welcome to join us(QML分享&交流)", "26188347")  // 发射信号
        }
    
        function sendToLiLei(message, qq) {
            console.log("Sending to LiLei: " + message + ", " + qq)
        }
        function sendToHanMeimei(message, qq) {
            console.log("Sending to HanMeimei: " + message + ", " + qq)
        }
    }

    广播一下,李雷和韩梅梅就可以很快的找到组织了~O(∩_∩)O~!

    有 connect() 方法,必然也会有相应的 disconnect() 方法,用于删除连接的信号:

    Rectangle {
        id: relay
        //...
    
        function removeLiLeiSignal() {
            relay.messageReceived.disconnect(sendToLiLei)
        }
    }

    用法很简单,和 connect() 相同。

    信号到信号的连接

    通过将信号连接到其他信号,connect() 方法可以形成不同的信号链。

    import QtQuick 2.3
    
    Rectangle {
        id: forwarder
        width: 100; height: 100
    
        signal sendToLiLei()  // 自定义信号
        signal sendToHanMeimei()  // 自定义信号
        onSendToLiLei: console.log("Send to LiLei")  // 信号处理程序
        onSendToHanMeimei: console.log("Send to HanMeimei")  // 信号处理程序
    
        MouseArea {
            id: mousearea
            anchors.fill: parent
            onClicked: console.log("Clicked")
        }
    
        Component.onCompleted: {
            // 连接信号至两个信号
            mousearea.clicked.connect(sendToLiLei)
            mousearea.clicked.connect(sendToHanMeimei)
        }
    }

    每当 MouseArea 的 clicked 信号被发射,sendToLiLei、sendToHanMeimei 信号也将自动发射,从而执行对应的信号处理程序。

    这时,输出如下:

    Clicked
    Send to LiLei
    Send to HanMeimei

    建议: 在 QML 中,信号和信号处理器程序是一个核心机制,一定要熟练掌握。。。Good Luck!

    展开全文
  • 铁路信号基础知识——信号部分

    千次阅读 2019-06-25 22:01:27
    一.信号 信号:是传递信息的符号。 铁路信号设备是一个总名称,概而言之为信号、联锁、闭塞 铁路信号:是向有关行车和调车作业人员发出的指示和命令; ...联锁设备:用于保证站内行车和调...视觉信号:是以颜色、形...

    一. 信号

    信号:是传递信息的符号。  

    铁路信号设备是一个总名称,概而言之为信号、联锁、闭塞

    铁路信号:是向有关行车和调车作业人员发出的指示和命令;

    联锁设备:用于保证站内行车和调车工作的安全和提高车站的通过能力;

    闭塞设备:用于保证列车区间内运行的安全和提高区间的通过能力。

    (一) 铁路信号的分类

    铁路信号按感官的感受方式可分为视觉信号和听觉信号两大类。

    视觉信号:是以颜色、形状、位置、灯光和状态等表达的信号。如用信号机、信号旗、信号灯、信号牌、信号表示器、信号标志及火炬等显示的信号都是视觉信号。

    听觉信号:是以不同器具发出音响的强度、频率、和音响的长短时间等表达的信号。如用号角、口笛、响墩发出的音响以及机车、轨道车鸣笛等发出的信号,都是听觉信号。

    铁路信号又按信号机具是否可以移动分为固定信号、移动信号和手信号。

    固定信号是铁路信号设备的主要组成部分。

    在我国铁路上,依据运营要求,采用下列基本的信号。

    1. 要求停车的信号;               (一般叫做禁止信号或简称停车信号)。

    2. 要求注意或减速运行的信号;     (一般叫做运行信号)。

    3. 准许按规定速度运行的信号。     (一般叫做运行信号)。

     

    视觉信号的基本颜色及其基本意义是:

    1. 红色-----停车;

    2. 黄色-----注意或减低速度;

    3. 绿色-----按规定速度运行。

    4. 月白色-----表示准许调车信号或引导信号。

    5. 兰色--------表示禁止调车信号或容许信号。

     

    固定的视觉信号可按下列主要基本性质分类:

    1. 按信号构造分为:色灯信号机、臂板信号机、机车自动信号和信号表示器。

    2. 按信号的使用时间分为:(1)昼间信号;(2)夜间信号;(3)昼夜通用信号。

    昼间信号以臂板信号机臂板的不同颜色、形状、尺寸及位置等显示;

    夜间信号以臂板信号机上的灯光和数目等显示;

    昼夜通用信号则以色灯信号机、机车自动信号显示器的灯光颜色、数目等显示。

    3. 按发送信号的方法分为:

    (1)位置信号;例如臂板信号机。

    (2)颜色信号;例如色灯信号机和机车自动信号。

    4.信号按用途分为12种:进站、出站、通过、进路、预告、遮断、防护、驼峰、复示、调车、容许、 引导信号

    进站、出站、通过、进路、防护等信号机,都能独立地显示信号,指示列车运行的条件,叫做主体信号机;

    预告、复示信号机等,本身不能独立存在,而是附属于某种信号机的,所以叫做从属信号机。对预告信号机来说,进站信号机又是它的主体信号机。

     

    5. 按停车信号的意义分为绝对信号和容许信号。

    (1)绝对信号------当显示禁止信号时,不论在任何情况下也不准许列车越过它,所有的非自动的或半自动的信号机,都属于这一类。

    (2)容许信号--------设于通过信号机上的一种附属信号,当容许信号显示一个兰色灯光时,准许铁路局规定停车后启动困难的货物列车,在该通过信号机显示红色灯光的情况下,以不超过20公里/小时的速度通过。当容许信号灯光熄灭,司机在能确认该通过信号机装有容许信号时,仍可按上述限制速度通过信号机。

    6. 信号按显示意义的数目分为:单显示、二显示、三显示、多显示。

    (1)单显示--------出站、进路的复示信号机及遮断信号机都是单显示的信号机。

    (2)二显示--------预告信号机就是二显示信号(绿灯或黄灯)。它预告进站、通过或防护信号机的禁止和进行信号显示。

    (3)三显示--------我国铁路自动闭塞区段的通过信号机是三显示信号。(红灯、绿灯或黄灯)

    (4)四显示--------适宜于铁路提速、高速区段的通过信号机是四显示信号。(红灯、绿灯、黄灯或黄绿两灯)

    7. 按动作方式分为:手动信号机、半自动信号机、自动信号机。

    (1)手动信号机------信号显示的变化是由人工通过机械握柄操纵的信号机。

    (2)半自动信号机---信号显示的变化,不仅需要人工操纵,还受列车的自动控制。

    (3)自动信号机------信号显示的变化,仅受列车的运行状态自动控制的信号机。

     

    8. 固定信号机的设置地点与显示方式

    我国铁路实行左侧行车,因此固定信号机一般均应设置在列车运行方向的左侧或所属线路中心线的上空。

    按照用途的不同,常用的固定信号机主要有以下几种:  (如下图所示)

    (1)进站信号机(X、S)

    它的作用是防护车站,指示列车可否由区间进入车站,与敌对进路相联锁。信号开放后,保证进路安全可靠。它应设在距车站进站道岔尖端(逆向道岔)或警冲标(顺向道岔)不少于50米的地点。

    (2)出站信号机(X1、XII、X3、S1、SII、S3)

    它的作用是:防护区间,作为列车占用区间的凭证,指示列车可否由车站开往区间;与敌对进路相联锁,信号开放后保证进路安全可靠;指示列车站内停车的位置,防止越过警冲标。每条发车线,均应单独设置出站信号机以免误认信号造成行车事故。

    它应设在每一发车线路警冲标内方的适当地点。

    (3)预告信号机(XY)

    当非自动闭塞区段未装机车信号时,在进站、通过、防护等信号机前方均应设置预告信号机;在采用色灯式进站信号机或进站信号机的显示距离不足、了望条件受限制的情况下,也必须设置预告信号机。它的作用是将主体信号机的显示状态提前告诉司机。它应设在距主体信号机不少于一个列车制动距离(目前我国为800米)的地点。

    (4)通过信号机    (如下图所示)

    通过信号机的作用是防护自动闭塞区段的闭塞分区或非自动闭塞区段的所间区间,指示列车可否开进它所防护的闭塞分区或所间区间。

    通过信号机通常设在所间区间或闭塞分区的分界处。

     

    (5)调车信号机

    调车信号机是用来进行指示调车机车进行作业的。它只在电气集中联锁的车站上采用,通常设在调车作业繁忙的线路上(如到发线、咽喉道岔区),以及从非联锁区到联锁区的入口处。

    调车信号机一般采用矮型色灯信号机。而在到发线上也可以在出站信号机上添设一个允许调车的月白色灯,成为出站兼调车信号机。

    (二)铁路信号的显示制度

    1. 进路-----列车或(调车)在站内行驶时所经过的径路。

    在车站上,为列车进站、出站所准备的通路,称为列车进路;凡是为各种调车作业准备的通路称为调车进路。一般每一个列车、调车进路的始端都应设有一架信号机进行防护,以保证作业时的安全。(信号机灯光显示的一方为信号机的前方,信号机的后方则为所防护的进路。)

    信号机是防护进路的,要有一个明确的范围,也就是说进路应有明确的始端和终端。不然的话,就没有办法防护。进路通常用信号机、警冲标、车挡表示器、站界标或次一信号机来确定管辖范围。

    例如:

    (1)下行I道接车进路:X为防护信号机;进路范围从X到XI(含股道)。

    (2)下行3道接车进路:X为防护信号机;进路范围从X到X3(含股道)。

    (3)下行5道接车进路:X为防护信号机;进路范围从X到X5(含股道)。

     

    (4)下行I道发车进路:XI为防护信号机;进路范围从XI到站界。

    (5)下行3道发车进路:X3为防护信号机;进路范围从X3到站界。

    (6)下行5道发车进路:X5为防护信号机;进路范围从X5到站界。

    (7)上行II道接车进路:S为防护信号机;进路范围从S到SII(含股道)。

    (8)上行4道发车进路:S为防护信号机;进路范围从S到S4 (含股道)。

    (9)上行5道发车进路:S为防护信号机;进路范围从S到S5 (含股道)。

    (10)上行II道发车进路:SII为防护信号机;进路范围从SII到站界。

    (11)上行4道发车进路:S4为防护信号机;进路范围从S4到到站界。

    (12)上行5道发车进路:S5为防护信号机;进路范围从S5到到站界。

     

    2. 铁路信号显示制度------速差制

    原则上讲,铁路信号所采用的显示制度,不外乎进路制和速差制两种。

    进路制------按列车运行的进路,分别装设信号机(一条进路一架信号机);或者按列车运行的性质,分别由不同的信号机来防护。实践证明,进路制有缺陷。

    速差制-----在同一地点,只装设一架信号机来防护列车运行的进路,根据不同进路的运行条件,在这架信号机上给出各种不同速度的信号。

    例如进站信号机,一架信号机以不同的显示防护正线、站线等多个不同的进路。

    (1)一个红灯-----停车,不准越过信号机。            (速度表示V0)

    (2)一个黄灯-----进正线停车,表示出站信号机关闭。  (速度表示V规→V0)

    (3)两个黄灯-----进到发线(侧线--站线)准备停车。  (速度表示V中)

    (4)一个绿灯-----按规定速度由正线通过,表示出站信号机开放。(V规→V规)

    (5)一个红灯和一个白灯------引导信号,以不超过15公里/小时的速度进站或

    通过接车进路,并随时准备停车。          (速度表示15 km/h)

      二.  道 岔

    道岔:由一条线路分歧为两条线路,在分歧点上铺设的转辙线路叫做道岔。道岔用来使机车车辆从一股道转入另一股道。

    道岔与信号设备的关系极为密切。

    (一)道岔类型

    道岔可分为单式和复式两种。每一种又有好些不同类型。

    1. 单式道岔:

    这种道岔按其几何图形可分为:普通单开道岔(如下图),简称单开道岔。异侧双开道岔(图略)和同侧双开道岔(图略)。道岔的不同开向对于道岔转辙机械的安装有不同要求,需要充分注意。

    单开道岔采用最广泛,占各类道岔总数95%以上。单开道岔是由一条直线线路,向左或向右分岔,同另一条线路连接的设备。

     

     

     道岔构成图

        2. 复式道岔

        在站场中,当需要连接的股道较多时,可以在主线的两侧或同侧连续铺设两个普通单开道岔,如因地形长度限制不能在主线上连续铺设两个单开道岔时,可以设法把一个道岔纳入另一个道岔之内,这就组成了复式道岔。

    复式道岔按其几何图形可分为,异侧三开道岔(有对称三开道岔和不对称三开道岔两种;同侧三开道岔和交分道岔。

    下图(a)所示的交分道岔,有四个辙叉,其中两个是锐角的,两个是钝角的;有四条曲合拢轨和八条尖轨,有两根拉杆,每根带动四条尖轨同时动作,扳动拉杆1和2使股道开通方向发生变化;如图所示的尖轨位置为A--B方向开通。这种交分道岔的四个辙叉都是固定型的,两个钝角辙叉处存在着没有护轮防护的有害空间,如道岔辙叉号数较大,机车车辆通过该处时有脱轨的可能,采用活动心轨钝角辙叉可以克服这个缺点。

    下图(b)是活动心轨钝角辙叉的交分道岔,八条尖轨及四条活动心轨分别由四根拉杆带动,扳动个拉杆使股道开通方向发生变化。

     

    交分道岔的优点是能缩短用地长度,特别是连接几条平行股道时,比用单开道岔连接的长度缩短得更为显著。由于列车通过时弯曲较少,走行平稳,速度可较高,了望条件也较好。但交分道岔构造复杂,零件数量较多,维修较困难。交分道岔一般仅在大编组站、旅客站或其它用地长度受限制的咽喉区上采用。

    (二)道岔的转换和锁闭

    改变道岔位置通常叫做转换,转换设备一般通称转换器,检查监督道岔状态,把道岔限制在一定位置(定位或反位),使之不能任意扳动的方法,通常叫做锁闭,实现锁闭所使用的设备一般称锁闭器。

    道岔的转换和锁闭对行车安全、运输效能以及改善工作人员的劳动条件等都有直接关系。

    在道岔的组成结构中,我们把一根密贴于基本轨的尖轨,叫做闭合尖轨;把另一根离开基本轨的尖轨,叫做开启尖轨。我们一般所说的道岔的定位和反位,只反映了尖轨与基本轨之间的相对位置,说明了进路的开通方向,但没有说明尖轨与基本轨之间的绝对状态,即闭合尖轨与基本轨之间密贴的程度。实际上,道岔的状态对行车安全影响极大。例如,一个对向道岔,如果闭合尖轨与基本轨的密贴程度没有达到规定标准,当机车或车辆迎着尖轨运行时,机车或车辆的轮缘有可能撞着尖轨的尖端而造成脱轨或巅复事故;如果开启尖轨离开基本轨的距离没有达到规定标准,也会造成此种危险。因此,在信号控制系统中不仅要考虑道岔的转换,还要考虑检查道岔的位置和状态。这里还要特别强调的是:检查道岔状态的设备,还应检查尖轨(尤其是闭合尖轨)是否被锁住(或叫锁闭)。因为当道岔的状态尽管良好,而没有把尖轨锁住时,由于外力的作用(如列车的震动等)可能使道岔的状态改变而造成危险。

    实际上,往往把道岔的转换与锁闭联系起来加以考虑,两者的作用往往在一套设备上体现出来,用一套设备(例如机械转辙装置或是电动转辙机)既达到转换道岔的目的,又适时地完成锁闭道岔的作用。

    不论是机械转辙装置,还是动力转辙机,设计的构造都要遵循规定的动作关系:

     

    定位转换至反位:     定位锁闭→解锁→转换(至反位)→反位锁闭

    反位转换至定位:     反位锁闭→解锁→转换(至反位)→定位锁闭

     

    车站的自动控制系统能否正常工作,在很大程度上决定于转辙机构造的好坏。

    从满足行车安全的要求出发,动力转辙机必须具有正确的操纵、监督和锁闭的作用。具体说来应满足如下的基本要求。

    1. 当道岔正常并在解锁状态下(即进路上的防护信号在关闭,道岔区段无车,道岔正常,没有被挤),应能不间断地随时依车站值班员的意图使道岔变位,假如道岔在转换途中如果由于某种原因(如尖轨夹有碎石)道岔尖轨转不到规定位置时,一方面要保护电动机使它不致烧坏,另一方面能够使之转回原位。

    2. 正确地反应道岔位置,只有当道岔转移到极处,闭合尖轨密贴于基本轨的条件下才容许发出与道岔位置相适应的表示。

    3. 闭合尖轨与基本轨的间隙超过容许限度时(即不密贴时),不容许锁闭道岔,在道岔锁闭后,限制由于外力(如列车经过时的振动力)移动道岔。

    4. 当遇有危险情况(如挤岔)时,应能自动地反映出道岔不密贴的情况,并限制再转换道岔。

    (四)道岔的电气锁闭

    电气锁闭方法是指用按钮、继电器以及其它电气元件构成联锁的方法。在目前的电气锁闭方法中,用有接点继电器来完成的还占有相当的比例。例如,在电气集中(继电集中)设备中,便是用继电器等元件来完成进路道岔锁闭。

    实现这种锁闭的方法是:给每个道岔设置一个经常通电吸起的锁闭继电器SJ(有时是锁闭复示继电器SFJ),把它的前接点串接在道岔控制电路里面。排列进路以后,进路上每个道岔的锁闭继电器都失磁落下,它的前接点断开就切断了道岔控制电路,因而也起到了锁闭道岔的作用。通常在锁闭继电器SJ电路中还要加进道岔轨道继电器DGJ的前接点。当车辆占用道岔区段时DGJ失磁落下,从而使这个道岔的SJ失磁落下,因而也起到进路道岔锁闭的作用。

    (五)提速道岔

    1.铁路的速度等级划分

    目前世界上把不同速度的铁路按列车运行的速度划分为以下几个等级:

        (1)时速在100—120Km时,称为常速铁路;

        (2)时速在120—160Km时,称为中(快)速铁路;

        (3)时速在160—200Km时,称为准高速铁路;

        (4)时速在200—400Km时,称为高速铁路;

        (5)时速在400Km以上时,称为特速铁路;

    2. 提速道岔

    提速道岔----简而言之就是为了提高列车运行速度而装设的道岔。

    影响列车运行速度的线路因素主要是道岔的长度与曲线半径,原来的60Kg钢轨、12号(工务道岔编号)道岔尖轨短,曲线半径小,限制了列车通过道岔的速度,而且原来的道岔都采用的是内锁闭装置(即锁闭装置在电动转辙机内部),不利于提速列车的运行安全,所以需要把正线上的道岔改设为提速道岔。

    3. 提速道岔的特点

        (1)尖轨----比普通道岔的尖轨长。60Kg型、12号道岔的尖轨长7.7米,改进AT型道岔的尖轨长11.3米,而提速道岔的尖轨长13.88米。

        (2)尖轨与辙叉的连接由普通活动连接改为非活动连接,减小了对车轮的冲击振动。

        (3)尖轨上设两处牵引点,心轨处设两处牵引点,增强了尖轨刨切部分的密贴。

    (4)尖轨采用分动外锁闭装置,即将道岔的密贴尖轨与基本轨在线路上直接进行锁闭。由外锁闭装置保证列车过岔的安全,外锁闭装置减小了转换力和密贴力,消灭了危险空间,可大大提高列车运行速度,提高转辙机的寿命及可靠性。

        (5)采用三相交流大功率转辙机,减少了电缆投资及转辙机引起的故障。

    (6)各牵引点外锁闭设备的动作杆、表示杆置于钢枕内,便于使用大型养路机械设备。

    道岔外锁闭装置:是指提速道岔的锁闭地点在转辙机外部,国内传统的道岔锁闭是在转辙机内部实现的,尖轨与基本轨的锁闭属于间接锁闭,不适应提速的需要;外锁闭装置是将道岔的密贴尖轨与基本轨在线路上直接进行锁闭,所以称之为外锁闭装置。外锁闭装置消除了转换设备的危险空间,保证了过岔列车的绝对安全

    由于提速道岔是由重型钢轨、长尖轨构成,拉动转换需要较大动力,所以采用转换力大的三相交流电动转辙机牵引。当前铁路现场的提速道岔,大多采用2台三相交流电动转辙机牵引尖轨,另外活动辙叉的可动心轨也要由1台或2台三相交流电动转辙机牵引。如下图所示。

        目前,最大的提速道岔型号为30号(工务编号),道岔尖轨用6台三相交流电动转辙机牵引,道岔可动心轨由3台三相交流电动转辙机牵引,列车过岔速度可达180Km/h。

          4. 提速设备

     提速信号设备:室内设有10KV/5KVA交流转辙机电源屏和提速道岔组合TDF。室外设有分动式外锁闭设备、若干台S700K电动转辙机或三相液压转辙机。

    三. 轨道电路

    (一)轨道电路的用途和构成

    在铁路行车组织时,迫切需要确认和监督客、货列车的位置,以便于列车运行调度。又因为铁路钢轨和机车车辆都是钢铁制造的,可以导电,这样就可以借助利用钢轨作为导体构成的的轨道电路来实现这一需求。

    轨道电路----是利用铁路的两条钢轨作为导线、以钢轨绝缘作为分界、并利用导线连接信号源和接受设备构成的电气电路。用来反映钢轨线路和道岔区段是否有车或钢轨是否完整。

    轨道电路的作用是监督钢轨线路是否有车占用,是由区段内的列车轮轴将两条钢轨短路(分路),以检查有无列车的电路。

    请注意:一般应用电气电路,都要极力避免导线短路和负载短路;然而,轨道电路的结构功能特殊,它正是利用电路导线(钢轨)的短路特性用来反映有车占用的。将列车轮轴短路两条钢轨的状态,作为轨道电路的一种正常工作状态。

    轨道电路有4种状态:调整状态(无车占用)、分路状态(有车占用)、断轨故障状态、短路故障状态。

        调整状态:从轨道电路工作原理图中看出:平时在轨道电路的两根钢轨完好、又无列车占用时,电源电流通过两根钢轨和接收设备——轨道继电器GJ,使它有电励磁吸起衔铁,并且闭合其前接点,反映了轨道电路空闲——调整状态,如图中(a)。

    分路状态:当有列车占用轨道区段时,电源电流被列车轮轴分路,使GJ由于得不到足够的电流而失磁落下衔铁, 并且闭合其后接点,反映了轨道电路被占用——分路状态,如图中(b)所示。

    断轨状态:当轨道电路发生断轨或断线等故障时,同样使接收电流减少而GJ失磁落下衔铁,反映出轨道电路故障——断轨状态,如图中(c)所示。

    短路故障状态:当轨道电路区段无列车占用时,由于钢轨辅助设备的不正常接触,或外界短路线造成两根钢轨之间短路(此时的短路也是分流),使GJ由于得不到足够的电流而失磁落下衔铁,并且闭合其后接点,是为短路故障状态。

    由上述轨道电路的三种工作状态可知:轨道电路可以检查钢轨线路上的列车运行情况及线路完整状态,将这些信息连续地传递到自动控制系统中去,从而可以迅速和准确地指挥列车运行。

    例如,区间自动闭塞与机车信号,就是利用轨道电路传递前方列车运行状态的信息,  自动地指挥后方续行列车,以最小的间隔运行,从而提高行车的密度和速度,更提高了行车安全性。在电气集中车站的到发线上装设轨道电路,就可以检查出轨道上是否有车占用,防止向有车占用的股道上再接入列车。道岔区段轨道电路,还可防止列车轮对占用道岔时,发生道岔中途转换的危险。由此可见,轨道电路在铁路信号自动控制系统中的重要作用。

    轨道电路的 残压 :人工在轨道电路两条钢轨上跨接“标准分路线”,测得的继电器端电压就是轨道电路的残压。(标准分路线相当于一列车所有车轮与钢轨的接触电阻,交流连续式为0.06欧姆)

    残压是衡量轨道电路性能参数的一个重要指标,残压偏高,就有可能造成有车压不死(即有车时轨道继电器不落下),会导致行车冲突严重后果。

    轨道电路有车占用时测得的继电器端电压虽然也是残压,但不是标准残压。

    (二)交流闭路式轨道电路

    交流闭路式(也叫交流连续式)轨道电路如下图所示。在送电端接有轨道变压器BG5和限流电阻Rx ;在受电端接BZ4型中继变压器和轨道继电器GJ。

    平时电流经由BG5,型变压器将220伏交流电源降压后送到轨道,经过轨道的传输,在受端经过BZ4型中继变压器,使钢轨线路的特性阻抗与继电器阻抗相匹配,然后经过JZXC-480带桥式整流器的安全型继电器,使继电器励磁吸起。

    轨道电路在调整状态时,轨道继电器交流端电压应不小于10.5V,道岔区段一般不大于16V。

    当列车进入轨道区段时,由于轮对分路使继电器失磁落下。这种轨道电路的设备简单,广泛用于电气集中车站(电力牵引区段显然不能用),随着技术的发展,它即将被淘汰。

    (三)25Hz相敏轨道电路

    在电气化铁路区段,由于轨道中流通强大的牵引电流,轨道电路就不可能运用与牵引电流频率相同的50Hz交流制式,为了防止干扰,站内可采用25Hz相敏轨道电路。

    工作原理:

    25Hz相敏轨道电路采用交流25Hz电源连续供电。其受电端采用二元二位轨道继电器。从电网送入50Hz电源,经专设的25Hz分频器分频作为轨道电路的专用电源。由于二元二位轨道继电器具有可靠的频率选择性,故该轨道电路不仅可用于交流电气化区段,而且可用于非电气化区段。25Hz相敏轨道电路的原理图如下图所示。

     

     

       技术特征:

    1.采用二元二位轨道继电器,局部和轨道线圈分别由独立的局部和轨道分频器供电,具有可靠的频率选择性和相位选择性,因而抗干扰能力强和有可靠的绝缘破损防护。

    2.采用集中调相方式,供使用的局部电源电压恒超前于轨道电源电压90°,而不需对每段轨道电路进行个别调相。

    3.轨道电源电流采用的频率低(25Hz),对轨道电路有良好的传输特性。

    4.可以与移频和交流计数电码机车信号结合。利用其可靠的频率选择性,在与移频机车信号结合时,电码化电路可以采用叠加方式,保持轨道电路原有的技术标准。

    5.轨道电路采用连续式供电,工作稳定,采用铁磁元件受环境温度影响小。

    6.轨道电路可采用干线供电,并因消耗功率低,可节省工程投资。

    技术指标:

    在电力牵引区段当钢轨连续牵引总电流≤400A,不平衡牵引电流≤20A(若牵引总电流为400A时,则不平衡系数≤5%)时,轨道电路保证正常工作。

    为沟通轨道区段回归牵引电流,将回归牵引电流引至吸上线或由接触网供电的变压器馈电线接地,当不能就近接向送受电端的扼流变压器中点时,允许设一台无受电设备的扼流变压器(以下简称空扼流)。

    扼流变压器:是沟通轨道区段电力机车回归牵引电流,又能传输轨道电路信息的专用变压器。两条钢轨牵引电流的磁通,在扼流变压器一次侧中互相抵消,而轨道电路25Hz交流信息则得到正常传输。

    二元二位轨道继电器:25Hz相敏轨道电路可靠的频率选择性和相位选择性,主要体现在二元二位轨道继电器上。该继电器属于交流感应式继电器,是根据电磁铁所建立的交变磁场与金属转子中感应电流之间相互作用的原理而动作的。

    它与电度表相似,局部线圈和轨道线圈相当于电度表中的电压线圈和电流线圈。当局部线圈电压超前轨道线圈电压90°时,能使继电器接通前接点;当局部线圈或轨道线圈断电时,依靠翼板和附件的重量使接点处于落下状态。这就是二元二位轨道继电器具备可靠的相位选择性。

    二元二位轨道继电器只有当轨道线圈流入与局部线圈电源相同频率(25Hz)的电流时才能动作,而混入其他频率的干扰电流则不会动作。这就是二元二位轨道继电器具备的可靠的频率选择性。

    正式25Hz相敏轨道电路的频率特性和相位特性,才是要求微机监测测试频率和相角的本质根据。

    (四)移频轨道电路

    在电力牵引区段,为了防护牵引电流工频基波及其皆波的干扰,站内与区间不能采用与牵引电流频率相同的50Hz交流轨道电路,可采用移频轨道电路。

    移频轨道电路采用频率调制信号,接收设备工作稳定,可靠工作的信干比较小,具有较强的抗干扰性能;相邻轨道电路区段采用不同的载频频率,对绝缘破损具有可靠的防护性能;

    所谓移频,就是一种频率调制制式,它的载频信号的频率是随调制信号的脉冲和间隔而改变的。如下图所示。

        当调制信号输出脉冲时,载频信号的频率为f1,当调制信号输出间隔时,载频信号的频 率变为f2,因此,在通道中是传输一种由f1和f2交替变换的移频波,其交替变换的速率即是调制信号的频率(即低频信息)。

    为了满足复线区段及防护钢轨绝缘破损的需要,移频自动闭塞的载频选用550赫、650赫、750赫和850赫四种中心频率,频偏为土55赫,低频调制信号根据机车自动信号的要求选用11赫、15赫、20赫和26赫四种。所以某个轨道电路的中心频率若为550赫,实际在钢轨中流通的电流为550赫士55赫,即605赫和495赫的交替变化的移频波。它的变换速率取决于低频调制信号的频率,如低频信号为11赫,则605赫和495赫在一秒钟内交替变换11次,20赫则变化20次等等。

    由上述可知,移频自动闭塞的载频信号实际是起到一个运载工具作用,而控制信号显示的是低频信号,我们规定四种低频信号代表的意义如下表所列。

     

        

    至于发送何种低频信号,则取决于列车占用区间的状态,如上图所示。

    当列车A占用区间1时,信号机a显示红灯,a点的黄灯和绿灯继电器都处于失磁落下状态,利用a点移频箱内信号继电器的落下条件,使a点箱内自动产生26赫低频信号,经调制后,向区间2传送,当信号机b接收设备收到26赫信号后,b信号点移频箱内的黄灯继电器吸起,使b信号机显示黄灯,由于b点的黄灯继电器吸起,使b点移频箱内产生15赫低频信号,经调制后向区间3发送。当信号机C接收到15赫信号后,  C信号点移频箱内的绿灯继电器吸起,使C点信号机显示绿灯,并使C信号点移频箱内产生11赫低频信号。经调制后向区间4发送11赫信号。从而使区间信号机根据区间占用的情况而自动的改变显示,指挥续行列车的运行。20赫信号只有在进站信号显示双黄灯指示列车进侧线时才使用。

    为了使机车信号设备能够接收到地面移频信号,地面发送设备必须迎着机车运行方向发送信息。

    为了在钢轨绝缘破损后,不使设备产生错误动作,移频自动闭塞采用的载频中心频率有四个,即550赫、650赫、750赫和850赫,以供复线区段相邻两闭塞分区使用,在设计时,必须根据全区段闭塞分区情况,统一交替配置,如图下所示。

     

     

       在单线区段,则采用650赫与850赫两种频率交替配置。

    (五)UM-71轨道电路

    UM-71轨道电路:是引进法国生产的无绝缘轨道电路。利用无绝缘轨道电路作为列车运行的连续速度信息的传输通道,在此基础上建成我国第一个四显示自动闭塞区段(郑州至武昌)。UM-71轨道电路具有可做到一次调整、抗强电干扰、无绝缘、多信息、有断轨检查等技术功能,经实际运用证明设备是先进的,安全程度是高的。

    四显示自动闭塞,在缩短列车间隔时分、增加列车密度、提高运行速度、以及增强运输能力、保证行车安全等方面产生显著的经济效益和社会效益.

    UM-71无绝缘轨道电路是一种低频调制的移频自动闭塞设备,具有较好的抗干扰性能,采用四个载频,能防护相邻轨道电路及上下行线轨道电路相互影响。由于列车速度控制的需要使用多信息机车信号,信息量为1 4个。  (国内使用),在复线区段上下行线各用两种载频。

    其频率为:    下行线    1700 Hz    2300 HZ

                  上行线    2000 Hz    2600 Hz

                  频偏      +11 Hz

    低频信息从10.3 Hz按1.1H z等差数列递增至29 Hz共18个频率(18信息)。

    速度代码/频率对照表如下:

         UM-71无绝缘轨道电路原理图如下。

    轨道电路的发送盒和接收盒轨道继电器,集中装在机械室内,通过电缆和室外设备接通;调谐单元、匹配变压器、空芯线圈、补偿电容等安装在现场。

    从发送器输出的调制信号经过电缆通道传输到匹配变压器及调谐单元,从轨道电路的送电端经钢轨传输到接收端的调谐单元,再经过接收端的匹配单元、电缆通道、将信号传入到接收器中,接收器将调制信号进行限幅、放大及解调后使轨道继电器可靠吸起。根据轨道继电器的吸起或落下来检查轨道的空闲与占用。

    发送器:产生的连续式移频信息通过电缆通道,匹配变压器,调谐单元.发送到轨道上。轨道上的移频信息,一方面提供受电端接收;另一方面通过机车的接收线卷,把移频信息送到机车上,为机车提供由1 8个低频信息组成的连续式机车信号控制信息。

    接收器:轨道电路受电端接受的移频信号,经匹配变压器、电缆通道送到接收器入口;接收器完成信息处理,动作轨道继电器。

    匹配单元:由匹配变压器、电容、电感和对称模拟电缆组成,起到隔离、变压、调整电缆长度的作用。这样以来,不管室外轨道电路距离信号楼有多远,都可以将电缆调整电缆的长度,即实际电缆长度加上模拟电缆长度等于7Km~7.5 Km 。好使得室内设备统一。

    调谐单元的种类及作用:针对四种载频,调谐单元共有四种,其中频率较低的1700HZ、2000HZ的调谐单元由一个电容和一个电感串联组成;频率较高的2300HZ、2600HZ的调谐单元由一个电容和一个电感串联后再与一个电容并联,选择不同的元件值就可制成对应不同频率值的调谐单元。调谐单元的作用:接收本区段的载频信号,短路掉相邻区段的载频信号。

    UM-71无绝缘轨道电路,指的是无有安装在钢轨上的机械绝缘节,但轨道区段之间设有电气绝缘节,是用电气绝缘节隔离的。电气绝缘节长度为26米,这26米是“死区间”----亦即有车不显示。

    电气绝缘节:是利用26米长的钢轨,在其两端各并联一个调谐单元BAl和BA2,

    26米长的钢轨中部加设一个空芯线圈,即组成了一个电气绝缘节。

    电气绝缘节工作原理:本区段的调谐单元对相邻区段的载频信号呈现串联谐振,相当于一根短路线,使相邻区段的载频信号进入不了本区段,调谐单元对本区段的载频信号呈现并联谐振,出现高阻,有利于传输和接收本区段的信号,这样就实现了不同区段两种载频信号的电气隔离。如下图所示。

    空芯线圈:是由直径为1.53毫米的19股铜丝绕成的无铁芯线圈,作用是平衡牵引电流的回流、减少干扰、保证调谐区工作的稳定。

     

    联锁部分

    一. 联锁概念

    什么叫联锁呢?

    在车站,为保证行车安全,在有关的道岔和信号机之间,以及信号机和信号机之间,必须建立一种互相制约的关系,这种互相制约的关系叫做联锁。

    通过技术方法使有关的信号、道岔和进路必须按照一定程序、一定条件才能动作或建立起来的相互制约的联系关系,叫做联锁。

    二. 联锁条件

    1. 当进路上的有关道岔开通位置不对或敌对信号机未关闭时,该信号机不能开放;信号机开放后,该进路上的有关道岔不能扳动,其敌对信号机不能开放。

    2. 正线上的出站信号机未开放时,进站信号机不能开放通过信号;主体信号机未开放时,预告信号机不能开放。

    3.区间内正线上的道岔,未开通正线时,两端站不能开放有关信号机。设在辅助所的闭塞设备与有关站闭塞设备应联锁。

    4.集中联锁设备应保证:当进路建立后,该进路上的道岔不可能转换(即为道岔的进路锁闭);当道岔区段有车占用时该区段的道岔不可能转换(即为道岔的区段锁闭);列车进路向占用线路上开通时,有关信号机不可能开放(引导信号除外);能监督是否挤岔,并于挤岔的同时,使防护该进路的信号机自动关闭。被挤道岔未恢复前,有关信号机不能开放。

    5.向占用线路排列进路时,有关列车信号机不得开放(引导信号除外)。

    6.联锁设备必须工作可靠并符合故障一安全原则。

    7.当外线任何一处发生断线或混线时,不能导致进路错误解锁、道岔错误转换以及信号机错误开放。

    三. 联锁类型

    实现上述联锁关系装置的称为联锁设备。

    如果以纯机械锁闭装置(例如,用联锁箱等)实现联锁,就叫做机械联锁。

    如果用机械和电气结合的锁闭方法(例如,用电锁器等)实现联锁,叫电锁器联锁。

    如果用电气方法(例如用机械室继电器等)实现联锁,就叫做电气集中联锁。

    在铁路上,最初采用的是机械联锁。因为机械联锁的锁闭装置容易磨损,可靠性和安全性较差,已逐渐被淘汰。

    电锁器联锁一般用于手动道岔,由于联锁设备分散设置,效率不高。电锁器联锁的主要缺点是不能防止某些人为的错误,安全性较差。

    在行车密度较大而又有可靠的交流电源的车站都采用电气集中联锁。

    电气集中联锁设备是集中设置的电气设备。进路、道岔、信号之间的联锁采用电气集中,操作简单、动作迅速、安全好、效率高。

    用继电器实现集中联锁叫继电集中。用电子器件实现集中联锁叫电子集中。

    用微型计算机实现集中联锁叫 微机联锁。

    四. 联锁说明

    列车或车列在站内行驶时所经过的经路叫做进路。列车或车列在进路上运行时,影响它的安全因素是很多的,但基本上可分为进路内的因素和进路外的因素两大类。进路内的因素苞括进路上的道岔位置和状态是否符合安全要求,车辆在进路上运行时,道岔是不是能扳动,以及进路上是否已有车辆占用等;进路外的因素是指进路与进路之间是否互相冲突。因为车站上有许多进路,有些进路如果同时开通,就将导致撞车的危险。要保证行车安全,就必须使防护进路的信号机与进路、道岔之间发生联锁。

    1. 进路与道岔的关系

    为了保证列车运行的安全,在列车驶入进路之前,对于进路上的道岔必须采取两项措施:一是必须检查它们的位置与需要开通进路方向相符。当道岔的位置确实符合进路开通方向时,我们说,进路在开通状态(道岔尖轨与基本轨密贴,间隙﹤4mm )。二是将它们锁闭在规定位置而不能再扳动。对道岔的这种锁闭,叫做进路锁闭。道岔在进路锁闭之后,我们称道岔处在锁闭状态。反之则称它在解锁状态。

    总的来说,进路与道岔的关系是这样的:当排列某一条进路时,与进路有关的道岔必须在规定位置,然后被锁闭在规定的位置。那么道岔锁闭之后在什么情况下才可能解锁呢?从安全角度看,显然是在没有列车驶入进路的情况下,或者列车驶入了进路而且通过了道岔区段之后才可以解锁。

    当道岔区段有车占用时,该区段内的道岔不能转换。 联锁道岔受进路锁闭、区段锁闭、人工锁闭,在任何一种锁闭状态下,道岔不得启动(人工锁闭系指利用操纵设备切断道岔控制电路或用转辙机的安全接点切断启动电路)。

    集中联锁道岔一经启动,不论其所在区段轨道电路故障或有车进入轨道区段,均应继续转换到规定位置。道岔因故被阻不能转换到规定位置时,对非调度集中操纵的道岔,应保证经操纵后转换到原位;对调度集中操纵的道岔,应自动切断供电电源,停止转换。

    道岔的表示电路应符合下列要求:

    (1)道岔表示应与道岔的实际位置相一致,并应检查自动开闭器两排接点组在规定位置。

    (2)联动道岔只有当各组道岔均在规定的位置时,方能构成规定的位置表示。

    (3)单动、联动或多点牵引道岔须检查各牵引点的道岔转换设备均在规定的位置。

    2. 进路与进路之间的联锁

    在车站上有些进路如果同时建立时,有可能造成列车互撞的危险。存在列车互撞危险的进路称它们为互为敌对进路。

    敌对进路-----两条或两条以上的进路,有一部分相互重叠或交叉,有可能发生列车或机车车辆冲突的进路称为敌对进路。防护敌对进路的信号机称为敌对信号机。

    站内联锁设备中,除引导接车外,敌对进路(必须互相照查,不能同时开通的进路)为:

    (1)同一到发线上对向的列车进路与列车进路。

    (2)同一到发线上对向的列车进路与调车进路。

    (3同一咽喉区内对向重叠的列车进路。

    (4)同一咽喉区内对向重叠的调车进路。

    (5)同一咽喉区内对向重叠或顺向重叠的列车进路与调车进路。

    (6)进站信号机外方,列车制动距离内接车方向为超过6%。的下坡道,而在该下坡道方向的接车线末端未设线路隔开设备时,该下坡道方向的接车进路与对方咽喉的接车进路、非同一到发线顺向的发车进路以及对方咽喉调车进路。(可参考下面图)

    (7)防护进路的信号机设在侵入限界的轨道绝缘节处,禁止同时开通的进路。

    (8)向驼峰推送车列占用的股道与另一端向该股道的接车进路或调车进路。

    (9)咽喉区内无岔区段上对向的调车进路(到发线上无岔区段应根据具体情况及运营要求另作规定)。

    在敌对进路之间必须采取锁闭措施,以便在建立一条进路时,将它的敌对进路锁闭,使它不能建立。更具体地说,当甲乙进路互为敌对进路时,在建立甲进路时必须先检查乙进路是没有建立,并且在建立了甲进路之后,将乙进路锁住,使它不能在建立。只有当甲进路取消之后,乙进路才能解锁,才有建立的可能。

    车站上,有些进路是因为对道岔位置的要求不一致而不能同时建立,这样由于道岔位置不同而不能同时建立的进路,叫做抵触进路。对于抵触进路不需另外采取措施来防止它们同时建立。

    3. 信号机是防护进路的

    只有在进路开通状态,以及敌对进路未建立的条件下,信号机才能开放,给出允许信号。在信号开放的时间内,与进路有关的道岔以及敌对进路都不能解锁。只有信号关闭后,它们才有解锁的可能。这样就保证了行车的安全。

    进站或接车进路信号机因故障不能正常开放信号或开通非固定接车线路时,应使用引导信号。开放引导信号,必须检查所属主体信号机红灯在点灯状态。

    列车主体信号机和调车信号机应设有灯丝监督,在信号机开放后,应不间断地检查灯丝完好状态;进站和有通过列车的正线出站或进路信号机,当红灯灭灯时该信号机不得开放;开放预告信号机或复示信号机时,应不间断地检查其主体信号机在开放状态。

    4. 安全线:当车站的进站制动距离内,如果有等于或大于6‰的下坡道,为了保证办理相对方向同时接车或同方向同时接发列车的作业安全,在到发线的末端也应设置安全线。

        在衔接有专用线的车站上,为了防止专用线上的机车车辆任意进入站内线路,和站内线路上的机车车辆发生冲突,在衔接地点应当设置安全线。

    5. 避难线:在山区长大下坡道下方的车站上,应该设置避难线。这是为了防止在长大下坡道上失去控制的列车,闯入站内股道上,发生撞车或其他事故。

    避难线的设置位置在出站端或进站端。

    6. 基本进路与迂回进路(变通进路)

    基本进路-----是指正常情况下最短和最合理的运行径路

    迂回进路-----(又叫变通进路)是对应与基本进路说的,当基本进路不能排通时,可以改为排列稍为绕远的迂回进路。

    (1)平行变通进路:

    大站,往往在进路始端和终端两点间,不只有一条进路。例如上图中下行III道接车进路(X→IIIG)就有两条,一条经由道岔(5/7)、9/11、13/15;另一条经由道岔5/7、1/3、(9/11)。(不带括号者为定位;带括号者为反位。)因为前者不影响由D17向IIAG区段调车,即影响其他作业较少,所以指定它为基本进路,即平时正常使用的进路;而称后者为变通进路,也叫迂回进路,只有基本进路排不通时,才使用它。由于渡线5/7和渡线9/11是平行铺设的,所以又称它们为平行变通进路。有时也称平行变通进路中的基本进路为优先进路,称变通进路为非优先进路。

    有变通进路的地方,在绕弯的线路段上,要设置一个变通按钮,如上图中的D7A或D9A(这里是用调车按钮兼作变通按钮用的。若此处没有D7A和D9A则需要在此处的线路模型上加设一个变通按钮,用方框表示,文字符号为BA)。

    (2)八字型变通进路:

    例如下行I道接车进路(X→IG)就有一条经由道岔(5/7)、(13/15)的变通进路。图中的D11A可兼作此变通进路的变通按钮。

    五. 联锁图表

    依据车站信号设备平面布置图,编制记载信号、进路以及道岔之间联锁关系的文件是联锁表,由车站信号设备平面布置图和联锁表组成联锁图表。

    联锁图表是决定车站信号设备设计工作的基本文件。

        在联锁表,由左至右,通常分为以下七栏:

    1. 方向:记载接发车方向和调车方向;

    2. 进路:记载列车进路到达哪一股道,或从哪一股道发车(通过进路是由接车进路和发车进路组成),记载调车进路由哪些股道或哪些线往外调车,以及向哪些股道或哪些线调车;

    3. 进路号码:将各条进路顺序编以号码,以便填写敌对进路关系时比较方便;

    4. 信号机:记载防护进路的信号机编号名称和相应的显示;

    5. 道岔: 记载与进路有关的道岔。 在该栏中,仅填道岔号码时,表示该道岔为定位;填有带小括弧( )道岔号码时,表示该道岔为反位;当道岔号码带中括弧〔 〕时,表示该道岔为防护道岔;

    6. 敌对进路:记载敌对进路的编号;

    7. 轨道区段:在设有轨道电路的车站,需要记载进路上轨道区段的编号。在未设轨道电路(为半自动闭塞所设的一段专用轨道电路除外)的车站,则可不列次栏。

     

    闭塞部分

    一.概述

    区间的界限,在单线区段以进站信号机为车站与区间的界限;在复线或多线区段,分别以各线的进站信号机或站界标为车站与区间的界限。

    由车站向区间发车时,必须确认区间无车。在单线线路上还必须防止两个车站同时向一个区间发车。为此,要求按照一定的方法组织列车在区间内运行,一般叫做行车闭塞法,或叫做闭塞。

    闭塞是指在一个区间内,在同一时间里,只能允许一个列车占用的行车方法。

    所谓“闭塞”,是指当一列车出发占用区间后,就使该区间两端封闭起来,不允许再向这一区间发车,直到该列车出清这一区间之后,才能向该区间发第二个列车。这样,就可以防止追尾事故,对于单线铁路,还要防止正面冲突事故。因此,人们便研究和创造出各种闭塞方法和闭塞制度以及相应的闭塞设备。

    实现区间闭塞的方法,一般有两种:

    1.时间间隔法:

    列车按照事先规定好的时间由车站发车,使二个列车之间间隔一定的时间运行。初有铁路时,曾用过这种方法,后来由于列车次数增多,速度加快,有时列车在区间内又会发生迟缓,停车、分离或尾追等事故,这种方法就越来越不能保证行车安全。    

    2.空间间隔法:

    自从有了电报电话以后,两站间就开始使用电报或电话互相联系,以了解列车开出和到达的情况,并规定必须在占用区间的列车全部到达接车站或退回原发车站后,才准许向区间再发出另一列车。也就是说,在同一空间(即区间)只允许运行一列列车,以保证列车在区间行驶的安全,这种行车方法,叫做空间间隔法。

    把铁路线路分成若干线段(区间或闭塞分区)。在每个线段内,同时只准许一个列车运行,即将列车按空间间隔开。由于这种方法能较好地保证行车安全,所以逐渐地代替了时间间隔法。现在我们所说的区间闭塞,就是指空间间隔法而言。

    实现区间闭塞的制度,一般有以下几种:

    1.人工闭塞:

    为了仅仅准许一列列车有权占用区间,必须发给一定形式的行车凭证。电报或电话闭塞的行车凭证是路票。路票是发车站值班员在和接车站值班员取得联系后签发的。列车司机得到路票后,即可向路票所指定的区间发车。因为这种方法是以人工保证的,所以也叫做人工闭塞方法,简称人工闭塞。

    在工作繁忙时容易因疏忽而造成错误签发路票,以至引起撞车事故,因而后来又采用了电气路签或电气路牌闭塞。此种闭塞方式的行车凭证是从闭塞机里取出的路签或路牌。在一个区间的两端车站上各安装一台闭塞机,并作为一组。在一组闭塞机里装有这个区间的行车凭证——路签或路牌。只有在区间开通的条件下,由两站的车站值班员协同操作,才能由一组闭塞机里取出一个路签或路牌。列车司机得到路签或路牌后,才有权占用该路签或路牌所属的区间。因此能保证区间只有一个列车运行。只有将已取出的路签或路牌再纳入该组的闭塞机里之后,才说明这个区间由闭塞状态又复原为开通状态,才有可能重新取出另一个路签或路牌,亦即才有可能向这个区间发出另一列车。很明显,这样一来,就克服了电报或电话闭塞的缺点,行车安全得到了保证。

    路牌和路签闭塞。虽然在铁路运输中起了很重要的作用,但事物总是向前发展的,当行车密度加大时,这种闭塞方法就不适应了。因为取送路牌或路签的工作很繁重,还会限制列车通过车站速度,有时会发生路签或路牌破损、丢失等事故,在运量不平衡区段还要调整路签或路牌数,因而延长了车站间隔时间,而车站间隔时间延长就阻碍着线路通过能力的进一步提高,不能适应高速行车的要求。正是因为如此,半自动闭塞就逐步发展了起来。

    2. 半自动闭塞:

    为了取消象路签或路牌那样的实物凭证,半自动闭塞以出站信号机的进行信号作为列车占用区间的行车凭证。某一区间的两个车站,所属同一区间的出站信号机同时只准许一架开放,并且只有取得证明在区间空闲时才能开放。

    发车站,必须在办好闭塞的基础上才能开放出发信号。出站信号机开放后,区间即成为闭塞状态。列车依据出站信号机的进行信号开出车站时,这架出站信号机就自动地关闭,并和有关出站信号机一样被锁在关闭的位置上。只有取得证明该列车确实全部出清区间以后,才能解除对出站信号机的锁闭,这个区间才又复原为开通状态。                                     

    可见,半自动闭塞能缩短会车时间,从而提高了区间的通过能力,改善了车站值班员和机车乘务人员的劳动条件。                                                            

    半自动闭塞只有列车进出车站的检查设备(用较短的一段轨道电路), 在区间没有检查设备。为了证实列车在区间没有遗留下车辆,列车到站要由车站值班员确认。亦即列车是否出清区间还要由人工保证。

    这种方法,既要人的操纵,又需依列车的作用自动动作,所以叫做半自动闭塞。                               

    目前继电半自动闭塞已作为一种主要闭塞制度在我国数万公里的铁路上安装运用。           

    由于半自动闭塞办理闭塞的手续(包括开放出站信号机)还是需要一定的时间,而且在这种制度下,一个区间仍只准有一列列车运行。这样,当铁路运量不断增大,要求进一步提高区间通过能力时,就显示出半自动闭塞本身的局限性。

    3. 自动闭塞:

    如果将区间划分若干个闭塞分区,每个闭塞分区都装以轨道电路,在分界点处设通过信号机,并使之与轨道电路相联系,依据列车占用和出清闭塞分区而自动地变换信号显示,这样就可以在一个区间内,同时允许几列列车运行,从而使线路的通过能力得到进一步提高;并且,闭塞分区内是否留有车辆也由设备直接检查出来。这种方法,不再需要人的操纵,我们称之为自动闭塞。

    自动闭塞运用在复线铁路上,提高线路通过能力的效果特别显著,因为复线铁路没有列车交会。                                                                            

    在自动闭塞区段,一般在机车上还要装有机车自动信号,以反映地面固定信号机的显示。机车自动信号又往往附有自动停车装置,当列车司机没有按机车自动信号的显示采取措施时,自动停车装置就发挥其作用,迫使列车自动地停车。很明显,装上机车自动信号和自动停车装置后,就能进一步地发挥出自动闭塞的效果。

    4.列车运行自动调整:

    这种设备不需要将区间划分成固定的若干闭塞分区,而是在两个列车间自动地调整运行间隔,使之经常保持一定的距离(例如通过卫星定位系统)。所以叫做列车运行自动调整,它可以大大地提高区段的通过能力,这种设备目前正在进一步研究中。

    一般说来,应当依据具体情况选用与不同发展时期的要求相适应的设备。就闭塞设备来说,在我国铁路上,目前一般单线区段多采用半自动闭塞,复线区段多采用自动闭塞。

    二.半自动闭塞

    (一)定义

    所谓半自动闭塞,就是利用人工来办理闭塞及开放出站信号机;而由出发列车自动地关闭出站信号机并进行区间闭塞,故称为半自动闭塞制度。

    继电半自动闭塞是以继电器做为基本单元构成电路的逻辑关系完成两站间的闭塞作用的。当采用这种制度时,相邻两站间要设置一对半自动闭塞机BB(叁看下图),并通过两站间的闭塞电话线连接起来,闭塞机可以完成以下作用:

    1.甲站要求向乙站发车,必须得到乙站同意后,甲站的出站信号机才能开放;

    2.列车自甲站出发进入区间后,实现区间闭塞,两站都不能再向区间发车;

    3.列车到达乙站后,车站值班员确认列车完全到达,以专用按钮办理到达复原后,区间才能解除闭塞。

     (二)继电半自动闭塞的技术条件

    保证行车安全方面

    1.单线继电半自动闭塞只有在本站发出请求发车信息并收到对方站的同意接车信息后,闭塞机才能开通,出站或通过信号机才能开放。

    2.复线继电半自动闭塞,只有在先行列车到达接车站,并收到接车站的到达复原信息之后,闭塞机才能开通,出站或通过信号机才能开放。

    3.单线继电半自动闭塞的发车站闭塞机开通后,接车站闭塞机应处于闭塞状态;复线继电半自动闭塞只有在区间空闲时发车站闭塞机才能开通,当列车出发进入发车轨道电路区段时,双方站的闭塞机均应处于闭塞状态。

    4.列车到达接车站,进入并出清轨道电路区段,车站值班员确认列车全部到达后,恢复接车手柄,才能以专用按钮发送到达复原信息,使双方站闭塞机复原。

    5.闭塞机闭塞后,在接车站未发送到达复原信息或事故复原信息之前,如发生各种故障或错误办理时,均不能使接车站闭塞机复原,更不能使发车站闭塞机开通。

    6.发车站闭塞机开通并开放出站信号后,如果轨道电路发生故障时,应使双方站

    闭塞机处于闭塞状态;列车到达接车站,如果轨道电路发生故障时,允许经过登记后,打破铅封使用事故按钮办理事故复原。

    7.继电半自动闭塞专用的轨道电路区段,其长度不少于25米。半自动闭塞专用的轨道电路最好能避免人为无意分路的障碍。

    8.继电半自动闭塞的外线,任何一处发生断线、接地、混线、混电以及外界干扰故障时,或错误办理时,均应保证闭塞机不能错误开通。

    9.继电半自动闭塞机与站间闭塞电话共用外线时,应保证电话振铃电流不能干扰闭塞机的正常运用;使用闭塞机时也不应降低通话质量和振铃信号。

    10.继电半自动闭塞电源设备停电复原时,闭塞机应处于闭塞状态。只有两站值班员确认区间空闲后,用事故按钮才能使闭塞机复原。

    提高行车效率方面

    11.闭塞机开通后在出站信号机开放之前,允许发车站取消已办好的闭塞。

    12.闭塞机开通后,在未办理接、发车进路之前,允许车站内进行调车作业。

    13.闭塞机应动作迅速、办理简便,表示清楚。具有开通,闭塞、列车出发通知和列车到达等信号和表示。

    14.闭塞机最好能把一般通话的呼叫信号和请求发车信息区分开,并能使请求发车信息有贮存性能。

    15.闭塞机最好具有便于检查闭塞设备和外线的性能,以便及时发现故障,保证正常运用。

    16.在保证“故障—安全”的原则下,应尽量减少元件,简化电路,提高闭塞机可靠性,保证设备运用安全,在发生故障后能迅速恢复使用。

     

    使用性能和经济方面

    17.闭塞机能与各种类型的车站信号设备相结合。

    18在继电半自动闭塞区间可以接入任何数量的线路所和分歧线,并可能满足补机、路用列车和机外调车等特殊情况的要求。

    19.能适应各种牵引类型的需要。

    20.元件应尽量采用通用元件,尽量缩小闭塞机的体积,并做成标准组合化。

    21.电源电压在士lo%波动范围内,闭塞设备应保证稳定动作。

     (三)半自动闭塞设备

    64D型继电半自动闭塞的主要设备:区间两端车站上各设一台闭塞机,一段专用的轨道电路和出站信号机,它们之间用电线相连,用来实现彼此间的电气联锁关系。为了实现两站闭塞设备之间的互相联系与控制,两站闭塞及也有电线相通,彼此间也发生电气联锁关系。

    闭塞机包括操纵箱、继电器、操纵按钮、表示灯和电铃等。

    操纵按钮有3个:闭塞按钮(BSA)、复原按钮(FUA)、事故按钮(SGA)。

    发车表示灯有3个:绿、红、黄。

    接车表示灯有3个:绿、红、黄。

    继电器有13个,主要是:

    闭塞继电器(BSJ),作用是监督闭塞机状态,有电吸起时表示区间空闲,无电落下时表示区间占用。

    开通继电器(KTJ),有电吸起时表示区间开通(注意:区间开通和区间空闲是有区别的。)表示发车站值班员与接车站值班员双方经过办理手续,发车站要求发车,接车站同意接车。用开通继电器吸起接点控制出站信号机开放的电路。

    复原继电器(FUJ),是为了使闭塞机复原用的。含到达复原和事故复原。

    其他继电器是办理闭塞过程中用的,起安全作用或逻辑作用。

    顺便说一句,我国自行研制的“64D型继电半自动闭塞设备”,为我国铁路运输事业发挥了巨大的作用,曾获得国家科技进步一等奖。

    三.自动闭塞

    (一) 自动闭塞的共同要求

        在双线区段上,应采用自动闭塞,自动闭塞的共同要求为:

    (1)闭塞分区被占用或轨道电路失效时,防护该闭塞分区的通过信号机应自动关闭。

    (2)当进站及通过信号机红灯灭灯时,其前一架通过信号机应自动显示红灯。带红灯保护区的四显示区段,保护区的通过信号机红灯灭灯时,其前一架信号机可自动显示黄灯。

    (3)双向运行的自动闭塞区段,在同一线路上,当一个方向的通过信号机开放后,相反方向的信号机均须在灭灯状态,与其衔接的车站向同一线路发车的出站信号机开放后,对方车站不得向该线路开放出站信号机。

    (4)双向运行的自动闭塞区段,当区间被占用或轨道电路失效时,经两站工作人员确认后,可通过规定的手续改变运行方向。

    (5)双向运行的自动闭塞区段,当发生设备故障或受外电干扰时,不得出现敌对发车状态。

    (6)闭塞设备中,当任一元件、部件发生故障或钢轨绝缘破损时,均不得出现信号的升级显示。

    (7)在自动闭塞区段,站内控制台上应设有下列区间表示:

        1)双向运行区间列车运行方向及区间占用。

        2)邻近车站两端的正线上,至少相邻两个闭塞分区的占用情况。

        3)必要的故障报警。

    (二) 自动闭塞的设备概况

    自动闭塞是由运行中的列车自动完成闭塞作用的一种闭塞设备。采用自动闭塞时,将两站间的区间正线划分成若干个小区间,这个小区间称为闭塞分区,每个闭塞分区的起点设置一个通过色灯信号机进行防护。由于每个闭塞分区都装设轨道电路,使信号机的显示根据列车的运行而自动变换因而能够正确反映列车的运行情况和钢轨的完整与否,并及时传给通过色灯信号机显示出来,向接近它的列车指示运行条件。

    在自动闭塞条件下,准许列车占用区间的行车凭证是出站信号机(闭塞分区为通过信号机)的进行显示(绿灯或黄灯)。通过色灯信号机经常显示绿灯,随着列车驶入或离开闭塞分区而自动变换。但进站、出站信号机的显示一般仍由车站实行人工控制,只有当连续地放行通过列车时,才改由列车运行控制。

    在每个闭塞分区的始端,都安装有色灯信号机,用来防护其后方的闭塞分区。这些通过色灯信号机平时显示状态是“开放定位式”,即显示绿灯,只有当列车占用该信号机所防护的闭塞分区或线路发生断轨坍方等故障时,才显示停车信号。

    由于自动闭塞能够在保证行车安全的前提下自动地指挥列车运行,并朗最大限度地缩短列车运行间隔,同时还不需要办理闭塞手续,所以能够充分发挥固有线路的通过能力,提高列车的密度与速度。综上所述,自动闭塞的主要特点表现在以下几方面:

    1.缩短了列车运行间隔,增加了行车密度,同时自动闭塞能不间断地向司机预告其前方线路状态,因而提高了列车的运行速度。使区段的通过能力得到显著提高。

    2.节省了车站办理闭塞的时间,简化了车站值班员办理接发及通过列车的手续。因此,不但提高了车站通过能力,而且还减轻了车站值班人员的劳动强度。

    3.由于闭塞分区设置了轨道电路,因此色灯信号机的显示状态,可以反映列车的位置及线路状态,当和机车信号配合使用时,可以使自动闭塞设备的效能得到更大的发挥,使运输效率得到进一步提高。

    (三)自动闭塞的技术条件

    根据自动闭塞的工作特点,在研究和设计自动闭塞时,应满足以下各项技术条件:

    1.当列车进入闭塞分区时,防护该分区的通过色灯信号机应自动地显示禁止灯光(红色),列车出清闭塞分区后,应自动地改变为允许灯光(黄色或绿色)。

    2.自动闭塞的工作不应该间断,当基本电源停电时,应能由备用电源向设备供电。

    3.自动闭塞的工作应当稳定可靠,当设备发生任何危及行车安全的故障时(如线路电路混线或断线,轨道电路钢轨绝缘破损,雷击等),应使色灯信号机显示较限制的信号。

    4.当色灯信号机应该显示红灯而灯泡断丝时,为了防止冒进信号引起危险,应将红色灯光自动转移到前一架色灯信号机上。

    5.当色灯信号机应该显示允许灯光而灯泡断丝时,最好能使该色灯信号机改为较限制的灯光,而其前方的色灯信号也应转移为相应的灯光。如果信号机本身不能改变其灯光时,(例如探照式色灯信号机),最好也要使其前方的色灯信号机转移为较限制的灯光。

    6.在采用有轨道电路的自动闭塞时,如遇断轨的情况,最好能使防护该分区的色灯信号机自动处于关闭状态。

    7.电路图的各环节最好能标准化,以便于工厂化施工。

    8.自动闭塞的设备要简单,机件少,消耗电能少。

    9.自动闭塞韵电路应尽量简单、灵活,既便于改建时能适应各种情况,如增加显示数目,由单线过渡到复线,增装机车信号,向电力牵引发展,向行车指挥自动化发展等,又便于工作人员熟悉和掌握。

    10.单线自动闭塞还应绝对防止有对向发车的可能性。

    总之,研究和设计自动闭塞设备时,应当用简单,可靠和经济的方法来实现上述技术条件。以保证行车安全和提高运输效率。

    (三)自动闭塞的分类

    自动闭塞按照运营上和技术上的特征,可作如下分类:

    1.按照行车组织方法,分为单向自动闭塞和双向自动闭塞。

    在复线上是采用单方向列车运行的,即一条线路只允许上行列车运行,而另一条线路只允许下行列车运行。为此对于每一条线路仅在一侧装设通过色灯信号机,这样的自动闭塞叫做单向自动闭塞,如下图(a)所示。

    在单线区段上,因为一条线路需要双方向行车,为了调整双方向列车运行而在线路两侧都装设通过色灯信号机,这样的自动闭塞叫双向自动闭塞,如下图(b)所示。

        单向自动闭塞只防护列车的尾部,而双向自动闭塞必须对列车的尾部和头部两个方向进行防护。双向自动闭塞,为了防护列车的头部,平时规定一个方向的通过色灯信号机亮灯,另一方向信号机则全部灭灯,只有在需要改变运行方向,而且区间是空闲的条件下,由车站值班员办理改变运行方向手续。所以双向自动闭塞设备要比单向自动闭塞设备复杂一些。

    2.依通过信号机的显示制度,分为三显示和四显示的自动闭塞。如下图中(a)是三显示自动闭塞,(b)是四显示自动闭塞。

       

     三显示自动闭塞----采用红、黄、绿三种颜色灯光的三显示自动闭塞。每一闭塞分区的长度一般为1200~3000米,这样有利于装设轨道电路和提高区间通过能力。

    四显示自动闭塞----采用红、黄、黄绿、绿,三种颜色灯光四种显示的自动闭塞。每一闭塞分区的长度一般为800~1000米,这样更有利于列车提速运行和提高区间通过能力。

    自动闭塞通过色灯信号机的显示,是调整列车运行的命令,它的显示意义如下。

     

    三显示自动闭塞通过色灯信号机的显示意义:(规定速度80-100Km/h)

    红灯——表示该通过色灯信号机所防护的闭塞分区有车占用或设备发生故障,要求续行列车停车。当列车停车两分钟后而显示仍不改变时,司机可鸣笛一长声,并根据运转车长的指示,以不超过20公里/小时的速度,继续运行至下一架通过色灯信号机,如下一架信号机仍显示红灯,仍可依上述办法处理。

    黄灯——表示列车前方有一个闭塞分区空闲,要求列车注意并减速运行。

    绿灯——表示列车前方至少有二个闭塞分区空闲,准许列车按规定速度运行。

    位于长上坡道的通过色灯信号机,当列车停车后不易启动时,可以附设特别容许信号——兰色灯光,准许被指定的列车(如重量很大的货物列车),以不超过20公里/小时的速度不停车越过上述通过色灯信号机的红色灯光。为了安全起见,这种特别容许信号不能装在预告或进站信号机上。

    四显示自动闭塞  通过色灯信号机的显示意义:(规定速度270-300Km/h)

    红灯——表示该通过色灯信号机所防护的闭塞分区有车占用(或前方只有一个闭塞分区空闲)或设备发生故障,要求续行列车停车。

    黄灯——表示列车前方有二个(或三个)闭塞分区空闲,要求列车按确定的速度运行。

    绿、黄二灯——表示列车前方有四个(或五个)闭塞分区空闲,要求列车按确定的速度运行。

    绿灯——表示列车前方至少有六个闭塞分区空闲,准许列车按规定速度运行。

    注意:四显示自动闭塞,有两个信号机显示红灯,有两个信号机显示黄灯,有两个信号机显示绿黄灯。

    两个信号机显示红灯:是因为闭塞分区短,列车速度高,制动距离长,一个闭塞分区不满足于制动距离。

    两个信号机显示黄灯:虽然都显示黄灯,但轨道电路中的电码不一样,所以机车信号显示的运行速度不一样。

    两个信号机显示绿黄灯:虽然都显示绿黄灯,但轨道电路中的电码不一样,同样机车信号显示的运行速度不一样。

    绿灯:同样是绿灯显示,但轨道电路中的电码不一样所以机车信号显示的运行速度不一样。

    总之,四显示自动闭塞区间通过信号机的显示,是根据运行前方空闲路程的长度来决定列车的运行速度。在显示同样信号的闭塞分区,机车信号的显示则不同。

    从机车信号看来,是从最高速度运行向停车的递减序列。例如:300Km/h、270Km/h、200Km/h、160Km/h、120Km/h、100Km/h、85Km/h、65Km/h、45Km/h、20Km/h、0Km/h。

    可见,只有多信息轨道电路才能实现以上诸多的速度要求。

     

    为什么要采用四显示自动闭塞呢?

     三显示自动闭塞利用红、黄、绿三种颜色显示来表明区间空闲或占用,仅能预告列车前方两个闭塞分区的状态,列车从最高速度到停车的制动距离为一个闭塞分区,提高列车速度和增加列车重量都要加大列车的制动距离,从而也就加大了闭塞分区的长度,导致列车追踪间隔加长,使区间通过能力下降。

    四显示自动闭塞是一种新型自动闭塞制式,它增加了黄绿显示,能预告列车前方至少四个闭塞分区的状态,这样即可适当缩短闭塞分区长度,从而缩短列车追踪间隙,增加区段内通过列车的对数。因此采用四显示自动闭塞对提高区间通过能力、提高运行速度、保证行车安全都有利。

    展开全文
  • 【UCOSIII】UCOSIII的互斥信号

    万次阅读 2018-07-02 21:18:54
    信号量用于控制对共享资源的保护,但是现在基本用来做任务同步用(不太清楚的可以参考链接:【UCOSIII】UCOSIII的信号量)。   优先级反转 优先级反转在可剥夺内核中是非常常见的,在实时系统中不允许出现这种...

    信号量用于控制对共享资源的保护,但是现在基本用来做任务同步用(不太清楚的可以参考链接:【UCOSIII】UCOSIII的信号量)。

     

    优先级反转

    优先级反转在可剥夺内核中是非常常见的,在实时系统中不允许出现这种现象,这样会破坏任务的预期顺序,可能会导致严重的后果,下图就是一个优先级反转的例子:

    关于这个优先级反转的例子,先来进行分析一下:

    1. 任务H和任务M起初处于挂起状态,等待某一事件的发生,而任务L正在运行;
    2. 某一时刻任务L想要访问共享资源,在此之前它必须先获得对应该资源的信号量;
    3. 任务L获得信号量并开始使用该共享资源;
    4. 由于任务H优先级高,它等待的事件发生后便剥夺了任务L的CPU使用权(或者说,任务L调用了延时函数,发生任务调度,任务H此时是最高优先级);
    5. 任务H开始运行;
    6. 任务H运行过程中也要使用任务L正在使用着的资源,由于该资源的信号量还被任务L占用着,任务H只能进入挂起状态,等待任务L释放该信号量;
    7. 任务L继续运行;
    8. 由于任务M的优先级高于任务L,当任务M等待的事件发生后,任务M剥夺了任务L的CPU使用权(或者说,任务L又调用了延时函数,发生任务调度,任务M此时是最高优先级);
    9. 任务M处理该处理的事;
    10. 任务M执行完毕后,将CPU使用权归还给任务L;
    11. 任务L继续运行;
    12. 最终任务L完成所有的工作并释放了信号量,到此为止,由于实时内核知道有个高优先级的任务在等待这个信号量,故内核做任务切换;
    13. 任务H得到该信号量并接着运行。

    在这种情况下,任务H的优先级实际上降到了任务L的优先级水平。因为任务H要一直等待直到任务L释放其占用的那个共享资源。由于任务M剥夺了任务L的CPU使用权,使得任务H的情况更加恶化,这样就相当于任务M的优先级高于任务H,导致优先级反转。

    解决这个问题大办法就是:提升优先级。当由于信号量被任务L占用而导致任务H被挂起之后,将任务L的优先级暂时提升至任务H的优先级,直到任务L释放信号量。也就是说,将拥有信号量的任务优先级暂时提升至目前正在等待该信号量的任务中的最高优先级!这样,就不会被比等待该信号量的任务的优先级低的任务,强行剥夺拥有信号量的任务,导致优先级反转。

     

    互斥信号量

    遵循解决优先级反转的一般解决思路,UCOSIII支持一种特殊的二进制信号量:互斥信号量,用它可以解决优先级反转问题,如下图所示:

    同样,对于这个流程也进行分析一下:

    1. 任务H和任务M起初处于挂起状态,等待某一事件的发生,而任务L正在运行;
    2. 某一时刻任务L想要访问共享资源,在此之前它必须先获得对应该资源的信号量;
    3. 任务L获得信号量并开始使用该共享资源;
    4. 由于任务H优先级高,它等待的事件发生后便剥夺了任务L的CPU使用权(或者说,任务L调用了延时函数,发生任务调度,任务H此时是最高优先级);
    5. 任务H开始运行;
    6. 任务H运行过程中也要使用任务L在使用的资源,考虑到任务L正在占用着资源,UCOSIII会将任务L的优先级升至同任务H一样,使得任务L能继续执行而不被其他中等优先级的任务打断;
    7. 任务L以任务H的优先级继续运行,注意此时任务H并没有运行,因为任务H在等待任务L释放掉互斥信号量;
    8. 任务L完成所有的任务,并释放掉互斥型信号量,UCOSIII会自动将任务L的优先级恢复到提升之前的值,然后UCOSIII会将互斥型信号量给正在等待着的任务H;
    9. 任务H获得互斥信号量开始执行;
    10. 任务H不再需要访问共享资源,于是释放掉互斥型信号量。
    11. 由于没有更高优先级的任务需要执行,所以任务H继续执行;
    12. 任务H完成所有工作,并等待某一事件发生,此时UCOSIII开始运行在任务H或者任务L运行过程中已经就绪的任务M;
    13. 任务M继续执行。

    注意!只有任务才能使用互斥信号量(中断服务程序则不可以),UCOSIII允许用户嵌套使用互斥型信号量,一旦一个任务获得了一个互斥型信号量,则该任务最多可以对该互斥型信号量嵌套使用250次,当然该任务只有释放相同的次数才能真正释放这个互斥型信号量。

    至于互斥信号量的思想:将拥有信号量的任务优先级暂时提升至目前正在等待该信号量的任务中的最高优先级!

     

    互斥信号量API函数

    互斥信号量API函数
    函数 说明
    OSMutexCreate() 创建一个互斥信号量
    OSMutexDel() 删除一个互斥型信号量
    OSMutexPend() 等待一个互斥型信号量
    OSMutexPendAbort() 取消等待
    OSMutexPost() 释放一个互斥型信号量

    创建互斥型信号量

    创建互斥信号量使用函数OSMutexCreate(),函数原型如下:

    void  OSMutexCreate (OS_MUTEX  *p_mutex,                        //指向互斥型信号量控制块
                         CPU_CHAR  *p_name,                            //互斥信号量的名字
                         OS_ERR    *p_err)
    {
        CPU_SR_ALLOC();
    
        OS_CRITICAL_ENTER();
        p_mutex->Type              =  OS_OBJ_TYPE_MUTEX;        /* Mark the data structure as a mutex                     */
        p_mutex->NamePtr           =  p_name;
        p_mutex->OwnerTCBPtr       = (OS_TCB       *)0;
        p_mutex->OwnerNestingCtr   = (OS_NESTING_CTR)0;         /* Mutex is available                                     */
        p_mutex->TS                = (CPU_TS        )0;
        p_mutex->OwnerOriginalPrio =  OS_CFG_PRIO_MAX;
        OS_PendListInit(&p_mutex->PendList);                    /* Initialize the waiting list                            */
    
        OSMutexQty++;
    
        OS_CRITICAL_EXIT_NO_SCHED();
       *p_err = OS_ERR_NONE;
    }

    互斥信号量控制块是什么结构呢?

    struct  os_mutex {                                          /* Mutual Exclusion Semaphore                             */
                                                                /* ------------------ GENERIC  MEMBERS ------------------ */
        OS_OBJ_TYPE          Type;                              /* Should be set to OS_OBJ_TYPE_MUTEX                     */
        CPU_CHAR            *NamePtr;                           /* Pointer to Mutex Name (NUL terminated ASCII)           */
        OS_PEND_LIST         PendList;                          /* List of tasks waiting on mutex                         */
    #if OS_CFG_DBG_EN > 0u
        OS_MUTEX            *DbgPrevPtr;
        OS_MUTEX            *DbgNextPtr;
        CPU_CHAR            *DbgNamePtr;
    #endif
                                                                /* ------------------ SPECIFIC MEMBERS ------------------ */
        OS_TCB              *OwnerTCBPtr;
        OS_PRIO              OwnerOriginalPrio;
        OS_NESTING_CTR       OwnerNestingCtr;                   /* Mutex is available when the counter is 0               */
        CPU_TS               TS;
    };

    可以看出,互斥信号量是一个二进制信号量,并没有用于记录当前信号量的值的成员变量Ctr。

    请求互斥型信号量

    当一个任务需要对资源进行独占式访问的时候就可以使用函数OSMutexPend(),如果该互斥信号量正在被其他的任务使用,那么UCOSIII就会将请求这个互斥信号量的任务放置在这个互斥信号量的等待表中。任务会一直等待,直到这个互斥信号量被释放掉,或者设定的超时时间到达为止。如果在设定的超时时间到达之前信号量被释放,UCOSIII将会恢复所有等待这个信号量的任务中优先级最高的任务。

    注意!如果占用该互斥信号量的任务比当前申请该互斥信号量的任务优先级低的话,OSMutexPend()函数会将占用该互斥信号量的任务的优先级提升到和当前申请任务的优先级一样。当占用该互斥信号量的任务释放掉该互斥信号量以后,恢复到之前的优先级。OSMutexPend()函数原型如下:

    void  OSMutexPend (OS_MUTEX  *p_mutex,                        //指向互斥信号量
                       OS_TICK    timeout,                        //指定等待互斥信号量的超时时间(时钟节拍数)
                       OS_OPT     opt,                           //用于选择是否使用阻塞模式
                       CPU_TS    *p_ts,                            //指向一个时间戳
                       OS_ERR    *p_err)
    {
        OS_PEND_DATA  pend_data;
        OS_TCB       *p_tcb;
        CPU_SR_ALLOC();
    
        if (p_ts != (CPU_TS *)0) {
           *p_ts  = (CPU_TS  )0;                                /* Initialize the returned timestamp                      */
        }
    
        CPU_CRITICAL_ENTER();
        if (p_mutex->OwnerNestingCtr == (OS_NESTING_CTR)0) {    /* Resource available?                                    */
            p_mutex->OwnerTCBPtr       =  OSTCBCurPtr;          /* Yes, caller may proceed                                */
            p_mutex->OwnerOriginalPrio =  OSTCBCurPtr->Prio;
            p_mutex->OwnerNestingCtr   = (OS_NESTING_CTR)1;
            if (p_ts != (CPU_TS *)0) {
               *p_ts  = p_mutex->TS;
            }
            CPU_CRITICAL_EXIT();
           *p_err = OS_ERR_NONE;
            return;
        }
    
        if (OSTCBCurPtr == p_mutex->OwnerTCBPtr) {              /* See if current task is already the owner of the mutex  */
            p_mutex->OwnerNestingCtr++;
            if (p_ts != (CPU_TS *)0) {
               *p_ts  = p_mutex->TS;
            }
            CPU_CRITICAL_EXIT();
           *p_err = OS_ERR_MUTEX_OWNER;                         /* Indicate that current task already owns the mutex      */
            return;
        }
    
        if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) {    /* Caller wants to block if not available?                */
            CPU_CRITICAL_EXIT();
           *p_err = OS_ERR_PEND_WOULD_BLOCK;                    /* No                                                     */
            return;
        } else {
            if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {    /* Can't pend when the scheduler is locked                */
                CPU_CRITICAL_EXIT();
               *p_err = OS_ERR_SCHED_LOCKED;
                return;
            }
        }
    
        OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();                  /* Lock the scheduler/re-enable interrupts                */
        p_tcb = p_mutex->OwnerTCBPtr;                           /* Point to the TCB of the Mutex owner                    */
        if (p_tcb->Prio > OSTCBCurPtr->Prio) {                  /* See if mutex owner has a lower priority than current   */
            switch (p_tcb->TaskState) {
                case OS_TASK_STATE_RDY:
                     OS_RdyListRemove(p_tcb);                   /* Remove from ready list at current priority             */
                     p_tcb->Prio = OSTCBCurPtr->Prio;           /* Raise owner's priority                                 */
                     OS_PrioInsert(p_tcb->Prio);
                     OS_RdyListInsertHead(p_tcb);               /* Insert in ready list at new priority                   */
                     break;
    
                case OS_TASK_STATE_DLY:
                case OS_TASK_STATE_DLY_SUSPENDED:
                case OS_TASK_STATE_SUSPENDED:
                     p_tcb->Prio = OSTCBCurPtr->Prio;           /* Only need to raise the owner's priority                */
                     break;
    
                case OS_TASK_STATE_PEND:                        /* Change the position of the task in the wait list       */
                case OS_TASK_STATE_PEND_TIMEOUT:
                case OS_TASK_STATE_PEND_SUSPENDED:
                case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
                     OS_PendListChangePrio(p_tcb,
                                           OSTCBCurPtr->Prio);
                     break;
    
                default:
                     OS_CRITICAL_EXIT();
                    *p_err = OS_ERR_STATE_INVALID;
                     return;
            }
        }
    
        OS_Pend(&pend_data,                                     /* Block task pending on Mutex                            */
                (OS_PEND_OBJ *)((void *)p_mutex),
                 OS_TASK_PEND_ON_MUTEX,
                 timeout);
    
        OS_CRITICAL_EXIT_NO_SCHED();
    
        OSSched();                                              /* Find the next highest priority task ready to run       */
    
        CPU_CRITICAL_ENTER();
        switch (OSTCBCurPtr->PendStatus) {
            case OS_STATUS_PEND_OK:                             /* We got the mutex                                       */
                 if (p_ts != (CPU_TS *)0) {
                    *p_ts  = OSTCBCurPtr->TS;
                 }
                *p_err = OS_ERR_NONE;
                 break;
    
            case OS_STATUS_PEND_ABORT:                          /* Indicate that we aborted                               */
                 if (p_ts != (CPU_TS *)0) {
                    *p_ts  = OSTCBCurPtr->TS;
                 }
                *p_err = OS_ERR_PEND_ABORT;
                 break;
    
            case OS_STATUS_PEND_TIMEOUT:                        /* Indicate that we didn't get mutex within timeout       */
                 if (p_ts != (CPU_TS *)0) {
                    *p_ts  = (CPU_TS  )0;
                 }
                *p_err = OS_ERR_TIMEOUT;
                 break;
    
            case OS_STATUS_PEND_DEL:                            /* Indicate that object pended on has been deleted        */
                 if (p_ts != (CPU_TS *)0) {
                    *p_ts  = OSTCBCurPtr->TS;
                 }
                *p_err = OS_ERR_OBJ_DEL;
                 break;
    
            default:
                *p_err = OS_ERR_STATUS_INVALID;
                 break;
        }
        CPU_CRITICAL_EXIT();
    }

    timeout:指定等待互斥信号量的超时时间(时钟节拍数),如果在指定的时间内互斥信号量没有释放,则允许任务恢复执行。该值设置为0的话,表示任务将会一直等待下去,直到信号量被释放掉。

    opt:用于选择是否使用阻塞模式,有下面两个选项。OS_OPT_PEND_BLOCKING:指定互斥信号量被占用时,任务挂起等待该互斥信号量;OS_OPT_PEND_NON_BLOCKING:指定当互斥信号量被占用时,直接返回任务。

    注意!当设置为OS_OPT_PEND_NON_BLOCKING,是timeout参数就没有意义了,应该设置为0。

    发送互斥信号量

    我们可以通过调用函数OSMutexPost()来释放互斥型信号量,只有之前调用过函数OSMutexPend()获取互斥信号量,才需要调用OSMutexPost()函数来释放这个互斥信号量,函数原型如下:

    void  OSMutexPost (OS_MUTEX  *p_mutex,                    //指向互斥信号量
                       OS_OPT     opt,                    //用来指定是否进行任务调度操作
                       OS_ERR    *p_err)
    {
        OS_PEND_LIST  *p_pend_list;
        OS_TCB        *p_tcb;
        CPU_TS         ts;
        CPU_SR_ALLOC();
    
        CPU_CRITICAL_ENTER();
        if (OSTCBCurPtr != p_mutex->OwnerTCBPtr) {              /* Make sure the mutex owner is releasing the mutex       */
            CPU_CRITICAL_EXIT();
           *p_err = OS_ERR_MUTEX_NOT_OWNER;
            return;
        }
    
        OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
        ts          = OS_TS_GET();                              /* Get timestamp                                          */
        p_mutex->TS = ts;
        p_mutex->OwnerNestingCtr--;                             /* Decrement owner's nesting counter                      */
        if (p_mutex->OwnerNestingCtr > (OS_NESTING_CTR)0) {     /* Are we done with all nestings?                         */
            OS_CRITICAL_EXIT();                                 /* No                                                     */
           *p_err = OS_ERR_MUTEX_NESTING;
            return;
        }
    
        p_pend_list = &p_mutex->PendList;
        if (p_pend_list->NbrEntries == (OS_OBJ_QTY)0) {         /* Any task waiting on mutex?                             */
            p_mutex->OwnerTCBPtr     = (OS_TCB       *)0;       /* No                                                     */
            p_mutex->OwnerNestingCtr = (OS_NESTING_CTR)0;
            OS_CRITICAL_EXIT();
           *p_err = OS_ERR_NONE;
            return;
        }
                                                                /* Yes                                                    */
        if (OSTCBCurPtr->Prio != p_mutex->OwnerOriginalPrio) {
            OS_RdyListRemove(OSTCBCurPtr);
            OSTCBCurPtr->Prio = p_mutex->OwnerOriginalPrio;     /* Lower owner's priority back to its original one        */
            OS_PrioInsert(OSTCBCurPtr->Prio);
            OS_RdyListInsertTail(OSTCBCurPtr);                  /* Insert owner in ready list at new priority             */
            OSPrioCur         = OSTCBCurPtr->Prio;
        }
                                                                /* Get TCB from head of pend list                         */
        p_tcb                      = p_pend_list->HeadPtr->TCBPtr;
        p_mutex->OwnerTCBPtr       = p_tcb;                     /* Give mutex to new owner                                */
        p_mutex->OwnerOriginalPrio = p_tcb->Prio;
        p_mutex->OwnerNestingCtr   = (OS_NESTING_CTR)1;
                                                                /* Post to mutex                                          */
        OS_Post((OS_PEND_OBJ *)((void *)p_mutex),
                (OS_TCB      *)p_tcb,
                (void        *)0,
                (OS_MSG_SIZE  )0,
                (CPU_TS       )ts);
    
        OS_CRITICAL_EXIT_NO_SCHED();
    
        if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0) {
            OSSched();                                          /* Run the scheduler                                      */
        }
    
       *p_err = OS_ERR_NONE;
    }

    opt:用来指定是否进行任务调度操作,有以下两个选项。OS_OPT_POST_NONE:不指定特定的选项;OS_OPT_POST_NO_SCHED:禁止在本函数内执行任务调度操作。

     

    UCOSIII实际例程

    在互斥信号量实验之前,首先先来一个优先级反转的实例。

    优先级反转实验

    例程要求:创建4个任务,任务A用于创建B、C和D这三个任务,A还创建了一个初始值为1的信号量TEST_SEM,任务B和D都请求信号量TEST_SEM,其中任务优先级从高到底分别为:B、C、D。

    例子:

    #include "sys.h"
    #include "delay.h"
    #include "usart.h"
    #include "led.h"
    #include "lcd.h"
    #include "key.h"
    #include "includes.h"
    
    //UCOSIII中以下优先级用户程序不能使用,ALIENTEK
    //将这些优先级分配给了UCOSIII的5个系统内部任务
    //优先级0:中断服务服务管理任务 OS_IntQTask()
    //优先级1:时钟节拍任务 OS_TickTask()
    //优先级2:定时任务 OS_TmrTask()
    //优先级OS_CFG_PRIO_MAX-2:统计任务 OS_StatTask()
    //优先级OS_CFG_PRIO_MAX-1:空闲任务 OS_IdleTask()
    
    //任务优先级
    #define START_TASK_PRIO			10
    //任务堆栈大小	
    #define START_STK_SIZE 			128
    //任务控制块
    OS_TCB StartTaskTCB;
    //任务堆栈	
    CPU_STK START_TASK_STK[START_STK_SIZE];
    //任务函数
    void start_task(void *p_arg);
    
    //任务优先级
    #define HIGH_TASK_PRIO			7
    //任务堆栈大小	
    #define HIGH_STK_SIZE 			128
    //任务控制块
    OS_TCB High_TaskTCB;
    //任务堆栈	
    CPU_STK HIGH_TASK_STK[HIGH_STK_SIZE];
    void high_task(void *p_arg);
    
    //任务优先级
    #define MIDDLE_TASK_PRIO		8
    //任务堆栈大小	
    #define MIDDLE_STK_SIZE 		128
    //任务控制块
    OS_TCB Middle_TaskTCB;
    //任务堆栈	
    CPU_STK MIDDLE_TASK_STK[MIDDLE_STK_SIZE];
    void middle_task(void *p_arg);
    
    //任务优先级
    #define LOW_TASK_PRIO			9
    //任务堆栈大小	
    #define LOW_STK_SIZE 			128
    //任务控制块
    OS_TCB Low_TaskTCB;
    //任务堆栈	
    CPU_STK LOW_TASK_STK[LOW_STK_SIZE];
    void low_task(void *p_arg);
    
    //LCD刷屏时使用的颜色
    int lcd_discolor[14]={	WHITE, BLACK, BLUE,  BRED,      
    						GRED,  GBLUE, RED,   MAGENTA,       	 
    						GREEN, CYAN,  YELLOW,BROWN, 			
    						BRRED, GRAY };
    
    OS_SEM	TEST_SEM;		//定义一个信号量
    
    int main(void)                    //主函数
    {
    	OS_ERR err;
    	CPU_SR_ALLOC();
    	
    	delay_init();  //时钟初始化
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组配置
    	uart_init(115200);   //串口初始化
    	LED_Init();         //LED初始化	
    	LCD_Init();			//LCD初始化	
    	
    	POINT_COLOR = RED;
    	LCD_ShowString(30,10,200,16,16,"ALIENTEK STM32F1");	
    	LCD_ShowString(30,30,200,16,16,"UCOSIII Examp 10-4");
    	LCD_ShowString(30,50,200,16,16,"Prio Inversion");
    	LCD_ShowString(30,70,200,16,16,"ATOM@ALIENTEK");
    	LCD_ShowString(30,90,200,16,16,"2015/5/28");
    	
    	OSInit(&err);		    //初始化UCOSIII
    	OS_CRITICAL_ENTER();	//进入临界区			 
    	//创建开始任务寸vs:v
    	OSTaskCreate((OS_TCB 	* )&StartTaskTCB,		//任务控制块
    		 (CPU_CHAR	* )"start task", 		//任务名字
                     (OS_TASK_PTR )start_task, 			//任务函数
                     (void		* )0,					//传递给任务函数的参数
                     (OS_PRIO	  )START_TASK_PRIO,     //任务优先级
                     (CPU_STK   * )&START_TASK_STK[0],	//任务堆栈基地址
                     (CPU_STK_SIZE)START_STK_SIZE/10,	//任务堆栈深度限位
                     (CPU_STK_SIZE)START_STK_SIZE,		//任务堆栈大小
                     (OS_MSG_QTY  )0,					//任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
                     (OS_TICK	  )0,					//当使能时间片轮转时的时间片长度,为0时为默认长度,
                     (void   	* )0,					//用户补充的存储区
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
                     (OS_ERR 	* )&err);				//存放该函数错误时的返回值
    	OS_CRITICAL_EXIT();	//退出临界区	 
    	OSStart(&err);      //开启UCOSIII
    }
    
    void start_task(void *p_arg)                //开始任务函数
    {    
    	OS_ERR err;
    	CPU_SR_ALLOC();
    	p_arg = p_arg;
    	
    	CPU_Init();
    #if OS_CFG_STAT_TASK_EN > 0u
       OSStatTaskCPUUsageInit(&err);  	//统计任务                
    #endif
    	
    #ifdef CPU_CFG_INT_DIS_MEAS_EN		//如果使能了测量中断关闭时间
        CPU_IntDisMeasMaxCurReset();	
    #endif
    	
    #if	OS_CFG_SCHED_ROUND_ROBIN_EN  //当使用时间片轮转的时候
    	 //使能时间片轮转调度功能,时间片长度为1个系统时钟节拍,既1*5=5ms
    	OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);  
    #endif	
    		
    	OS_CRITICAL_ENTER();	//进入临界区
    
    	OSSemCreate ((OS_SEM*	)&TEST_SEM,            	//创建一个信号量
                     (CPU_CHAR*	)"TEST_SEM",
                     (OS_SEM_CTR)1,				//信号量初始值为1
                     (OS_ERR*	)&err);
    
    	OSTaskCreate((OS_TCB 	* )&High_TaskTCB,	        	//创建HIGH任务	
    				 (CPU_CHAR	* )"High task", 		
                     (OS_TASK_PTR )high_task, 			
                     (void		* )0,					
                     (OS_PRIO	  )HIGH_TASK_PRIO,     
                     (CPU_STK   * )&HIGH_TASK_STK[0],	
                     (CPU_STK_SIZE)HIGH_STK_SIZE/10,	
                     (CPU_STK_SIZE)HIGH_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void   	* )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR 	* )&err);			
    
    	OSTaskCreate((OS_TCB 	* )&Middle_TaskTCB,	            	//创建MIDDLE任务	
    				 (CPU_CHAR	* )"Middle task", 		
                     (OS_TASK_PTR )middle_task, 			
                     (void		* )0,					
                     (OS_PRIO	  )MIDDLE_TASK_PRIO,     
                     (CPU_STK   * )&MIDDLE_TASK_STK[0],	
                     (CPU_STK_SIZE)MIDDLE_STK_SIZE/10,	
                     (CPU_STK_SIZE)MIDDLE_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void   	* )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR 	* )&err);		
    
    	OSTaskCreate((OS_TCB 	* )&Low_TaskTCB,	            	//创建LOW任务	
    				 (CPU_CHAR	* )"Low task", 		
                     (OS_TASK_PTR )low_task, 			
                     (void		* )0,					
                     (OS_PRIO	  )LOW_TASK_PRIO,     
                     (CPU_STK   * )&LOW_TASK_STK[0],	
                     (CPU_STK_SIZE)LOW_STK_SIZE/10,	
                     (CPU_STK_SIZE)LOW_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void   	* )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR 	* )&err);					 
    	OS_CRITICAL_EXIT();	//退出临界区
    	OSTaskDel((OS_TCB*)0,&err);	//删除start_task任务自身
    }
    
    void high_task(void *p_arg)            //高优先级任务的任务函数
    {
    	u8 num;
    	OS_ERR err;
    	
    	CPU_SR_ALLOC();
    	POINT_COLOR = BLACK;
    	OS_CRITICAL_ENTER();
    	LCD_DrawRectangle(5,110,115,314); 	//画一个矩形	
    	LCD_DrawLine(5,130,115,130);		//画线
    	POINT_COLOR = BLUE;
    	LCD_ShowString(6,111,110,16,16,"High Task");
    	OS_CRITICAL_EXIT();
    	while(1)
    	{
    		OSTimeDlyHMSM(0,0,0,500,OS_OPT_TIME_PERIODIC,&err);   	//延时500ms
    		num++;
    		printf("high task Pend Sem\r\n");
    		OSSemPend(&TEST_SEM,0,OS_OPT_PEND_BLOCKING,0,&err); 	//请求信号量
    		printf("high task Running!\r\n");
    		LCD_Fill(6,131,114,313,lcd_discolor[num%14]); //填充区域
    		LED1 = ~LED1;
    		OSSemPost(&TEST_SEM,OS_OPT_POST_1,&err);				//释放信号量
    		OSTimeDlyHMSM(0,0,0,500,OS_OPT_TIME_PERIODIC,&err);   	//延时500ms
    	}
    }
    
    void middle_task(void *p_arg)                //中等优先级任务的任务函数
    {	
    	u8 num;
    	OS_ERR err;
    	CPU_SR_ALLOC();
    	
    	POINT_COLOR = BLACK;
    	OS_CRITICAL_ENTER();
    	LCD_DrawRectangle(125,110,234,314); //画一个矩形	
    	LCD_DrawLine(125,130,234,130);		//画线
    	POINT_COLOR = BLUE;
    	LCD_ShowString(126,111,110,16,16,"Middle Task");
    	OS_CRITICAL_EXIT();
    	while(1)
    	{
    		num++;
    		printf("middle task Running!\r\n");
    		LCD_Fill(126,131,233,313,lcd_discolor[13-num%14]); //填充区域
    		LED0 = ~LED0;
    		OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);   //延时1s
    	}
    }
    
    void low_task(void *p_arg)                //低优先级任务的任务函数
    {	
    	static u32 times;
    	OS_ERR err;
    	while(1)
    	{
    		OSSemPend(&TEST_SEM,0,OS_OPT_PEND_BLOCKING,0,&err);     //请求信号量
    		printf("low task Running!\r\n");
    		for(times=0;times<10000000;times++)
    		{
    			OSSched();			//发起任务调度
    		}
    		OSSemPost(&TEST_SEM,OS_OPT_POST_1,&err);	
    		OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);   //延时1s
    	}
    }
    	//创建一个信号量
                     (CPU_CHAR*	)"TEST_SEM",
                     (OS_SEM_CTR)1,				//信号量初始值为1
                     (OS_ERR*	)&err);
    
    	OSTaskCreate((OS_TCB 	* )&High_TaskTCB,	        	//创建HIGH任务	
    				 (CPU_CHAR	* )"High task", 		
                     (OS_TASK_PTR )high_task, 			
                     (void		* )0,					
                     (OS_PRIO	  )HIGH_TASK_PRIO,     
                     (CPU_STK   * )&HIGH_TASK_STK[0],	
                     (CPU_STK_SIZE)HIGH_STK_SIZE/10,	
                     (CPU_STK_SIZE)HIGH_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void   	* )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR 	* )&err);			
    
    	OSTaskCreate((OS_TCB 	* )&Middle_TaskTCB,	            	//创建MIDDLE任务	
    				 (CPU_CHAR	* )"Middle task", 		
                     (OS_TASK_PTR )middle_task, 			
                     (void		* )0,					
                     (OS_PRIO	  )MIDDLE_TASK_PRIO,     
                     (CPU_STK   * )&MIDDLE_TASK_STK[0],	
                     (CPU_STK_SIZE)MIDDLE_STK_SIZE/10,	
                     (CPU_STK_SIZE)MIDDLE_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void   	* )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR 	* )&err);		
    
    	OSTaskCreate((OS_TCB 	* )&Low_TaskTCB,	            	//创建LOW任务	
    				 (CPU_CHAR	* )"Low task", 		
                     (OS_TASK_PTR )low_task, 			
                     (void		* )0,					
                     (OS_PRIO	  )LOW_TASK_PRIO,     
                     (CPU_STK   * )&LOW_TASK_STK[0],	
                     (CPU_STK_SIZE)LOW_STK_SIZE/10,	
                     (CPU_STK_SIZE)LOW_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void   	* )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR 	* )&err);					 
    	OS_CRITICAL_EXIT();	//退出临界区
    	OSTaskDel((OS_TCB*)0,&err);	//删除start_task任务自身
    }
    
    void high_task(void *p_arg)            //高优先级任务的任务函数
    {
    	u8 num;
    	OS_ERR err;
    	
    	CPU_SR_ALLOC();
    	POINT_COLOR = BLACK;
    	OS_CRITICAL_ENTER();
    	LCD_DrawRectangle(5,110,115,314); 	//画一个矩形	
    	LCD_DrawLine(5,130,115,130);		//画线
    	POINT_COLOR = BLUE;
    	LCD_ShowString(6,111,110,16,16,"High Task");
    	OS_CRITICAL_EXIT();
    	while(1)
    	{
    		OSTimeDlyHMSM(0,0,0,500,OS_OPT_TIME_PERIODIC,&err);   	//延时500ms
    		num++;
    		printf("high task Pend Sem\r\n");
    		OSSemPend(&TEST_SEM,0,OS_OPT_PEND_BLOCKING,0,&err); 	//请求信号量
    		printf("high task Running!\r\n");
    		LCD_Fill(6,131,114,313,lcd_discolor[num%14]); //填充区域
    		LED1 = ~LED1;
    		OSSemPost(&TEST_SEM,OS_OPT_POST_1,&err);				//释放信号量
    		OSTimeDlyHMSM(0,0,0,500,OS_OPT_TIME_PERIODIC,&err);   	//延时500ms
    	}
    }
    
    void middle_task(void *p_arg)                //中等优先级任务的任务函数
    {	
    	u8 num;
    	OS_ERR err;
    	CPU_SR_ALLOC();
    	
    	POINT_COLOR = BLACK;
    	OS_CRITICAL_ENTER();
    	LCD_DrawRectangle(125,110,234,314); //画一个矩形	
    	LCD_DrawLine(125,130,234,130);		//画线
    	POINT_COLOR = BLUE;
    	LCD_ShowString(126,111,110,16,16,"Middle Task");
    	OS_CRITICAL_EXIT();
    	while(1)
    	{
    		num++;
    		printf("middle task Running!\r\n");
    		LCD_Fill(126,131,233,313,lcd_discolor[13-num%14]); //填充区域
    		LED0 = ~LED0;
    		OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);   //延时1s
    	}
    }
    
    void low_task(void *p_arg)                //低优先级任务的任务函数
    {	
    	static u32 times;
    	OS_ERR err;
    	while(1)
    	{
    		OSSemPend(&TEST_SEM,0,OS_OPT_PEND_BLOCKING,0,&err);     //请求信号量
    		printf("low task Running!\r\n");
    		for(times=0;times<10000000;times++)
    		{
    			OSSched();			//发起任务调度
    		}
    		OSSemPost(&TEST_SEM,OS_OPT_POST_1,&err);	
    		OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);   //延时1s
    	}
    }

    这个实验的步骤是:

    1. low_task任务获得下信号量TEST_SEM开始运行;
    2. high_task请求信号量TEST_SEM,但是此时信号量TEST_SEM被任务low_task占用着,因此high_task就要一直等待,直到low_task任务释放信号量TEST_SEM;
    3. 由于high_task没有请求到信号量TEST_SEM,只能一直等待,而middle_task一直在运行,给人的感觉就是middle_task的任务优先级高于high_task。但是事实上high_task任务的任务优先级是高于middle_task的,这个就是优先级反转!

    high_task任务因为获得信号量TEST_SEM而运行从上例中可以看出,当一个低优先级任务和一个高优先级任务同时使用同一个信号量,而系统中还有其他中等优先级任务时。如果低优先级任务获得了信号量,那么高优先级的任务就会处于等待状态,但是,中等优先级的任务可以打断低优先级任务而先于高优先级任务运行(此时高优先级的任务在等待信号量,所以不能运行),这是就出现了优先级反转的现象。

    互斥信号量实验

    在上例中由于使用了信号量导致了优先级反转发生,下例中我们将信号量换成互斥信号量。

    例子:

    #include "sys.h"
    #include "delay.h"
    #include "usart.h"
    #include "led.h"
    #include "lcd.h"
    #include "key.h"
    #include "includes.h"
    
    //UCOSIII中以下优先级用户程序不能使用,ALIENTEK
    //将这些优先级分配给了UCOSIII的5个系统内部任务
    //优先级0:中断服务服务管理任务 OS_IntQTask()
    //优先级1:时钟节拍任务 OS_TickTask()
    //优先级2:定时任务 OS_TmrTask()
    //优先级OS_CFG_PRIO_MAX-2:统计任务 OS_StatTask()
    //优先级OS_CFG_PRIO_MAX-1:空闲任务 OS_IdleTask()
    
    //任务优先级
    #define START_TASK_PRIO			10
    //任务堆栈大小	
    #define START_STK_SIZE 			128
    //任务控制块
    OS_TCB StartTaskTCB;
    //任务堆栈	
    CPU_STK START_TASK_STK[START_STK_SIZE];
    //任务函数
    void start_task(void *p_arg);
    
    //任务优先级
    #define HIGH_TASK_PRIO			7
    //任务堆栈大小	
    #define HIGH_STK_SIZE 			128
    //任务控制块
    OS_TCB High_TaskTCB;
    //任务堆栈	
    CPU_STK HIGH_TASK_STK[HIGH_STK_SIZE];
    void high_task(void *p_arg);
    
    //任务优先级
    #define MIDDLE_TASK_PRIO		8
    //任务堆栈大小	
    #define MIDDLE_STK_SIZE 		128
    //任务控制块
    OS_TCB Middle_TaskTCB;
    //任务堆栈	
    CPU_STK MIDDLE_TASK_STK[MIDDLE_STK_SIZE];
    void middle_task(void *p_arg);
    
    //任务优先级
    #define LOW_TASK_PRIO			9
    //任务堆栈大小	
    #define LOW_STK_SIZE 			128
    //任务控制块
    OS_TCB Low_TaskTCB;
    //任务堆栈	
    CPU_STK LOW_TASK_STK[LOW_STK_SIZE];
    void low_task(void *p_arg);
    
    //LCD刷屏时使用的颜色
    int lcd_discolor[14]={	WHITE, BLACK, BLUE,  BRED,      
    						GRED,  GBLUE, RED,   MAGENTA,       	 
    						GREEN, CYAN,  YELLOW,BROWN, 			
    						BRRED, GRAY };
    
    OS_MUTEX	TEST_MUTEX;		//定义一个互斥信号量
    
    int main(void)                            //主函数
    {
    	OS_ERR err;
    	CPU_SR_ALLOC();
    	
    	delay_init();  //时钟初始化
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组配置
    	uart_init(115200);   //串口初始化
    	LED_Init();         //LED初始
    	LCD_Init();			//LCD初始化	
    	
    	POINT_COLOR = RED;
    	LCD_ShowString(30,10,200,16,16,"ALIENTEK STM32F1");	
    	LCD_ShowString(30,30,200,16,16,"UCOSIII Examp 10-5");
    	LCD_ShowString(30,50,200,16,16,"Mutex test");
    	LCD_ShowString(30,70,200,16,16,"ATOM@ALIENTEK");
    	LCD_ShowString(30,90,200,16,16,"2015/5/28");
    	
    	OSInit(&err);		    //初始化UCOSIII
    	OS_CRITICAL_ENTER();	//进入临界区			 
    	//创建开始任务
    	OSTaskCreate((OS_TCB 	* )&StartTaskTCB,		//任务控制块
    				 (CPU_CHAR	* )"start task", 		//任务名字
                     (OS_TASK_PTR )start_task, 			//任务函数
                     (void		* )0,					//传递给任务函数的参数
                     (OS_PRIO	  )START_TASK_PRIO,     //任务优先级
                     (CPU_STK   * )&START_TASK_STK[0],	//任务堆栈基地址
                     (CPU_STK_SIZE)START_STK_SIZE/10,	//任务堆栈深度限位
                     (CPU_STK_SIZE)START_STK_SIZE,		//任务堆栈大小
                     (OS_MSG_QTY  )0,					//任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
                     (OS_TICK	  )0,					//当使能时间片轮转时的时间片长度,为0时为默认长度,
                     (void   	* )0,					//用户补充的存储区
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
                     (OS_ERR 	* )&err);				//存放该函数错误时的返回值
    	OS_CRITICAL_EXIT();	//退出临界区	 
    	OSStart(&err);      //开启UCOSIII
    }
    
    void start_task(void *p_arg)                //开始任务函数
    {
    	OS_ERR err;
    	CPU_SR_ALLOC();
    	p_arg = p_arg;
    	
    	CPU_Init();
    #if OS_CFG_STAT_TASK_EN > 0u
       OSStatTaskCPUUsageInit(&err);  	//统计任务                
    #endif
    	
    #ifdef CPU_CFG_INT_DIS_MEAS_EN		//如果使能了测量中断关闭时间
        CPU_IntDisMeasMaxCurReset();	
    #endif
    	
    #if	OS_CFG_SCHED_ROUND_ROBIN_EN  //当使用时间片轮转的时候
    	 //使能时间片轮转调度功能,时间片长度为1个系统时钟节拍,既1*5=5ms
    	OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);  
    #endif	
    		
    	OS_CRITICAL_ENTER();	//进入临界区
    
    	OSMutexCreate((OS_MUTEX*	)&TEST_MUTEX,                	//创建一个互斥信号量
    				  (CPU_CHAR*	)"TEST_MUTEX",
                      (OS_ERR*		)&err);
    
    	OSTaskCreate((OS_TCB 	* )&High_TaskTCB,		            	//创建HIGH任务
    				 (CPU_CHAR	* )"High task", 		
                     (OS_TASK_PTR )high_task, 			
                     (void		* )0,					
                     (OS_PRIO	  )HIGH_TASK_PRIO,     
                     (CPU_STK   * )&HIGH_TASK_STK[0],	
                     (CPU_STK_SIZE)HIGH_STK_SIZE/10,	
                     (CPU_STK_SIZE)HIGH_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void   	* )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR 	* )&err);			
    
    	OSTaskCreate((OS_TCB 	* )&Middle_TaskTCB,	                	//创建MIDDLE任务	
    				 (CPU_CHAR	* )"Middle task", 		
                     (OS_TASK_PTR )middle_task, 			
                     (void		* )0,					
                     (OS_PRIO	  )MIDDLE_TASK_PRIO,     
                     (CPU_STK   * )&MIDDLE_TASK_STK[0],	
                     (CPU_STK_SIZE)MIDDLE_STK_SIZE/10,	
                     (CPU_STK_SIZE)MIDDLE_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void   	* )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR 	* )&err);		
    
    	OSTaskCreate((OS_TCB 	* )&Low_TaskTCB,			    //创建LOW任务
    				 (CPU_CHAR	* )"Low task", 		
                     (OS_TASK_PTR )low_task, 			
                     (void		* )0,					
                     (OS_PRIO	  )LOW_TASK_PRIO,     
                     (CPU_STK   * )&LOW_TASK_STK[0],	
                     (CPU_STK_SIZE)LOW_STK_SIZE/10,	
                     (CPU_STK_SIZE)LOW_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void   	* )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR 	* )&err);					 
    	OS_CRITICAL_EXIT();	//退出临界区
    	OSTaskDel((OS_TCB*)0,&err);	//删除start_task任务自身
    }
    
    void high_task(void *p_arg)                    //高优先级任务的任务函数
    {
    	u8 num;
    	OS_ERR err;
    	
    	CPU_SR_ALLOC();
    	POINT_COLOR = BLACK;
    	OS_CRITICAL_ENTER();
    	LCD_DrawRectangle(5,110,115,314); 	//画一个矩形	
    	LCD_DrawLine(5,130,115,130);		//画线
    	POINT_COLOR = BLUE;
    	LCD_ShowString(6,111,110,16,16,"High Task");
    	OS_CRITICAL_EXIT();
    	while(1)
    	{
    		OSTimeDlyHMSM(0,0,0,500,OS_OPT_TIME_PERIODIC,&err);   		//延时500ms
    		num++;
    		printf("high task Pend Mutex\r\n");
    		OSMutexPend (&TEST_MUTEX,0,OS_OPT_PEND_BLOCKING,0,&err);	//请求互斥信号量
    		printf("high task Running!\r\n");
    		LCD_Fill(6,131,114,313,lcd_discolor[num%14]); 				//填充区域
    		LED1 = ~LED1;
    		OSMutexPost(&TEST_MUTEX,OS_OPT_POST_NONE,&err);				//释放互斥信号量
    		OSTimeDlyHMSM(0,0,0,500,OS_OPT_TIME_PERIODIC,&err);   		//延时500ms
    	}
    }
    
    void middle_task(void *p_arg)                        //中等优先级任务的任务函数
    {	
    	u8 num;
    	OS_ERR err;
    	CPU_SR_ALLOC();
    	
    	POINT_COLOR = BLACK;
    	OS_CRITICAL_ENTER();
    	LCD_DrawRectangle(125,110,234,314); //画一个矩形	
    	LCD_DrawLine(125,130,234,130);		//画线
    	POINT_COLOR = BLUE;
    	LCD_ShowString(126,111,110,16,16,"Middle Task");
    	OS_CRITICAL_EXIT();
    	while(1)
    	{
    		num++;
    		printf("middle task Running!\r\n");
    		LCD_Fill(126,131,233,313,lcd_discolor[13-num%14]); //填充区域
    		LED0 = ~LED0;
    		OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);   //延时1s
    	}
    }
    
    void low_task(void *p_arg)                    //低优先级任务的任务函数
    {	
    	static u32 times;
    	OS_ERR err;
    	while(1)
    	{
    		OSMutexPend (&TEST_MUTEX,0,OS_OPT_PEND_BLOCKING,0,&err);//请求互斥信号量
    		printf("low task Running!\r\n");
    		for(times=0;times<10000000;times++)
    		{
    			OSSched();											//发起任务调度
    		}
    		OSMutexPost(&TEST_MUTEX,OS_OPT_POST_NONE,&err);			//释放互斥信号量
    		OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);   	//延时1s
    	}
    }
    	//创建一个互斥信号量
    				  (CPU_CHAR*	)"TEST_MUTEX",
                      (OS_ERR*		)&err);
    
    	OSTaskCreate((OS_TCB 	* )&High_TaskTCB,		            	//创建HIGH任务
    				 (CPU_CHAR	* )"High task", 		
                     (OS_TASK_PTR )high_task, 			
                     (void		* )0,					
                     (OS_PRIO	  )HIGH_TASK_PRIO,     
                     (CPU_STK   * )&HIGH_TASK_STK[0],	
                     (CPU_STK_SIZE)HIGH_STK_SIZE/10,	
                     (CPU_STK_SIZE)HIGH_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void   	* )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR 	* )&err);			
    
    	OSTaskCreate((OS_TCB 	* )&Middle_TaskTCB,	                	//创建MIDDLE任务	
    				 (CPU_CHAR	* )"Middle task", 		
                     (OS_TASK_PTR )middle_task, 			
                     (void		* )0,					
                     (OS_PRIO	  )MIDDLE_TASK_PRIO,     
                     (CPU_STK   * )&MIDDLE_TASK_STK[0],	
                     (CPU_STK_SIZE)MIDDLE_STK_SIZE/10,	
                     (CPU_STK_SIZE)MIDDLE_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void   	* )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR 	* )&err);		
    
    	OSTaskCreate((OS_TCB 	* )&Low_TaskTCB,			    //创建LOW任务
    				 (CPU_CHAR	* )"Low task", 		
                     (OS_TASK_PTR )low_task, 			
                     (void		* )0,					
                     (OS_PRIO	  )LOW_TASK_PRIO,     
                     (CPU_STK   * )&LOW_TASK_STK[0],	
                     (CPU_STK_SIZE)LOW_STK_SIZE/10,	
                     (CPU_STK_SIZE)LOW_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void   	* )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR 	* )&err);					 
    	OS_CRITICAL_EXIT();	//退出临界区
    	OSTaskDel((OS_TCB*)0,&err);	//删除start_task任务自身
    }
    
    void high_task(void *p_arg)                    //高优先级任务的任务函数
    {
    	u8 num;
    	OS_ERR err;
    	
    	CPU_SR_ALLOC();
    	POINT_COLOR = BLACK;
    	OS_CRITICAL_ENTER();
    	LCD_DrawRectangle(5,110,115,314); 	//画一个矩形	
    	LCD_DrawLine(5,130,115,130);		//画线
    	POINT_COLOR = BLUE;
    	LCD_ShowString(6,111,110,16,16,"High Task");
    	OS_CRITICAL_EXIT();
    	while(1)
    	{
    		OSTimeDlyHMSM(0,0,0,500,OS_OPT_TIME_PERIODIC,&err);   		//延时500ms
    		num++;
    		printf("high task Pend Mutex\r\n");
    		OSMutexPend (&TEST_MUTEX,0,OS_OPT_PEND_BLOCKING,0,&err);	//请求互斥信号量
    		printf("high task Running!\r\n");
    		LCD_Fill(6,131,114,313,lcd_discolor[num%14]); 				//填充区域
    		LED1 = ~LED1;
    		OSMutexPost(&TEST_MUTEX,OS_OPT_POST_NONE,&err);				//释放互斥信号量
    		OSTimeDlyHMSM(0,0,0,500,OS_OPT_TIME_PERIODIC,&err);   		//延时500ms
    	}
    }
    
    void middle_task(void *p_arg)                        //中等优先级任务的任务函数
    {	
    	u8 num;
    	OS_ERR err;
    	CPU_SR_ALLOC();
    	
    	POINT_COLOR = BLACK;
    	OS_CRITICAL_ENTER();
    	LCD_DrawRectangle(125,110,234,314); //画一个矩形	
    	LCD_DrawLine(125,130,234,130);		//画线
    	POINT_COLOR = BLUE;
    	LCD_ShowString(126,111,110,16,16,"Middle Task");
    	OS_CRITICAL_EXIT();
    	while(1)
    	{
    		num++;
    		printf("middle task Running!\r\n");
    		LCD_Fill(126,131,233,313,lcd_discolor[13-num%14]); //填充区域
    		LED0 = ~LED0;
    		OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);   //延时1s
    	}
    }
    
    void low_task(void *p_arg)                    //低优先级任务的任务函数
    {	
    	static u32 times;
    	OS_ERR err;
    	while(1)
    	{
    		OSMutexPend (&TEST_MUTEX,0,OS_OPT_PEND_BLOCKING,0,&err);//请求互斥信号量
    		printf("low task Running!\r\n");
    		for(times=0;times<10000000;times++)
    		{
    			OSSched();											//发起任务调度
    		}
    		OSMutexPost(&TEST_MUTEX,OS_OPT_POST_NONE,&err);			//释放互斥信号量
    		OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);   	//延时1s
    	}
    }

     

    展开全文
  • 【UCOSIII】UCOSIII的任务内嵌信号

    千次阅读 2018-07-03 18:11:24
    我们一般使用信号量时都需要先创建一个信号量,不过在UCOSIII中每个任务都有自己的内嵌的信号量,这种功能不仅能够简化代码,而且比使用独立的信号量更有效。任务信号量是直接内嵌在UCOSIII中的,任务信号量相关代码...

    任务内嵌信号量API函数

    我们一般使用信号量时都需要先创建一个信号量,不过在UCOSIII中每个任务都有自己的内嵌的信号量,这种功能不仅能够简化代码,而且比使用独立的信号量更有效。任务信号量是直接内嵌在UCOSIII中的,任务信号量相关代码在os_task.c中的。任务内嵌信号量相关函数如下表所示:

    任务内嵌信号量API函数
    函数 说明
    OSTaskSemPend

    等待任务信号量

    OSTaskSemPendAbort 取消等待任务信号量
    OSTaskSemPost 发布任务信号量
    OSTaskSemSet 强行设置任务信号量计数

    等待任务信号量

    等待任务内嵌信号量使用函数OSTaskSemPend(),OStaskSemPend()允许一个任务等待由其他任务或者ISR直接发送的信号,使用过程基本和独立的信号量相同,OSTaskSemPend()函数原型如下:

    OS_SEM_CTR  OSTaskSemPend (OS_TICK   timeout,                //指定等待互斥信号量的超时时间(时钟节拍数)
                               OS_OPT    opt,                    //用于选择是否使用阻塞模式
                               CPU_TS   *p_ts,                   //指向一个时间戳
                               OS_ERR   *p_err)
    {
        OS_SEM_CTR    ctr;
        CPU_SR_ALLOC();
    
        if (p_ts != (CPU_TS *)0) {
           *p_ts  = (CPU_TS  )0;                                /* Initialize the returned timestamp                      */
        }
    
        CPU_CRITICAL_ENTER();
        if (OSTCBCurPtr->SemCtr > (OS_SEM_CTR)0) {              /* See if task already been signaled                      */
            OSTCBCurPtr->SemCtr--;
            ctr    = OSTCBCurPtr->SemCtr;
            if (p_ts != (CPU_TS *)0) {
               *p_ts  = OSTCBCurPtr->TS;
            }
            CPU_CRITICAL_EXIT();
           *p_err = OS_ERR_NONE;
            return (ctr);
        }
    
        if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) {    /* Caller wants to block if not available?                */
            CPU_CRITICAL_EXIT();
           *p_err = OS_ERR_PEND_WOULD_BLOCK;                    /* No                                                     */
            return ((OS_SEM_CTR)0);
        } else {                                                /* Yes                                                    */
            if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {    /* Can't pend when the scheduler is locked                */
                CPU_CRITICAL_EXIT();
               *p_err = OS_ERR_SCHED_LOCKED;
                return ((OS_SEM_CTR)0);
            }
        }
    
        OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();                  /* Lock the scheduler/re-enable interrupts                */
        OS_Pend((OS_PEND_DATA *)0,                              /* Block task pending on Signal                           */
                (OS_PEND_OBJ  *)0,
                (OS_STATE      )OS_TASK_PEND_ON_TASK_SEM,
                (OS_TICK       )timeout);
        OS_CRITICAL_EXIT_NO_SCHED();
    
        OSSched();                                              /* Find next highest priority task ready to run           */
    
        CPU_CRITICAL_ENTER();
        switch (OSTCBCurPtr->PendStatus) {                      /* See if we timed-out or aborted                         */
            case OS_STATUS_PEND_OK:
                 if (p_ts != (CPU_TS *)0) {
                    *p_ts                    =  OSTCBCurPtr->TS;
                 }
                *p_err = OS_ERR_NONE;
                 break;
    
            case OS_STATUS_PEND_ABORT:
                 if (p_ts != (CPU_TS *)0) {
                    *p_ts  =  OSTCBCurPtr->TS;
                 }
                *p_err = OS_ERR_PEND_ABORT;                     /* Indicate that we aborted                               */
                 break;
    
            case OS_STATUS_PEND_TIMEOUT:
                 if (p_ts != (CPU_TS *)0) {
                    *p_ts  = (CPU_TS  )0;
                 }
                *p_err = OS_ERR_TIMEOUT;                        /* Indicate that we didn't get event within TO            */
                 break;
    
            default:
                *p_err = OS_ERR_STATUS_INVALID;
                 break;
        }
        ctr = OSTCBCurPtr->SemCtr;
        CPU_CRITICAL_EXIT();
        return (ctr);
    }

    timeout:如果在指定的节拍数内没有收到信号量任务就会因为等待超时而恢复运行,如果timeout为0的话任务就会一直等待,直到收到信号量。

    opt:用于选择是否使用阻塞模式,有两个选项可以选择。OS_OPT_PEND_BLOCKING:指定互斥信号量被占用时,任务挂起等待该互斥信号量;OS_OPT_PEND_NON_BLOCKING:指定当互斥信号量被占用时,直接返回任务。

    注意!当设置为OS_OPT_PEND_NON_BLOCKING,是timeout参数就没有意义了,应该设置为0。

    从参数列表上来看,其实任务内嵌信号量和一般的信号量、互斥信号量没有什么差别,也仅仅是少了一个参数。请求信号量、互斥信号量的参数列表中多了一个指向信号量控制块的成员变量。

    那么任务内嵌信号量究竟在哪里呢?

    我们在将任务管理的时候讲过,一个任务的几乎所有的属性都在它的任务控制块中(OS_TCB类型)。下面就是在其中截取的一些成员的定义:

    struct os_tcb {
        ...
    
        CPU_CHAR            *NamePtr;                           /* Pointer to task name                                   */
        ...
    
        CPU_TS               TS;                                /* Timestamp                                              */
    
        OS_SEM_CTR           SemCtr;                            /* Task specific semaphore counter                        */
        ...
    
    #if OS_CFG_DBG_EN > 0u
        OS_TCB              *DbgPrevPtr;
        OS_TCB              *DbgNextPtr;
        CPU_CHAR            *DbgNamePtr;
    #endif
    };

    很明显的就是,这些成员变量其实和信号量控制块的成员变量几乎都是一样的:

    struct  os_sem {                                            /* Semaphore                                              */
                                                                /* ------------------ GENERIC  MEMBERS ------------------ */
        OS_OBJ_TYPE          Type;                              /* Should be set to OS_OBJ_TYPE_SEM                       */
        CPU_CHAR            *NamePtr;                           /* Pointer to Semaphore Name (NUL terminated ASCII)       */
        OS_PEND_LIST         PendList;                          /* List of tasks waiting on semaphore                     */
    #if OS_CFG_DBG_EN > 0u
        OS_SEM              *DbgPrevPtr;
        OS_SEM              *DbgNextPtr;
        CPU_CHAR            *DbgNamePtr;
    #endif
                                                                /* ------------------ SPECIFIC MEMBERS ------------------ */
        OS_SEM_CTR           Ctr;                            //信号量当前的取值
        CPU_TS               TS;
    };

    这就真相大白了。其实所谓的任务内嵌信号量,其实就是在每个任务的任务控制块中添加了一个信号量所需要的成员。

    发布任务信号量

    OSTaskSemPost()可以通过一个任务的内置信号量向某个任务发送一个信号量,函数原型如下:

    OS_SEM_CTR  OSTaskSemPost (OS_TCB  *p_tcb,                        //指向要用信号通知的任务的TCB
                               OS_OPT   opt,                            //用来指定是否进行任务调度操作
                               OS_ERR  *p_err)
    {
        OS_SEM_CTR  ctr;
        CPU_TS      ts;
    
        ts = OS_TS_GET();                                       /* Get timestamp                                          */
    
        ctr = OS_TaskSemPost(p_tcb,
                             opt,
                             ts,
                             p_err);
    
        return (ctr);
    }
    

    p_tcb:指向要用信号通知的任务的TCB,当设置为NULL的时候可以向自己发送信号量。

    opt:用来指定是否进行任务调度操作,有两个选项可以选择。OS_OPT_POST_NONE:不指定特定的选项;OS_OPT_POST_NO_SCHED:禁止在本函数内执行任务调度操作。

    注意:请求(等待)信号量,每个任务只能请求自己任务的任务信号量,不能请求其他任务的任务信号量。但是,发送信号量,每个任务可以向自己本身发送信号量,也可以向其他任务发送任务信号量。其实,在信号量请求函数中,也没有参数用来选择信号量的来源。

     

    UCOSIII实际例程

    任务内嵌信号量实验

    例程要求:创建3个任务,任务start_task用于创建其他两个任务,任务task1_task主要用于扫描按键,当检测到KWY_UP按下以后就向任务task2_task发送一个任务信号量。任务task2_task请求任务信号量,当请求到任务信号量的时候就更新一次屏幕指定区域的背景颜色。

    例子:

    #include "sys.h"
    #include "delay.h"
    #include "usart.h"
    #include "led.h"
    #include "lcd.h"
    #include "key.h"
    #include "includes.h"
    
    //UCOSIII中以下优先级用户程序不能使用,ALIENTEK
    //将这些优先级分配给了UCOSIII的5个系统内部任务
    //优先级0:中断服务服务管理任务 OS_IntQTask()
    //优先级1:时钟节拍任务 OS_TickTask()
    //优先级2:定时任务 OS_TmrTask()
    //优先级OS_CFG_PRIO_MAX-2:统计任务 OS_StatTask()
    //优先级OS_CFG_PRIO_MAX-1:空闲任务 OS_IdleTask()
    
    //任务优先级
    #define START_TASK_PRIO		3
    //任务堆栈大小	
    #define START_STK_SIZE 		128
    //任务控制块
    OS_TCB StartTaskTCB;
    //任务堆栈
    CPU_STK START_TASK_STK[START_STK_SIZE];
    //任务函数
    void start_task(void *p_arg);
    
    //任务优先级
    #define TASK1_TASK_PRIO		4
    //任务堆栈大小	
    #define TASK1_STK_SIZE 		128
    //任务控制块
    OS_TCB Task1_TaskTCB;
    //任务堆栈	
    CPU_STK TASK1_TASK_STK[TASK1_STK_SIZE];
    void task1_task(void *p_arg);
    
    //任务优先级
    #define TASK2_TASK_PRIO		5
    //任务堆栈大小	
    #define TASK2_STK_SIZE 		128
    //任务控制块
    OS_TCB Task2_TaskTCB;
    //任务堆栈	
    CPU_STK TASK2_TASK_STK[TASK2_STK_SIZE];
    void task2_task(void *p_arg);
    
    //LCD刷屏时使用的颜色
    int lcd_discolor[14]={	WHITE, BLACK, BLUE,  BRED,      
    						GRED,  GBLUE, RED,   MAGENTA,       	 
    						GREEN, CYAN,  YELLOW,BROWN, 			
    						BRRED, GRAY };
    
    int main(void)                    //主函数
    {
    	OS_ERR err;
    	CPU_SR_ALLOC();
    	
    	delay_init();  	//时钟初始化
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组配置
    	uart_init(115200);  //串口初始化
    	LED_Init();         //LED初始化	
    	LCD_Init();			//LCD初始化	
    	KEY_Init();			//按键初始化
    	
    	POINT_COLOR = RED;
    	LCD_ShowString(30,10,200,16,16,"ALIENTEK STM32F1");	
    	LCD_ShowString(30,30,200,16,16,"UCOSIII Examp 10-6");
    	LCD_ShowString(30,50,200,16,16,"TaskSem Sync");
    	LCD_ShowString(30,70,200,16,16,"ATOM@ALIENTEK");
    	LCD_ShowString(30,90,200,16,16,"2015/5/20");
    	
    	POINT_COLOR = BLACK;
    	LCD_DrawRectangle(5,110,234,314);	
    	LCD_DrawLine(5,130,234,130);
    	POINT_COLOR = RED;
    	LCD_ShowString(30,111,200,16,16,"Task_Sem Value:  0");
    	POINT_COLOR = BLUE;
    	
    	OSInit(&err);		    	//初始化UCOSIII
    	OS_CRITICAL_ENTER();	//进入临界区			 
    	//创建开始任务
    	OSTaskCreate((OS_TCB 	* )&StartTaskTCB,		//任务控制块
    				 (CPU_CHAR	* )"start task", 		//任务名字
                     (OS_TASK_PTR )start_task, 			//任务函数
                     (void		* )0,					//传递给任务函数的参数
                     (OS_PRIO	  )START_TASK_PRIO,     //任务优先级
                     (CPU_STK   * )&START_TASK_STK[0],	//任务堆栈基地址
                     (CPU_STK_SIZE)START_STK_SIZE/10,	//任务堆栈深度限位
                     (CPU_STK_SIZE)START_STK_SIZE,		//任务堆栈大小
                     (OS_MSG_QTY  )0,					//任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
                     (OS_TICK	  )0,					//当使能时间片轮转时的时间片长度,为0时为默认长度,
                     (void   	* )0,					//用户补充的存储区
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
                     (OS_ERR 	* )&err);				//存放该函数错误时的返回值
    	OS_CRITICAL_EXIT();	//退出临界区	 
    	OSStart(&err);      //开启UCOSIII
    }
    
    void start_task(void *p_arg)                //开始任务函数
    {
    	OS_ERR err;
    	CPU_SR_ALLOC();
    	p_arg = p_arg;
    	
    	CPU_Init();
    #if OS_CFG_STAT_TASK_EN > 0u
       OSStatTaskCPUUsageInit(&err);  	//统计任务                
    #endif
    	
    #ifdef CPU_CFG_INT_DIS_MEAS_EN		//如果使能了测量中断关闭时间
        CPU_IntDisMeasMaxCurReset();	
    #endif
    	
    #if	OS_CFG_SCHED_ROUND_ROBIN_EN  //当使用时间片轮转的时候
    	 //使能时间片轮转调度功能,时间片长度为1个系统时钟节拍,既1*5=5ms
    	OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);  
    #endif	
    		
    	OS_CRITICAL_ENTER();	//进入临界区
    
    	OSTaskCreate((OS_TCB 	* )&Task1_TaskTCB,	                	//创建TASK1任务	
    				 (CPU_CHAR	* )"Task1 task", 		
                     (OS_TASK_PTR )task1_task, 			
                     (void		* )0,					
                     (OS_PRIO	  )TASK1_TASK_PRIO,     
                     (CPU_STK   * )&TASK1_TASK_STK[0],	
                     (CPU_STK_SIZE)TASK1_STK_SIZE/10,	
                     (CPU_STK_SIZE)TASK1_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void   	* )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR 	* )&err);			
    
    	OSTaskCreate((OS_TCB 	* )&Task2_TaskTCB,		               //创建TASK2任务
    				 (CPU_CHAR	* )"Task2 task", 		
                     (OS_TASK_PTR )task2_task, 			
                     (void		* )0,					
                     (OS_PRIO	  )TASK2_TASK_PRIO,     
                     (CPU_STK   * )&TASK2_TASK_STK[0],	
                     (CPU_STK_SIZE)TASK2_STK_SIZE/10,	
                     (CPU_STK_SIZE)TASK2_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void   	* )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR 	* )&err);				 
    	OS_CRITICAL_EXIT();	//退出临界区
    	OSTaskDel((OS_TCB*)0,&err);	//删除start_task任务自身
    }
    
    void task1_task(void *p_arg)                            //任务1的任务函数
    {
    	u8 key;
    	u8 num;
    	OS_ERR err;
    	while(1)
    	{
    		key = KEY_Scan(0);  //扫描按键
    		if(key==WKUP_PRES)	
    		{
    			OSTaskSemPost(&Task2_TaskTCB,OS_OPT_POST_NONE,&err);	//使用系统内建信号量向任务task2发送信号量
    			LCD_ShowxNum(150,111,Task2_TaskTCB.SemCtr,3,16,0);		//显示信号量值
    		}
    		num++;
    		if(num==50)
    		{
    			num=0;
    			LED0=~LED0;
    		}
    		OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_PERIODIC,&err);   		//延时10ms
    	}
    }
    
    void task2_task(void *p_arg)                        //任务2的任务函数
    {	
    	u8 num;
    	OS_ERR err;
    	while(1)
    	{ 
    		OSTaskSemPend(0,OS_OPT_PEND_BLOCKING,0,&err);		//请求任务内建的信号量
    		num++;
    		LCD_ShowxNum(150,111,Task2_TaskTCB.SemCtr,3,16,0);	//显示任务内建信号量值
    		LCD_Fill(6,131,233,313,lcd_discolor[num%14]);		//刷屏
    		LED1 = ~LED1;
    		OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);   //延时1s
    	}
    }
    	//创建TASK1任务	
    				 (CPU_CHAR	* )"Task1 task", 		
                     (OS_TASK_PTR )task1_task, 			
                     (void		* )0,					
                     (OS_PRIO	  )TASK1_TASK_PRIO,     
                     (CPU_STK   * )&TASK1_TASK_STK[0],	
                     (CPU_STK_SIZE)TASK1_STK_SIZE/10,	
                     (CPU_STK_SIZE)TASK1_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void   	* )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR 	* )&err);			
    
    	OSTaskCreate((OS_TCB 	* )&Task2_TaskTCB,		               //创建TASK2任务
    				 (CPU_CHAR	* )"Task2 task", 		
                     (OS_TASK_PTR )task2_task, 			
                     (void		* )0,					
                     (OS_PRIO	  )TASK2_TASK_PRIO,     
                     (CPU_STK   * )&TASK2_TASK_STK[0],	
                     (CPU_STK_SIZE)TASK2_STK_SIZE/10,	
                     (CPU_STK_SIZE)TASK2_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void   	* )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR 	* )&err);				 
    	OS_CRITICAL_EXIT();	//退出临界区
    	OSTaskDel((OS_TCB*)0,&err);	//删除start_task任务自身
    }
    
    void task1_task(void *p_arg)                            //任务1的任务函数
    {
    	u8 key;
    	u8 num;
    	OS_ERR err;
    	while(1)
    	{
    		key = KEY_Scan(0);  //扫描按键
    		if(key==WKUP_PRES)	
    		{
    			OSTaskSemPost(&Task2_TaskTCB,OS_OPT_POST_NONE,&err);	//使用系统内建信号量向任务task2发送信号量
    			LCD_ShowxNum(150,111,Task2_TaskTCB.SemCtr,3,16,0);		//显示信号量值
    		}
    		num++;
    		if(num==50)
    		{
    			num=0;
    			LED0=~LED0;
    		}
    		OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_PERIODIC,&err);   		//延时10ms
    	}
    }
    
    void task2_task(void *p_arg)                        //任务2的任务函数
    {	
    	u8 num;
    	OS_ERR err;
    	while(1)
    	{ 
    		OSTaskSemPend(0,OS_OPT_PEND_BLOCKING,0,&err);		//请求任务内建的信号量
    		num++;
    		LCD_ShowxNum(150,111,Task2_TaskTCB.SemCtr,3,16,0);	//显示任务内建信号量值
    		LCD_Fill(6,131,233,313,lcd_discolor[num%14]);		//刷屏
    		LED1 = ~LED1;
    		OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err);   //延时1s
    	}
    }

     

    展开全文
  • 【UCOSIII】UCOSIII的信号

    万次阅读 2018-07-01 20:42:34
    信号信号量像是一种上锁机制,代码必须获得对应的钥匙才能继续执行,一旦获得了钥匙,也就意味着该任务具有进入被锁部分代码的权限。一旦执行至被锁代码段,则任务一直等待,直到对应被锁部分代码的钥匙被再次...
  • 信号的采样

    千次阅读 2014-09-16 15:22:31
    2048HZ对信号来说是过采样了,事实上只要信号不混叠就好(满足尼奎斯特采样定理),所以可以对过采样的信号作抽取,即是所谓的“降采样”。在现场中采样往往受具体条件的限止,或者不存在300HZ的采样率,或调试非常...
  • 2020多媒体信号处理复习笔记

    千次阅读 多人点赞 2020-05-20 02:00:55
    1.什么是信号处理? 信号处理是系统工程,电气工程和应用数学领域中涉及的 领域模拟或数字信号的操作或分析, 代表时间变化或空间变化的物理量。 典型的操作和应用 信号采集与重建 信号压缩(源编码) 特征提取,...
  • 光及颜色 1.光:是人类眼睛可以看见的一种电磁波,也称可见光谱。在科学上的定义,光是指所有的电磁波谱。光是由光子为基本粒子组成,具有粒子性与波动性,称为波粒二象性,一般人的眼睛所能接受的光的波长在380—...
  • 连续信号的频域分析 ...频率特性是信号的客观性质,如光线的颜色、声音的音调,比信号的时域特性更能反映信号的基本特性。 周期信号的频谱分析 周期信号: x(t)=x(t+mT)m=0,±1,±2,⋯ x(t)=x(t+mT) \quad m=0,\pm1
  • Qt Quick 事件处理之信号与槽

    万次阅读 多人点赞 2014-06-11 12:52:33
    而这里边,我们熟稔的,鼎鼎大名大名鼎鼎的,要不断打交道的,就是信号与槽了。历史是割不断的,继承与发展才是正确的价值观……,了解过 Qt 的开发者一定对信号与槽印象深刻。在 QML 中,在 Qt Quick 中,要想妥善...
  • 若该文为原创文章,未经允许不得转载 原博主博客地址:https://blog.csdn.net/qq21497936 本文章博客地址:https://blog.csdn.net/qq21497936/article/details/100976153 目录 前言 基础数据结构 基础图像矩阵...
  • 1 什么是颜色 2 颜色的数字化 3 常见的颜色模型 3.1 RGB 模型 3.2 CMY/CMYK 模型 3.3 HSI 模型 3.4 HSV 模型 3.5 HSB 模型 3.6 Lab 模型 3.7 YUV 模型 3.8 模型分类 4 Python代码示例 参考资料 1 ...
  • 共模信号和差模信号的区别和抑制

    千次阅读 2018-08-22 15:03:26
    了解共模和差模信号之间的差别,对正确理解脉冲磁路和工作模块之间的关系是至关重要的。变压器、共模扼流圈和自耦变压器的端接法,对在局域网(LAN)和通信接口电路中减小共模干扰起关键作用。共模噪音在用无屏蔽对绞...
  • 它们在没有开发代码的情况下工作,手动确定颜色或交通信号灯的位置。例如,优化的R-CNN(https://arxiv.org/abs/1506.01497)模型能够以实时的速度获得最先进的精度。 那么它是如何工作的呢? 交通信号灯在哪里? ...
  • Modelsim修改波形显示颜色

    千次阅读 2020-02-21 09:51:49
    本文由FPGA爱好者小梅哥编写,未经作者许可,本文仅允许网络论坛复制转载,且转载时请标明原作者。 为啥要修改颜色?逻辑开发工程师和学生工作学习中免不了需要为设计的逻辑编写设计报告,在编写设计报告时,仿真图...
  • 颜色传感器TCS230及颜色识别电路(转)

    千次阅读 多人点赞 2017-01-23 17:19:00
    该传感器具有分辨率高、可编程的颜色选择与输出定标、单电源供电等特点;输出为数字量,可直接与微处理器连接。文中主要介绍TCS230的原理和应用,以及色光和白平衡的知识,并用一个实例说明TCS230识别颜色的过程。 ...
  • 语音信号端点检测

    千次阅读 2018-12-12 14:43:39
    %语音段中允许的最大静音长度,如果语音段中的静音帧数未超过此值,则认为语音还没结束;如果超过了 %该值,则对语音段长度count进行判断,若count,则认为前面的语音段为噪音,舍弃,跳到静音 %状态0;若count>...
  • VGA信号详解(VHDL版)

    千次阅读 2020-02-15 19:16:19
    VGA信号详解(VHDL版) 文章目录VGA信号详解(VHDL版)1. 简要说明2. 接口示意3. VGA时序标准3.1. 基本时序说明3.2. 地址码线说明4. 硬件连接5. 示例代码 1. 简要说明 VGA即视频图形阵列(Video Graphics Array),...
  • 本文来自对论文《Reconfiguring the Image Pipeline for Computer Vision》的附录关于ISP内容的整理。 从数码单反相机到智能手机,现代的任何...图像信号处理器(ISP)单元,它把图像信号进行转换、增强、压缩等...
  • CPU接口信号说明

    千次阅读 2008-03-29 17:15:00
    一、CPU接口信号说明1. A[31:3]# I/O Address(地址总线) n 这组地址信号定义了CPU的最大内存寻址空间为4GB。在地址周期的第一个子周期中,这些Pin传输的是交易的地址,在地址周期的第二个子周期中,这些Pin...
  • 语音信号特征处理--Fbank\MFCC

    千次阅读 多人点赞 2021-05-22 20:26:26
    基本的数字信号处理知识,Fbank和MFCC过程及python实现
  • ColorSpace颜色空间简介

    千次阅读 2020-10-10 19:44:59
    如果看过之前的介绍的图像颜色迁移《color transfer between images》和颜色协调模型Color Harmoniztion就会发现,大部分图像处理算法虽然输入输出是RGB像素值,但是中间进行算法处理时很少直接更改RGB值,而是转换...
  • SI信号完整性分析术语

    千次阅读 2012-04-10 20:38:20
    Skew slew EMC 2007-09-20 14:42 SI信号完整性分析术语 http://publishblog.blogchina.com/blog/tb.b?diaryID=5579242 ...SI信号完整性分析术语 ...1、什么是信号完整性(Singnal Int
  • 视频信号vsync hsync dotclock 的关系

    千次阅读 2017-05-26 15:47:08
    本文为博主原创文章,未经博主允许不得转载。 在图像里面的参数如图所示: Dotclk = Htotal × Vtotal × framerate Htotal = Hactive + Hsync + HfrontPorch + HbackPorch Vtotal = Vactive + Vsync + ...
  • 图像颜色校正的几种方法

    万次阅读 2016-01-21 10:13:25
    各种教学视频或文档资料 +QQ:635992897 注:本文主要参考“彩色人脸图像颜色校正及其在肝病诊断中的...我们采用的颜色校正算法是基于监督的思想,即通过标准色板对图片进行颜色校正,目前在颜色校正方向上,已经...
  • 信号完整性分析7——传输线的物理基础 传输线定义: 同轴电缆线是一种传输线,多层板中的PCB线条也是一种传输线。 简单地说,传输线是由两条有一定长度的导线组成的。 作用: :在可接受的失真度下, 把信号从...
  • 语音信号处理初学者概念总结

    千次阅读 2014-02-27 22:05:33
    它将对信号的研究从时域引到频域,从而带来更直观的认识。 2. 把残差信号可能出现的、已经量化了的、按一定规则排列的各种样值事先存储在存储器中,好像一本字典一样。每一个样值组合都有一地址码,所以这...
  • 共模和差模信号及其噪音抑制

    千次阅读 2013-12-24 23:20:16
    共模和差模信号及其噪音抑制1 引言 了解共模和差模信号之间的差别,对正确理解脉冲磁路和工作模块之间的关系是至关重要的。变压器、共模扼流圈和自耦变压器的端接法,对在局域网(LAN)和通信接口电路中减小共模干扰...
  • 往期回顾: 上一篇:基于Matlab-Simulink 的 2FSK 数字调制原理与仿真 上一篇:Simulink仿真系列-- 扩频通信-跳频扩频通信系统的原理和Simulink仿真 ...对于无线理论的仿真,信号观测仪器能够直观的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 25,886
精华内容 10,354
关键字:

允许信号的颜色