hjr-嵌入式:ucos-II 信号量、互斥信号量、消息邮箱

因为ucos-II是基于多任务的操作系统

本节说一下任务中很重要的三个概念

在之前先科普几个重要函数:

 

(1)OSStart();:操作系统多任务启动

(2)OSinit()l:操作系统全局变量,数据结构初始化,建立空闲、统计、定时任务

(1)创建了几个用户任务,优先级

OSTaskCreate(任务处理函数首地址指针,任务处理函数传参,任务分配的堆栈栈顶指针,任务优先级号);

有几句该程序就有几个任务

优先级号代表该任务优先级,从0开始,越小优先级越高,ucos-II总运行进入就绪态的优先级最高的任务

OSTimeOlg(1)//延时一个时钟节拍

OSTimeDlyHMSM(0,0,1,0)//延时  时,分,秒,毫秒

下面正式开始

1、信号量的使用方法

(1)定义事件指针,例如”OS_EVENT *LedSem”;这里LedSem为一个事件指针

(2)调用OSSemCreate();函数创建信号量

例如”LedSem = OSSemCreate(0);”,此时LedSem被装入一个信号量,初始计算数值为0,。

(4)在另一个任务中请求该信号量,例如”OSSedPend(LedSem,0,&err)”

#include <stdio.h>
#include"includes.h"
#include"system.h"//宏定义PIO_LED_BASE
#include"altera_avalon_pio_regs.h"
OS_STK task1_stk[TASK_STACKSIZE];//为要创建的任务定义堆栈
OS_STK task2_stk[TASK_STACKSIZE];
#define TASK1_PRIORITY 1//为创建的任务指定优先级号
#define TASK1_PRIORITY 2
#define TASK_STACKSIZE 2048//定义2048kb
OS_EVENT *RandomSem;//定义一个指向信号量RandomSem的指针(定义事件指针)
INT8U err;
void task1(void* pdata)//定义用户任务1{
	while(1)//必须死循环{
		OSSemPend(RandomSem,0,&err);//请求信号量[os_sem.c中]
		IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE,0X00);//#define PIO_LED_BASE 0X4001000
		usleep(500000);//任务挂起500000微秒,即0.5秒
		OSSePost(RandomSem);//在一个任务中周期性地释放信号量
		OSTimeDly(1);//调用该函数的任务被延时一个时钟节拍([位于os_time.c中])
	}
}
void task2(void* pdata)//定义用户任务2{
	while(1)//必须死循环{
		OSSemPend(RandomSem,0,&err);//请求信号量[os_sem.c中]
		IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE,0X0F);//#define PIO_LED_BASE 0X4001000
		usleep(500000);//任务挂起500000微秒,即0.5秒
		OSSePost(RandomSem);//在一个任务中周期性地释放信号量
		OSTimeDly(1);//调用该函数的任务被延时一个时钟节拍([位于os_time.c中])
	}
}
int main(void){
	OSInit();//对ucos-II操作系统初始化(初始化全局变量或数据结构,建立空闲任务、统计任务和定时任务等系统服务)
	//调用OSStart函数之前必调用该函数(位于os_core.c中)
	IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE,0X00);
	RandomSem = OSSemCreate(1);//调用OSSemCreate();创建信号量,信号量初始值设置为1
	//创建用户任务[los_task.c]
	OSTaskCrateExt(task1,//函数名 NULL,//函数参数
				   (void *)&task1_stk[TASK_STACKSIZE-1],//栈顶指针
				   TASK1_PRIORITY,//优先级号TASK1_PRIORITY,//任务ID号
				   task1_stk,//栈底指针ASK_STACKSIZE,//栈大小
				   NULL,//用户定义空间指针0//任务选项参数
	);
	OSTaskCrateExt(task1,//函数名
				   NULL,//函数参数(void *)&task2_stk[TASK_STACKSIZE-1],//栈顶指针
				   TASK2_PRIORITY,//优先级号TASK2_PRIORITY,//任务ID号
				   task2_stk,//栈底指针TASK_STACKSIZE,//栈大小
				   NULL,//用户定义空间指针0//任务选项参数
	);
	OSStart();//启动ucos-II操作系统多任务调度[必须在调用OSInit函数后使用(位于os_core.c)中]
}

