STM32keilMDK仿真检验

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

信号函数
当µVision3模拟执行目标程序时,信号函数可以在后台实现信号输入、脉冲输入等重复操作。

信号函数可用于模拟和测试串行I/O、模拟I/O、端口通讯和其他一些重复发生的外部事件。

因为当µVision3模拟目标程序时,信号函数是在后台执行。

因此,信号函数必须在某些地方调用twatch函数来进行延迟,以便让µVision3能运行目标程序。

若信号函数从不调用twatch,则µVision3会报告错误。

µVision3提供了一部分能在信号函数中使用的系统变量。

详情请参考
系统变量。

系统变量
系统变量可在程序中任何位置的变量和其他表达式中使用,用于获取一些特殊功能值。

下表列出了允许使用的系统变量,以及数据类型和使用方法。

变量类型描述
$ unsigned long 表示当前程序计数器值。

可以使用$表达和修改程序计数器。

例如,$ = 0x4000可将当前程序计数器值设置为0x4000。

_break_ unsigned int 令目标程序中止运行。

如果将_break_ 设置为一个非零值,µVision 将挂起目标程序的执行。

在用户和信号函数中使用该变量可挂起目标程序的执行。

_traps_ unsigned int 若将_traps_ 设置为一个非零值,µVision将现实166个硬件陷阱:未定义的操作码,被保护指令错,非法字操作访问,非法指令访问,堆栈上溢,堆栈下溢等。

states unsigned long CPU指令状态计数器的当前值;当目标程序开始执行时,该计数器从0开始每执行一条就加1。

注意
states 是一个只读变量。

itrace unsigned int 表示目标程序执行时是否记录跟踪过程。

若itrace 为0,则不记录跟踪过程;若itrace 是一个非0值,则记录跟踪过程。

更多相关信息可参考Trace Recording 。

radix unsigned int 设置显示数据的进制,radix 可为10 或16,默认值为16 用于HEX 输出.
信号函数的定义由关键字SIGNAL开始,格式如下:
SIGNAL void fname (parameter_list) {
statements
}
fname i函数名
parameter_list i传递给函数的参数表,每个参数必须包括一个类型声明和一个名字。

如果没有参数,则用void代替参数表。

多个参数之间用逗号间隔。

statements 函数体
{ 函数起始标识。

只有函数起始标识和函数结束标识(“}”)保持平衡,函数才是完整的。

例如
下面的例子表示一个信号函数每隔1,000,000个CPU周期将字符'A'传送至串行输入缓冲区一次。

SIGNAL void StuffS0in (void) {
while (1) {
S1IN = 'A';
twatch (1000000);
}
}
调用这个函数时,在控制窗口输入如下命令:
StuffS0in()
调用时StuffS0in信号函数会将字符'A'的ASCII值传送至串行输入缓冲区并延迟1,000,000 个CPU周期,不断重复。

信号函数受到如下约束:
函数的返回值类型必须为void。

函数最多只能有8个参数。

信号函数可以调用其他重定义函数和用户函数。

信号函数之间不能相互调用。

信号函数可以被用户函数调用。

信号函数必须调用twatch至少一次。

如果信号函数从不调用twatch,则目标程序将得不到时间执行。

而且由于不能使用Ctrl+C中断信号函数,在这种情况下µVision3将进入死循环。

信号函数的管理
一个信号函数要么处于空闲态,要么处于运行态。

µVision3通过队列来保存被激活的信号函数。

处于空闲态的信号函数将被延迟,直到延迟完指定的CPU周期等待之后调用twatch 来唤醒她。

运行态的信号函数则执行函数内的语句。

当一个信号函数被调用时,µVision3将此函数加入队列中并将其状态标明为运行。

一个信号函数只能被激活一次,如果要被激活的函数已经在队列中,则会发出警告。

通过SIGNAL STATE命令可以查看信号函数的状态,SIGNAL KILL命令可以将信号函数从队列中消除掉。

当信号函数调用twatch函数时,经过数个CPU周期处理完twatch函数之后信号函数将进入空闲态,直到用户程序执行指定数目个CPU周期后信号函数才从twatch函数之后的语句开始继续执行。

当信号函数退出时,返回语句自动将该函数从队列中清除。

下面的例子表示一个信号函数在C167上改变模拟输入的值。

函数从0伏特开始以0.5伏为
单位增加或减少输入电压,并且增加上限被设置。

该信号函数不定期的重复,每次电压改变将延迟200,000个CPU周期。

