“鸽子周咕咕”通过精心收集,向本站投稿了9篇WinCE Eboot中的OEM控制函数,下面就是小编给大家带来的WinCE Eboot中的OEM控制函数,希望大家喜欢,可以帮助到有需要的朋友!

篇1:WinCE Eboot中的OEM控制函数
在EBOOT中有很多以OEM开头的函数,这些函数都会直接或间接的被BLCOMMON模块调用,来完成相应的功能,这些OEM函数就是我们需要根据自己的平台来实现的。可以说,实现了这些OEM函数,EBOOT的功能就完成了。
在EBOOT中有很多OEM函数,有些是必须实现的,有些是不必实现的,而有些是根据你的EBOOT的功能需求来决定是否要实现的。下面会介绍一下直接由BLCOMMON调用的OEM控制函数:
1. void OEMDebugInit(void)
这应该是第一个被调用的OEM函数,用来初始化串口来打印调试信息。这里要提一下另一个函数叫OEMInitDebugSerial,是OAL中用于初始化串口的函数。所以一般会实现OEMInitDebugSerial函数,然后在OEMDebugInit中调用它就可以了。实际上这只是一个初始化函数,如果想实现串口调试,还需要实现另外几个函数,如下;
OEMWriteDebugString
OEMWriteDebugByte
OEMReadDebugByte
上述三个函数在我以前的博客“WinCE BSP中打印信息的实现介绍”中有介绍,这里不再重复了。
2. BOOL OEMPlatformInit(void)
这个函数用于初始化硬件平台,就是说出实话硬件板子的相关外设。一般会先初始化RTC,然后初始化Nandflash控制器,初始化硬件中断,初始化网卡,如果需要,还可以在这个时候初始化Display,然后显示一个Logo。下面是微软提供的该函数的模板:
1.BOOL OEMPlatformInit(void)
2.{
3. BOOL fRet = FALSE;
4. BOOT_ARGS *pBootArgs;
5. ETH_HARDWARE_SETTINGS *pEdbgSettings;
6. EDBG_ADDR *pMyAddr;
7.
8.
9. //打印版本号和时间日期信息
10. EdbgOutputDebugString(“Microsoft Windows Embedded CE Ethernet Bootloader %d.%d for Platform. Example (%s %s)\n\n”, EBOOT_VERSION_MAJOR,EBOOT_VERSION_MINOR, __DATE__, __TIME__);
11.
12.
13. //初始化Driver Globals区域中的Boot引导参数信息
14. pBootArgs = (BOOT_ARGS*)BOOT_ARGS_PHYSICAL_MEMORY_START;
15. memset(pBootArgs, 0, sizeof(BOOT_ARGS));
16.
17. pBootArgs->dwSig= BOOTARG_SIG;
18. pBootArgs->dwLen= sizeof(BOOT_ARGS);
19. pBootArgs->dwEdbgDebugZone = EdbgDebugZone;
20.
21. //添加按键输入判断,允许用户进入Shell
22. if (WaitForKeyPress)
23. {
24. //允许用户设置网络相关的信息,比如IP地址等
25. LoaderMainMenu();
26. }
27.
28. //初始化以太网控制器
29. pEdbgSettings = &pBootArgs->Edbg;
30. fRet = InitEthernet(pEdbgSettings);
31.
32. if (!fRet)
33. {
34. EdbgOutputDebugString(“ERROR: Ethernet initialization failed\r\n”);
35. SpinForever();
36. }
37.
38. pMyAddr = &pEdbgSettings->Adapter.Addr;
39. EdbgOutputDebugString(“INFO: Debug Ethernet MAC Address: %B:%B:%B:%B:%B:%B\r\n”, pMyAddr->wMAC[0] & 0x00FF, pMyAddr->wMAC[0] >>8,
40. pMyAddr->wMAC[1] & 0x00FF, pMyAddr->wMAC[1] >>8,
41. pMyAddr->wMAC[2] & 0x00FF, pMyAddr->wMAC[2] >>8);
42.
43. return(TRUE);
44.}
45.
46.
47.
3. DWORD OEMPreDownload(void)
该函数一般用于初始化网络,初始化用于下载WinCE image的TFTP。首先调用OALKitlCreateName函数根据MAC地址创建设备名称。然后判断是否是DHCP,并分配IP地址。调用EbootInitEtherTransport函数初始化TFTP,该函数属于eboot模块代码,在”\WINCE600\PUBLIC\COMMON\OAK\DRIVERS\ETHDBG\EBOOT”下面可以找到,该函数返回pfJumpImg,返回值作为OEMPreDownload的返回值,决定是下载WinCE image还是直接跳转执行。
4. void OEMLaunch(DWORD dwImageStart, DWORD dwImageLength, DWORD dwLaunchAddr, const ROMHDR* pRomHdr)
该函数用于运行WinCE,首先会根据需要将EBOOT的引导参数进行更新,并写入存储设备,然后会判断变量g_DownloadImage的值,有时候可能是g_bWaitForConnect的值,但是意思都是一样的。如果该值为0,则表示不是下载的WinCE image,是从Flash中load出来的,就会直接调用Launch函数运行WinCE,Launch函数一般是汇编写的,就是直接把PC指针指到WinCE image加载的地址开始运行;如果值为1,则调用EbootWaitForHostConnect函数等待Platform. Builder发送信息,把该函数的返回值更新到Driver Globals内存中,这样WinCE启动后,OAL模块的代码可以访问到,然后调用Launch函数运行WinCE image,
微软提供了该函数的模板:
1.void OEMLaunch(DWORD dwImageStart, DWORD dwImageLength, DWORD dwLaunchAddr, const ROMHDR *pRomHdr)
2.{
3. DWORD dwPhysLaunchAddr;
4. EDBG_OS_CONFIG_DATA *pCfgData;
5. EDBG_ADDR EshellHostAddr;
6. EBOOT_CFG EbootCfg;
7.
8. memset(&EshellHostAddr, 0, sizeof(EDBG_ADDR));
9. memset(&EbootCfg, 0, sizeof(EBOOT_CFG));
10.
11.
12. //从Flash中读取Eboot的参数信息
13. ReadEbootConfig(&EbootCfg);
14.
15. if (g_bWaitForConnect)
16. {//等待Platform. Builder发送信息
17. if (!(pCfgData = EbootWaitForHostConnect(&pDriverGlobals->eth.TargetAddr, &EshellHostAddr)))
18. {
19.EdbgOutputDebugString(“ERROR: OEMLaunch: EbootWaitForHostConenct failed.\r\n”);
20.SpinForever();
21. }
22.
23. if (pCfgData->Flags & EDBG_FL_DBGMSG)
24. {//支持基于Ethernet的Debug信息,更新Driver Globals中的IP和端口号 25.memcpy(&pDriverGlobals->eth.DbgHostAddr.wMAC,& EshellHostAddr.wMAC, 6);
26.pDriverGlobals->eth.DbgHostAddr.dwIP = pCfgData->DbgMsgIPAddr;
27.pDriverGlobals->eth.DbgHostAddr.wPort = pCfgData->DbgMsgPort;
28. }
29. if (pCfgData->Flags & EDBG_FL_PPSH)
30. {//支持基于Ethernet的Target Control,更新Driver Globals中的IP和端口号 31.memcpy(&pDriverGlobals->eth.PpshHostAddr.wMAC, &EshellHostAddr.wMAC, 6);
32.pDriverGlobals->eth.PpshHostAddr.dwIP = pCfgData->PpshIPAddr;
33.pDriverGlobals->eth.PpshHostAddr.wPort = pCfgData->PpshPort;
34. }
35. if (pCfgData->Flags & EDBG_FL_KDBG)
36. {//支持基于Ethernet的kernel debugger,更新Driver Globals中的IP和端口号 37.memcpy(&pDriverGlobals->eth.KdbgHostAddr.wMAC, &EshellHostAddr.wMAC, 6);
38.pDriverGlobals->eth.KdbgHostAddr.dwIP = pCfgData->KdbgIPAddr;
39.pDriverGlobals->eth.KdbgHostAddr.wPort = pCfgData->KdbgPort;
40. }
41.
42. memcpy(&pDriverGlobals->eth.DownloadHostAddr, &EshellHostAddr, sizeof(EDBG_ADDR));
43. pDriverGlobals->eth.etherFlags = pCfgData->Flags;
44. pDriverGlobals->eth.KitlTransport = pCfgData->KitlTransport;
45. }
46.
47. //保存WinCE kernel的launch地址
48. if (dwLaunchAddr && (EbootCfg.NKRegion.LaunchAddress != dwLaunchAddr))
49. {
50. EbootCfg.NKRegion.LaunchAddress = dwLaunchAddr;
51. WriteEbootConfig(&EbootCfg);
52. }
53. else
54. {
55. dwLaunchAddr= EbootCfg.NKRegion.LaunchAddress;
56. }
57.
58. // 跳转到WinCE Image的地址开始执行
59. Launch(dwPhysLaunchAddr);
60.
61. //死循环
62. SpinForever();
63.}
64.
篇2:WinCE Eboot中的OEM Flash函数
在EBOOT中提供了操作Flash的功能,可以将下载的WinCE image烧到Flash当中,这需要实现一些Flash相关的OEM函数,
这些OEM函数会在BLCOMMON模块中被调用,也就是在blcommon.c文件的DownloadImage函数中被调用。在DownloadImage函数中,一般image文件的header会被先下载并进行解析。然后调用OEMIsFlashAddr判断image所在的区域,如果是在Flash的地址空间内,那么接下来会下载image文件并调用Flash相关的OEM函数将Flash擦除并写入。下面简单介绍一下这些函数:
1.BOOL OEMIsFlashAddr(DWORD dwAddr)
该函数用于判断下载的WinCE image文件是在Flash区域中还是在RAM区域中,dwAddr是image文件的地址,如果在Flash区域中返回TRUE,否则返回FALSE,给个微软的例子:
1.#define FLASH_START02.#define FLASH_LENGTH 0x00003.BOOL OEMIsFlashAddr(DWORD dwAddr)4.{5. //根据Flash的起始地址和长度判断该地址是否在Flash区域内6. if ((dwAddr >= FLASH_START) && (dwAddr < (FLASH_START + FLASH_LENGTH)))7. {8. return(TRUE);9. }10.11. return(FALSE);12.}13.
2.BOOL OEMStartEraseFlash(DWORD dwStartAddr, DWORD dwLength)
该函数用于初始化Flash的擦除,dwStartAddr表示要擦除的起始地址,dwLength为长度。通过这两个参数计算Flash中要被擦除的起始block和最后一个block,以及要擦除多少个block,给个微软的例子:
1.BOOL OEMStartEraseFlash (DWORD dwStartAddr, DWORD dwLength)2.{3. ULONG i = 0;4. ULONG nNumBlocks = 0;5.6. //判断起始地址和终止地址是否都在Flash区域内7. if (!OEMIsFlashAddr(dwStartAddr) || !OEMIsFlashAddr(dwStartAddr + dwLength - 1))8. {9. return(FALSE);10. }11.12. //确认该起始地址是Block对齐的13. if (dwStartAddr % FLASH_BLOCK_SIZE)14. {15. return(FALSE);16. }17. //确认长度是4字节对齐18. if (dwLength & 0x03)19. {20. return(FALSE);21. }22.23. //根据Flash的基地址和Flash的Block大小计算要擦除的起始block和最后一个24. //block以及多少个Block25. gnStartBlock = (dwStartAddr - FLASH_BASE) / FLASH_BLOCK_SIZE;26. gnEndBlock = ((dwStartAddr + dwLength + (FLASH_BLOCK_SIZE - 1) - FLASH_BASE) / FLASH_BLOCK_SIZE);27. gnBlocks = (int)(gnEndBlock - gnStartBlock);28. gnBlockCount = gnStartBlock;29.30. EdbgOutputDebugString(“Erasing flash blocks: start block = %d end block = %d\r\n”, gnStartBlock, gnEndBlock);31.32.33. return(TRUE);34.}
3.void OEMContinueEraseFlash (void)
该函数用于擦除Flash区域,它会在image下载后被调用来擦除Flash中的block,给个微软的例子:
1.void OEMContinueEraseFlash(void)2.{3. UCHAR nEraseCount = BLOCK_ERASE_STEP; //要擦除的块4.5.6. //确认所有需要擦除的block都被擦除了7. if (!gnBlocks || (gnBlockCount == gnEndBlock))8. return;9.10. //擦除block11. while ((gnBlockCount < gnEndBlock) && nEraseCount)12. {13. if (CFI_Erase_Block((unsigned32*)BLOCK_ADDR(gnBlockCount), 0, NULL) != PASS)14. {15.EdbgOutputDebugString(“ERROR: OEMContinueEraseFlash - flash erase error (block number %d).\r\n”, gnBlockCount);16.return;17. }18.19. ++gnBlockCount;20. --nEraseCount;21. }22.23.24. return;25.}26.27.
4.BOOL OEMFinishEraseFlash (void)
该函数用于确认Flash中所有的block都被擦除完成,给个微软的例子:
1.BOOL OEMFinishEraseFlash(void)2.{3. EdbgOutputDebugString(“INFO: Finishing flash erase...\r\n”);4.5. while(gnBlocks && (gnBlockCount != gnEndBlock))6. {7. OEMContinueEraseFlash();8. }9.10. return(TRUE);11.}12.
5.BOOL OEMWriteFlash(DWORD dwImageStart, DWORD dwImageLength)
该函数用于将下载的image写入到Flash当中,dwImageStart为被写入image在Flash中的起始地址,dwImageLength为image的大小,给个微软的例子:
1.BOOL OEMWriteFlash(DWORD dwImageStart, DWORD dwImageLength)2.{3. DWORD dwFlashAddr, dwExtraBytes = 0;4. LPBYTE pbCache = NULL;5. UCHAR nNumBlocks = 0;6.7.8. //确认起始地址和长度都在Flash区域内9. if (!OEMIsFlashAddr(dwImageStart) || !OEMIsFlashAddr(dwImageStart + dwImageLength - 1))10. {11. return(FALSE);12. }13.14. //确认起始地址是Block字节对齐的15. if (dwImageStart % FLASH_BLOCK_SIZE)16. {17. return(FALSE);18. }19.20. //计算要写入的block数量21. nNumBlocks = (UCHAR)(dwImageLength / FLASH_BLOCK_SIZE);22. dwExtraBytes = (dwImageLength % FLASH_BLOCK_SIZE);23. dwFlashAddr = dwImageStart;24. pbCache= OEMMapMemAddr (dwImageStart, dwFlashAddr);25.26.27. //写Flash28. while(nNumBlocks)29. { 30. if (CFI_Write_Block((unsigned32*)dwFlashAddr, (unsigned32*)pbCache, FLASH_BLOCK_SIZE, NULL) != PASS)31. {32.EdbgOutputDebugString(“ERROR: OEMWriteFlash - unable to write to block (block address=0x%x).\r\n”, dwFlashAddr);33.return(FALSE);34. }35.36. dwFlashAddr += FLASH_BLOCK_SIZE;37. pbCache = OEMMapMemAddr (dwImageStart, dwFlashAddr);38. --nNumBlocks;39. }40.41. //将额外的数据写入Flash中42. if (dwExtraBytes)43. {44. if (CFI_Write_Block((unsigned32*)dwFlashAddr, (unsigned32*)pbCache, dwExtraBytes, NULL) != PASS)45. {46.EdbgOutputDebugString(“ERROR: OEMWriteFlash - unable to write to block (block address=0x%x).\r\n”, dwFlashAddr);47.return(FALSE);48. }49. }50.51. return(TRUE);52.}53.54.
上面的5个函数用于在eboot中支持Flash操作功能,
一般在开发BSP的时候,如果需要在EBOOT中实现Flash的功能,会在EBOOT中创建一个Flash.c文件,在该文件中实现上述这些函数。建议看看blcommon.c中的DownloadImage函数,可以帮助理解。
篇3:Erlang中的函数与流程控制介绍
这篇文章主要介绍了Erlang中的函数与流程控制介绍,本文先是讲解了函数的一些知识,然后讲解了case语句和if语句及算术表达式等内容,需要的朋友可以参考下
一:函数
1:在Erlang中,【名字相同但参数数目不同】的两个函数是完全不同的函数,
2:其他模块内的函数用完全限定名称 被调用:
代码如下:
-module(sort1).
-export([reverse_sort/1, sort/1]).
reverse_sort(L) ->
lists1:reverse(sort(L)).
sort(L) ->
lists:sort(L).
3:子句间以分号【;】分隔,在最后的结尾处以【.】结尾。
4:每个函数都由一组子句组成。子句间以分号“;”分隔。每个子句都包含一个子句头部、一个可选的保护式和子句主体。子句的头部包含一个函数名和一组以逗号分隔的参数当函数调用发生时,将会按顺序对函数定义中的子句头部依次进行匹配。对保护式求值时所有的断言都将被求值。若所有断言都为真,则保护式成立,否则就失败。保护式中各个断言的求值顺序是不确定的。
如果保护式成立,则会对子句的主体进行求值。如果保护式失败,则尝试下一个候选子句。一旦子句的头部和保护式都匹配成功,系统将指定这条子句并对其主体求值。子句首部模式与保护式的组合可以唯一确定一个正确的子句。
保护式断言的完整集合如下:
保护式成立条件atom(X)X 是一个原子式constant(X)X 不是列表或元组float(X)X 是一个浮点数integer(X)X 是一个整数list(X)X 是一个列表或 []numberX 是一个整数或浮点数pid(X)X 是一个进程标识符port(X)X 是一个端口reference(X)X 是一个引用tuple(X)X 是一个元组binary(X)X 是一段二进制数据
另外,一些BIF和算术表达式的组合也可以作为保护式。它们是:
代码如下:
element/2, float/1, hd/1, length/1, round/1, self/0, ze/1
trunc/1, tl/1, abs/1, node/1, node/0, nodes/0
可以出现在保护式中的项式比较运算符如下:
运算符描述类型X > YX 大于YcoerceX < YX 小于YcoerceX =< YX 小于或等于YcoerceX >= YX 大于或等于YcoerceX == YX 等于YcoerceX /= YX 不等于YcoerceX =:= YX 等于YexactX =/= YX 不等于Yexact
比较运算符工作机制如下:首先对运算符两边求值(如,在表达式两边存在算术表达式或包含BIF保护式函数时);然后再进行比较。
为了进行比较,定义如下的偏序关系:
代码如下:
number < atom < reference < port < pid < tuple < list
元组首先按大小排序,然后再按元素排序。列表的比较顺序是先头部,后尾部。
如果比较运算符的两个参数都是数值类型且运算符为coerce型,则如果一个参数是integer另一个是float,那么integer将被转换为float再进行比较。
exact类型的运算符则不做这样的转换。
因此5.0 == 1 + 4为真,而5.0 =:= 4 + 1为假。
保护函数子句示例:
代码如下:
foo(X, Y, Z) when integer(X), integer(Y), integer(Z), X == Y + Z ->
foo(X, Y, Z) when list(X), hd(X) == {Y, length(Z)} ->
foo(X, Y, Z) when {X, Y, size(Z)} == {a, 12, X} ->
foo(X) when list(X), hd(X) == c1, hd(tl(X)) == c2 ->
注意在保护式中不可引入新的变量。
二、流程控制
case语句
case表达式允许在子句主体内部于多个选项中进行选择,语法如下:
代码如下:
case Expr of
Pattern1 [when Guard1] ->Seq1;
Pattern2 [when Guard2] ->Seq2;
...
PatternN [when GuardN] ->SeqN
end
首先,对Expr求值,然后,Expr的值将依次与模式Pattern1、Pattern2……PatternN进行匹配,直到匹配成功,
如果找到一个匹配并且(可选的)的保护式成立,则对应的调用序列将被求值。注意case保护式与函数保护式形式相同。case原语的值就是被选中的序列的值。
至少得有一个模式必须得以匹配――否则就会产生一个运行时错误并引发第??章中的错误处理机制。
举个例子,比方说我们我有个函数allocate(Resource)用于分配某种资源Resource。假设这个函数只返回{yes, Address}或no。这样,这个函数便可以放在一个case结构里:
代码如下:
...
case allocate(Resource) of
{yes,Address} when Address >0, Address =< Max ->
Sequence 1 ... ;
no ->
Sequence 2 ...
end
...
在Sequence 1 ...中,变量Address已经被绑定在了allocate/1的返回结果上。
为了避免匹配错误的发生,我们常常追加一个必会匹配的模式作为case原语的最后一个分支:
代码如下:
case Fn of
...
_ ->
true
end
IF
if表达式的语法如下:
代码如下:
if
Guard1 ->
Sequence1 ;
Guard2 ->
Sequence2 ;
...
end
在这种情况下,保护式Guard1,...将被依次求值。如果一个保护式成立则对与之关联的序列求值。该序列的求值结果便是if结构的结果。if保护式与函数保护式形式相同。与case相同,一个保护式都不成立的话将引发一个错误。如果需要,可以增加保护式断言true作为垃圾箱:
代码如下:
if
...
true ->
true
end
算术表达式
算术表达式由以下运算符构成:
运算符描述类型操作数类型优先级+ X+ X单目混合1- X- X单目混合1X * YX * Y双目混合2X / YX / Y (浮点除法)双目混合2X div YX 整除Y双目整数2X rem YX 除以Y 的余数双目整数2X band YX 与Y 的位与双目整数2X + YX + Y双目混合3X - YX - Y双目混合3X bor YX 与Y 位或双目整数3X bxor YX 与Y 的位算数异或双目整数3X bsl NX 算数左移N 位双目整数3X bsr NX 右移N 位双目整数3
单目 运算符有一个参数,双目 运算符有两个参数。混合 意味着参数即可以是integer 也可以是float 。单目运算符的返回值与其参数类型相同。
双目混合运算符(即* 、- 、+ )在参数都是integer 时返回类型为integer 的对象,在参数至少包含一个float 时返回一个float 。浮点除法运算符/ 总是返回一个float 。
双目整数运算符(即band 、div 、rem 、bor 、bxor 、bsl 、bsr )的参数必须是整数,其返回值也是整数。
求值顺序取决于运算符的优先级:首先计算第1优先级的运算符,然后是第2优先级,以此类推。括号内的表达式优先求值。
优先级相同的运算符从左到右进行求值。
篇4:excel中如何自定义函数
Excel函数虽然丰富,但并不能满足我们的所有需要,我们可以自定义一个函数,来完成一些特定的运算。下面,我们就来自定义一个计算梯形面积的函数:
1、执行“工具→宏→Visual Basic编辑器”菜单命令(或按“Alt+F11”快捷键),打开Visual Basic编辑窗口,
2、在窗口中,执行“插入→模块”菜单命令,插入一个新的模块——模块1。
3、在右边的“代码窗口”中输入以下代码:
Function V(a,b,h)V = h*(a+b)/2End Function
4、关闭窗口,自定义函数完成。
以后可以像使用内置函数一样使用自定义函数。
提示:用上面方法自定义的函数通常只能在相应的工作簿中使用。
篇5:一类光滑控制函数构造研究
一类光滑控制函数构造研究
以自抗扰控制理论中跟踪微分器为研究对象,针对用sat函数表示的二阶连续跟踪微分器控制作用连续但不光滑的缺点,构造了带饱和限幅的连续光滑控制函数.将该函数引入二阶连续跟踪微分器,通过数学仿真验证,各项性能指标明显优于原跟踪微分器.
作 者:陈新龙 杨涤 翟坤 朱承元 作者单位:哈尔滨工业大学航天工程与力学系,哈尔滨,150001 刊 名:宇航学报 ISTIC PKU英文刊名:JOURNAL OF ASTRONAUTICS 年,卷(期): 28(6) 分类号:V448.21 关键词:自抗扰控制 跟踪微分器 连续光滑控制篇6:实战VC时间控制函数.net
随着软硬件的飞速发展,计算机技术已经广泛地应用到自动化控制领域,为了实现实时控制,控制程序必须能够精确地完成定时和计时功能,VC提供了很多关于时间操作的函数,下面根据它们精度的不同,分别进行说明。 一般时控函数 VC 程序员 都会利用 Windows 的WM
随着软硬件的飞速发展,计算机技术已经广泛地应用到自动化控制领域,为了实现实时控制,控制程序必须能够精确地完成定时和计时功能。VC提供了很多关于时间操作的函数,下面根据它们精度的不同,分别进行说明。
一般时控函数
VC程序员都会利用Windows的WM―TIMER消息映射来进行简单的时间控制:1.调用函数SetTimer设置定时间隔,如SetTimer(0,200,NULL)即为设置200毫秒的时间间隔;2.在应用程序中增加定时响应函数OnTimer(),并在该函数中添加响应的处理语句,用来完成时间到时的操作。这种定时方法是非常简单的,但其定时功能如同Sleep()函数的延时功能一样,精度较低,只可以用来实现诸如位图的动态显示等对定时精度要求不高的情况,而在精度要求较高的条件下,这种方法应避免采用。
精度时控函数
在要求误差不大于1毫秒的情况下,可以采用GetTickCount()函数,该函数的返回值是DWORD型,表示以毫秒为单位的计算机启动后经历的时间间隔。使用下面的编程语句,可以实现50毫秒的精确定时,其误差小于1毫秒。
DWORD dwStart, dwStop;
// 起始值和终止值
dwStop = GetTickCount();
while(TRUE)
{
dwStart = dwStop;
// 上一次的终止值变成新的起始值
// 此处添加相应控制语句
do
{
dwStop = GetTickCount();
} while(dwStop - 50 < dwStart);
}
高精度时控函数
对于一般的实时控制,使用GetTickCount()函数就可以满足精度要求,但要进一步提高计时精度,就要采用QueryPerformanceFrequency()函数和QueryPerformanceCounter()函数。这两个函数是VC提供的仅供Windows 9X使用的高精度时间函数,并要求计算机从硬件上支持高精度计时器。QueryPerformanceFrequency()函数和QueryPerformanceCounter()函数的原型为:
BOOL QueryPerformanceFrequency(LARGE―INTEGER *lpFrequency);
BOOL QueryPerformanceCounter(LARGE―INTEGER *lpCount) ;
数据类型LARGE―INTEGER既可以是一个作为8字节长的整型数,也可以是作为两个4字节长的整型数的联合结构,其具体用法根据编译器是否支持64位而定,
该类型的定义如下:
typedef union ―LARGE―INTEGER
{
struct
{
DWORD LowPart; // 4字节整型数
LONG HighPart; // 4字节整型数
};
LONGLONG QuadPart;
// 8字节整型数
} LARGE―INTEGER;
在进行计时之前,应该先调用QueryPerformanceFrequency()函数获得机器内部计时器的时钟频率。笔者在主频为266、300、333的三种PentiumⅡ机器上使用该函数,得到的时钟频率都是1193180Hz。接着,笔者在需要严格计时的事件发生之前和发生之后分别调用QueryPerformanceCounter()函数,利用两次获得的计数之差和时钟频率,就可以计算出事件经历的精确时间。以下程序是用来测试函数Sleep(100)的精确持续时间。
LARGE―INTEGER litmp;
LONGLONG QPart1,QPart2;
double dfMinus, dfFreq, dfTim;
QueryPerformanceFrequency(&litmp);
// 获得计数器的时钟频率
dfFreq = (double)litmp.QuadPart;
QueryPerformanceCounter(&litmp);
// 获得初始值
QPart1 = litmp.QuadPart;
Sleep(100) ;
QueryPerformanceCounter(&litmp);
// 获得终止值
QPart2 = litmp.QuadPart;
dfMinus = (double)(QPart2 - QPart1);
dfTim = dfMinus / dfFreq;
// 获得对应的时间值
执行上面程序,得到的结果为dfTim=0.097143767076216(秒)。细心的读者会发现,每次执行的结果都不一样,存在一定的差别,这是由于Sleep()自身的误差所致。
本文介绍了三种定时或计时的实现方法,读者可以根据自己的实际情况进行选择,以达到程序的定时和计时功能。以上程序均在VC 6.0、Windows 98环境下调试通过。
原文转自:www.ltesting.net
篇7:C++11: nullptr、默认函数的控制、lambda函数
1 nullptr
nullptr是nullptr_t类型的实例化,替代了传统的NULL,C++11的指针空值常量,
nullptr_t是指针空值类型,nullptr仅仅是nullptr_t的一个实例,nullptr_t的使用规则:
1) 所有定义为nullptr_t类型的数据都是等价的,行为也完全一致
2) nullptr_t类型数据可以隐式转换成任意一个指针类型
3) nullptr_t类型类型不能转换为非指针类型,即使使用reinterpret_cast()的方式也是不可以的
4) nullptr_t类型数据不适用于算术表达式
5) nullptr_t类型数据可以用于关系运算表达式,但仅能于nullptr_t类型数据或者指针类型数据进行比较,当且仅当关系运算符为==、<=、>=等时返回true。
下面的例子演示了上面的规则:
#include
#include
using namespace std;
int main()
{
// nullptr可以隐式转换为 char*
char * cp = nullptr;
// 不可转换为整型,而任何类型也不能转换为nullptr_t,
// 以下代码不能通过编译
// int n1 = nullptr;
// int n2 = reinterpret_cast
// nullptr与nullptr_t类型变量可以作比较,
// 当使用“==”, “<=”, “>=”符号比较时返回true
nullptr_t nptr;
if (nptr == nullptr)
cout << “nullptr_t nptr == nullptr” << endl;//输出
else
cout << “nullptr_t nptr != nullptr” << endl;
if (nptr < nullptr)
cout << “nullptr_t nptr < nullptr” << endl;
else
cout << “nullptr_t nptr !< nullptr” << endl;//输出
// 不能转换为整型或bool类型, 以下代码不能通过编译
// if (0 == nullptr);
// if (nullptr);
// 不可进行算术运算, 以下代码不能通过编译
// nullptr += 1;
// nullprt * 5;
// 以下操作均可以正常进行
sizeof(nullptr);
typeid(nullptr);
throw(nullptr);
return 0;
}
虽然nullptr_t是个类型,但是在实例化模板的时候却不能实例化为任何指针:
#include
using namespace std;
template
template
int main()
{
g(nullptr); // 编译失败, nullptr的类型是nullptr_t,而不是指针
g((float*) nullptr); // 推导出T = float
h(0); // 推导出T = int
h(nullptr); // 推导出T = nullptr_t
h((float*)nullptr); // 推导出T = float*
}
nullptr和void*所占内存空间一样,但是nullptr是个编译期常量,而(void*)0是强制转换表达式,nullptr到任何指针的转换是隐式的,而(void*)0则必须经过类型转换后才能使用,nullptr可以完全替换null和(void*)0,
int* ptr=(void*)0;//错误
int* p=nullptr;//正确
nullptr_t对象的地址可以被用户使用,但是用户确却不能获得nullptr的地址,因为nullptr是右值常量,但是C++11没有禁止声明一个nullptr的右值引用并打印该右值引用的地址。
2 默认函数的控制=default、=delete
自定义的类型一但显示定义了构造函数后将不再是POD,即使函数体内什么也没有定义,但是可以通过=default恢复编译器默认的构造版本。
#include
#include
using namespace std;
class TwoCstor {
public:
// 提供了带参数版本的构造函数,再指示编译器
// 提供默认版本,则本class依然是POD类型
TwoCstor() = default;//TwoCstor(){}函数体内什么也没定义也不是POD
TwoCstor(int i): data(i) {}
private:
int data;
};
int main(){
cout << is_pod
}
可以在函数后面加=delete禁止函数的生成,如下禁止拷贝构造函数:
#include
#include
using namespace std;
class NoCopyCstor {
public:
NoCopyCstor() = default;//编译器默认的构造函数
// 使用 “= delete” 同样可以有效阻止用户
// 错用拷贝构造函数
NoCopyCstor(const NoCopyCstor &) = delete;//禁止拷贝构造
};
int main(){
NoCopyCstor a;
NoCopyCstor b(a); // 无法通过编译
}
=default和=delete可以在类外定义,这样就可以在不同的cpp文件中实现不同的版本
class DefaultedOptr{
public:
// 使用“= default”来产生缺省版本
DefaultedOptr() = default;
// 这里没使用“= default”
DefaultedOptr & operator = (const DefaultedOptr & );//类内不需要=default
};
// 在类定义外用“= default”来指明使用缺省版本
篇8:C语言输入输出函数及控制流程语句
控制流程语句主要包括: 条件语句、循环语句和开关语句,
1.1 标准输入输出函数
1.1.1 格式化输入输出函数
Turbo C2.0 标准库提供了两个控制台格式化输入、输出函数printf( ) 和 scanf, 这两个函数可以在标准输入输出设备上以各种不同的格式读写数据。 printf()函数用来向标准输出设备(屏 幕)写数据; scanf() 函数用来从标准输入 设备(键盘)上读数据。下面详细介绍这两个函数的用法。
一、printf()函数
printf()函数是格式化输出函数, 一般用于向标准输出设备按规定格式输出 信息。在编写程序 时经常会用到此函数。printf()函数的调用格式为:
printf(“<格式化字符串>”, <参量表>);
其中格式化字符串包括两部分内容: 一部分是正常字符, 这些字符将按原 样输出; 另一部分是格式化规定字符, 以“%”开始, 后跟一个或几个规定字符, 用来确定输出内容格式。
参量表是需要输出的一系列参数, 其个数必须与格式化字符串所说明的输出 参数个数一样多, 各参数之间用“,”分开, 且顺序一一对应, 否则将会出现意想 不到的错误。
1. 格式化规定符
Turbo C2.0提供的格式化规定符如下:
━━━━━━━━━━━━━━━━━━━━━━━━━━
符号 作用
──────────────────────────
%d 十进制有符号整数
%u 十进制无符号整数
%f 浮点数
%s 字符串
%c 单个字符
%p 指针的值
%e 指数形式的浮点数
%x, %X 无符号以十六进制表示的整数
%0 无符号以八进制表示的整数
%g 自动选择合适的表示法
━━━━━━━━━━━━━━━━━━━━━━━━━━
说明:
(1). 可以在“%”和字母之间插进数字表示最大场宽,
例如: %3d 表示输出3位整型数, 不够3位右对齐。
%9.2f 表示输出场宽为9的浮点数, 其中小数位为2, 整数位为6,
小数点占一位, 不够9位右对齐。
%8s 表示输出8个字符的字符串, 不够8个字符右对齐。
如果字符串的长度、或整型数位数超过说明的场宽, 将按其实际长度输出。
但对浮点数, 若整数部分位数超过了说明的整数位宽度, 将按实际整数位输出;
若小数部分位数超过了说明的小数位宽度, 则按说明的宽度以四舍五入输出。
另外, 若想在输出值前加一些0, 就应在场宽项前加个0。
例如: %04d 表示在输出一个小于4位的数值时, 将在前面补0使其总宽度
为4位。
如果用浮点数表示字符或整型量的输出格式, 小数点后的数字代表最大宽度,
小数点 前的数字代表最小宽度。
例如: %6.9s 表示显示一个长度不小于6且不大于9的字符串。若大于9, 则
第9个字符以后 的内容将被删除。
(2). 可以在“%”和字母之间加小写字母l, 表示输出的是长型数。
例如: %ld 表示输出long整数
%lf 表示输出double浮点数
(3). 可以控制输出左对齐或右对齐, 即在“%”和字母之间加入一个“-” 号可
说明输出为左对齐, 否则为右对齐。
例如: %-7d 表示输出7位整数左对齐
%-10s 表示输出10个字符左对齐
2. 一些特殊规定字符
━━━━━━━━━━━━━━━━━━━━━━━━━━
字符 作用
──────────────────────────
篇9:巧用EXCEL中的函数
很多时候我们常会遇到很多重复录入的工作,比如我们要制作职工简明登记表时,常常要输入身份证号码、性别、出生年月等内容。其实,身份证号码中已经包含了性别、出生年月等信息;身份证号码有两种格式,一种是15位号码;一种是18位号码;在15位号码中,第7—12位数字,表示持证人的出生时间,第15位数字(如2)表示持证人的性别(奇数为“男”,偶数为“女”);18位号码同理。
利用Excel中的函数,把可以重复利用的信息提取出来:
LEN(text)、MID(text,start_num,num_chars)、MOD(number,divisor)IF(logical_test,value_if_true,value_if_false),
假设身份证号码的信息保存在E列中,性别和出生年月分别保存在C列和D列中。
1、性别的显示:
选中C2单元格输入公式:=IF(MOD(IF(LEN(E2)=15,MID(E2,15,1),MID(E2,17,1)),2)=0,“女”,“男”)
如果IF函数提取出来的数值[MOD(IF(LEN(E2)=15,MID(E2,15,1),MID(E2,17,1)),2)=0],除以“2”后余数为“0”,,则显示为“女”,反之显示为“男”,输入完成后,按下“Enter”键进行确认,第1位员工的性别则自动显示在C2单元格中[如图1],
图1
2、出生时间的显示
选中D2单元格,输入公式:=IF(LEN(E2)=15,MID(E2,7,2)+1900,MID(E2,7,4))&“/”& IF(LEN(E2)=15,MID(E2,9,2),MID(E2,11,2))&“-”& IF(LEN(E2)=15,MID(E2,11,2),MID(E2,13,2)),
输入完成后,按下“Enter”键进行确认,第1位员工的出生时间则自动显示在D2单元格中[参见图1]。
3、用COUNTIF(range,criteria)函数统计出男、女职工的人数
Range 计算其中满足条件的单元格数目的单元格区域。
Criteria 确定那些单元格区域将被计算在内的条件,其形式可以为数字、表达式或文本。
计算男、女职工人数的就可设置为:COUNTIF(C2:C5,”男”)和COUNTIF(C2:C5,”女”),如图2
注意输入公式的时候,其中的字符通常要用双引号括起来,是英文输入法状态下的双引号。
图2