2、互斥信号量使用方法

(1)定义事件控制模块指针,例如”OS_EVENT *LedMutex;”

(2)指定一个优先级号mx_prio作为优先级继承优先级(PIP)

该PIP的数值应小于所有请求共享资源的任务的优先级号

(3)调用OSMutexCreate();函数创建互斥信号量,例如”LedMutex = OSMutexCreate (mx_prio,&err);”

(4)如果一个任务要使用共享资源,应先调用OSMutexPend();函数请求互斥信号量,请求道互斥信号量后,使用共享资源,使用完后再调用OSMutexPost();函数释放互斥信号量

#include <stdio.h>
#include"includes.h"
#include"system.h"//宏定义PIO_LED_BASE
#include"altera_avalon_pio_regs.h"
OS_STK task1_stk[TASK_STACKSIZE];//为要创建的任务定义堆栈
OS_STK task2_stk[TASK_STACKSIZE];
#define TASK1_PRIORITY 1//为创建的任务指定优先级号
#define TASK1_PRIORITY 2

#define TASK_STACK_SIZE 512;
OS_EVENT *RandomMutex;
INT8U my_prio = 2;//my_pario称为优先级继承优先级(pip)[os_mutex.c中]
INT8U my_err;
void task1(void* pdata);
void task2(void* pdata);
void main(void){
	OSInit();
	IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE,0X00);
	RandomMutex = OSMutexCreate(my_prio,&my_err);//创建并初始化一个互斥信号量,用于使任务获得对共享资源的独占式访问权
	//必须确保my_prio的值小于所有可能请求互斥信号量的任务优先级
	OSTaskCreate(task1,//函数名NULL,//函数参数&task1_stk[TASK_STACK_SIZE-1],//栈顶指针
				 TASK1_PRIO//优先级号
	);
	OSTaskCreate(task2,//函数名NULL,//函数参数&task2_stk[TASK_STACK_SIZE-1],//栈顶指针
				 TASK2_PRIO//优先级号
	);
	OSStart();
}
void task1(void* pdata){
	while(1){
		OSMutexPend(RandomMutex,0,&my_err);//请求互斥信号量[os_mutex.c中]
		IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE,0Xff);
		OSTimeDlyHMSM(0,0,1,0);
		OSMutexPost(RandomMutex);//释放互斥信号量
	}
}
void task1(void* pdata){
	while(1){
		OSMutexPend(RandomMutex,0,&my_err);//请求互斥信号量[os_mutex.c中]
		IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE,0X00);
		OSTimeDlyHMSM(0,0,1,0);
		OSMutexPost(RandomMutex);//释放互斥信号量
	}
}

3、消息邮箱使用方法

(1)定义事件指针,例如”OS_EVENT *LedMbox;”,这里LedMbox为一个事件指针

(2)使用消息邮箱前,必须调用OSMboxCreate();函数创建消息邮箱

例如”LedMbox = OSMboxCreate(NULL);”,表示创建一个空的消息邮箱,也可以在创建消息邮箱时给消息赋初值。

(3)首先在一个任务中定义一个一维数组,例如”INI8U myMessage[80];”,然后将要传递出去的消息存入myMessage数组中,例如”strcpy((char *)myMessage,’Led 1 Light’)”,接着调用函数OSMboxPost周期地释放该消息。例如”OSMboxPost(LedMbox,(void *)&myMessage[0]);”

(4)首先在另一个任务中定义局部一维指针变量存放收到的消息,例如”void *pmsg;”,然后调用函数OSMboxPend请求消息邮箱中的消息。

例如”pmsg = OSMboxPend(edMbox,OS_TICKS_PER_SEC,&err);”,这样消息”Led 1 Light!”就从别的任务传递到该任务中来。

 

#include <stdio.h>
#include"includes.h"
#include"system.h"//宏定义PIO_LED_BASE
#include"altera_avalon_pio_regs.h"
OS_STK task1_stk[TASK_STACKSIZE];//为要创建的任务定义堆栈
OS_STK task2_stk[TASK_STACKSIZE];
#define TASK1_PRIORITY 1//为创建的任务指定优先级号
#define TASK1_PRIORITY 2

