嵌入式系统设计实验报告

111

实验项目名称:基于ucOS的多任务系统

一、实验目的

(1) 掌握LPC2200(for MagicARM2200)专用工程模板的使用;

(2) 能够在MagicARM2200-S 上运行基于μC/OS-II 操作系统的程序;

(3) 掌握基于μC/OS-II 操作系统的用户程序的编写格式。

二、实验内容及要求

建立三个或三个以上的μC/OS-II 的任务,一个任务用于检测KEY1 按键输入,称之为按键检测任务,另一个任务用于控制蜂鸣器,就称之为蜂鸣器控制任务。还有LED灯任务和电机任务。要求各个任务之间不是独立的,而是有相互关联的,达到多任务间的数据通信和同步的实验要求。

三、实验设备及软件

硬件:PC 机 一台

MagicARM2200-S 教学实验开发平台 一套

软件:Windows98/XP/2000 系统,ADS 1.2 集成开发环境

μC/OS-II 操作系统(V2.52)

四、设计方案

方案一: 建立四个任务:LED灯、按键、电机、蜂鸣器

LED任务:LED灯有不同的花样,由数组中的十六进制数据决定。可通过设计数组的数据来设计出很多的花型。

按键任务:按键任务主要是对按下的键在0到4内计数,再将所计的数通过邮箱发送给LED、电机任务,来控制任务间的通信。

电机任务:电机的转速会不断的改变,电机的转速也是靠按键任务里发送的广播邮箱的值确定的,有五种转速。每次按下一次按键,转速就会改变一次。

蜂鸣器任务:蜂鸣器的响灭是由LED任务里发送的信号量控制的,当LED灯亮完一个周期后就发送一个信号让蜂鸣器响起来,响完后蜂鸣器自己删除信号量,等着LED灯再一次并且发送信号。

这四个任务间都有着相互的交互关系。

方案二: 建立三个任务:LED灯、蜂鸣器、按键 LED任务:LED灯花样在数组中确定,方法很简单,只要改变数组内十六进制的数据后,就可以很简单的控制灯的闪烁方式了, LED显示完一个周期就会继续执行下一个周期,往复循环,直到按下REST键就会停止。

蜂鸣器任务:蜂鸣器可由按键控制,当按键1按下后,蜂鸣器开始鸣叫,鸣叫的次数可由程序控制,延时也同样可控,在本人的设计中,我把鸣响次数设为10.,同样按下REST键就会停止鸣响。

按键任务:按键任务其实就是进行等待按键按下,然后发送信号量给LED任务、蜂鸣器任务。

方案选择:

在我的这个设计中任务之间的联系并不是很紧密,而且每一个状态都很简单的, 通过设置优先级来控制优先发生次序,但是四个功能都是很好的实现了的,但是在调试方案一时,程序老是出不来,电机总是不转,检查了程序,但是最后因为时间有限就放弃了四个任务的,选择了稍微简单的三个任务的程序,虽然简单了一些,但是道理都是一样的。为了更完美一些,我设计了很多种LEDA灯的花型 。相对而言程序比较简单,易懂!适合我们这些初学者。

五﹑实验步骤

在MagicARM2200-S 上运行基于μC/OS-II 操作系统的程序的具体操作步骤如下。 安装ADS 1.2 (PC)

了解ADS 1.2 (PC)

连接EasyJTAG 仿真器和MagicARM2200-S (硬件)

安装EasyJTAG 驱动程序 (PC)

添加工程模板 (PC)

建立项目目录并添加μC/OS源代码和移植代码 (PC)

用工程模板建立工程 (PC)

仿真调试工程 (PC+硬件)

(1) 安装ADS 1.2

运行在ADS 目录下Setup.exe,开始安装ADS1.2。(若已安装过,此步省略)

按照安装软件的提示安装,与其它软件安装操作方法基本一致。

(2) 了解ADS 1.2

使用ADS1.2 建立工程,编译链接设置,调试操作等,更详细的使用方法参考ADS1.2 的在线帮助文档或相关资料。(若已熟悉ADS 1.2,此步省略)

(3) 连接EasyJTAG 仿真器和MagicARM2200-S

将EasyJTAG 仿真器的25 针接口通过并口延长线与PC 机的并口连接,先给

MagicARM2200-S 实验箱供电,再将EasyJTAG 仿真器的20 针接口通过20 PIN 连接电缆接