signal void analog0 (float limit) {
float volts;
printf ("Analog0 (%f) entered.\n", limit);
while (1) { /* forever */
volts = 0;
while (volts <= limit) {
ain0 = volts; /* analog input-0 */
twatch (200000); /* 200000 states Time-Break */
volts += 0.1; /* increase voltage */
}
volts = limit;
while (volts >= 0.0) {
ain0 = volts;
twatch (200000); /* 200000 states Time-Break */
volts -= 0.1; /* decrease voltage */
}
}
}
信号函数analog0能以如下方式被调用:
>ANALOG0 (5.0) /* Start of 'ANALOG()' */
ANALOG0 (5.000000) ENTERED
SIGNAL STATE命令显示analog0函数的当前状态:
>SIGNAL STATE
1 idle Signal = ANALOG0 (line 8)
该命令列举出内部函数的编号,信号函数的状态:空闲态还是运行态,函数名和执行语句行号。

因为信号函数的处于空闲态,可以推测出analog0正在执行twatch函数(在analog0的第8行)并等待指定的CPU周期时间。

200,000个CPU周期之后,analog0继续执行直到在程序的第8行或14行twatch 函数再一次被调用。

以下命令将analog0函数从激活信号函数队列中清除。

>SIGNAL KILL ANALOG0
建立函数
µVision3 中有一个内建的函数编辑器,通过Debug –Function Editor来打开。

打开函数编辑器时需要输入一个文件名或者打开一个由Options for Target –Debug –
Initialization File指定的文件。

该编辑器的用法与µVision3编辑器相同,允许用户输入和编译调试函数。

参考函数编辑对话框帮助可获取更多对话项目信息。

当建立一个调试函数文件后,可用INCLUDE 命令可以读取和处理该文本文件的内容。

例如,如果在命令窗口输入下列命令,µVision3将完成对MYFUNCS.INI文件内容的读取和解释功能。

>INCLUDE MYFUNCS.INI
MYFUNCS.INI 可能包含调试命令和函数定义,通过Options for T arget –Debug - Initialization File可以进入该文件。

每次打开µVision3调试器时,MYFUNCS.INI文件的内容将被执行。

INCLUDE 命令用于指定一个命令文件,命令被从此文件中一行一行地被读取并被传递给µVision3 来执行。

在µVision3中可以利用INCLUDE 文件执行重复操作。

例如,定义INCLUDE 文件用于载入目标程序,运行程序到主C函数,初始化工具箱按钮及生成几个用户函数。

INCLUDE 文件可以嵌套4层,要使用INCLUDE 命令时,必须先停止目标程序的执行。

例子
INCLUDE measure.ini
不需要的函数可以通过KILL 来删除。

Debug - Function Editor
关于创建函数文件的详细信息请参考创建函数。

Open
打开浏览对话框,选择一个要编辑的文件。

New...
创建一个新的文件以加入函数。

Save
保存文件的编辑内容。

Save As...
在不同的文件中保存当前的编辑内容。

Compile
编译当前文件,相应的结果在Output Window的Build页中显示。

Compile Errors
显示编译错误。

选择一个错误可以在编辑窗口定位相应的出错行
KILL 命令可用于删除已定义的工具箱按钮和µVision3函数。

KILL BUTTON 命令用于移除前面已定义的一个工具箱按钮。

当使用这个命令时,必须要指定要移除工具箱按钮的编号。

这个编号在工具箱窗口中每个按钮的前面。

KILL FUNC * 命令用于移除前面已定义的所有用户函数和信号函数。

µVision3 内部定义函数不能被删除。

KILL FUNC function_name 命令用于删除指定的用户函数或信号函数。

例子
>KILL FUNC ANALOG /* Delete user function analog */
>KILL FUNC myregs /* Delete user function myregs */
>KILL FUNC * /* Delete all user functions */
>KILL BUTTON 3 /* Kill Toolbox Button number 3 */
>KILL BUTTON 1 /* Kill Toolbox Button number 1 */
外围设备变量
根据工程所选择的CPU,µVision3会自动地定义一些符号。

这些符号分为两类:外围寄存器(或SFRs)和虚拟仿真寄存器(VTREGs)。

在Simulation Script Templates下,调试函数Debug Functions可利用这些外围设备变量自动向外设输入信号。

外围寄存器(SFRs)
µVision3为外围寄存器定义了符号。

外围寄存器符号的定义依赖于选择的微控制器。

外围寄存器符号都具有相关的地址,可被用于表达式中。

虚拟仿真寄存器(VTREGs)
虚拟仿真寄存器的存在,使得模拟CPU的引脚进行输入和输出成为可能。

VTREGs不是公有符号,也不能常驻CPU的内存。

它们可以用于表达式中,但其值及用法是依赖于CPU的。

VTREGs提供了一种输入来自被仿真硬件上的信号到CPU引脚的方法。

可以使用DIR VTREG 命令列出这些符号。

下表描述了VTREG符号。

VTREG符号的可用性依赖于所选的CPU。

