如何使Arduino进行多线程工作
文件列表(压缩包大小 6.68K)
免费
概述
为了使用Arduino进行多线程工作,我们需要protothreading。
该视频描述了你在原型开发初期可能想要做的事情,促使单核arduino一次完成3件事情。在这种情况下,我们的要求是
以恒定速率脉动背光灯而不会中断
每秒递增一个数并将其写入显示屏而不会中断
每几秒钟轮换几条消息,并将其写到显示屏上而不会中断
Protothreading是一种通常在Arduino上执行多任务操作(一次或以不同的时间间隔执行两项或多项操作)的方式。换句话说,它是“多线程”。但是Arduino是具有过程代码的单核芯片,因此不可能实现真正的多线程。为什么呢?Protothreading和通常的多线程有何不同?
为了正确理解Protothreading,我们首先需要了解为什么它不是真正的多线程。
英特尔在Pentium处理器上向我们出售过这种新的“超线程”功能,超线程是英特尔采用的一种技术,可在处理器上使单个内核就像两个内核一样起作用,或者使两个内核像是4内核一样起作用。但这与Arduino有什么关系?答案是循环。
微处理器和CPU均以“周期”工作。他们执行这些操作的速度(每秒几秒钟)是时钟速率。你已经看到了CPU的Ghz等级,并且你可能知道它与它的速度有关。Ghz越大越好,对吗?但为什么?因为那是处理器每秒可达到的周期数。
如果你是一个datasheet的爱好者,你可能会知道Arduino Uno的微处理器芯片Atmel ATMega328P起初以16Mhz运行。它具有20Mhz的能力,但是可以下调,因此不会弄乱诸如将数据写入内存之类的事情。16Mhz表示每秒你的Arduino处理1600万个周期,也就是做1600万个工作。现在,这些不是代码行,他们的运行速度非常快,而Arduino则相对较慢,这些是处理器指令,例如将数据移入和移出寄存器。
因此,如果我们只能在可用的最佳芯片满载之前在内核上如此工作,我们是否会永远停留在该速度上?那是我们最快的工作速度吗?事实证明,不!这就提出了多核CPU和多线程。在计算机CPU上,多线程应用程序是两个单独的进程,它们在CPU的不同内核上彼此并行工作。这些过程相互作用以使工作一起完成,但是不一定像你想象的那样平均分配工作。通常有一个主进程/“线程”充当其他线程的管理器,然后由它管理一个或多个工作线程,每个工作线程都可能执行特定的任务。Chrome就是一个很好的例子。Chrome是你所有网页标签(线程)的管理器,但是由于chrome是多线程的,因此每个标签都是自己的小程序。这意味着,如果你有多个内核来分布每个选项卡,它不仅可以运行得更快,而且还具有其他好处,例如当一个选项卡崩溃时不会崩溃整个浏览器。这是Protothreading不是多线程的第一个原因——我们只有一个内核可以在MCU上使用,因此传统的多线程是不可能的。我们只需要在单个内核上管理工作,但仍然可以同时执行多项操作。我们需要protothreading。
在某种程度上,Protothreading与我提到的Hyperthreading非常相似。Hyperthreading将模拟第二个内核,并假装为两个虚拟内核,从字面上划分一个内核正在执行的工作。之所以起作用,是因为它们确实存在于相同的内核上,因此共享相同的资源空间。由于arduino MCU不支持超线程,因此我们无法在此处执行。Protothreading是相似的,除了代替CPU周期和指令,我们可以通过草图执行的代码的“循环”或“行列”来分解工作。就像你想象的那样,如果我们做更多的事情,循环将花费更长的时间,因此每个项目将具有截然不同的“每秒循环”。Protothreading有不同的实现方式,我在这里使用的实现方式显然是次充好,基本上,每个循环我们没有其他工作要做,我们在主循环中进行一些需求较少或不那么频繁的工作(或根本不做)。当我们不忙时,我们正在检查是否需要进行其他工作之一。如果是这样,我们会分支并去做。重要的是要注意,“阻塞”操作意味着它们必须立即完成所有操作而不会中断,从而占用MCU一段时间(例如从SD卡读取数据和执行其他一些任务)仍会阻塞其他Protothreading是“按时”发生的,但是对于诸如两个循环同时执行的简单操作(如变量更改或更改输出值)的快速操作而言,它将非常出色,这或多或少是我们在这里要做的。一些MCU支持实时操作系统(RTOS),该实时操作系统可以提供更多类似超线程的多任务处理功能,可以帮助缓解“阻塞”任务引起的问题。
我们首先弄清楚我们需要执行哪些任务。就我而言,我选择(a)淡入或淡出LCD面板的背光以产生整洁的“脉冲”效果,而(b)以较慢的(可能是不可分割的)间隔对数字进行计数,以及(c)以较慢的间隔旋转一些字符串消息。为了确保此过程顺利进行,需要遵循的一些准则是对你的功能从最小阻塞到最大阻塞进行评级。花费较长时间的操作(从现在开始将它们称为“功能”),例如读取数据或具有其他较长的延迟,并且触发时间间隔较长的功能是最阻塞的功能。阻塞最少的函数是(即使不是每个循环)触发频率很高且不需要很长时间才能完成的函数。最不阻塞的功能是应该用作主“线程”的功能。你能猜出最上面的那个吗?
是的,它是“ a”,将背光脉冲调入和调出。这将以规则且非常快速的时间间隔进行,除非完成工作,否则永久之间不会有火灾之间的延迟,并且工作本身非常快。完美的管理器线程。
我们将使用该线程(以及其中的任何循环)来检查其他线程是否需要执行任何工作。在这一点上最好阅读通篇-它已被大量记录。见底部的主循环。你可以看到我在调用numberThread.check()
和的地方检查线程是否需要任何工作textThread.check()
。
我还需要在主线程中的任何循环中执行此操作,因为如果没有,它们将阻塞直到完成。我设置了在初始化或代码的设置部分初始化线程时需要触发的时间间隔。如果是时候触发这些线程,.check()
则在继续执行主线程之前将看到并执行其工作。
其余的你可能可以通过逐步执行代码来弄清楚自己。最后,我想说一下,尽管我并不是protothreading专家,这只是我简单理解的一个简单示例。如果你有任何提示,或者我在任何事情上做错了,我鼓励你提供反馈和更正!
所有需要的文件在下载区均可找到。 via:How to "Multithread" an Arduino (Protothreading Tutorial) - Arduino Project Hub
如果遇到文件不能下载或其他产品问题,请添加管理员微信:ligongku001,并备注:产品反馈
评论(0)