当前位置导航:炫浪网>>网络学院>>编程开发>>C++教程>>C++基础入门教程

CB和汇编混合编程

 我在写定时提醒 时碰到一个问题:怎么发声?我开始是用 32 位 Windows 的 API 函数 MessageBeep( -1 ); 那声音又小又难听。原来在 16 位的 Windows API 中有的一套 PlaySound 的函数在 32 位 Windows 中又取消了, DOS 下的 Sound 函数更是早就不能用了。

幸好我对硬件还算了解,知道 PC Speaker 的声音是通过系统中的定时计数芯片 8253/8254 产生的,只要通过硬件端口访问芯片就可以产生想要的声音了。 问题在于 Windows 是工作在保护模式下,大多数硬件端口都要在特权级0(PL0, 这是搞硬件的人的说法,后来我才知道在搞 OS 和 Driver 的人中是叫 Ring 0 的, 这才比较正确,因为如果不是 Intel 的 CPU 可能就不叫 PL 了)中, 即操作系统核心态中,才可以访问(比如硬盘口,访问时是不会出错,但结果不正确), 这也就意味着要写成驱动程序的形式,天啊! VxD 和 WDM 我都不会,怎么办? 事实上没有这么困难,像 PC Speaker 这种无伤大体的端口, Windows 是不保护的, 即在用户态下也可以正常访问。

现在还有一个问题就是用什么语句访问端口? DOS 中 C 语言里的那几个端口操作函数在 Windows 中都取消了,只好用汇编。我开始是用 ASM 语句插入汇编代码,结果发现 BCB 在编译时碰到 ASM 时会把 BCB 文件编译成一个巨大的 ASM 文件, 再重新启动汇编程序汇编,速度太慢。最后采用了我在 DOS 编程时常用的方法, 做一个单独的 ASM 文件加入工程文件中。

下面是两个用于发声的函数,最前面声明了两个外部 C 调用形式的函数, 是两个用汇编写的字节端口输入/输出函数,注意:在 C++ 中一定要注意外部函数应为 C 调用形式。程序中多处强制类型转换是为了不出现警告,我对程序一向要求 Error/Warning/Hint 全为 0。


extern "C" {
Byte InPortB( int aPort );
void OutPortB( int aPort, Byte aValue );
}

void __fastcall Sound( int aFreq )
{
if ( ( aFreq >= 20 ) && ( aFreq <= 20000 ) )
{
aFreq = 1193181 / aFreq;
Byte b = InPortB( 0x61 );
if ( ( b & 3 ) == 0 )
{
OutPortB( 0x61, Byte( b 3 ) );
OutPortB( 0x43, 0xb6 );
}
OutPortB( 0x42, ( Byte )aFreq );
OutPortB( 0x42, ( Byte )( aFreq >> 8 ) );
}
}

void __fastcall NoSound( void )
{
Byte b = Byte( InPortB( 0x61 ) & 0xfc );
OutPortB( 0x61, b );
}


下面是两个端口 I/O 的函数的汇编源程序,即定时提醒(Alarm)中的 IOPortB.asm 文件的全部内容,是在 BCB 产生的 ASM 文件基础上作了一点点的优化。 注意:

共2页 首页 上一页 1 2 下一页 尾页 跳转到
相关内容
赞助商链接