到MagicARM2200-S 的J3 上。(若已连接好,此步省略)

(4) EasyJTAG 仿真器的安装与应用

若已安装过,此步省略。

(5) 添加工程模板

若已添加过,此步省略。

(6) 建立项目目录并添加μC/OS源代码和移植代码

建立一个项目目录,比如uCOS-II。将μC/OS源代码Source(目录)复制到项目目录, 将移植代码ARM(目录) 复制到项目目录。

将移植的PC 服务代码Arm_Pc 复制到项目目录,使用移植的PC 服务代码,就可以通 过串口向PC 发送显示数据(由EasyARM 软件的DOS 字符窗口显示)。

μC/OS 源代码可以从参考文献[4]的附带光盘上获得。

移植代码ARM 和移植的PC 服务代码Arm_Pc 可以从MagicARM2200-S 的产品配套光 盘上获得。

(7) 用工程模板建立工程

使用LPC2200(for MagicARM2200)专用工程模板建立工程(比如“ARM Executable Image for UCOSII(MagicARM2200)”工程模板),工程存放路径为项目目录下,建立源文件并加入

工程,然后编写程序代码。更改Os_cfg.h 文件,配置μC/OS-II 操作系统。 编译链接工程,若有错误,则修改程序,然后再次编译。

(8) 仿真调试工程

正确设置MagicARM2200-S 的跳线;

启动AXD 进行仿真调试。

六、部分主要代码

方案一程序如下:

#include "config.h"

#include "stdlib.h"

#define KEY1 (1 << 20) /* P0.20 为KEY1 */

#define BEEP (1 << 7) /* P0.7 为蜂鸣器*/

#define LED_OFF() IO1SET=LED_IOCON

#define LED_DISP(dat) LED_OFF(); IO1CLR=((dat)<<LED_ADJ) #define LED_ADJ 16

#define LED_IOCON (0xFF<<LED_ADJ)

#define LEDCON 0x00ff0000 // LED 控制字

#define CYCLE_DATA 200000 // 定义周期

#define DUTY_CYCLE_DATA 20000 // 定义基本占空比参数 #define LED1 1<<16 // P1.16

#define LED2 1<<17 // P1.17

#define LED3 1<<18 // P1.18

#define LED4 1<<19 // P1.19

#define LED5 1<<20 // P1.20

#define LED6 1<<21 // P1.21

#define LED7 1<<22 // P1.22

#define LED8 1<<23 // P1.23

#define TaskStkLengh 64

OS_STK TaskStk0[TaskStkLengh];

OS_STK TaskStk1[TaskStkLengh];

OS_STK TaskStk2[TaskStkLengh];

OS_STK TaskStk3[TaskStkLengh];

void Task0(void *pdata); //Task0 任务

void Task1(void *pdata); //Task0 任务

void Task2(void *pdata); //Task2 任务

void Task3(void *pdata); //Task2 任务

OS_EVENT *semled;

OS_EVENT *sempwm;

OS_EVENT *sembeep;

int main(void)

{

OSInit ();

OSTaskCreate (Task0,(void *)0, &TaskStk0[TaskStkLengh - 1],3); OSTaskCreate (Task2,(void *)0, &TaskStk2[TaskStkLengh - 1],5);

OSTaskCreate (Task3,(void *)0, &TaskStk3[TaskStkLengh - 1],4); OSStart ();

return 0;

}

void Task0(void *pdata)

{

INT8U err;

const uint8 DISP_TAB[24] = {

0xFF,0xEE, 0xDD,0xCC, 0X55,0xBB,0xAA,0x99,0x88,0x77,0x66, 0x55,0xCC, 0x44,0x22,0x11,0x00

,0xFF,0x18, 0x3C,0x7E, 0xFF,0x00,0xFF};

uint8 i;

pdata = pdata;

semled=OSSemCreate(0);

TargetInit ();

PINSEL0 = 0x00000000;

IO0DIR = BEEP;

IO1DIR = LED_IOCON;

LED_OFF();

OSTaskCreate (Task1,(void *)0, &TaskStk1[TaskStkLengh - 1],6); while (1)

{

OSSemPend(semled,0,&err);

for(i=0; i<24; i++)

{

LED_DISP(DISP_TAB[i]);

OSTimeDly(OS_TICKS_PER_SEC);

}

OSSemPost(sempwm);

}

}

