补充:
信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。
Semaphore分为单值和多值两种,前者只能被一个线程获得,后者可以被若干个线程获得。
以一个停车场是运作为例。为了简单起见,假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,看门人允许其中三辆不受阻碍的进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车拦,放入一辆,如果又离开两辆,则又可以放入两辆,如此往复。
在这个停车场系统中,车位是公共资源,每辆车好比一个线程,看门人起的就是信号量的作用。
更进一步,信号量的特性如下:信号量是一个非负整数(车位数),所有通过它的线程(车辆)都会将该整数减一(通过它当然是为了使用资源),当该整数值为零时,所有试图通过它的线程都将处于等待状态。在信号量上我们定义两种操作: Wait(等待) 和 Release(释放)。 当一个线程调用Wait(等待)操作时,它要么通过然后将信号量减一,要么一直等下去,直到信号量大于一或超时。Release(释放)实际上是在信号量上执行加操作,对应于车辆离开停车场,该操作之所以叫做“释放”是因为加操作实际上是释放了由信号量守护的资源。
在java中,还可以设置该信号量是否采用公平模式,如果以公平方式执行,则线程将会按到达的顺序(FIFO)执行,如果是非公平,则可以后请求的有可能排在队列的头部。
JDK中定义如下:
Semaphore(int permits, boolean fair)
创建具有给定的许可数和给定的公平设置的Semaphore。
URL: http://blog.csdn.net/oxp7085915/article/details/17377655
代码工作流程:在freertos系统中创建一个二值信号量,并且创建两个任务,任务A:循环输出helloworld,任务B:获取二值信号量,当获取到后设置LED灯亮或灯灭,如果没有获取到则挂起,直到获取到二值信号量。设置按键中断,并在按键中断程序中释放二值信号量。
实验现象:按键按下则LED灯实现亮或灭
/* Kernel includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "timers.h"
#include "xil_printf.h"
#include "xscugic.h"
/* App includes. */
#include "xgpiops.h"
/*
* The following constants map to the XPAR parameters created in the
* xparameters.h file. They are defined here such that a user can easily
* change all the needed parameters in one place.
*/
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
/*
* Following constant define the Input and Output pins.
*/
#define OUTPUT_PIN_LED 55 /* Pin connected to LED/Output */
#define INPUT_PIN_BTN 54 /* Pin connected to LED/Output */
/* Priorities at which the tasks are created. */
#define mainLED_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )
#define mainHELLO_WORLD_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )
/*
* The following are declared globally so they are zeroed.
*/
static XGpioPs Gpio; /* The driver instance for GPIO Device. */
static XScuGic *mXScuGic;
/* Task handle */
xTaskHandle xTask;
/* Semaphore handle */
xSemaphoreHandle xSemaphore_led = NULL;
/*-----------------------------------------------------------*/
static void prvLed_Task( void *pvParameters );
void prvSetGpioHardware(void);
void prvShutdown(void);
static void prvPrintf(void *pvParameters);
int main( void )
{
prvInitializeExceptions();
/* Create Binary Semaphore */
vSemaphoreCreateBinary(xSemaphore_led);
configASSERT( xSemaphore_led );
/* Setup the GPIO Hardware. */
prvSetGpioHardware();
xTaskCreate(prvPrintf,(signed char *)"Hello",configMINIMAL_STACK_SIZE,NULL,mainHELLO_WORLD_TASK_PRIORITY,&xTask);
/* Create the task */
xTaskCreate( prvLed_Task, ( signed char * ) "LED_TASK",
configMINIMAL_STACK_SIZE, NULL,
mainLED_TASK_PRIORITY, &xTask );
/* Starting the scheduler will start the timers running as it is already
been set into the active state. */
vTaskStartScheduler();
/* Should not reach here. */
for( ;; );
}
/*-----------------------------------------------------------*/
static void prvPrintf(void *pvParameters)
{
const portTickType xDelay = 500 / portTICK_RATE_MS;
for( ;; )
{
xil_printf("Hello World\r\n");
vTaskDelay(xDelay);
taskYIELD();
}
}
/*-----------------------------------------------------------*/
static void prvLed_Task( void *pvParameters )
{
unsigned int uiLedFlag = 0;
for (;;)
{
if ( xSemaphoreTake( xSemaphore_led,
( portTickType ) portMAX_DELAY ) == pdTRUE )
{
uiLedFlag ^= 1;
if (uiLedFlag) {
/*
* Set the GPIO Output to High.
*/
XGpioPs_WritePin(&Gpio, OUTPUT_PIN_LED, 0x1);
} else {
/*
* Set the GPIO Output to Low.
*/
XGpioPs_WritePin(&Gpio, OUTPUT_PIN_LED, 0x0);
}
} else {
xil_printf("xSemaphore_led take fail\r\n");
/* Call shutdown */
prvShutdown();
}
}
}
/*-----------------------------------------------------------*/
/*
* GPIO ISR
*/
void vGpioPsISRHandler(void *CallBackRef,int bank,u32 Status)
{
if(bank != 2)
return;
static portBASE_TYPE xHandler;
xHandler=pdFALSE;
XGpioPs *pXGpioPs = (XGpioPs *)CallBackRef;
XGpioPs_IntrDisablePin(pXGpioPs,INPUT_PIN_BTN);
xSemaphoreGiveFromISR(xSemaphore_led,&xHandler);
if(xHandler==pdTRUE)
xil_printf("semaphoreGive\r\n");
XGpioPs_IntrEnablePin(pXGpioPs,INPUT_PIN_BTN);
}
void prvSetGpioHardware( void )
{
int Status;
XGpioPs_Config *ConfigPtr; /* The driver config instance for GPIO Device. */
/*
* Initialize the GPIO driver.
*/
ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
Status = XGpioPs_CfgInitialize(&Gpio, ConfigPtr,
ConfigPtr->BaseAddr);
if (Status != XST_SUCCESS) {
xil_printf("GPIO Initialize failed\n");
}
/*
* Set the direction for the pin to be output and
* Enable the Output enable for the LED Pin.
*/
XGpioPs_SetDirectionPin(&Gpio,INPUT_PIN_BTN,0);
XGpioPs_SetDirectionPin(&Gpio, OUTPUT_PIN_LED, 1);
XGpioPs_SetOutputEnablePin(&Gpio, OUTPUT_PIN_LED, 1);
/*
* Set the GPIO output to be low.
*/
XGpioPs_WritePin(&Gpio, OUTPUT_PIN_LED, 0x0);
/*
* SET BTN INTR
*/
XGpioPs_SetIntrTypePin(&Gpio,INPUT_PIN_BTN,XGPIOPS_IRQ_TYPE_EDGE_RISING);
XGpioPs_SetCallbackHandler(&Gpio,(void*)&Gpio,vGpioPsISRHandler);
XGpioPs_IntrEnablePin(&Gpio,INPUT_PIN_BTN);
}
void prvShutdown( void )
{
vSemaphoreDelete( xSemaphore_led );
vTaskDelete( xTask );
}
/*-----------------------------------------------------------*/
void vApplicationMallocFailedHook( void )
{
/* vApplicationMallocFailedHook() will only be called if
configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook
function that will get called if a call to pvPortMalloc() fails.
pvPortMalloc() is called internally by the kernel whenever a task, queue or
semaphore is created. It is also called by various parts of the demo
application. If heap_1.c or heap_2.c are used, then the size of the heap
available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in
FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used
to query the size of free heap space that remains (although it does not
provide information on how the remaining heap might be fragmented). */
taskDISABLE_INTERRUPTS();
for( ;; );
}
/*-----------------------------------------------------------*/
void vApplicationStackOverflowHook( xTaskHandle *pxTask, signed char *pcTaskName )
{
( void ) pcTaskName;
( void ) pxTask;
/* vApplicationStackOverflowHook() will only be called if
configCHECK_FOR_STACK_OVERFLOW is set to either 1 or 2. The handle and name
of the offending task will be passed into the hook function via its
parameters. However, when a stack has overflowed, it is possible that the
parameters will have been corrupted, in which case the pxCurrentTCB variable
can be inspected directly. */
taskDISABLE_INTERRUPTS();
for( ;; );
}
/*
* GPIO GIC INIT
*/
void vApplicationSetupHardware( void )
{
mXScuGic = (XScuGic *)prvGetInterruptControllerInstance();
XScuGic_Disable(mXScuGic,XPAR_XGPIOPS_0_INTR);
XScuGic_SetPriorityTriggerType(mXScuGic,XPAR_XGPIOPS_0_INTR,0x02,0x01);
XScuGic_Connect(mXScuGic,XPAR_XGPIOPS_0_INTR,(Xil_ExceptionHandler)XGpioPs_IntrHandler,(void*)&Gpio);
XScuGic_Enable(mXScuGic,XPAR_XGPIOPS_0_INTR);
}