项目2:DigIlent Pro MX7和延迟
软件时序延迟
这个项目的目的是研究创建软件时间延迟来调整处理器操作的方法。控制进程何时执行的计时方法可以通过使用对自由运行时钟进行抽样的轮询技术或通过执行需要固定时间的代码来实现。该项目还演示了信号调节中使用时间延迟的方法。
先决条件
-
工作知识MPLABX®IDE
-
I / O销控制
库存
时间延迟:需要多长时间?
通常,执行软件所需的时间越多,对系统性能的损害就越大。然而,在某些情况下,程序实际上运行得太快,我们面临着开发减缓它的方法的挑战。处理器执行的每条指令都需要有限的时间。有时,我们可以通过使用程序循环来产生延迟,从而利用固有的代码执行时间。考虑清单1中所示的程序,该程序添加两个整数变量并将结果赋给第三个整数变量:
清单1。
/* * File: P1.c * Author: Richard Wall * * Created on July 5, 2013, 12:56 PM */ #include#include "../config_bits.h" int main(void) {int a = 5, b = 10, c;c = a + b;返回(EXIT_SUCCESS);}
每个C源代码语句都是通过将其转换为给定处理器能够理解的指令来实现的。然后处理器对这些指令进行操作。实现此语句的实际处理器级指令可以用汇编语言表示。C语言被认为是一种独立于硬件的“高级”语言,而汇编语言不同于它所运行的特定处理器。汇编语言指令随后被转换成处理器实际使用的机器语言。虽然教授汇编语言编程超出了本项目的范围,但我们将考虑一点汇编代码,因为它在时间考虑方面具有指导意义。如果有些细节看起来有点神秘,你也不必特别担心。清单1所示程序中的C语句C = a+b;是作为清单2所示的四个汇编语言指令序列实现的。
清单2。为add语句生成的汇编语言代码。
9D000038 8FC30010 lw v1,16(s8);负载字Reg V1间接9D00003C 8FC20014 lw v0,20(s8);Load word Reg V0 indirect 9D000040 00621021 addu V0,v1, V0;Add 9D000044 AFC20018 sw v0,24(s8);存储字间接
列表2的前两个列是以十六进制表示法表示的32位数字。第一列显示存储机器代码的存储器地址。第二列是处理器用于实现第三列中显示的指令的实际机器代码。第三列给出了所用的汇编语言指令以及所涉及的处理器存储器寄存器在第四列中给出。将分号遵循的任何文本被处理为注释,如第五列所示。
要确定每条指令需要多少周期,我们需要查看PIC™32MX使用的MIPS体系结构的汇编语言。根据编译器优化选项的选择,C指令到汇编代码的转换可能是不同的。如果PIC32MX的核心时钟运行在80兆赫,一个CPU周期是12.5 ns(即,一个时钟周期的周期是时钟频率的倒数)。
由于MIPS核心使用的流水线架构,很难隔离一段代码,并严格根据指令的数量确定其执行时间。通过使用嵌入在MPLAB®X IDE中的秒表诊断工具对清单2中的四条指令计时,我们发现需要31个CPU周期。(有关如何使用MPLAB X秒表功能的说明,请参阅右边的确定延迟常数选项卡。)当核心时钟运行在80时,这相当于387.5纳秒兆赫.撇开从汇编代码行确定执行时间的困难不提,指令的数量是一个相对的指标。完成任何特定的C指令所需的执行时间是由C语句的复杂性、C指令被转换成的汇编代码以及处理器运行的速度决定的。
足以说每个C指令可能需要多个汇编语言指令实现,并且每个组装指令需要执行时间来执行。底线是C代码的执行需要时间,我们可以使用此时间来生成可预测的时间延迟。生成时间延迟的替代方法是使用处理器的定时器资源之一。我们将研究这两种在该项目中创建延迟功能的方法。
起飞电脑
当处理器执行代码的速度快于应用程序的要求时,基于微处理器的系统就有多余的时间。例如,假设有一个应用程序引领是以一秒的速度在开和关之间切换。用于切换I/O引脚的LATGINV指令只需要4个处理器时钟周期,占所需的1秒周期的50 ns。由于微处理器总是希望以每秒8000万条指令的速度执行下一行代码,因此必须执行额外的指令来实现延时操作。在大多数情况下,时间延迟功能除了消磨时间之外没有其他用途。
在该项目中探讨了两个开发延迟函数的两种方法。其中一个不需要特殊的硬件,而是严格依赖于软件循环的执行时间。我们将把这种方法称为软件延迟方法。另一个使用处理器的内置定时器之一来通过计时循环来生成延迟。我们称之为硬件辅助软件延迟方法。延迟函数有两个控制相互关联的元素:分辨率和范围。该分辨率由最小可能的延迟和范围定义,通过最长可能的延迟。在某种程度上,这些参数由选择以实现延迟的方法确定。
纯软件延迟
首先,让我们关注软件延迟方法,考虑一个软件环路来生成延迟函数。有三种编写软件循环的方法:“for”循环、“while”循环和“do -while”循环。一个使用for循环的例子是:我< COUNTS_PER_MS;我+ +);。在这个程序语句中,选择常量“COUNTS_PER_MS”的值以导致单位延迟(一个单位的延迟)为1毫秒。清单3显示了如何使用固定数量的for循环迭代生成指定时间的软件延迟。然后使用while循环为每一毫秒所需的延迟重复执行这个for循环。处理器执行代码的速度会影响常量COUNTS_PER_MS的值。常数COUNTS_PER_MS的标称值越大,周期的分辨率就越高,因此可以更精确地设置延迟周期。 The lines of code that are annotated with the comment “ / / SW Stop breakpoint” identify the lines of code where break points are inserted to allow execution timing using the MPLAB X stopwatch tool. (See the third tab on the right for information on using the stopwatch.)
清单3。软件延迟功能。
/*下面的define语句是在chipKIT_PROM_MX.h中声明的#define LEDA BIT_2 // IOPORT B */ /*下面的define语句是在Project2.h中声明的#define COUNTS_PER_MS 1000 //初始猜测*/ void sw_msDelay (unsigned int mS) {int i;while(mS——)// SW停止断点{for (i = 0;我< COUNTS_PER_MS;i++) // 1 ms delay loop{//什么都不做}LATBINV = LEDA;//切换LEDA每个ms for instrumentation}} // SW停止断点
给定指定延迟的毫秒数的“mS”变量是一个无符号整数,那么范围或可能的最长延迟是4,294,967,295毫秒或49.71天。软件延迟循环的缺点是分配给COUNTS_PER_MS的值取决于处理器速度。如果处理器速度改变,则延迟功能不再正确校准。
软件延迟的校准时间
使用上面列表3所示的“SW_MSDelay”功能时,请致意几个问题。“应该用于counts_per_ms的值以及延迟的准确程度如何?”随后,您必须解决问题,以便如何最好地确定用于Counts_per_ms常量的值。如前所述,难以简单地积累指令时间,因此将使用替代方法。
我们建议添加软件代码以允许软件操作可观察到。实现这一点的一种方法是通过在微处理器上切换I / O引脚。这要求外部仪器连接到连接到被切换的位的电路板的引脚。适用于该测试的仪器包括频率计数器,示波器和逻辑分析仪。现在,必须考虑一个适当的位置来插入代码以设置I / O引脚高或低意识到插入此类代码可能会影响延迟功能的准确性。建议放置仪器代码,在那里它将执行最小次数。应当注意,LatXinV指令用于切换Lat寄存器中的特定位,而不修改其他LAT寄存器位。当特定端口的I / O引脚用于控制独立输出和不同时间时,这是一个重要的考虑因素。用于确定Counts_per_delay值的详细过程呈现在右侧的第二个选项卡中。
测量延迟时间的一种有效的替代方法是使用MPLAB X秒表工具,如右边第三个选项卡所示。
借助硬件延迟
硬件辅助的软件延迟方法产生一个延迟函数,利用处理器的一个硬件计时器。对于基于计时器的延迟,常用的时间单位与CPU晶体周期、计时器滴答或毫秒有关。chipKIT Pro MX7板采用8兆赫水晶。即,与可编程PIC32乘法器和分隔器结合使用,导致PIC32MX795F512处理器能够以80的最大核心频率运行兆赫.在config_bits.h文件中,“#pragma config FPLLIDIV=DIV_2”语句首先除以8的频率兆赫振荡器到2.语句#pragma config fpllmul = mul_20将输入分频器的输出乘以20,导致80兆赫.最后,语句#pragma config FPLLODIV = 1除80兆赫乘以1,得到核心频率为80兆赫.由于处理器消耗的功率与处理器速度有关,因此乘数和两个除法器的组合允许开发人员设置最适合特定应用程序的时间和功率需求的核心频率。有关核心振荡器配置选项的信息,请参阅PIC32MX5XX/6XX/7XX技术参考手册的第6节。
PIC32MX处理器家族有几个内部计时器。对于这个项目,我们将使用核心计时器来生成任意时间段的延迟。核心计时器每两次滴答一次,系统时钟滴答两次.因此,每毫秒的核心振荡器数量等于系统时钟频率的一半划分为1000.清单4中的前三个#define语句在毫秒内建立了核心振荡器周期的数量。列表4中显示的“HW_Delayms”功能中的循环实现了总毫秒延迟操作。
清单4。硬件辅助的软件延迟功能。
/ *以下定义语句中声明chipKIT_PROM_MX.h * / / / # define GetSystemClock () (80000000 ul) / / Hz / / # define GetInstructionClock () (GetSystemClock () / 2) / / # define CORE_TICKS_per_MS (GetInstructionClock () / 1000) / / # define勒达BIT_2 / / IOPORT B空白hw_DelayMs (unsigned int mS) {unsigned int tWait tStart;tStart = ReadCoreTimer ();/*读取core timer - SW Start breakpoint */ twwait = (CORE_MS_TICK_RATE * mS);/*设置等待时间*/ while((ReadCoreTimer() - tStart) <= twwait);/*等待时间通过*/ LATBINV = LEDA;/*在延迟周期结束时切换LED */} /* SW停止断点*/
在清单4中,开始时间使用ReadCoreTimer()函数直接从核心计时器中获取。传递给hw_DelayMs的变量" mS "是等待的总毫秒数。变量twwait被赋值为每毫秒的滴答数乘以等待的毫秒数ms,清单4的第11行包含一个while循环,它持续读取核心计时器并减去变量tStart中保存的初始核心计时器值。当这个差值等于或大于为twwait计算的值时,延迟完成。重复读取核心计时器的值被称为“轮询”核心计时器。
硬件辅助延迟方法的延迟周期分辨率由核心振荡器频率建立。延迟范围受到用于变量的无符号整数数据类型可以表示的最大值。一个80.兆赫系统频率,这导致232/ core_ticks_per_ms = 232/40000000,等于107,374毫秒,或1.79分钟
处理硬件辅助延迟的计时器滚动
我们将参考PMODStep™的仪器测试点,用于此项目。具体而言,我们将使用与LEDA和LEDB相关的测试点,如右侧顶部标签所示的部件布局上所识别。您要使用两种时间延迟方式编写单个程序。编译程序,以便一次仅使用两个时间延迟方法中的一个。对于使用清单3中的代码的程序,您必须确定项目1.h中定义的counts_per_ms常量的适当值。提示:尝试从5000开始。项目2.h程序看起来像清单5和Project2.c如清单6.如果切换引脚RB2和RB3以进行计时目的,则不会更改其他位。确定延迟延迟的相对精度,延迟的不同持续时间为1 ms至1000ms。(请参阅下面的项目测试。)
清单5。
/********************** 项目2 ********************************* * * 文件:Project2.h *作者:理查德*墙日期:5月22日,2013年* * / / *软件定时器定义* / # define COUNTS_PER_MS 5000 / *精确值是确定* / / *函数原型* /空白system_init(无效);/*硬件初始化*/ void sw_DelayMs (unsigned int mS);/*只允许软件延迟*/ void hw_DelayMs (unsigned int mS);/*硬件辅助SW延迟*/
清单6。
/******************************** 项目2 **************************** * * 文件:Project2.c *作者姓名:理查德*墙启日期:5月22日,2013年* *项目描述:这个项目的目的是调查*的特点和局限性两种类型的轮询延迟。* **********************************************************************/ # 包括< plib.h > # include“Project2.h”#包括“config_bits.h”#包括“chipKIT_PRO_MX7.h”int主要(){int女士= 1;/* Set total delay time - change as needed */ init ();/*安装系统硬件。*/ while(1) {LATBINV = LEDB;/*切换LEDB的每个延迟周期*/ /*运行时只有以下两条语句中的一条未注释*/ sw_DelayMs (mS);/*软件延迟*/ // hw_DelayMs (mS);/*硬件辅助SW延迟*/}返回0;/* system_init函数描述*********************************** * SYNTAX: void system_init (void); /* system_init函数描述*********************************** * SYNTAX: void system_init (void);描述:设置B端口的配置来控制LEDA * - LEDH。 * RETURN VALUE: none * END DESCRIPTION *****************************************************/ void system_init(void) { /* Setup processor board */ chipKIT_PRO_MX7_Setup(); PORTSetPinsDigitalOut(IOPORT_B, SM_LEDS);/* Set PmodSTEP LEDs outputs */ LATBCLR = SM_LEDS; /* Turn off LEDA through LEDH */ } /* sw_DelayMs Function Description ************************************ * SYNTAX: void sw_DelayMs(unsigned int mS); * DESCRIPTION: This is a millisecond delay function that will repeat * a specified number of times. The constant "COUNTS_PER_MS" * must be calibrated for the system frequency. * KEYWORDS: delay, ms, milliseconds, software delay * PARAMETER1: mS - the total number of milliseconds to delay * RETURN VALUE: None: * Notes: The basic loop counter "COUNTS_PER_MS" is dependent on * the CPU frequency. LEDA will toggle at 500 Hz. *END DESCRIPTION ******************************************************/ void sw_DelayMs(unsigned int mS) { /* Use code from Listing 3 */ } /* hw_DelayMs Function Description ************************************** * SYNTAX: void hw_DelayMs (unsigned int mS); * DESCRIPTION: This is a millisecond delay function uses the core time * to set the base millisecond delay period. Delay periods * of zero are permitted. LEDA is toggled each millisecond. * KEYWORDS: delay, ms, milliseconds, software delay, core timer * PARAMETER1: mS - the total number of milliseconds to delay * RETURN VALUE: None: * END DESCRIPTION ******************************************************/ void hw_DelayMs(unsigned int mS) { /* Use code from Listing 4 */ } // End of Project2.c
项目测试
使用LATBINV = LEDA;and LATBINV = LEDB;切换两个led的说明。您需要两个指令来实现两个不同的延迟程序。将示波器或逻辑分析仪连接到LEDB (RB3)的测试点将允许您测量从主要功能调用的总延迟。将示波器/逻辑分析仪探头连接到LEDA (RB2)的测试点将测量环路延迟的毫秒数,但仅用于sw_msDelay函数。(记住把示波器或逻辑分析仪接地到pmodstep.地面销。请查看右上方的第一个选项卡,以了解引脚位置。)
图1是用于确定20毫秒延迟时间的仪表示例。LEDA跟踪每1毫秒切换一次,导致频率为500赫兹.LEDB跟踪每20毫秒切换一次,导致频率为25赫兹.
图1.屏幕截图20 ms延迟。Digilent WaveForms在微软Windows 7上运行的截图。
使用连接到LEDB测试点的仪器提供的信号,然后使用MPLAB X秒表工具完成表1的数据条目。在使用MPLAB X秒表工具时,将用于延迟函数的第一行可执行代码的Stopwatch Start放置在延迟函数中,并将用于延迟函数的Stopwatch Stop设置为关闭大括号,如清单3和清单4的注释中所示。
设计总延迟 - MS | 软件延迟 - 测量 - MS | 硬件延迟 - 测量 - MS | ||
---|---|---|---|---|
LEDB | 秒表 | LEDB | 秒表 | |
1 | 1 | 0.99775 | 1 | 1.00066 |
10 | 10 | 9.97491. | 10 | 10.00359 |
100. | 100. | 99.74654 | 100. | 100.03284 |
1000 | 1000 | 无效的 | 1000 | 无效的 |
(解值是红色的,在分发给学生之前应该删除。)
你自己试试吧!
现在你已经完成了这个项目,你应该看看下面的问题和问题:
- 根据表1中记录的结果报告您的观察和结论。
答:MPLAB X秒表工具似乎比使用逻辑分析仪提供更好的分辨率。高分辨率的长延迟测量,至少与秒表提供的度数相比,是很难用示波器或逻辑分析仪获得的。秒表对可以测量的延迟时间有一个上限,在这种情况下需要逻辑或示波器。
- 何时以及为什么您将使用为此分配编写的软件延迟功能,以及为什么您将使用核心计时器实现软件延迟功能?
- 当创建周期性延迟时,是什么决定了延迟周期的稳定性和准确性?
- 使用sw_DelayMs函数,在MPLAB X中秒表工具报告的1毫秒延迟是什么?
- 是什么决定了本项目中提出的两种基于轮询的时延实现方法的解决方案?
- 为什么使用hw_msDelay函数时LEDA和LEDB切换速率相同?
- 如何扩展清单4中所示的hw_msDelay函数的有限范围?
答:读取核心定时器有更高的精度,因为32位核心定时器有更高的分辨率,并直接与振荡器有关,通常是一个晶体或谐振器。软件循环是一个简单的延迟,可以在任何处理器上实现。这两种延迟都取决于处理器运行的速度。软件延迟方法的优点之一是易于理解概念,易于编写代码来实现。然而,超出这个项目的范围,软件中断也可以被中断抢占。这将导致延迟时间的延长。缺点是处理器完全占用了一个数字的增量,除非被中断。底线是,它们很简单,只消耗处理器时间。
答:尝试通过测量定期事件(例如切换一位)来校准软件延迟循环时,必须考虑在延迟循环之外执行代码所需的时间。更长的延迟往往更准确,因为软件环路相对于在循环之外执行代码所需的时间所花费的时间更大,因此对总周期的影响较小。如果软件延迟循环中断,则项目5中的情况会因此将始终扩展纯软件延迟循环的延迟时间。然而,当使用硬件辅助的软件延迟时,延迟时段可以或可能不会延长。
答:在sw_msdelay函数中的第一行代码和sw_msdelay函数的最后一个支架的第二个断点上放置断点,秒表报告了79820的循环计数。基于80 MHz运行的处理器,这相当于0.000998多发性硬化症。
答:对于纯软件方法,分辨率是COUNTS_PER_MS确定的值中的一部分。对于硬件辅助延迟方法,它是指令周期频率(SYSTEM_FREQUENCY/2)的一部分。一个结论是,硬件辅助延迟范围的不足可以通过提高分辨率来弥补。
ANSWER: hw_msDelay函数不执行多个1毫秒的延迟。延迟总是完全延迟。
答:此方法将延迟范围扩展到4,294,967,295 ms或49.71天。