有关微控制器中多任务的更多信息

根据作者的说法,在前一篇文章中,我们讨论了如何实时对微控制器的常规动作进行编程,将它们分为彼此独立(或几乎独立)的几个任务。


选择了一个微控制器,其内核来自非常广泛的ARM Cortex M系列。在很多人(不仅是作者)中,选择了数字0、3、4和7的选项是M4,因为它就在眼前。


正如一些读者巧妙地指出的那样,促使我们走上“发明自行车”的湿滑道路的两个考虑实际上很简单。 首先是我们仍然必须与这些“皮质”共存。 第二种是尝试不做通用的事情(获得名利),而是做更狭narrow的事情,以期达到效率和简单性。 那些有时用手做一些事情的人会很容易记住,通常,特别选择的螺丝刀要比从通用的螺丝刀中取出的要好。


给出了一个汇编器示例,以显示切换所花费的时间不超过80个时钟周期。 而在72兆赫兹的时钟速度下,结果略超过1微秒。 因此,一个50微秒的刻度不会太贵。 仅开销的2%。 因此,正如作者最喜欢的角色之一所说,“最好受苦”。


因此,我们有N个任务,保证每个任务都要花费一段时间(滴答T),并保证不迟于(N-1)个T滴答之后再重复此段,加上不超过D的延迟。幸运的是,这种令人讨厌的延迟由最大可能的时间大小限制,该大小等于所有允许的中断的操作持续时间之和。 换句话说,在下一个滴答之前给定时间段内中断可能性最大的任务是最不幸运的。 在更长的时间内,任务不会被延迟。 她不可避免地会在(N-1) T + D微秒内收到自己的时隙 。 在我看来,这称为硬实时。


任务必须完成其任务并报告实施情况。 我应该向谁报告? 显然,有人负责,通常情况下,他们要比下属小得多(实际上,作者还遇到了一个例外,当时三个左手的工人有四个老板,其中只有一个人知道并尊重“足够”)。


如果“你们很多,但我合而为一”,那就意味着要排队。 许多人将开始努力并尝试通过。 而有些人将不得不等待,然后迟到并进行解释。 尽管这一切看起来都很糟糕,但它被称为美丽:为资源而战。 队列是众所周知的解决方案。 我知道许多人不喂面包-让我站着。


但是我们迫不及待! 从某种意义上说,任务。 他们来自困难的实时。 假设有两个任务每秒读取一次读数,第三个任务应该每10毫秒测量一次,将其堆积一堆,然后报告给顶部。 然后他们对她说:“告诉我,我们还没有结束厨师的工作。”


显然,您必须稍微说一点就转向不太实时(软实时)。


让我们有一个特别的任务,知道如何等待并喜欢这样做。 它将服务的资源将是通信渠道。 如您所知,您不会立即将所有内容都塞进去。
但是,您可以立即弄清楚通道的速度,这样就不会丢失任何信号。 为此,您需要了解我们所有的笔误,pah和任务的工作性能。 显然,您还必须计算一个或多个缓冲区的大小,所有包将从中发送(或向右发送)。


如果渠道不是一个渠道,那么本质就不会改变。 对于每个频道,只需添加一个单独的任务即可等待(当然还有希望和信任)。


关于与操作员或更简单地与人进行沟通的几句话。 这里的通道是双向的,但向外的方向最有趣。 立即做出保留,在一种情况下,即使有强烈的愿望,也无法排除。 这是通道过载。 在测试过程中,我们必须达到目标,并且必须具有一种机制来查看其发作。 我不认为,欺骗是不好的,但可以省略一点。 格拉西姆·沃恩(Vaughn)完全滥用了它。


因此,我们立即假定从任务发送给操作员的消息可能会丢失。 为了使一个人知道这一点,我们将给他们编号。 这将确定我们的操作员在什么地方和什么地方什么都没剩下。 最终,您始终可以在代码中进行某些操作,或添加计算,甚至将其连接到电路中以纠正这种情况。 暂时看来,它将变得更加容易。 但是,当然,对于军事应用而言,这不是必需的。 老实说,仅在调试时丢失消息看起来并不可耻。


例如,让我们有一个在115200波特下没有确认的双工串行接口。 例如,RS422在配置“经济”时有两根线-那里,两根-回来了。 其能力约为每秒10,000字节。 让我们以一个人的平均消息大小等于50个字节为例。 我们每秒收到200条消息,或者在5毫秒内收到一条消息。 如果我们有三个要交流的任务,那么让他们每15毫秒执行一次。 当然,平均而言。 如果不是平均水平,则需要进行认真的统计计算或全面的实验。 选择最后一个。 毕竟,我们已经学会了检测丢失的消息,并将在终端仿真器的屏幕上看到所有内容。
因此,让这三个任务创建单独的消息。 让消息在内容的重要性或紧迫性上有所不同,我们的任务将它们放在适当的缓冲区中。 为三个紧急级别分配这三个环形缓冲区,如图1所示。



第四个任务根据我们批准的计划从这些缓冲区中选择一条消息,然后尝试传递它。 如果尚无法发送,则第四个任务将估计它可以休眠的次数并执行该操作。 睡觉后,她在环形缓冲区中已经有必要的空间可以发送。


