uCOSii信号量的作用 |
您所在的位置:网站首页 › 浮点数sem › uCOSii信号量的作用 |
uCOSii中信号量的作用: 在创建信号量时,Sem_Event=OSSemCreate(1)用于分时复用共享资源; Sem_Event=OSSemCreate(0)用于中断和任务间同步或任务之间的同步。 具体在使用时,需要灵活运用。在访问共享资源时,我喜欢用互斥信号量,爱好不同而已。 一、uCOSii信号量用于对共享资源的保护 1、举例如下: 任务1每隔1小时,将DATA1数据保存到EEPROM。 任务2每隔2小时,将DATA2数据保存到EEPROM。 可见,任务1和任务2都要使用公共资源“写EEPROM”。为了防止使用冲突,我们通过发送信号量和接收信号量来分时操作“写EEPROM”,保证写入正确。 当然也可以放在一个任务里去做,为了了解怎么使用共享资源,这里使用信号量来实现。 2、实现方法: 1)、声明事件指针 OS_EVENT *Sem_Event;//定义一个事件指针 2)、任务1 //函数功能:任务1每隔1小时,将DATA1数据保存到EEPROM。 void SaveDATA1_Task(void *pdata) { u16 SaveDATA1_Cnt; u8 Sem_Err; while(1) { OSTimeDlyHMSM(0,0,0,1000);//延时1秒 SaveDATA1_Cnt++; if(SaveDATA1_Cnt >3600)//1小时时间到,保存DATA1 { OSSemPend(Sem_Event,0,&Sem_Err);//等待一个信号量,实现资源保护 EEPROM_U8_Data_Write(DATA1, DATA1_address); OSSemPost(Sem_Event);//发出一个信号量 SaveDATA1_Cnt =0; } } } 3)、任务2 //函数功能:任务2每隔2小时,将DATA2数据保存到EEPROM。 void SaveDATA2_Task(void *pdata) { u16 SaveDATA2_Cnt; u8 Sem_Err; while(1) { OSTimeDlyHMSM(0,0,0,1000);//延时1秒 SaveDATA2_Cnt++; if(SaveDATA2_Cnt >7200)//2小时时间到,保存DATA2 { OSSemPend(Sem_Event,0,&Sem_Err);//等待一个信号量,实现资源保护 EEPROM_U8_Data_Write(DATA2, DATA2_address); OSSemPost(Sem_Event);//发出一个信号量 SaveDATA2_Cnt =0; } } } 4)、启动任务 void Start_Task(void *pdata) { OS_CPU_SR cpu_sr=0; OS_ENTER_CRITICAL(); //进入临界区(无法被中断打断),需要定义cpu_sr变量 Sem_Event=OSSemCreate(1); //创建信号量Sem_Event,设置计数器初始值设置为1,即发送了一个信号量。 OSTaskCreate( SaveDATA1_Task,/* 函数指针*/ (void *)0,/* 建立任务时,传递的参数*/ (OS_STK*)&SaveDATA1_Task_STACK[SaveDATA1_Task_STACK_SIZE-1], /* 指向堆栈任务栈顶的指针*/ SaveDATA1_Task_PRIORITY/* 任务优先级*/ ); OSTaskCreate( SaveDATA2_Task,/* 函数指针*/ (void *)0,/* 建立任务时,传递的参数*/ (OS_STK*)&SaveDATA2_Task_STACK[SaveDATA2_Task_STACK_SIZE-1], /* 指向堆栈任务栈顶的指针*/ SaveDATA2_Task_PRIORITY/* 任务优先级*/ );
OSTaskDel(OS_PRIO_SELF); //删除自己 OS_EXIT_CRITICAL(); //退出临界区(可以被中断打断) } 二、uCOSii使用信号量实现中断和任务之间的同步 1、举例如下: 串口接收一组配置参数,然后将该参数需要保存到EEPROM中。显然,我们不能在中断中写EPPROM,这样会导致串口中断执行时间太长。因此需要分成两个部分实现,一个是串口接收,一个是负责保存参数,同时还要干其他事情。 有人会在某个任务中扫描串口,若收完配置信息立即保存,不用搞这个信号量也实现,实现方法千万种。这里使用信号量实现中断和任务之间的同步,完成中断和任务之间无缝隙对接。 2、实现方法: 1)、声明事件指针 OS_EVENT *Sem_Event;//定义一个事件指针 2)中断 uint8_t UART4HeadFlag; uint8_t UART4_in; //UART4接收缓冲区的输入下标; #define UART4_RCV_buffer_Size 100 //定义UART4接收缓冲区的长度100; uint8_t UART4_RCV_buffer[UART4_RCV_buffer_Size]; //用来存放硬件串口接收到的数据; //(ID=04661219C1677461) //函数功能:USART4中断服务函数 void UART4_IRQHandler(void) { unsigned char temp; (void)temp;//不让temp产生警告 if(USART_GetITStatus(UART4, USART_IT_RXNE) != RESET) { temp=USART_ReceiveData(UART4); //从UART4串口读取一个字节; if(temp==’(’&& UART4HeadFlag==0) { UART4_in =0; UART4HeadFlag=1; } if(UART4HeadFlag==1) { UART4_RCV_buffer[UART4_in]=temp; UART4_in++; } if(temp==’)’&& UART4HeadFlag==1) { UART4_in =0; UART4HeadFlag=0;//接收完成 OSSemPost(Sem_Event);//发出一个信号量 } } if(USART_GetFlagStatus(UART4,USART_FLAG_PE) != RESET) { USART_ReceiveData(UART4);//读串口 USART_ClearFlag(UART4, USART_FLAG_PE); } if(USART_GetFlagStatus(UART4,USART_FLAG_ORE) != RESET) { USART_ReceiveData(UART4);//读串口 USART_ClearFlag(UART4,USART_FLAG_ORE); //清除溢出中断 } if(USART_GetFlagStatus(UART4,USART_FLAG_FE) != RESET) { USART_ReceiveData(UART4);//读串口 USART_ClearFlag(UART4,USART_FLAG_FE); } } 3)、任务1 void Task1(void *pdata) { u8 Sem_Err; while(1) { OSSemPend(Sem_Event,0,&Sem_Err);//等待一个信号量,实现无缝对接 { Save_String_To_EEPROM(UART4_RCV_buffer,UART4_in,ID_address); } } } void LED1_Task(void *pdata) { while(1) { LED1=!LED1;//信号有效 OSTimeDlyHMSM(0,0,0,500);//500毫秒闪烁1次 } } 4)、启动任务 void Start_Task(void *pdata) { OS_CPU_SR cpu_sr=0; OS_ENTER_CRITICAL(); //进入临界区(无法被中断打断),需要定义cpu_sr变量 Sem_Event=OSSemCreate(0); //创建信号量Sem_Event,设置计数器初始值设置为0,即不发送一个信号量 OSTaskCreate( Task1,/* 函数指针*/ (void *)0,/* 建立任务时,传递的参数*/ (OS_STK*)&Task1_STACK[Task1_STACK_SIZE-1], /* 指向堆栈任务栈顶的指针*/ Task1_PRIORITY/* 任务优先级*/ ); OSTaskCreate( LED1_Task,/* 函数指针*/ (void *)0,/* 建立任务时,传递的参数*/ (OS_STK*)&LED1_TASK_STACK[LED1_TASK_STACK_SIZE-1], /* 指向堆栈任务栈顶的指针*/ LED1_TASK_PRIORITY/* 任务优先级*/ ); OSTaskDel(OS_PRIO_SELF); //删除自己 OS_EXIT_CRITICAL(); //退出临界区(可以被中断打断) } 三、uCOSii使用信号量实现任务和任务之间的同步 1、举例如下: 任务1为负责按键触发 任务2负责点灯。 任务1中的按键KEY按下,任务2负责点灯ED1开灯关灯。 使用信号量实现任务与任务之间的同步,完成任务与任务之间无缝隙对接。 2、实现方法: 1)、声明事件指针 OS_EVENT *Sem_Event;//定义一个事件指针 2)、任务1 //函数功能:任务1负责按键触发。 void Key_Task(void *pdata) { u8 Sem_Err; while(1) { if(KEY)OSSemPost(Sem_Event);//发出一个信号量 LED0=!LED0; OSTimeDlyHMSM(0,0,0,500);//500毫秒闪烁1次 } } 3)、任务2 void LED_Task(void *pdata) { u8 Sem_Err; while(1) { OSSemPend(Sem_Event,0,&Sem_Err);//等待一个信号量,实现无缝对接 LED1=!LED1;//信号有效 } } 4)、启动任务 void Start_Task(void *pdata) { OS_CPU_SR cpu_sr=0; OS_ENTER_CRITICAL(); //进入临界区(无法被中断打断),需要定义cpu_sr变量 Sem_Event=OSSemCreate(0); //创建信号量Sem_Event,设置计数器初始值设置为0,即不发送一个信号量 OSTaskCreate( LED_Task,/* 函数指针*/ (void *)0,/* 建立任务时,传递的参数*/ (OS_STK*)&LED_Task_STACK[LED_Task_STACK_SIZE-1], /* 指向堆栈任务栈顶的指针*/ LED_Task_PRIORITY/* 任务优先级*/ ); OSTaskCreate( Key_Task,/* 函数指针*/ (void *)0,/* 建立任务时,传递的参数*/ (OS_STK*)&KEY_TASK_STACK[KEY_TASK_STACK_SIZE-1], /* 指向堆栈任务栈顶的指针*/ KEY_TASK_PRIORITY/* 任务优先级*/ ); OSTaskDel(OS_PRIO_SELF); //删除自己 OS_EXIT_CRITICAL(); //退出临界区(可以被中断打断) } |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |