四个编程问题,请稍加留意
No.1 一个由VB编译引起的错误
在VB编译环境下,常有这样种事情发生,第一次初始化控制卡时,往往正常通过,若中途中断或意外退出,则再次启动程序,则初始化时却找不到控制卡了,有时弄得人很郁闷,一点成熟感都没有,在没有别的招的情况下,搞得程序员一怒之下重启PC才得以好转。然事情却很让人不开心。
这个问题是由VB编译引起的,由于VB是一种解释语言,其程序运行时被加载的速度不够快,故会把程序调用的动态库等资源暂放置内存,直到VB整个软件结束才会释放。而在调试控制卡软件时,由于中途中断或调试意外退出,没有执行到控制卡关闭函数,则控制卡资源还未被释放,故程序再次运行初始化控制卡资源时,则找不到有效的资源了,因而也找不到控制卡了。
解决问题很简单,关闭整个VB编译器软件,以释放所有资源,再次进入即可。此过程稍为麻烦,但比上重启PC来讲,还是稍有效率一些。
No.2 取位运算
在使用控制卡编程时,常常碰到取位运算的案例,如下面函数:
d3000_get_axis_status
在其《软件手册》上有对其返回值的每一位进行了详细说明,即使这样,有些新手面对具体编程时,一时还转不过弯过来。如:要从返回值内判断原点信号的高低电平状态到底该怎样编程呢,以下列出在C/C++、Basic取位运算的代码片段,其它状态位类同:
(注:DMC3000控制卡的原点信号在d3000_get_axis_status的返回值第9位,从0位开始数)
1、 C/C++
DWORD nStatus = d3000_get_axis_status( XCH );//读取X轴的专用输入信号
//XCH的值为0
if( (nStatus&(1<<9)) != 0 )
//高电平或低电平
else
//低电平或高电平
(用移位方法在《控制卡编程几招》中有介绍)
2、 Basic
Dim nStatus as long
nStatus = d3000_get_axis_status ( XCH ) ‘读取X轴的专用输入信号
if (nStatus and &H200) <> 0 then
//高电平或低电平
else
//低电平或高电平
end if
注意:第9位为1时的十六进制数值为0x200
No.3 关于大数平方和平方根溢出的解决方法
平方和平方根的计算常常遇到,一般都会用浮点数来表示,当计算大数时,由于电脑内部定义的数据类型字节宽有限,总会有溢的可能,如:
double kx = 1000000.0; //一个double在VC++中为64位,在DOS环境下为32位
double ky = 1000000.0;
double len = sqrt( kx * kx + ky * ky );//求两者的平方和之根
想必上面的表达算式大家都见怪不怪了吧,但很容易溢出哦,要是多次系数,就更容易了,那么到底该如何解决这个问题呢?我们改一下表达算法,也可达到同样效果,可将溢出的机率大大降低,请看:
double kx = 1000000.0;
double ky = 1000000.0;
ky = (ky/kx); //注意变化,实际应用时,要避免kx=0.0
double len = kx * sqrt( 1 + ky * ky );
//想一想,若kx,ky的数值有效,那么len的值也不会溢出了
No.4 精确定时器的实现(仅用在VC++)
MFC提供的定时器OnTimer,虽然可以通过SetTimer设定响应时间间隔,但无论怎样都不能超过每少20次的调用频率,在一些需要精确计时的场合当然就不适合了。API提供一个性能较好的函数GetTickCount,这个函数理论上可以跑到毫秒级,但是它的时间积累误差很大,而且不可以得到更精确的计时。
在《Windows图形编程》一书当中有封装好的一个精确计时类,可以根据CPU的时钟周期来计时,够酷吧,然此书有很多人暂未购得,故由本人做一做义务,公布其主要的核心片段,也足够大家用了,具体大家再根据需要去完善吧。
typedef __int64 I64; //一个64位整数类型的定义
I64 GetQueryCount()
{//返回当前时钟周期,若不明白以下语法,就不明白,反正能用就行,在NT下也正常
_asm _emit 0x0F
_asm _emit 0x31
}
//取得1秒中的周期计数值
I64 start = GetQueryCount ();
Sleep(1000);
I64 stop = GetQueryCount ();
//转化成1微秒的计数值,可根据需要进行,我在一个软件当中使用1微秒就够了
//单位关系:1秒=1000毫秒=1000000微秒
long double fUnit = (long double)(stop-start)*0.000001;//取得1微秒的时种周期值
若你想要达到100微秒中断一次,则可以写出下面程序:
I64 nTimers = I64( fUnit * 100 );//将100再转化周期值
I64 nStart = GetQueryCount();
I64 nEnd = nStart;
While( 你的有效循环条件 )
{
nEnd = GetQueryCount();
if( labs(nEnd – nStart) >= nTimers )
{
…做你想做的事情,记得你要作的事情不要太复杂,以致于运行的周期超过自己定义的中断间隔周期。
nEnd = nStart;
}
else
::DoEvents();//此函数在我的相关文章有详解,故不赘述
}
|