当然,各种紧急情况的缓冲区不存储消息本身,而是存储它们的地址(链接)。 同时,任务本身根本不需要等待。 好吗 不,不是。 那是行不通的,这就是原因。 这三个环形缓冲区中的每一个都是共享资源。 想象一下任务1将要在中间缓冲区中放置一个地址。 她读了单词,检查该位置是否为空,即该值是否为零,并且(此刻,她被另一个任务2替换,该任务想做完全一样,并且成功了),第一个任务返回,将单词放在那里,覆盖所有成功第二。 这是一个同事要问话。 我似乎知道他会说什么。
-是的,一切都非常简单,您可以在测试期间禁止中断,并且不会发生任何不好的事情,这不会太久。
-是的,不是很长时间,而是多少次? 我们将花费多少时间完成这项任务? 哪一个呢? 我忘记警告了,我们从不禁止中断,我们实时的硬性规定禁止我们这样做。
-并且,如果您不禁止中断,则可以要求我们的任务开关在其中放置消息地址。 他可以原子地做到这一点。
-是的,也许吧,但是我想问一下他,然后再问另一个。 那么为什么我们达到72度,然后用水稀释一切呢? 抱歉,我的意思是切换上下文需要72个周期。
让我们尝试使其更轻松,如图2所示。



在这种情况下,如果您想要不同的紧迫性,盛况和重要性,则每个任务都有其自己的缓冲区或一组缓冲区。 就我个人而言,作为一个简单的运算符,我对每个人仍然具有相同的重要性。


这样的方案不会使您为资源而战。 现在我们有一个非常可行的选择。 只是不喜欢它。 但是,如果图片左侧的任务无话可发送怎么办? 然后,更明智的做法是在出现原因时要求唤醒右侧的任务,而不是仅仅为了再次设置警报而唤醒。 左侧的任务更容易完成。 另外,在以前的文章中提到了帮助唤醒朋友的功能。


我预见了一个合理化的建议:“让串行端口(UART)本身的中断参与任务4现在正在做的事情,将会节省很多钱。” 您可以这样做,但我认为这不好。 我会尽力澄清。 实际上,左边的任务本身可以激活UART中断过程,它将开始工作,直到完成所有工作后才会停止。 现在,中断过程应该执行任务4曾经做过的所有事情,处理中断所花费的时间将会增加,在下一个“假脱机”结束之前,无法打开任何单个任务。 我们从持续的实时圈子对我们的同志说些什么? 但是我们被告知,对任何外部中断的响应应尽可能短。 这只是一个很好的基调。 或者,换句话说:要做好事,坏事,没有你就行了。


图3解释了什么是过程以及面临的挑战。



现在我们来谈谈这种情况,也许可以说是一面镜子。 这是信息来自外部的时候。 让它成为一个SPI频道,其中有几位平底船船夫,吊船和一个小型业余弦乐团。 不,现在考虑休息还为时过早。 仅保留SPI接口和一些芯片。 例如,大气压传感器,加速度计和存储的内存。


我必须马上说-一个愚蠢的例子。 并不是因为船夫带着他们永恒的“先生,先生,我应该补充。” 不,实际上,将不同重要性的输入数据混入一个界面是很愚蠢的。 确实,如果您需要了解加速度,那么可以肯定的是,为了迅速找出何时卸下油门踏板,转动襟翼或闭上眼睛,是什么。 通常需要此信息。 但是,压力变化缓慢,必须向下飞行约三米,这样,处于较低等级的人的生活就会变暖。


至于存储的内存,通常谁将它放在此SPI上? 是否有第二个SPI? 并没有预期吗? 无处可去,需要做些事情。 将箭头指向与图2相反的方向并开始思考。


任务4现在为SPI服务,并且仅通过其信号唤醒。 它与任务1的连接(要在存储的内存中放入一些内容)向外指向,并通过队列执行。 还需要提供一种机制来监视环形缓冲区的溢出。 任务4的加速度和压力值的产生应在没有两个消耗性任务的情况下提供。 您只需要旋转并跟上。 现在我们可以勾勒出一张解释性图片并写下一个解释性注释。 在图4中,这些
动作以示意图形式(或框图)显示。



下溢检查-这些操作可帮助您确定在消耗任务再次读取加速度值之前是否有时间更改加速度值。 此检查仅在图4中通过单独的操作显示,以引起注意。 实际上,此步骤与根据该方案读取加速度计的值一起发生,如图5所示。



应该注意的是,存在共享资源,因为结果的存储位置也是操作(信号量)的指示器。 在这里可以说种族的语言来进行比赛,但是对我们来说这不是疏忽。 毕竟,仅在生命中滑入汽车的关门可被视为一种财富。 在这里,我们将有信心地认为这是一个延迟。


为了限制每个这样的步骤的时间,存储器访问分部分进行。 因此,我们将确保一致读取快速变化的加速度值,并且在此之间我们将及时照顾其余的人。


好吧,现在仍然有必要从铁中找到合适的东西并进行实验。 我认为,这将是下一个故事。

Source: https://habr.com/ru/post/zh-CN456242/


All Articles