2-3 toggleLed
在 Arcom 的电路板上,有两个LED:一红一绿。每个LED 的状态都被一
个叫做端口2I/O 锁存寄存器(缩写是 P2LTCH)的一个位来控制。这个寄存器
和CPU 在同一个芯片里,它实际上包含了芯片外围的8 个I/O 引脚的锁存状态。
这8 个引脚合在一起叫做端口2。P2LTCH 寄存器里的每一位都和相应的I/O 引
脚的电压联系到一起。比如,第6 位控制送到绿色LED 的电压:
#define LED_GREEN 0X40 /* The green LED is controlled by bit 6.*/
通过修改这一位,就可以改变相应外部引脚的电压从而改变了绿色LED 的状态。
如图 2-1 所示,当P2LTCH 的第6 位是1 的时候LED 关,第6 位是0 则LED
打开。
P2LTCH 寄存器位于I/O 空间的一块特定内存里,偏移为OxFF5E。不幸的
是,80x86 处理器的I/O 空间里的寄存器只能使用汇编语言指令in 和out 来操作。
C 语言没有内嵌的类似操作。最接近的替换函数是定义在面向PC 平台的头文件
dos.h 里的inport()和outport()。理想情况下,我们可以包含这个头文件并从我们
的嵌人式程序里调用这两个库函数。不过,因为它们是DOS 编程库的一部分,
我们必须要考虑到最坏的情况:它们在我们的系统上不工作。最起码的是,我
们在第一个程序里不应该依赖它们。
下面列出了面向 Arcom 电路板并且不依赖库例程的toggleLed 例程的实现。
实际的算法是很简单的:读P2LTCH 寄存器的内容,切换要控制的LED 的相应
位,再把新的值写回寄存器。你会注意到尽管这个例程是用C 书写的,而实际
的控制部分是用汇编语言实现的。这种简便的方法叫内嵌汇编语言(inline
assembly)。它一方面使程序员避开了复杂的C 函数凋用和参数的传递和转换过
程,同时使她可以随意地使用汇编语言来工作(注2)。
#define P2LTCH 0xFE5E /*The offset the P2LTCH regiser.*/
—————————————————————————————————————————————
注 2:不幸的是,各种编译器的内嵌汇编语法是不一样的。我在示例中使用的是
Borland C++编译器的格式。Borland 的内嵌汇编格式非常好,它主持在汇编行
里引用用C 代码定义的变量和常数。
/******************************************************************/
* Function toggleLed()
* Description: Toggle the state of one or both LEDs.
* Notes: This function is specific to Arcom’s Target188EB board.
* Returns: None defined.
/******************************************************************/
void
toggleLed(unsigned char ledMask)
{
asm {
mov dx, P2LTCH /*Load the address of the register.*/
in al, dx /*Read the content of the register.*/
mov ah, ledMask /*Move the ledMask into a register.*/
xor a1, ah /*Toggle the requested bits.*/
out dx, al /*Write the new register contents.*/
}
} /*toggleLed()*/
个叫做端口2I/O 锁存寄存器(缩写是 P2LTCH)的一个位来控制。这个寄存器
和CPU 在同一个芯片里,它实际上包含了芯片外围的8 个I/O 引脚的锁存状态。
这8 个引脚合在一起叫做端口2。P2LTCH 寄存器里的每一位都和相应的I/O 引
脚的电压联系到一起。比如,第6 位控制送到绿色LED 的电压:
#define LED_GREEN 0X40 /* The green LED is controlled by bit 6.*/
通过修改这一位,就可以改变相应外部引脚的电压从而改变了绿色LED 的状态。
如图 2-1 所示,当P2LTCH 的第6 位是1 的时候LED 关,第6 位是0 则LED
打开。
P2LTCH 寄存器位于I/O 空间的一块特定内存里,偏移为OxFF5E。不幸的
是,80x86 处理器的I/O 空间里的寄存器只能使用汇编语言指令in 和out 来操作。
C 语言没有内嵌的类似操作。最接近的替换函数是定义在面向PC 平台的头文件
dos.h 里的inport()和outport()。理想情况下,我们可以包含这个头文件并从我们
的嵌人式程序里调用这两个库函数。不过,因为它们是DOS 编程库的一部分,
我们必须要考虑到最坏的情况:它们在我们的系统上不工作。最起码的是,我
们在第一个程序里不应该依赖它们。
下面列出了面向 Arcom 电路板并且不依赖库例程的toggleLed 例程的实现。
实际的算法是很简单的:读P2LTCH 寄存器的内容,切换要控制的LED 的相应
位,再把新的值写回寄存器。你会注意到尽管这个例程是用C 书写的,而实际
的控制部分是用汇编语言实现的。这种简便的方法叫内嵌汇编语言(inline
assembly)。它一方面使程序员避开了复杂的C 函数凋用和参数的传递和转换过
程,同时使她可以随意地使用汇编语言来工作(注2)。
#define P2LTCH 0xFE5E /*The offset the P2LTCH regiser.*/
—————————————————————————————————————————————
注 2:不幸的是,各种编译器的内嵌汇编语法是不一样的。我在示例中使用的是
Borland C++编译器的格式。Borland 的内嵌汇编格式非常好,它主持在汇编行
里引用用C 代码定义的变量和常数。
/******************************************************************/
* Function toggleLed()
* Description: Toggle the state of one or both LEDs.
* Notes: This function is specific to Arcom’s Target188EB board.
* Returns: None defined.
/******************************************************************/
void
toggleLed(unsigned char ledMask)
{
asm {
mov dx, P2LTCH /*Load the address of the register.*/
in al, dx /*Read the content of the register.*/
mov ah, ledMask /*Move the ledMask into a register.*/
xor a1, ah /*Toggle the requested bits.*/
out dx, al /*Write the new register contents.*/
}
} /*toggleLed()*/