#define TASK_STACKSIZE 2048
OS_EVENT *RandomSem;
INT8U my_err;
OS_EVENT *MsgMbox;//定义消息邮箱指针
void task1(void* pdata){
	int txMsg = 0;
	while(1){
		OSMboxPost(MsgMbox,&txMsg);//向邮箱传入消息(发消息给TASK2)[os_mbox.c]
		txMsg++;
		if(txMsg == 5)txMsg = 0;
		OSTimeDlyHMSM(0,0,1,0);
	}
}
void task2(void* pdata){
	int * rxMsg = 0;
	while(1){
		rxMsg = (int *)OSMboxPend(MsgMbox,0,&my_err);//向邮箱请求消息[os_mbox.c](返回消息指针,据该指针可获取消息)
		IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE,*rxMsg);
		OSTimeDlyHMSM(0,0,1,0);
	}
}
int main(void){
	OSInit();
	IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_BASE,0X00);
	MsgBox = OSMboxCreate((void *)0);//创建并初始化一个消息邮箱(如果参数不为空,则新建的邮箱将包含消息)[os_mbox.c]
	OSTaskCreate(task1,//建立任务NULL,&task1_stk[TASK_STACKSIZE-1],TASK1_PRIOPITY);
	OSTaskCreate(task2,//建立任务NULL,&task2_stk[TASK_STACKSIZE-1],TASK2_PRIOPITY);
	OSStart();
	return 0;
}

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
嵌入实时操作系统(RTOS)的事件处理是嵌入系统中非常重要的一部分,它可以处理各种事件,例如定时器事件、外部中断事件、通信事件等。下面我来介绍一个简单的事件实验,以帮助您更好地理解事件处理。 在这个实验中,我们将使用基于ARM Cortex-M4内核的STM32F4Discovery开发板和FreeRTOS实时操作系统。我们将使用板载的LED和按钮模拟事件,当按下按钮时,LED会闪烁一次。 首先,我们需要在Keil MDK中创建一个新的工程,并将FreeRTOS添加到工程中。然后,我们需要配置FreeRTOS的内存管理器和调度器,并创建任务、队列和信号。 接下来,我们将创建一个任务来处理事件。该任务将等待一个事件标志,当事件标志被设置时,该任务将处理相应的事件并将标志清除。任务代码如下: ``` void vEventTask( void *pvParameters ) { for( ;; ) { // Wait for event flag ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); // Handle event vHandleEvent(); // Clear event flag xEventGroupClearBits( xEventGroup, EVENT_FLAG ); } } ``` 在该任务中,我们使用了FreeRTOS提供的事件标志和任务通知机制来等待事件。当事件标志被设置时,任务将执行vHandleEvent()函数来处理事件,并将标志清除。 现在,我们需要创建一个中断服务例程来处理按键事件。当按键被按下时,中断服务例程将设置事件标志,以通知任务处理事件。中断服务例程代码如下: ``` void EXTI0_IRQHandler( void ) { // Clear interrupt flag EXTI_ClearITPendingBit( EXTI_Line0 ); // Set event flag xEventGroupSetBitsFromISR( xEventGroup, EVENT_FLAG, NULL ); } ``` 在该中断服务例程中,我们使用了FreeRTOS提供的事件标志和中断安全函数来设置事件标志。当事件标志被设置时,任务将被唤醒并处理事件。 最后,我们需要在主函数中创建任务并启动FreeRTOS调度器。主函数代码如下: ``` int main( void ) { // Initialize hardware vHardwareInit(); // Create event group xEventGroup = xEventGroupCreate(); // Create event task xTaskCreate( vEventTask, "Event Task", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL ); // Start FreeRTOS scheduler vTaskStartScheduler(); // Should never get here for( ;; ); } ``` 在该主函数中,我们创建了一个事件组和一个事件任务,并启动了FreeRTOS调度器。 现在,我们可以编译和下载程序到STM32F4Discovery开发板中。当按下开发板上的按钮时,LED将闪烁一次,表示事件已经被处理。 通过这个简单的事件实验,我们可以更好地理解嵌入实时操作系统中的事件处理机制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

架构师小侯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值