dsp数字信号处理课程设计报告.docx
- 文档编号:7330923
- 上传时间:2023-01-23
- 格式:DOCX
- 页数:21
- 大小:301.44KB
dsp数字信号处理课程设计报告.docx
《dsp数字信号处理课程设计报告.docx》由会员分享,可在线阅读,更多相关《dsp数字信号处理课程设计报告.docx(21页珍藏版)》请在冰豆网上搜索。
dsp数字信号处理课程设计报告
淮阴工学院
《DSP技术及应用》课程设计报告
选题名称:
µC/OS-II在DSP上的任务通讯
系(院):
计算机工程学院
专业:
计算机科学与技术(嵌入式系统软件设计)
班级:
计算机1073班
姓名:
芦晓飞学号:
1071306118
指导教师:
马岱常波
学年学期:
2009~2010学年第2学期
2010年6月12日
摘要:
在µC/OS-II中,有多种方法可以保护任务之间的共享数据和提供任务之间的通讯。
一是利用宏OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()来关闭中断和打开中断。
二是利用函数OSSchedLock()和OSSchekUnlock()对µC/OS-II中的任务调度函数上锁和开锁。
本文将介绍另外三种用于数据共享和任务通讯的方法:
信号量、邮箱和消息队列。
本文将着重介绍了在DSP上任务和中断服务子程序之间是如何进行通讯的。
一个任务或者中断服务子程序可以通过事件控制块ECB来向另外的任务发信号,所有的信号都被看成是事件。
一个任务还可以等待另一个任务或中断服务子程序给它发送信号,只有任务可以等待事件发生,中断服务子程序是不能这样做的。
对于处于等待状态的任务,还可以给它指定一个最长等待时间,以此来防止因为等待的事件没有发生而无限期地等下去。
多个任务可以同时等待同一个事件的发生,当该事件发生后,所有等待该事件的任务中,优先级最高的任务得到了该事件并进入就绪状态,准备执行。
这些事件,可以是信号量、邮箱或者消息队列等。
关键词:
µC/OS-II;信号量;邮箱;消息队列;DSP
目录
1课题综述1
1.1课题性质和目的1
1.2课题设计任务1
1.3课题设计要求1
1.4课题背景1
2系统分析2
2.1CCS简介2
2.2µC/OS-II简介3
2.3信号量3
2.4邮箱4
2.5消息队列5
3系统详细设计8
3.1建立一个邮箱,OSMboxCreate()8
3.2等待一个邮箱中的消息,OSMboxPend()9
3.3发送一个消息到邮箱中,OSMboxPost()11
3.4无等待地从邮箱中得到一个消息,OSMboxAccept()13
3.5查询一个邮箱的状态,OSMboxQuery()14
3.6用邮箱作二值信号量15
3.7用邮箱实现延时,而不使用OSTimeDly()15
4源程序16
总结20
参考文献21
1课题综述
1.1课题性质和目的
《DSP技术及应用》课程设计是一项重要的实践性教育环节,是学生在校期间必须接受的一项工程训练。
在课程设计过程中,在教师指导下,运用工程的方法,通过一个简单课题的设计练习,可使学生初步体验定点DSP应用系统的设计过程、设计要求、完成的工作内容和具体的设计方法,了解必须提交的各项工程文件,也达到巩固、充实和综合运用所学知识解决实际问题的目的。
通过课程设计,应能加强学生如下能力的培养:
独立工作能力和创造力;综合运用专业及基础知识,解决实际工程技术问题的能力;查阅图书资料、产品手册和各种工具书的能力;工程绘图的能力;程序编写的能力;编写技术报告和编制技术资料的能力。
1.2课题设计任务
布置一定难度的设计课题,要求独立或协作完成。
在设计过程中,养成良好的电路设计、编程习惯,学会分析实际问题能力,系统设计的能力和系统综合的能力,锻炼代码调试技巧,撰写设计文档。
1.3课题设计要求
在课程教学大纲主要内容和基本要求的基础上,结合课程体系的实际需求及学生的实践能力、实验条件等外部因素,选择恰当的设计课题,既体现教学目的,又能反映实际教学情况。
安排充足的实践课时,配备专门指导老师。
学生完成设计任务后,应按要求提交课程设计报告,课程设计报告力求规范化。
1.4课题背景
在µC/OS-II中,有多种方法可以保护任务之间的共享数据和提供任务之间的通讯。
一是利用宏OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()来关闭中断和打开中断。
当两个任务或者一个任务和一个中断服务子程序共享某些数据时,可以采用OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()及OS_CPU.H。
二是利用函数OSSchedLock()和OSSchekUnlock()对µC/OS-II中的任务调度函数上锁和开锁。
用这种方法也可以实现数据的共享,给调度器上锁和开锁。
本文将介绍另外三种用于数据共享和任务通讯的方法:
信号量、邮箱和消息队列。
本文将着重介绍了任务和中断服务子程序之间是如何进行通讯的。
一个任务或者中断服务子程序可以通过事件控制块ECB来向另外的任务发信号,所有的信号都被看成是事件。
一个任务还可以等待另一个任务或中断服务子程序给它发送信号,只有任务可以等待事件发生,中断服务子程序是不能这样做的。
对于处于等待状态的任务,还可以给它指定一个最长等待时间,以此来防止因为等待的事件没有发生而无限期地等下去。
多个任务可以同时等待同一个事件的发生,当该事件发生后,所有等待该事件的任务中,优先级最高的任务得到了该事件并进入就绪状态,准备执行。
这些事件,可以是信号量、邮箱或者消息队列等。
当事件控制块是一个信号量时,任务可以等待它,也可以给它发送消息。
2系统分析
2.1CCS简介
CCS是一种针对TMS320系列DSP的集成开发环境,在Windows操作系统下,采用图形接口界面,提供有环境配置、源文件编辑、程序调试、跟踪和分析等工具。
CCS有两种工作模式,即软件仿真器模式:
可以脱离DSP芯片,在PC机上模拟DSP的指令集和工作机制,主要用于前期算法实现和调试。
硬件在线编程模式:
可以实时运行在DSP芯片上,与硬件开发板相结合在线编程和调试应用程序。
CCS的开发系统主要由以下组件构成:
TMS320C54x集成代码产生工具;CCS集成开发环境;DSP/BIOS实时内核插件及其应用程序接口API;实时数据交换的RTDX插件以及相应的程序接口API;由TI公司以外的第三方提供的各种应用模块插件。
CCS的功能十分强大,它集成了代码的编辑、编译、链接和调试等诸多功能,而且支持C/C++和汇编的混合编程,其主要功能如下:
具有集成可视化代码编辑界面,用户可通过其界面直接编写C、汇编、.cmd文件等;含有集成代码生成工具,包括汇编器、优化C编译器、链接器等,将代码的编辑、编译、链接和调试等诸多功能集成到一个软件环境中;高性能编辑器支持汇编文件的动态语法加亮显示,使用户很容易阅读代码,发现语法错误;工程项目管理工具可对用户程序实行项目管理。
在生成目标程序和程序库的过程中,建立不同程序的跟踪信息,通过跟踪信息对不同的程序进行分类管理;基本调试工具具有装入执行代码、查看寄存器、存储器、反汇编、变量窗口等功能,并支持C源代码级调试;断点工具,能在调试程序的过程中,完成硬件断点、软件断点和条件断点的设置;探测点工具,可用于算法的仿真,数据的实时监视等;分析工具,包括模拟器和仿真器分析,可用于模拟和监视硬件的功能、评价代码执行的时钟;数据的图形显示工具,可以将运算结果用图形显示,包括显示时域/频域波形、眼图、星座图、图像等,并能进行自动刷新;提供GEL工具。
利用GEL扩展语言,用户可以编写自己的控制面板/菜单,设置GEL菜单选项,方便直观地修改变量,配置参数等。
CCS支持多DSP的调试,支持RTDX技术,可在不中断目标系统运行的情况下,实现DSP与其他应用程序的数据交换,提供DSP/BIOS工具,增强对代码的实时分析能力。
2.2µC/OS-II简介
uC/OS是一种免费公开源代码、结构小巧、具有可剥夺实时内核的实时操作系统。
μC/OS-II的前身是μC/OS,最早出自于1992年美国嵌入式系统专家JeanJ.Labrosse在《嵌入式系统编程》杂志的5月和6月刊上刊登的文章连载,并把μC/OS的源码发布在该杂志的BBS上。
μC/OS和μC/OS-II是专门为计算机的嵌入式应用设计的,绝大部分代码是用C语言编写的。
CPU硬件相关部分是用汇编语言编写的、总量约200行的汇编语言部分被压缩到最低限度,为的是便于移植到任何一种其它的CPU上。
用户只要有标准的ANSI的C交叉编译器,有汇编器、连接器等软件工具,就可以将μC/OS-II嵌人到开发的产品中。
μC/OS-II具有执行效率高、占用空间小、实时性能优良和可扩展性强等特点,最小内核可编译至2KB。
μC/OS-II已经移植到了几乎所有知名的CPU上。
严格地说uC/OS-II只是一个实时操作系统内核,它仅仅包含了任务调度,任务管理,时间管理,内存管理和任务间的通信和同步等基本功能。
没有提供输入输出管理,文件系统,网络等额外的服务。
但由于uC/OS-II良好的可扩展性和源码开放,这些非必须的功能完全可以由用户自己根据需要分别实现。
uC/OS-II目标是实现一个基于优先级调度的抢占式的实时内核,并在这个内核之上提供最基本的系统服务,如信号量,邮箱,消息队列,内存管理,中断管理等。
2.3信号量
µC/OS-II中的信号量由两部分组成:
一个是信号量的计数值,它是一个16位的无符号整数(0到65,535之间);另一个是由等待该信号量的任务组成的等待任务表。
用户要在OS_CFG.H中将OS_SEM_EN开关量常数置成1,这样µC/OS-II才能支持信号量。
在使用一个信号量之前,首先要建立该信号量,也即调用OSSemCreate()函数,对信号量的初始计数值赋值。
该初始值为0到65,535之间的一个数。
如果信号量是用来表示一个或者多个事件的发生,那么该信号量的初始值应设为0。
如果信号量是用于对共享资源的访问,那么该信号量的初始值应设为1(例如,把它当作二值信号量使用)。
最后,如果该信号量是用来表示允许任务访问n个相同的资源,那么该初始值显然应该是n,并把该信号量作为一个可计数的信号量使用。
µC/OS-II提供了5个对信号量进行操作的函数。
它们是:
OSSemCreate(),OSSemPend(),OSSemPost(),OSSemAccept()和OSSemQuery()函数。
图2-1说明了任务、中断服务子程序和信号量之间的关系。
图中用钥匙或者旗帜的符号来表示信号量:
如果信号量用于对共享资源的访问,那么信号量就用钥匙符号。
符号旁边的数字N代表可用资源数。
对于二值信号量,该值就是1;如果信号量用于表示某事件的发生,那么就用旗帜符号。
这时的数字N代表事件已经发生的次数。
从图2-1中可以看出OSSemPost()函数可以由任务或者中断服务子程序调用,而OSSemPend()和OSSemQuery()函数只能有任务程序调用。
2.4邮箱
邮箱是µC/OS-II中另一种通讯机制,它可以使一个任务或者中断服务子程序向另一个任务发送一个指针型的变量。
该指针指向一个包含了特定“消息”的数据结构。
为了在µC/OS-II中使用邮箱,必须将OS_CFG.H中的OS_MBOX_EN常数置为1。
使用邮箱之前,必须先建立该邮箱。
该操作可以通过调用OSMboxCreate()函数来完成,并且要指定指针的初始值。
一般情况下,这个初始值是NULL,但也可以初始化一个邮箱,使其在最开始就包含一条消息。
如果使用邮箱的目的是用来通知一个事件的发生(发送一条消息),那么就要初始化该邮箱为NULL,因为在开始时,事件还没有发生。
如果用户用邮箱来共享某些资源,那么就要初始化该邮箱为一个非NULL的指针。
在这种情况下,邮箱被当成一个二值信号量使用。
µC/OS-II提供了5种对邮箱的操作:
OSMboxCreate(),OSMboxPend(),OSMboxPost(),OSMboxAccept()和OSMboxQuery()函数。
图2-2描述了任务、中断服务子程序和邮箱之间的关系,这里用符号“I”表示邮箱。
邮箱包含的内容是一个指向一条消息的指针。
一个邮箱只能包含一个这样的指针(邮箱为满时),或者一个指向NULL的指针(邮箱为空时)。
从图2-2可以看出,任务或者中断服务子程序可以调用函数OSMboxPost(),但是只有任务可以调用函数OSMoxPend()和函数OSMboxQuery()。
图2-2任务、中断服务子程序和邮箱之间的关系
2.5消息队列
消息队列是µC/OS-II中另一种通讯机制,它可以使一个任务或者中断服务子程序向另一个任务发送以指针方式定义的变量。
因具体的应用有所不同,每个指针指向的数据结构变量也有所不同。
为了使用µC/OS-II的消息队列功能,需要在OS_CFG.H文件中,将OS_Q_EN常数设置为1,并且通过常数OS_MAX_QS来决定µC/OS-II支持的最多消息队列数。
在使用一个消息队列之前,必须先建立该消息队列。
这可以通过调用OSQCreate()函数,并定义消息队列中的单元数(消息数)来完成。
µC/OS-II提供了7个对消息队列进行操作的函数:
OSQCreate(),OSQPend(),OSQPost(),OSQPostFront(),OSQAccept(),OSQFlush()和OSQQuery()函数。
图2-3是任务、中断服务子程序和消息队列之间的关系。
其中,消息队列的符号很像多个邮箱。
实际上,我们可以将消息队列看作时多个邮箱组成的数组,只是它们共用一个等待任务列表。
每个指针所指向的数据结构是由具体的应用程序决定的。
N代表了消息队列中的总单元数。
当调用OSQPend()或者OSQAccept()之前,调用N次OSQPost()或者OSQPostFront()就会把消息队列填满。
从图2-4中可以看出,一个任务或者中断服务子程序可以调用OSQPost(),OSQPostFront(),OSQFlush()或者OSQAccept()函数。
但是,只有任务可以调用OSQPend()和OSQQuery()函数。
图2-3任务、中断服务子程序和消息队列之间的关系
图2-4是实现消息队列所需要的各种数据结构。
这里也需要事件控制块来记录等待任务列表,而且,事件控制块可以使多个消息队列的操作和信号量操作、邮箱操作相同的代码。
当建立了一个消息队列时,一个队列控制块(OS_Q结构,见OS_Q.C文件)也同时被建立,并通过OS_EVENT中的.OSEventPtr域链接到对应的事件控制块。
在建立一个消息队列之前,必须先定义一个含有与消息队列最大消息数相同个数的指针数组。
数组的起始地址以及数组中的元素数作为参数传递给OSQCreate()函数。
事实上,如果内存占用了连续的地址空间,也没有必要非得使用指针数组结构。
文件OS_CFG.H中的常数OS_MAX_QS定义了在µC/OS-II中可以使用的最大消息队列数,这个值最小应为2。
µC/OS-II在初始化时建立一个空闲的队列控制块链表,如图2-5所示。
图2-4用于消息队列的数据结构
图2-5空闲队列控制块链表
队列控制块是一个用于维护消息队列信息的数据结构,它包含了以下的一些域。
这里,仍然在各个变量前加入一个[.]来表示它们是数据结构中的一个域。
.OSQPtr在空闲队列控制块中链接所有的队列控制块。
一旦建立了消息队列,该域就不再有用了。
而.OSQStart是指向消息队列的指针数组的起始地址的指针。
用户应用程序在使用消息队列之前必须先定义该数组。
.OSQEnd是指向消息队列结束单元的下一个地址的指针。
该指针使得消息队列构成一个循环的缓冲区。
.OSQIn是指向消息队列中插入下一条消息的位置的指针。
当.OSQIn和.OSQEnd相等时,.OSQIn被调整指向消息队列的起始单元。
.OSQOut是指向消息队列中下一个取出消息位置的指针。
当.OSQOut和.OSQEnd相等时,.OSQOut被调整指向消息队列的起始单元。
.OSQSize是消息队列中总的单元数。
该值是在建立消息队列时由用户应用程序决定的。
在µC/OS-II中,该值最大可以是65535。
.OSQEntries是消息队列中当前的消息数量。
当消息队列是空的时,该值为0。
当消息队列满了以后,该值和.OSQSize值一样。
在消息队列刚刚建立时,该值为0。
消息队列最根本的部分是一个循环缓冲区,如图2-6。
其中的每个单元包含一个指针。
队列未满时,.OSQIn指向下一个存放消息的地址单元。
如果队列已满(.OSQEntries与.OSQSize相等),.OSQIn则与.OSQOut指向同一单元。
如果在.OSQIn指向的单元插入新的指向消息的指针,就构成FIFO(First-In-First-Out)队列。
相反,如果在.OSQOut指向的单元的下一个单元插入新的指针,就构成LIFO队列(Last-In-First-Out)。
当.OSQEntries和.OSQSize相等时,说明队列已满。
消息指针总是从.OSQOut指向的单元取出。
指针.OSQStart和.OSQEnd定义了消息指针数组的头尾,以便在.OSQIn和.OSQOut到达队列的边缘时,进行边界检查和必要的指针调整,实现循环功能。
图2-6消息队列是一个由指针组成的循环缓冲区
3系统详细设计
3.1建立一个邮箱,OSMboxCreate()
下面是OSMboxCreate()函数的源代码。
在于事件控制块的类型被设置成OS_EVENT_TYPE_MBOX,以及使用.OSEventPtr域来容纳消息指针,而不是使用.OSEventCnt域。
OSMboxCreate()函数的返回值是一个指向事件控制块的指针。
这个指针在调用函数OSMboxPend(),OSMboxPost(),OSMboxAccept()和OSMboxQuery()时使用。
因此,该指针可以看作是对应邮箱的句柄。
值得注意的是,如果系统中已经没有事件控制块可用,函数OSMboxCreate()将返回一个NULL指针。
邮箱一旦建立,是不能被删除的。
比如,如果有任务正在等待一个邮箱的信息,这时删除该邮箱,将有可能产生灾难性的后果。
OS_EVENT*OSMboxCreate(void*msg)
{
OS_EVENT*pevent;
OS_ENTER_CRITICAL();
pevent=OSEventFreeList;
if(OSEventFreeList!
=(OS_EVENT*)0)
{
OSEventFreeList=(OS_EVENT*)OSEventFreeList->OSEventPtr;
}
OS_EXIT_CRITICAL();
if(pevent!
=(OS_EVENT*)0)
{
pevent->OSEventType=OS_EVENT_TYPE_MBOX;
pevent->OSEventPtr=msg;
OSEventWaitListInit(pevent);
}
return(pevent);
}
3.2等待一个邮箱中的消息,OSMboxPend()
下面是OSMboxPend()函数的源代码。
OSMboxPend()首先检查该事件控制块是由OSMboxCreate()函数建立的。
当.OSEventPtr域是一个非NULL的指针时,说明该邮箱中有可用的消息。
这种情况下,OSMboxPend()函数将该域的值复制到局部变量msg中,然后将.OSEventPtr置为NULL。
这正是我们所期望的,也是执行OSMboxPend()函数最快的路径。
如果此时邮箱中没有消息是可用的(.OSEventPtr域是NULL指针),OSMboxPend()函数检查它的调用者是否是中断服务子程序。
和OSSemPend()函数一样,不能在中断服务子程序中调用OSMboxPend(),因为中断服务子程序是不能等待的。
这里的代码同样是为了以防万一.但是,如果邮箱中有可用的消息,即使从中断服务子程序中调用OSMboxPend()函数,也一样是成功的。
如果邮箱中没有可用的消息,OSMboxPend()的调用任务就被挂起,直到邮箱中有了消息或者等待超时。
当有其它的任务向该邮箱发送了消息后(或者等待时间超时),这时,该任务再一次成为最高优先级任务,OSSched()返回。
这时,OSMboxPend()函数要检查是否有消息被放到该任务的任务控制块中。
如果有,那么该次函数调用成功,对应的消息被返回到调用函数。
void*OSMboxPend(OS_EVENT*pevent,INT16Utimeout,INT8U*err)
{
void*msg;
OS_ENTER_CRITICAL();
if(pevent->OSEventType!
=OS_EVENT_TYPE_MBOX)
{
OS_EXIT_CRITICAL();
*err=OS_ERR_EVENT_TYPE;
return((void*)0);
}
msg=pevent->OSEventPtr;
if(msg!
=(void*)0)
{
pevent->OSEventPtr=(void*)0;
OS_EXIT_CRITICAL();
*err=OS_NO_ERR;
}
elseif(OSIntNesting>0)
{
OS_EXIT_CRITICAL();
*err=OS_ERR_PEND_ISR;
}
else
{
OSTCBCur->OSTCBStat|=OS_STAT_MBOX;
OSTCBCur->OSTCBDly=timeout;
OSEventTaskWait(pevent);
OS_EXIT_CRITICAL();
OSSched();
OS_ENTER_CRITICAL();
if((msg=OSTCBCur->OSTCBMsg)!
=(void*)0)
{
OSTCBCur->OSTCBMsg=(void*)0;
OSTCBCur->OSTCBStat=OS_STAT_RDY;
OSTCBCur->OSTCBEventPtr=(OS_EVENT*)0;
OS_EXIT_CRITICAL();
*err=OS_NO_ERR;
}
elseif(OSTCBCur->OSTCBStat&OS_STAT_MBOX)
{
OSEventTO(pevent);
OS_EXIT_CRITICAL();
msg=(void*)0;
*err=OS_TIMEOUT;
}
else{
msg=pevent->OSEventPtr;
pevent->OSEventPtr=(void*)0;
OSTCBCur->OSTCBEventPtr=(OS_EVENT*)0;
OS_EXIT_CRITICAL();
*err=OS_NO_ERR;
}
}
return(msg);
}
在OSMboxPend()函数中,通过检查任务控制块中的.OSTCBStat域中的OS_STAT_MBOX位,可以知道是否等待超时。
如果该域被置1,说明任务等待已经超时。
这时,通过调用函数OSEventTo()可以将任务从邮箱的等待
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- dsp 数字信号 处理 课程设计 报告