void Task1(void *pdata)

{

INT8U err;

pdata = pdata;

sembeep=OSSemCreate(0);

sempwm=OSSemCreate(0);

while(1)

{

OSSemPend(sembeep,0,&err);

OSTimeDly(OS_TICKS_PER_SEC/8);

IO0CLR = BEEP;

OSTimeDly(OS_TICKS_PER_SEC/4); IO0SET = BEEP;

OSTimeDly(OS_TICKS_PER_SEC/2); IO0CLR = BEEP;

OSTimeDly(OS_TICKS_PER_SEC/4); IO0SET = BEEP;

OSTimeDly(OS_TICKS_PER_SEC/8); IO0CLR = BEEP;

OSTimeDly(OS_TICKS_PER_SEC/2); IO0SET = BEEP; }

}

void Task2(void *pdata)

{

pdata = pdata;

IO0DIR&=~KEY1;

while(1)

{

while((IO0PIN & KEY1) != 0)

{

OSTimeDly(OS_TICKS_PER_SEC ); OSSemPost(sembeep);

OSSemPost(sempwm);

}

OSSemPost(semled);

while ((IO0PIN & KEY1) == 0) {

}

}

void Task3 (void *pdata)

{ INT8U err;

uint8 i = 0;

pdata = pdata;

PINSEL1 = 0x01<<10;

IO1DIR = LEDCON;

PWMPR = 0x00;

PWMMCR = 0x02;

PWMMR0 = CYCLE_DATA;

PWMMR5 = DUTY_CYCLE_DATA;

PWMLER = 1 << 0 | 1<< 5;

PWMPCR = 1 << 13;

PWMTCR = 0x09;

while (1)

{

OSSemPend(sempwm, 0, &err);

PWMMR5 = DUTY_CYCLE_DATA*i;

PWMLER = 1 << 0 | 1<< 5;

PWMTCR = 0x09;

i = (i+1)%5;

OSTimeDly(OS_TICKS_PER_SEC*3 );

}

}

方案二程序如下:

#include "config.h"

#include "stdlib.h"

// P0.7 为蜂鸣器的控制I/O

#define BEEP (1<<7)

#define KEY1 (1<<20)

// LED 控制宏函数定义。LED1--LED8 的控制I/O 为P1.16--P1.23

#define LED_ADJ 16

#define LED_IOCON (0xFF<<LED_ADJ)

#define LED_OFF() IO1SET=LED_IOCON

#define LED_DISP(dat) LED_OFF(); IO1CLR=((dat)<<LED_ADJ)

#define TaskStkLengh 100 //定义用户任务堆栈长度

OS_STK TaskStk0[TaskStkLengh]; //Define the Task0 stack 定义用户任务0 的堆栈 OS_STK TaskStk1[TaskStkLengh]; //Define the Task1 stack 定义用户任务1 的堆栈 OS_STK TaskStk2[TaskStkLengh]; //Define the Task2 stack 定义用户任务2 的堆栈

void Task0(void *pdata); //Task0 任务0

void Task1(void *pdata); //Task1 任务1

void Task2(void *pdata); //Task2 任务2

OS_EVENT *Mbox;

int dly;

int main (void)

{

OSInit();

OSTaskCreate (Task0,(void *)0, &TaskStk0[TaskStkLengh - 1], 4);/*创建LED任务*/ OSTaskCreate (Task1,(void *)0, &TaskStk1[TaskStkLengh - 1], 6); /*创建BEEP任务*/ OSTaskCreate (Task2,(void *)0, &TaskStk2[TaskStkLengh - 1], 2); /*创建KEY任务*/

OSStart ();

return 0;

}

/*****************************************************************************************

** Task0 任务0

*****************************************************************************************/

void Task0(void *pdata)

{ const uint8 DISP_TAB[32] = { 0x18,0x3C,0x7E,0xFF,0x7E,0x3C,0x18,0x00,0xAA,0x55,0xAA,0x55,0xCC,0x33,0xCC,0x33,0x99,0x66,0x99,0x66,0x18,0x3C,0x81,0xC3,0x00,0xC3,0x66,0x3C,0x18,0x3C,0x66,0xC3

};

//INT8U err;

//INT16U *pd;

uint8 i;

//pdata = pdata;

TargetInit ();

PINSEL1=0x00000000;

IO0DIR = BEEP; // 设置蜂鸣器控制口为输出

IO0SET = BEEP;

IO1DIR = LED_IOCON; // 设置LED1-LED8 的控制口为输出 LED_OFF();

Mbox=OSMboxCreate(NULL);

while(1)

{

// pd=(INT16U *)OSMboxPend(Mbox,0,&err);

for(i=0;i<32;i++)

{

LED_DISP(DISP_TAB[i]); // 输出LED 显示数据

OSTimeDly(OS_TICKS_PER_SEC/2); // 延时0.5S

}

}

}

/********************TASK1****************************/ void Task1(void *pdata)

{ int i;

INT8U err;

INT16U *pd;

pdata=pdata;

IO0DIR|=BEEP;

while(1) {

pd=(INT16U *)OSMboxPend(Mbox,0,&err);

for(i=0;i<10;i++)

{

IO0CLR=BEEP;

OSTimeDly(50);

IO0SET=BEEP;

OSTimeDly(50);

}

}

}

/********************TASK2**************************/ void Task2(void *pdata)

{

pdata=pdata;

IO0DIR&=~KEY1;

while(1)

{

while((IO0PIN&KEY1)!=0)

{

OSTimeDly(1);

}

OSMboxPostOpt(Mbox,&dly,OS_POST_OPT_BROADCAST);

while((IO0PIN&KEY1)==0)

{

OSTimeDly(1);

}

}

}

六、测试结果

方案一仿真测试后并没有实现理想的设计功能,电机没有转动,可能是软件设计有问题或者是试验箱由问题,功能不齐全了。由于实验考试的时间关系,也没有仔细的花费时间检查,于是我就采取了简单一些的三个任务的程序,实现起来还是很好的,该有的功能也有,而且花型比较好看,满足老师的设计要求。

方案二实现了LED等闪烁、蜂鸣器响、电机转动、按键有效的功能。并且他们之间也存在着一定的关系。

LED灯的花型如下:

○○○●●○○○ ●○●○●○●○

○○●●●●○○ ○●○●○●○●

○●●●●●●○ ●○●○●○●○

●●●●●●●● ○●○●○●○●

○●●●●●●○ ●●○○●●○○

○○●●●●○○ ○○●●○○●●

○○○●●○○○ ●●○○●●○○

○○○○○○○○ ○○●●○○●●

●○○●●○○● ○○○○○○○○

○●●○○●●○ ●●○○○○●●

○○○●●○○○ ○●●○○●●○

○○●●●●○○ ○○●●●●○○

○○○●●○○○ ○○○●●○○○

○○●●●●○○ ○○●●●●○○

●○○○○○○● ○●●○○●●○

●●○○○○●● ●●○○○○●●

七、总结体会

说实话,ARM这门课对于我来说是比较难学和难理解的一门课,在学习当中遇到了很多的问题,对于很多很抽象的概念不理解,但是通过做了好几次的实验,在老师的精心指导和严格要求下,还是掌握了不少的知识,记得刚开始做实验的时候连软件的用起来很吃力,但是通过几次的实验和最后的综合实验,让我掌握了MagicARM2200-S的使用方法,而且对ARM嵌入式系统的知识有了很具体的理解,有利于更好的学习这门课,为以后的学习奠定良好的基础。

这个综合实验是MagicARM2200-S 上运行基于μC/OS-II 操作系统的程序,让我掌握了μC/OS-II程序设计的方法,任务间通信可以通过信号量,消息邮箱和消息队列实现,在本次设计中,我采用了消息邮箱的方法,因为我对这种方法理解的更深。邮箱用来在任务间或中断与任务间传递一个指针,以便任务可以通过指针发送和接受任意类型的数据,一个邮箱只能存放一条消息。邮箱的工作方式有一对一工作方式和多对一工作方式,一对多工作方式。

本来为了更好的完成设计,想实现四个任务的,由于没有及时的调试出来,时间有限,只有选择一个稍微简单一些的设计了,但是设计的思路应该是没有问题的,相信如

果有足够的时间的话一定可以调试出来的。为了使它不是很单调,我设计了很多种花型,希望可以弥补没有完成四个任务的不足。这次的实验让我学会了自学,学会了耐心,学会了请教他人,收获良多,受益匪浅。

相关推荐