VTRE
G
描述
ADx 片上的一个模拟输入引脚,它的典型代表是A/D转换器输入。

目标程序可以读取写入到ADx VTREGs中的值。

DAx 片上的一个模拟输出引脚。

这个值反应了D/A转换器的输出。

xxVRE
F
相关引脚的电压输入。

PORT x 片上端口的一组I/O引脚。

例如,PORTA 代表了PORTA的所有引脚,这些寄存器可以仿真端口I/0.
SxIN 串行接口x的输入缓冲。

可以向SxIN写入一个8位或9位的值,它们可以被目标程序读取。

读取SxIN以取决于什么时候输入缓冲准备好以接收另外的字符。

值0xFFFF意味着前面的值已被处理完,新的值可以写入了。

SxOU T 串行接口x的输出缓冲。

µVision3 拷贝8位或9位的值到SxOUT VTREG中。

SxTIM E 定义串行端口x的波特率时序。

当SxTIME为1时, µVision3 使用编程的波特率来仿真串口的时序。

当SxTIME为0时(默认值),编程的波特率时序被忽略,串行传输时间是即时的。

CLOC
仿真的CPU的真实频率。

K
XTAL 仿真的CPU的晶振频率,在Options –Target dialog下定义。

可以使用VTREGs来仿真外部输入和输出,包括与内部外设的接口,如中断和时钟。

例如,若选中PORT3(在8051设备上)的位2,则CPU驱动仿真外部中断0。

I/O 口
µVision3为每个I/O口定义了一个VTREG: 例如PORTA。

不要把每个端口(如PIOA_OSR)的外围寄存器与这些VTREGs混淆了。

外围寄存器可以在CPU存储空间内被访问,VTREGs 则代表了引脚上的信号。

使用µVision3可以很容易模拟来自外部硬件上的输入,若外部有一串脉冲到达端口引脚,则可以使用信号函数来模拟这些信号。

如下面的信号函数以1000Hz的频率在端口PORTA 的引脚0处输入一个方波。

signal void one_thou_hz (void) {
while (1) { /* repeat forever */
PORTA |= 1; /* set PORTA bit 0 */
swatch (0.0005); /* delay for .0005 secs */
PORTA &= ~1; /* clear PORTA bit 0 */
swatch (0.0005); /* delay for .0005 secs */
} /* repeat */
下面的命令启动了这个函数:
one_thou_hz ()
有关用户及信号函数的更多信息请参阅µVision3 调试函数(Debug Functions)。

仿真一个与输出端口引脚对应的外部硬件稍少一些困难。

需要两步,第一步,写一个µVision3的用户或信号函数来执行希望的操作;第二步,创建一个断点以调用该用户函数。

假如使用了输出引脚(PORTA的位0)来点亮或熄灭LED,下面的信号函数使用PORT2 VTREG来检查CPU的输出,并在命令窗口显示信息。

signal void check_pA0 (void) {
if (PORTA & 1)) { /* Test PORTA bit 0 */
printf ("LED is ON\n"); } /* 1? LED is ON */
else { /* 0? LED is OFF */
printf ("LED is OFF\n"):
}
}
现在,必须为端口1的写操作添加一个断点。

下面的命令行将为所有向PORT2的写操作添加一个断点。

BS WRITE PORT2, 1, "check_p20 ()"
现在,不论目标程序何时向端口PORT2写入,check_P20 函数都会打印出LED的当前状态。

串行端口
片上的串行端口由S0TIME、S0IN和S0OUT控制。

S0IN和S0OUT 代表了CPU上的串行输入和串行输出流。

S0TIME用于指定串行端口的时序是即时的(STIME = 0)还是与指定的波特率有关(SxTIME = 1)。

当S0TIME为1时,串行窗口中显示的串行数据以指定的波特率被输出。

当S0TIME为0时,,串行窗口中显示的串行数据将被很快地输出。

模拟串行输入就像模拟数字输入一样容易。

假如有一个外部串行设备周期性(间隔1s)地输入指定的数据,可以建一个信号函数来向CPU的串口中输入数据。

signal void serial_input (void) {
while (1) { /* repeat forever */
twatch (CLOCK); /* Delay for 1 second */
S0IN = 'A'; /* Send first character */
twatch (CLOCK / 900); /* Delay for 1 character time */
/* 900 is good for 9600 baud */ S0IN = 'B'; /* Send next character */
twatch (CLOCK / 900);
S0IN = 'C'; /* Send final character */
} /* repeat */
}
当信号函数运行时,它延时1s,输入‘A’,‘B’和‘C’到串行输入行且重复下去。

串行输出被仿真的方式与使用用户或信号函数及一个如上所述的写访问断点很相似。

相关文档
最新文档