
首先在Main函数中,因为这是整个系统的入口点。
(1)Main函数
所有程序运行首先是在主函数下开始的,这里也不例外。找到Zmainc文件下的主函数:
ZSEG int main( void )
{
// 初始化时要关中断
osal_int_disable( INTS_ALL );
// 电压检测程序
zmain_vdd_check();
// 初始化堆栈
zmain_ram_init();
// 第一次初始化平台 注释1
InitBoard( OB_COLD );
// 硬件驱动初始化注释2
HalDriverInit();
…………
//系统初始化注释3
osal_init_system();
// 第二次初始化平台注释4
InitBoard( OB_READY );
……………
osal_start_system(); // *** 作系统开始运行
}
说明:
(1)注释1:该函数在onboardc中,原型如下
void InitBoard( byte level )
{
if ( level == OB_COLD )
{
这里执行第一次初始化的内容
}
else
}
(2)注释2:这个函数在hal_driversc中
void HalDriverInit (void)
{
………
#if (defined HAL_KEY) && (HAL_KEY == TRUE)
HalKeyInit();
#endif
………
}
HalKeyInit()这个函数在hal_keyc中
void HalKeyInit( void )
{
#if (HAL_KEY == TRUE)
/ Initialize previous key to 0 /
halKeySavedKeys = 0;
申请香港的大学研究生与申请美国大学研究生程序是基本一样的首先你要去你想申请的香港高校的官方网站查询你要报读专业的资料和信息,了解并确定之后开始正式申请。 (前三强为:香港大学、香港中文大学、香港科技大学,这三所世界排名均在前一百位,其次是香港理工大学、香港城市大学等,香港的大学学历是受国际认可的,全球任何一家跨国公司都接受香港的学历)1.本科成绩单: 中英文的各一份,必须经过学校公证。2.英文能力,需要提供托福成绩单一份,现在有些香港高校也接受雅思成绩。3.提供你的GRE成绩单。4.申请表格:发电子邮件给你所申请大学招生办公室或者系里,对方会寄来有关表格。你也可以从官方网站下载相关表格,中文大学好像以前是要求你先寄10港币左右的汇票过去,然后才寄材料和表格来,也许是一种名校的架子吧。(香港大学、香港中文大学、香港科技大学是香港前三强,世界大学排名前50位。)5.研究计划:RESEARCHP ROPOSAL是纯学术的,香港的大学会要求你说明自己的研究意向,无须加入诸如个人经历、感情这些东西。它要求申请者要有一个明确的研究方案并对此有较好的掌握。研究计划一般包括以下几点:(1)研究对象(TOPIC),即你想要解决的问题(2)研究此问题的意义(3)前人的研究状况即遗留的问题(4)你的研究方法(METHODOLOGY)6.推荐信:一般需要两封推荐信,必须是学术领域中的人,如你大学时的老师教授系主任等等,其他人则不被接受。内容是对你学术才能的评价。此外还要求对你的研究计划做出评价和建议,这一点也不应忽视。注:以上所有的申请表格,研究计划,论文报告全部要求全英文。申请香港的全日制研究型master或者PhD都有奖学金,申请奖学金要同你申请的专业的教授联系,如果他对你的学术研究很满意会给你全额奖学金,大概每月12500港币~15000港币左右,如果得到STUDENDSHIP的话,所有开销便无须担心了。足够支付学费还有生活费。所以只要申请成功,钱不是太大的问题的!
网上和论坛里面很多帖子都把精力集中到分析协议栈的串口工作机制上,比如分析DMA
工作原理,中断工作原理,然后分析输入和输出Buffer的处理等内容,学习者跟着协议栈的
串口底层一直到顶层转圈、转圈、再转圈,蒙圈了。
实际上,从应用角度讲,我们根本就没有必要去深入的追究Zstack中串口的工作机制,
也没有必要去搞清楚到底是怎么DMA和Interrupt的,我们只要调用几个简单函数就可以正
常使用串口了。其实协议栈已经把使用串口的条件准备好了,我们何必再纠结硬件底层实现
呢?应用者应该把协议栈看作一个平台,平台之上的应用才是我们的目标。下面我就讲一下
如何利用协议栈现有平台来实现自己的串口应用。这里我所提及的现有平台即是Zstack自带
的MT包,其实Zstack中的这个MT包功能相当强大,通过TI提供的ZTOOL工具可以用串
口的方式同整个协议栈进行交互,在我们编写Zigbee应用程序的过程中,很多不知道该如何
调用的函数都能在MT中找到参考!这个不多说了,有兴趣的同学可以去专门研究一下MT
包。
二、使用方法
在MT包中,已经有了串口初始化即串口数据处理函数可用,关键的几个函数出现在
MT_Uartc文件中。我们拿出来几个关键函数说明一下(我捡重要语句注释):
第一个函数
void MT_UartInit ()
{ // 这个是MT中的一个串口初始化函数,主要作用是初始化串口工作的一些规矩
halUARTCfg_t uartConfig;
App_TaskID = 0; //处理串口数据的任务ID,可以先不管
uartConfigconfigured = TRUE;
uartConfigbaudRate = MT_UART_DEFAULT_BAUDRATE;
//默认38400波特率;可以更改,但是可能有新问题,具体解释内容比较多,我不说;
uartConfigflowControl = FALSE;//MT_UART_DEFAULT_OVERFLOW;
//禁止硬件流控,如果你的串口只有RXD,TXD和GND三条线,必须这么做;
uartConfigflowControlThreshold= MT_UART_DEFAULT_THRESHOLD;
uartConfigrxmaxBufSize = MT_UART_DEFAULT_MAX_RX_BUFF;
uartConfigtxmaxBufSize = MT_UART_DEFAULT_MAX_TX_BUFF;
uartConfigidleTimeout = MT_UART_DEFAULT_IDLE_TIMEOUT;
uartConfigintEnable = TRUE;
#if defined (ZTOOL_P1) || defined (ZTOOL_P2)
uartConfigcallBackFunc = MT_UartProcessZToolData;
//如果编译的时候选择使用ZTOOL,那么MT_UartProcessZtoolData将会处理串口接到的数
//据串
#elif defined (ZAPP_P1) || defined (ZAPP_P2)
uartConfigcallBackFunc = MT_UartProcessZAppData;
//如果编译的时候没有选择ZTOOL,而是选择使用了ZAPP,则由MT_UartProcessZAppData
//函数来处理串口数据串
(如果是用CC2530的P0口那两根串口引脚,你就要define ZTOOL_P1,如果是P1口的那
两根串口引脚,你就要define ZTOOL_P2,对于ZAPP_P1和ZAPP_P2也是一个情况)
#else
uartConfigcallBackFunc = NULL;
//这个地方,如果你有兴趣自己写一个串口处理函数,那么你实现一个My_UartProcessData
//函数,然后填到这里,替换NULL。
#endif
#if defined (MT_UART_DEFAULT_PORT)
HalUARTOpen (MT_UART_DEFAULT_PORT, &uartConfig);
//如果定义了默认串口,(0或者1),打开串口,这个HalUartOpen函数会做一大堆工作,具
//体说来就是初始化呗。。。,我没有必要展开。需要注意的是这个函数把前面哪一堆初始化
//的uartConfig做为参数传进去了噢!
#else
(void)uartConfig;
#endif
#if defined (ZAPP_P1) || defined (ZAPP_P2)
MT_UartMaxZAppBufLen = 1;
MT_UartZAppRxStatus = MT_UART_ZAPP_RX_READY;
//这两句,如果是不想使用MT_UartProcessZToolData来处理串口数据,就。。。。
//再说就要深入串口机制了,网上讲解文章太多了,自己看吧,我一会儿使用
//MT_UartProcessZToolData。
#endif
}
第二个函数
void MT_UartRegisterTaskID( byte taskID )
{
App_TaskID = taskID;
}
第三个函数
void MT_UartProcessZToolData ( uint8 port, uint8 event )
osal_msg_deallocate ( (uint8 )pMsg );
}
我们往上看看这个Message是什么?MT_UartProcessZToolData函数开始不远的地方有以下程
序段:
if (pMsg)
{
pMsg->hdrevent = CMD_SERIAL_MSG;
pMsg->msg = (uint8)(pMsg+1);
pMsg->msg[MT_RPC_POS_LEN] = LEN_Token;
state = CMD_STATE1;
}
从这里看到,这个函数建立了一个消息头,用CMD_SERIAL_MSG做为消息,那么
osal_msg_send给任务的那个消息将会以CMD_SERIAL_MSG出现。。。。。。。
好了,以上三个函数看完,我们试着使用一下:
以GenericApp例子为例:
void GenericApp_Init( byte task_id )
{
XXXXXXXXXXXXX
XXXXXXXXXXXXX
(这个函数的最后,其实放在这个函数的哪里都行)
MT_UartInit(); //added by kennan
MT_UartRegisterTaskID(GenericApp_TaskID);
}
再看一下MT_UartRegisterTaskID(GenericApp_TaskID):
void MT_UartRegisterTaskID( byte taskID )
{
App_TaskID = taskID;
}
好了,这样,我们顺利地把串口发来的数据用MT_UartProcessZToolData来处理,并且把处理
后的数据打包发给了任务GenericApp_TaskID。
接下来,我们看一下在GenericApp_TaskID中如何处理吧。
在GenericApp的主处理函数中:
UINT16 GenericApp_ProcessEvent( byte task_id, UINT16 events )
{
if ( events & SYS_EVENT_MSG )
{
MSGpkt = (afIncomingMSGPacket_t)osal_msg_receive( GenericApp_TaskID );
while ( MSGpkt )
{
switch ( MSGpkt->hdrevent )
{
case ZDO_CB_MSG:
GenericApp_ProcessZDOMsgs( (zdoIncomingMsg_t )MSGpkt );
break;
case KEY_CHANGE:
GenericApp_HandleKeys( ((keyChange_t )MSGpkt)->state, ((keyChange_t
)MSGpkt)->keys );
break;
//增加
Case CMD_SERIAL_MSG:
ProcessUartData((mtOSALSerialData_t )MSGpkt);
//这个函数你自己实现吧,想做啥呢?想做啥就做啥。如果想把接
//到的数据发回串口,调用HalUARTWrite就行了。
}
如果你不知道如何提取串口消息并处理,我就好人做到底,帮你实现一个ProcessUartData()
函数吧。这个函数的作用是把接收到的数据从CM0开始一直到payload的最后一个字节发送
给串口回显,不包括校验字节噢。
ProcessUartCommand((mtOSALSerialData_t )MSGpkt)
{ //为了正确地进行下面工作,用mtOSALSerialData_t类型来指向整个zigbee数据包(不是串
//口数据包)
uint8 pMsg;
pMsg = MSGpkt->msg;
//定义一个指针,指向真正的串口接收数据存放位置,MSGptk里面还有一些别的Header噢。
switch ( MSGpkt->hdrevent )
{
case CMD_SERIAL_MSG://如果是串口消息。。。。
HalLedSet( HAL_LED_RED, HAL_LED_MODE_FLASH );
//用LED灯指示一下收到数据啦
uint8 pBuffer;
uint8 datalength;
uint8 i;
//定义几个变量,为从接收到的串口包里面提取数据以及写回串口做准备
datalength = pMsg++;
//串口包中第一个字节是数据长度噢
pBuffer = osal_mem_alloc(datalength);
//分配一块内存准备把串口消息数据拿出来
if(pBuffer != NULL)
{
for(i = 0;i < datalength; i++)
pBuffer++ = pMsg++;
//把消息中的串口数据按照datalength数量挨个捞出来放血(放血啥意思?把池子
//里面那东西捞出来放血,明白不?
HalUARTWrite(0,pBuffer,datalength);
//捞出来放血的串口数据再写回串口,也就是送到串口助手显示
Osal_memfree(pBuffer);
//动态申请的内存记得用完了free一下噢
}
break;
default:
break;
}
}
说明:因为ZTOOL发过来的数据是有格式的,所以如果你用串口助手来测试,那么发的数
据要按照格式来,如果你不想按那个格式,你可以自己去修改MT_UartProcessZToolData里面
的相关程序。这种方法对于想要通过PC来控制zigbee的应用场合非常实用,因为你PC发过
来的一般也会有命令和数据,如果不用MT的格式,你自己也要规范一个格式,既然MT已
经有了,我们就借用就好。
对于MT_UartProcessZAppData这个处理方法,也就是你define了ZAPP_P1或ZAPP_P2
的情况,其机制也是类似的,只不过没有规定格式,你更自由,这里我就不多说了。
再有,如果你真的在测试的时候不知道那么一长串数据的xor 结果是多少,也可以去
MT_UartProcessZToolData函数中,找到:
//if ((MT_UartCalcFCS ((uint8)&pMsg->msg[0], MT_RPC_FRAME_HDR_SZ +
LEN_Token) == FSC_Token))
{
osal_msg_send( App_TaskID, (byte )pMsg );
}
else
//{
//osal_msg_deallocate ( (uint8 )pMsg );
//}
把我标红的几个位置注释掉,就不会校验了,你也不用算xor结果了,不过发数据的时候
这个位置还是要的,你随便填个0好了。
系统整体结构设计与工作原理
目前楼宇门禁装置大多为一个简单的可控电子开
关,一般采取语音对话的有线控制方式,不具备可视化
能力和无线控制能力,其存在交互效果差、有线网络布
线繁琐、智能化程度不够高的缺点。随着视频编、解
码技术和无线传输技术的快速发展,智能化楼宇系统也
得到了快速的发展。嵌入式无线网络产品以其体积
小、成本低、使用灵活方便等优点,得到了越来越广泛
的应用。随着市场上智能化楼宇的不断升温,门铃系统
已作为智能化办公室和智能化小区的一个重要组成部
分。
本研究介绍的智能小区无线可视化门铃系统正是
在这样的应用前景下,基于80211无线网络协议进行设
计的。
如图1所示,该系统采用低功耗、高性能的嵌入式
IDT RC32434作为主控芯片,使用VW2010芯片进行硬
实时编解码以提高编解码效率,采用PHILIPS公司的
BGW200无线芯片进行音视频码流的转发控制。整个
系统由服务器端和客户端两部分组成,主要实现音频视
频数据采集和高质量编解码以及无线网络传输功能。
●服务器端工作原理
由CCD Sensor和音频端口进来的输入信号,经过视
频A/D和音频A/D转换后,进行MPEG4视频编码和
MPEG MP3音频编码。编码后的视音频码流送到网络
复用模块打包后,将压缩编码后的数据流经过80211x
无线网络送到客户端。如下图1所示:
系统客户端工作原理
由无线网络接收的音视频码流数据,经过网络解复
用模块解复用后,获得的视频码流和音频码流分别送至
视频解码模块和音频解码模块进行MPEG4视频解码和
MP3音频解码。解码后的数据经过视频模拟编码、D/A
和音频D/A转换后送到可视终端显示。如下图2所示:
系统的硬件设计主要分四个部分:主控制系统、音
视频采集系统、多媒体编解码系统、无线网络系统。
它是一款64位MIPS,内部集成了NAND Flash控制器
(FlashC)、32位PCI总线控制器(PCIC)、4通道DMA控制器、
4通道SDRAM控制器(SDRAMC)、外部总线控制器(EBUSC)、
外部总线接口(E—BUSI)以及2个通用串口等,并通过内部总
线对它们分别进行控制。该芯片提供高达400MHz的频率
集成了标准外围元件互连(PCI)接口,可与80211a/b/g和串行
Ⅵ、等先进外围设备连接。处理速度快,功能强,性价比高,
能很好满足嵌入式ucLinux系统的需求。
SAA 7110是Philips公司生产的可编程前端视频解码
器,它可将输入的视频模拟信号转换为YUV数字信号。其
内部包含三路模拟处理通道,能实现视频源的选择,数据
输出格式有YUV 4:1:1(8bit)和YUV4:2:2(8bit)两种。它还包
括抗混叠滤波,A/D转换,自动嵌位,自动增益控制,时钟产
生,多制式解码及亮度、对比度和饱和度的控制等功能。
该系统采用VW2010作为多媒体编解码芯片,它是一种
实时MPEG-4音视频压缩/解压芯片。其片内集成有3个信
号处理/控制单元,包括一个视频编码(压缩)器、一个视频解
码(解压)器和一个片内CPU(内部扩展一个音频编码DSP、一
个音频解码DSP、一个多路复合单元和一个多路解复合单元
。具有可编程、高性能和低功耗特点,因为每个信号处理/控
制单元都由一个RISC处理器和专用的硬件加速构成。
无线模块采用的芯片是PHILIPS公司的BGW200,该芯
片通过高速串口SPI2与处理器的SPI1口连接。SPI(Seria
Peripheral Interface,串行外设接口)是一种同步外设接口,允
许MCU与各种外围设备以串行方式进行通信、数据交
换。当IDTRC32434与BGW200之间互相通信时只能通过
BGW200的SPI2口进行,此时IDT RC32434是主(HOST),
BGW200是从机(SLAVE),传输的时钟由HOST控制。
本系统软件设计按层次划分主要分为三层:系统初始化
引导和嵌入式系统内核移植、外设驱动程序编写(包括USB摄
像头驱动、无线网络模块驱动等)、数据采集与无线传输。
虽然Linux内核小、效率高,但嵌入式系统的硬件资源
毕竟有限,因此不能直接把Linux作为 *** 作系统,要针对具体的
三、硬件设计
四、软件设计
1、主控芯片采用IDT RC32434
2、CCD摄像头和A/D转换芯片
3、多媒体编解码芯片
4、80211b芯片
1、系统引导、内核移植和文件系统的建立
应用通过配置内核、裁减shell和嵌入式C库对系统进行定制,
使整个系统能够存放到容量较小的Flash中。嵌入式Linux系
统主要由4个部分组成:引导内核启动的文件(bootloader)、
Linux内核文件(kernel)、虚拟磁盘文件(ramdisk)、用户空间文
件(user)。把它们分别放在DataFlash内的4个分区模块中。对
于不需要动态改变,使用较节省空间的ROMFS只读文件系统;
user模块内需要进行较多的读写 *** 作,所以使用支持动态擦
写保存的JFFS2文件系统。在构建完软件平台后,下面就主
要涉及到USB摄像头驱动和无线驱动模块设计、视频采集
模块和基于80211无线网络传输模块的程序设计。
2、USB摄像头驱动
搭建好嵌入式Linux的开发环境后,下一步就首要
完成USB摄像头驱动工作。Video4Linux(V4L)是Linux
中关于视频设备的内核驱动,它为针对视频设备的应用
程序编程提供一系列接口函数。对于USB口摄像头,其
驱动程序中提供了基本的I/O *** 作接口函数open,
read,write,close的实现。当应用程序对设备文件进行系
统调用 *** 作时,Linux内核将通过file-operations结构访
问驱动程序提供的函数。在编译时选取动态加载模式,
确定USB摄像头被正常驱动后,下一步就是使用
Video4Linux提供的API函数集来编写视频采集程序。
3、音视频数据采集
在完成USB摄像头驱动后,就可以针对设备文件
/dev/video进行视频捕捉方面的程序设计。其中用到的
主要函数有:Camera open():用来开启视频设备文件;
Camera get capability():取得设备文件的相关信息;
Camera get picture():获取图像的相关信息;Camera close(
):用来关闭设备文件;Camera grab image():用来抓取图像,
采用mmap方式,直接将设备文件/dev/video0映射到内存,
加速文件I/O *** 作,还可以使多个线程共享数据。如图3
4、音视频压缩编解码
获取图像数据后,可以直接输出到FrameBuffer
进行显示,由于本系统要将采集到的音视频通过无线
网络传输出去,所以在传输之前要对原始的图像数据
进行压缩编码,在此选用VW2010芯片来实现MPEG-
4视频编解码方案。和其他标准相比,MPEG-4压缩
比更高,节省存储空间,图像质量更好,特别适合在低
带宽条件下传输视频,并能保持图像的质量。对视频
流进行压缩编码以后,接下来就要实现网络传输部分
的功能。
无线驱动模块的软件架构分为三部分:客户驱动(
client driver)、主机硬件抽象层(HHAL)、主机 *** 作系统
抽象层(HOSAL)。设备驱动程序本质上来说就是一组
相关函数的集合。它利用结构体file_operations与文件
系统联系起来,内核使用该结构体访问驱动程序的函数,
该数据结构定义再<linux/fsh>头文件中。在这个数据类
型中,每一个成员变量指向驱动程序中特定 *** 作的函数,
对于没有的 *** 作函数,相应的成员函数可以设置位
NULL。
设备驱动程序通常包含下面3个最主要的部分:(
1)驱动程序的注册和注销;(2)设备的打开和释放;(3)
设备的读写 *** 作。对于需要动态加载的模块,通过执
行Makefile文件,在当前目录会生成目标文件
wirelesso。将目标文件wirelesso下载到已经烧写好的
文件系统中。当目标板重新启动后,运行命令:insmod
wirelesso即可将无线驱动模块链接到内核中。一旦驱
动程序被注册到内核表中,对驱动程序的 *** 作就和它
的主设备号对应起来了。当应用程序对设备文件进行
某种 *** 作时,内核会从file_operations结构中找到并去
调用正确的函数。卸载模块可输入下面的命令:
rmmod wirelesso。
(1)初始化
系统初始化包括对SAA 7110、VW2010、RC32434、
BGW20等芯片的初始化。初始化过程主要包括对一些
数据寄存器、地址寄存器、中断服务寄存器等进行相
应的 *** 作以形成系统运行环境的初始状态。
(2)传输控制策略
上电开始初始化程序后,服务器端USB摄像头的
模拟视频信号在程序控制下通过SAA7110视频解码
芯片完成模数转换,接着mpeg4编码芯片VW2010将
接收的数字图像信号进行DCT变换、量化编码、熵
6、无线网络传输控制过程
编码后,把数据流输出到相应的SDRAM内部的FIFO
中。RC32434MCU在FIFO中查找帧同步标志,如果
找到,判断缓冲区内是否有一帧的数据,如果有则微
处理器读出压缩数据流并发送到BGW20进行扩
频、调制发射出去。客户端初始化过程与服务器端
类似,在系统初始化完毕后通过与服务器端交互,建
立网络连接,并将SDRAM用作硬解码时的数据缓冲
区,采用LCD接口连液晶屏用来显示图像。整个系统
中,由RC32434完成对各器件的初始化、协调整个
系统的工作。
系统采用64位MIPS芯片IDT RC32434作为主控制
器,以VW2010作为MPEG-4编、解码芯片实现网络端口
输入和输出的MPEG-4码流、采用BGW200无线模块进
行音视频数据传输,在uclinux平台上结合先进的多媒体
无线传输技术实现的,结果表明其具有较高的传输效
率、和普遍的门禁设备相比,本系统具有更好的灵活性
与扩展性、交互能力、控制能力更强。而且该无线音
视频传输技术也可广泛用于IP电视、卫星电视、安防
系统、智能楼宇系统和基于MPEG-4标准的数字电视
广播系统中,应用前景十分广阔。
5、无线网络模块驱动
6、无线网络传输控制过程
五、结论
参考文献
[1]杜春雷编著,《ARM体系结构与编程》,清华大
学出版社,2003
管理中心机
,主机
,用户分机
,围墙机
,连网转换器
,中继器,
保护器,
解码器,
电源,
开锁控制器,
综合布线系统
有线电视系统
闭路电视监控系统
门禁系统(含可视对讲)
防盗报警系统
楼宇自控系统
会议系统
广播系统
问题点找到了,debug_str()会将在LCD显示的数据同时也传到PC,它是通过调用MT层中的MT_ProcessDebugStr()来完成的,所以每条显示的内容都会增加一个包头,也就是你看到的乱码。
这里给你两个建议,一个屏蔽debug_str(),不增加后面的那一行,在LCD的外部是写串口通信。二是屏蔽debug_str()后,使用HalUARTWrite()函数来发送数据,就没有乱码了。我个人鄙视第二种做法。
//=================================[说明]=======================================/
//学生成绩管理
//文件名:maincpp
//------!!!!!!---------BOF-[程序代码开始]-------------------
#include<iostream>
#include<string>
using namespace std;
//=============<开始定义结构体>===================================================
struct combox
{
int num;
int mark;
string name;
combox next;
};
//=============<结束定义结构体>===================================================
//=============<开始定义Commonbox类>==============================================
//-----类体开始------------------------
class Commonbox
{
private:
combox head;
void Swap(combox ,combox ); //交换两个combox变量的数据域
void Print(combox ); //输出一combox指定的记录
combox Find(int); //查找条例条件的记录,并返回该记录的指针
public:
Commonbox()
{
head=NULL;
}
int ListCount(); //统计当前链表的记录总数,返回一个整数
void AddItem(int num, string name, int mark); //添加一条记录到表尾
void RemoveItem(int); //删除一条指定的记录
void List(); //列出当前链表中的所有记录
void Sort(); //对当前链表进行排序
void Search(int); //在当前链表查找指定记录并输出
float Average(); //计算平均成绩
};
//-----类体结束------------------------
//-----类成员函数开始----------------------------------
int Commonbox::ListCount() //统计当前链表的记录总数,返回一个整数
{
if (! head)return 0;
combox p=head;
int n=0;
while (p)
{
n++;
p=p->next;
}
return n;
}
void Commonbox::AddItem(int num, string name, int mark) //添加一条记录到表尾
{
if (! head)
{
head=new combox;
head->mark=mark;
head->num=num;
head->name=name;
head->next=NULL;
return;
}
combox t=head;
while (t && t->num!=num)
t=t->next;
if (t)
{
cout<<" *** 作失败:学号为"<<num<<"的记录已经存在!"<<endl;
return;
}
combox p=head;
while (p->next)p=p->next;
combox p1=new combox;
p1->num=num;
p1->mark=mark;
p1->name=name;
p1->next=NULL;
p->next=p1;
return;
}
void Commonbox::RemoveItem(int num) //删除一条指定的记录
{
combox t=Find(num);
if (! t)return;
combox p=head;
//如果要删除的记录位于表头
if (head==t)
{
head=head->next;
delete p;
cout <<"成功删除学号为 "<<num<<" 的记录!"<<endl<<endl;
return;
}
while (p->next!=t)p=p->next;
combox p1=p->next;
p->next=p1->next;
delete p1;
cout <<"成功删除学号为 "<<num<<" 的记录!"<<endl<<endl;
return;
}
void Commonbox::Print(combox p) //输出一combox指定的记录
{
cout<<p->num<<"\t\t";
cout<<p->name<<"\t\t";
cout<<p->mark<<endl;
return;
}
void Commonbox::List() //列出当前链表中的所有记录
{
if (ListCount()==0)
{
cout <<"错误:当前的列表为空!"<<endl;
return;
}
combox p=head;
cout<<"共有记录:"<<ListCount()<<endl;
cout<<"学号\t\t姓名\t\t分数"<<endl;
while (p)
{
Print(p);
p=p->next;
}
cout <<endl;
return;
}
void Commonbox::Search(int num) //在当前链表查找指定记录并输出
{
cout <<"Searching"<<endl;
combox p=Find(num);
if (p)
{
cout<<"学号\t\t姓名\t\t分数"<<endl;
Print(p);
}
cout <<endl;
}
combox Commonbox::Find(int num)
{
if (ListCount()==0)
{
cout <<"错误:当前的列表为空!"<<endl;
return NULL;
}
combox p=head;
while (p)
{
if (p->num==num)break;
p=p->next;
}
if (! p)
{
cout <<"错误:找不到该记录!\n";
return NULL;
}
return p;
}
void Commonbox::Swap(combox p1, combox p2) //交换两个combox变量的数据域
{
combox temp=new combox;
temp->num=p1->num;
temp->mark=p1->mark;
temp->name=p1->name;
p1->num=p2->num;
p1->mark=p2->mark;
p1->name=p2->name;
p2->num=temp->num;
p2->mark=temp->mark;
p2->name=temp->name;
}
void Commonbox::Sort() //对当前链表进行排序
{
cout <<"Sorting"<<endl;
if (ListCount()<2) return;
combox temp=NULL,p=NULL,p1=NULL,p2=NULL,k=NULL;
int n=ListCount(),i,j;
p=head;
for (i=1;i<n;i++)
{
k=p;
p1=p->next;
for (j=0;j<n-i;j++)
{
if (k->num > p1->num)
{
k=p1;
}
p1=p1->next;
}
if (p!=k)Swap(k,p);
p=p->next;
}
cout <<"Complete successfully!"<<endl<<endl;
return;
}
float Commonbox::Average() //计算平均成绩
{
if (ListCount()==0)
{
cout <<"错误:当前的列表为空!"<<endl;
return -1;
}
int sum=0,n=0;
combox p=head;
while (p)
{
sum += p->mark;
p=p->next;
n++;
}
return float(sum)/n;
}
//-----类成员函数结束----------------------------------
//=============<结束定义Commonbox类>==============================================
Commonbox student; //定义全局变量
int Menu()
{
cout <<"===========[主选单:]==========="<<endl;
int n=1,select=-1;
cout <<n++<<"输入学生成绩;"<<endl<<endl;
cout <<n++<<"按学号排序;"<<endl<<endl;
cout <<n++<<"按学号查找记录;"<<endl<<endl;
cout <<n++<<"删除由学号指定的记录;"<<endl<<endl;
cout <<n++<<"列出所有记录;"<<endl<<endl;
cout <<n++<<"计算平均成绩;"<<endl<<endl;
cout <<"0退出;"<<endl<<endl;
cout <<"[请选择(输入相应数字)]:";
cin >>select;
return select;
}
char Exit() //返回一个字符患,用于确认退出
{
char s;
cout<<"确定要退出程序吗[Y/N]:";
cin >>s;
return s;
}
void Input(int num, string name, int mark) //输入学生信息
{
cout <<"请输入 学号 姓名 分数:";
cin >>num;
if (num==-1)return;
cin >>name>>mark;
return;
}
void AddNew() //增加记录
{
int num=0,mark=0;
string name="";
cout<<endl<<"当输入的学号为-1时表示结束输入"<<endl;
Input(&num, &name, &mark);
while (num!=-1)
{
studentAddItem(num,name,mark);
Input(&num, &name, &mark);
}
return;
}
void DoFind() //按学号查找
{
int num;
cout<<endl<<"当输入的学号为-1时表示结束输入"<<endl;
do
{
cout <<"请输入要查找的学生的学号: ";
cin>>num;
if (num==-1)continue;
studentSearch(num);
}
while (num!=-1);
return;
}
void DoDelete() //删除记录
{
cout<<endl<<"当输入的学号为-1时表示结束输入"<<endl;
int num;
do
{
cout <<"请输入要删除的学生的学号:";
cin>>num;
if (num==-1)continue;
studentRemoveItem(num);
}
while (num!=-1);
return;
}
void ShowAverage() //输出平均数
{
float avr=studentAverage();
if (avr>0)
{
cout<<"共有记录:\t"<<studentListCount()<<endl<<endl;
cout<<"平均成绩:\t"<<avr<<endl<<endl;
}
return;
}
//-------<主函数开始>-------
int main()
{
cout<<"Welcome!\n学生成绩管理系统\nVer 101\nBy FondBoy\n\n";
int select;
char s;
while (1)
{
select=Menu();
switch (select)
{
case 0: //退出程序
s=Exit();
if (s=='y' || s=='Y')return 0;
break;
case 1: //输入学生成绩
AddNew();
break;
case 2: //按学号排序
studentSort();
break;
case 3: //按学号查找记录
DoFind();
break;
case 4: //删除由学号指定的记录
DoDelete();
break;
case 5: //列出所有记录
studentList();
break;
case 6: //输出平均成绩
ShowAverage();
break;
default:
cout<<"无效输入!"<<endl;
}
}
return 0;
}
//-------<主函数结束>-------
//------!!!!!!---------EOF-[程序代码结束]-------------------
以上就是关于z-stack中uartrxcb什么时候被触发全部的内容,包括:z-stack中uartrxcb什么时候被触发、报考香港理工大学研究生有什么程序、如何在Zstack 中使用串口等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)