最近在研究实时操作系统FreeRTOS。FreeRTOS作为开源的RTOS,源码规模不大,可以供操作系统学习,加上我的STM32 Nano开发板正好可以学习OS。借着五一放假宅家里学习。
实现的FreeRTOSMini源码
FreeRTOS有很强的可配置性和硬件适配性。代码里面有大量的宏定义和宏代码分支,看着比较费解,还有一些汇编和关键操作比较费解。然后融合了其他功能增加初学难度。读源码很久才搞通,为了验证是否理解到位,阉割出一个Mini版的系统,只包含基本的任务调度,最小内核。
本次开发基于FreeRTOS代码阉割。去掉了很多可配置性,实现任务创建和任务调度。理解本次代码的前提是先理前两篇xList数据结构和Heap4内存管理。
使用内核调度任务需要三步: 1.引入InitOS.h头文件后调用InitHardware()初始化硬件环境设置时钟和NVIC等。 2.调用xTaskCreate创建任务,创建任务的内部涉及到tcb内存申请、栈内存申请、初始化任务列表。把创建的任务加入就绪状态列表。 3.调用vTaskStartScheduler启动任务调度。内部先创建空闲任务,然后设置PendSV和SYSTick中断优先级为最低和设置SYSTick的定时频率。然后触发SVC中断启动第一个任务。由PendSVC中断读取pxCurrentTCB的栈信息引导执行进入第一个任务方法。后续就在Systick中断下判断是否需要切换上下文,如果需要切换上下文就在Systick中断里写PendSV中断触发器。PendSV中断处理函数完成OS任务切换。
实现分下面步骤: 1.定义基础类型FreeRTOSBase.h 基础的类型别名和定义都放在这个头文件里面,所有内核文件都直接或者间接引用了该文件。
2.定义FreeRTOSMini.h 定性内核基础数据结构TCB(任务控制块)和基础操作,主要的内核定义在该文件了,重点数据结构就是TCB定义,和基于各种状态列表的调度。
3.定义list.h 定义内核调度依赖list的数据结构和列表基本操作,内核的就绪列表,延迟列表等就是依赖该双向列表实现。
4.实现list.c 实现内核调度的列表,和列表基础操作。
5.定义heap_4.h 定义内存管理的链表结构,堆和基本操作。基于自由块链表管理内存控制。
6.实现heap_4.c 实现内存申请和释放,为内核提供内存申请基础。内核通过pvPortMalloc方法申请内存,通过vPortFree方法释放内存。
7.定义port.h 移植层头文件定性,和硬件移植相关放这里面。中断函数、屏蔽中断、初始化Systick时钟、触发PendSV等。
8.实现port.c 实现OS移植层。内核调度重要的Systick中断、PendSV中断、SVC中断、屏蔽中断、放开中断屏蔽等都在这里面实现。
9.实现FreeRTOSMini.c 基于前面的基础融合内核任务调度,任务调度由此实现。通过创建任务的方法,初始化内存分配、初始化调度列表、构造任务TCB、加入TCB到就绪列表等。通过开启调度方法初始化Systick时钟。触发SVC服务,通过SCV中断引导调度第一个任务,至此OS通过Systick在多个死循环的任务逻辑进行上下文切换来让不同任务调度使用CPU,中断实验MSP栈指针,任务用PSP栈指针,切换上下文时候PendSV逻辑通过MSP在主栈执行,在PendSV里面压栈当前任务的寄存器值到PSP指向的当前任务栈,然后切换当前任务指针,再出栈切换后任务的压栈寄存器值,在退出PendSV时候PSP和寄存器值已经换成切换的新任务的值了。就这样一直在Systick时钟节拍下判断是否需要切换上下文,需要切换上下文就触发PendSV异常进行上下文切换。这个代码和以上共同构造Mini内核。后面部分就是使用和测试内核的部分了。
10.定义InitOS.h 定义初始化OS硬件的操作,方便使用。
11.实现InitOS.c 实现操作系统的硬件初始化工作。初始化时钟等。
12.定义led.h 定义led的操作和初始化。
13.定义led.c 实现led操作逻辑。
14.定义beep.h 定义蜂鸣器操作。
15.实现beep.c 实现蜂鸣器操作。
16.实现main.c 测试OS的任务调度
具体的就只能看代码理解了。每个概念都够一个讲解了。TC、Systick、Nvic、PendSV、SVC、屏蔽中断、切换上下文和保存现场等。
实现代码如下:
1.定义基础类型FreeRTOSBase.h
#ifndef __FreeRTOSBase
#define __FreeRTOSBase
#include <stdlib.h>
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
typedef void (*TaskFunction_t)(void*);
typedef unsigned short int uint16_t;
#define configSTACK_DEPTH_TYPE uint16_t
typedef unsigned int uint32_t;
#define portSTACK_TYPE uint32_t
typedef portSTACK_TYPE StackType_t;
typedef uint32_t TickType_t;
typedef unsigned char uint8_t;
#define pdFALSE ( ( BaseType_t ) 0 )
#define pdTRUE ( ( BaseType_t ) 1 )
#define pdPASS ( pdTRUE )
#define pdFAIL ( pdFALSE )
#define PRIVILEGED_FUNCTION
#define PRIVILEGED_DATA
#define portBYTE_ALIGNMENT 8
#define portBYTE_ALIGNMENT_MASK ( 0x0007 )
#define mtCOVERAGE_TEST_MARKER()
#define portPOINTER_SIZE_TYPE uint32_t
#define portINITIAL_XPSR ( 0x01000000 )
#define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL )
#define portNVIC_SHPR3_REG ( *( ( volatile uint32_t * ) 0xe000ed20 ) )
#define portNVIC_PENDSV_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )
#define portNVIC_SYSTICK_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )
#define portNVIC_SYSTICK_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000e010 ) )
#define portNVIC_SYSTICK_LOAD_REG ( *( ( volatile uint32_t * ) 0xe000e014 ) )
#define portNVIC_SYSTICK_CURRENT_VALUE_REG ( *( ( volatile uint32_t * ) 0xe000e018 ) )
#define portNVIC_SYSTICK_CLK_BIT ( 1UL << 2UL )
#define portNVIC_SYSTICK_INT_BIT ( 1UL << 1UL )
#define portNVIC_SYSTICK_ENABLE_BIT ( 1UL << 0UL )
#define portNVIC_INT_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
#define portSY_FULL_READ_WRITE ( 15 )
#define tskIDLE_PRIORITY ((UBaseType_t ) 0U)
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
#endif
2.定义FreeRTOSMini.h
#ifndef __FreeRTOSMini
#define __FreeRTOSMini
#include <stdlib.h>
#include "FreeRTOSBase.h"
#include "stm32f10x_it.h"
#include "stm32f10x_nvic.h"
#include "list.h"
#define configCPU_CLOCK_HZ ( ( unsigned long ) 72000000 )
#define configTICK_RATE_HZ ( ( TickType_t ) 100 )
#define configTOTAL_HEAP_SIZE (( size_t) (17*1024))
#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15
#define configMAX_PRIORITIES ( 32 )
#define configKERNEL_INTERRUPT_PRIORITY 255
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 191
typedef struct tskTaskControlBlock
{
volatile StackType_t* pxTopOfStack;
ListItem_t xStateListItem;
ListItem_t xEventListItem;
UBaseType_t uxPriority;
StackType_t* pxStack;
char pcTaskName[16];
UBaseType_t uxCriticalNesting;
UBaseType_t uxTCBNumber;
UBaseType_t uxTaskNumber;
UBaseType_t uxBasePriority;
UBaseType_t uxMutexesHeld;
uint8_t ucStaticallyAllocated;
uint8_t ucDelayAborted;
int iTaskErrno;
} tskTCB;
typedef tskTCB TCB_t;
typedef struct tskTaskControlBlock* TaskHandle_t;
#define prvAddTaskToReadyList(pxTCB) \
taskRECORD_READY_PRIORITY((pxTCB)->uxPriority); \
\
listINSERT_END(&(pxReadyTasksLists[(pxTCB)->uxPriority]), &((pxTCB)->xStateListItem));
BaseType_t xTaskCreate(TaskFunction_t pxTaskCode,
const char* const pcName,
const configSTACK_DEPTH_TYPE usStackDepth,
void* const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t* const pxCreatedTask);
static void prvInitialiseNewTask(TaskFunction_t pxTaskCode,
const char* const pcName,
const uint32_t ulStackDepth,
void* const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t* const pxCreatedTask,
TCB_t* pxNewTCB);
void prvTaskExitError(void);
static void prvAddNewTaskToReadyList(TCB_t* pxNewTCB);
static void prvInitialiseTaskLists(void) PRIVILEGED_FUNCTION;
static void prvResetNextTaskUnblockTime(void);
void vTaskSuspendAll(void);
BaseType_t xTaskResumeAll(void);
void vTaskStartScheduler(void);
BaseType_t xTaskIncrementTick(void);
void vPortExitCritical(void);
static void vPortSetBASEPRI(uint32_t ulBASEPRI);
void vTaskSwitchContext(void);
static void prvIdleTask(void* pvParameters);
BaseType_t xPortStartScheduler(void);
void prvStartFirstTask(void);
void vTaskDelay(const TickType_t xTicksToDelay);
static void prvAddCurrentTaskToDelayedList(TickType_t xTicksToWait,
const BaseType_t xCanBlockIndefinitely);
#endif
3.定义list.h
#ifndef __list
#define __list
#include <stdlib.h>
#include "FreeRTOSBase.h"
struct xLIST;
struct xLIST_ITEM
{
volatile TickType_t xItemValue;
struct xLIST_ITEM* volatile pxNext;
struct xLIST_ITEM* volatile pxPrevious;
void* pvOwner;
struct xLIST* volatile pxContainer;
};
typedef struct xLIST_ITEM ListItem_t;
struct xMINI_LIST_ITEM
{
volatile TickType_t xItemValue;
struct xLIST_ITEM* volatile pxNext;
struct xLIST_ITEM* volatile pxPrevious;
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;
typedef struct xLIST
{
volatile UBaseType_t uxNumberOfItems;
ListItem_t* volatile pxIndex;
MiniListItem_t xListEnd;
} List_t;
#define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( ( &( ( pxList )->xListEnd ) )->pxNext->pvOwner )
#define listLIST_IS_EMPTY(pxList) (((pxList)->uxNumberOfItems == (UBaseType_t )0) ? pdTRUE : pdFALSE)
#define listSET_LIST_ITEM_OWNER(pxListItem, pxOwner) (( pxListItem )->pvOwner = (void *)(pxOwner))
#define listSET_LIST_ITEM_VALUE(pxListItem, xValue) ((pxListItem)->xItemValue = (xValue))
#define listGET_ITEM_VALUE_OF_HEAD_ENTRY(pxList) (((pxList)->xListEnd).pxNext->xItemValue )
#define listGET_LIST_ITEM_VALUE(pxListItem) ((pxListItem)->xItemValue)
#define listLIST_ITEM_CONTAINER( pxListItem ) ( ( pxListItem )->pxContainer )
#define listCURRENT_LIST_LENGTH(pxList) ((pxList)->uxNumberOfItems)
#define listGET_OWNER_OF_NEXT_ENTRY(pxTCB,pxList) \
{ \
List_t * const pxConstList = (pxList); \
\
(pxConstList)->pxIndex = (pxConstList)->pxIndex->pxNext; \
\
if((void *) (pxConstList)->pxIndex ==(void *) &((pxConstList)->xListEnd)) \
{ \
(pxConstList)->pxIndex=(pxConstList)->pxIndex->pxNext; \
} \
\
(pxTCB)=(pxConstList)->pxIndex->pvOwner; \
}
#define listINSERT_END( pxList, pxNewListItem ) \
{ \
ListItem_t * const pxIndex = (pxList)->pxIndex; \
(pxNewListItem)->pxNext = pxIndex; \
(pxNewListItem)->pxPrevious = pxIndex->pxPrevious; \
\
pxIndex->pxPrevious->pxNext = (pxNewListItem); \
pxIndex->pxPrevious = (pxNewListItem); \
\
(pxNewListItem)->pxContainer = (pxList); \
\
((pxList)->uxNumberOfItems)++; \
}
#define listREMOVE_ITEM(pxItemToRemove) \
{ \
\
List_t * const pxList = (pxItemToRemove)->pxContainer; \
\
\
( pxItemToRemove)->pxNext->pxPrevious = (pxItemToRemove)->pxPrevious; \
\
( pxItemToRemove)->pxPrevious->pxNext = (pxItemToRemove)->pxNext; \
\
if(pxList->pxIndex == (pxItemToRemove)) \
{ \
pxList->pxIndex = (pxItemToRemove)->pxPrevious; \
} \
\
(pxItemToRemove)->pxContainer = NULL; \
\
(pxList->uxNumberOfItems)--; \
}
void vListInitialiseItem(ListItem_t* const pxItem);
void vListInitialise(List_t* const pxList);
void vListInsert(List_t* const pxList, ListItem_t* const pxNewListItem);
UBaseType_t uxListRemove(ListItem_t* const pxItemToRemove);
#endif
4.实现list.c
#include "list.h"
void vListInitialiseItem(ListItem_t* const pxItem)
{
pxItem->pxContainer = NULL;
}
void vListInitialise(List_t* const pxList)
{
pxList->pxIndex = (ListItem_t*)&(pxList->xListEnd);
pxList->xListEnd.xItemValue = portMAX_DELAY;
pxList->xListEnd.pxNext = (ListItem_t*)&(pxList->xListEnd);
pxList->xListEnd.pxPrevious = (ListItem_t*)&(pxList->xListEnd);
pxList->uxNumberOfItems = (UBaseType_t)0U;
}
void vListInsert(List_t* const pxList, ListItem_t* const pxNewListItem)
{
ListItem_t* pxIterator;
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
if (xValueOfInsertion == portMAX_DELAY)
{
pxIterator = pxList->xListEnd.pxPrevious;
}
else
{
for (pxIterator = (ListItem_t*)&(pxList->xListEnd); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext)
{
}
}
pxNewListItem->pxNext = pxIterator->pxNext;
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
pxNewListItem->pxPrevious = pxIterator;
pxIterator->pxNext = pxNewListItem;
pxNewListItem->pxContainer = pxList;
(pxList->uxNumberOfItems)++;
}
UBaseType_t uxListRemove(ListItem_t* const pxItemToRemove)
{
List_t* const pxList = pxItemToRemove->pxContainer;
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
if (pxList->pxIndex == pxItemToRemove)
{
pxList->pxIndex = pxItemToRemove->pxPrevious;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
pxItemToRemove->pxContainer = NULL;
(pxList->uxNumberOfItems)--;
return pxList->uxNumberOfItems;
}
5.定义heap_4.h
#ifndef __heap4
#define __heap4
void* pvPortMalloc(size_t xWantedSize);
void vPortFree(void* pv);
#endif
6.实现heap_4.c
#include "FreeRTOSMini.h"
#include "heap_4.h"
#define heapMINIMUM_BLOCK_SIZE ((size_t) ( xHeapStructSize << 1))
#define heapBITS_PER_BYTE ((size_t) 8)
#if (configAPPLICATION_ALLOCATED_HEAP == 1)
extern uint8_t ucHeap[configTOTAL_HEAP_SIZE];
#else
PRIVILEGED_DATA static uint8_t ucHeap[configTOTAL_HEAP_SIZE];
#endif
typedef struct A_BLOCK_LINK
{
struct A_BLOCK_LINK* pxNextFreeBlock;
size_t xBlockSize;
} BlockLink_t;
static void prvInsertBlockIntoFreeList(BlockLink_t* pxBlockToInsert) PRIVILEGED_FUNCTION;
static void prvHeapInit(void) PRIVILEGED_FUNCTION;
static const size_t xHeapStructSize = (sizeof(BlockLink_t) + ((size_t)(portBYTE_ALIGNMENT - 1))) & ~((size_t)portBYTE_ALIGNMENT_MASK);
PRIVILEGED_DATA static BlockLink_t xStart, * pxEnd = NULL;
PRIVILEGED_DATA static size_t xFreeBytesRemaining = 0U;
PRIVILEGED_DATA static size_t xMinimumEverFreeBytesRemaining = 0U;
PRIVILEGED_DATA static size_t xNumberOfSuccessfulAllocations = 0;
PRIVILEGED_DATA static size_t xNumberOfSuccessfulFrees = 0;
PRIVILEGED_DATA static size_t xBlockAllocatedBit = 0;
void* pvPortMalloc(size_t xWantedSize)
{
BlockLink_t* pxBlock, * pxPreviousBlock, * pxNewBlockLink;
void* pvReturn = NULL;
vTaskSuspendAll();
{
if (pxEnd == NULL)
{
prvHeapInit();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
if ((xWantedSize & xBlockAllocatedBit) == 0)
{
if ((xWantedSize > 0) && ((xWantedSize + xHeapStructSize) > xWantedSize))
{
xWantedSize += xHeapStructSize;
if ((xWantedSize & portBYTE_ALIGNMENT_MASK) != 0x00)
{
if ((xWantedSize + (portBYTE_ALIGNMENT - (xWantedSize & portBYTE_ALIGNMENT_MASK)))
> xWantedSize)
{
xWantedSize += (portBYTE_ALIGNMENT - (xWantedSize & portBYTE_ALIGNMENT_MASK));
}
else
{
xWantedSize = 0;
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
xWantedSize = 0;
}
if ((xWantedSize > 0) && (xWantedSize <= xFreeBytesRemaining))
{
pxPreviousBlock = &xStart;
pxBlock = xStart.pxNextFreeBlock;
while ((pxBlock->xBlockSize < xWantedSize) && (pxBlock->pxNextFreeBlock != NULL))
{
pxPreviousBlock = pxBlock;
pxBlock = pxBlock->pxNextFreeBlock;
}
if (pxBlock != pxEnd)
{
pvReturn = (void*)(((uint8_t*)pxPreviousBlock->pxNextFreeBlock) + xHeapStructSize);
pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
if ((pxBlock->xBlockSize - xWantedSize) > heapMINIMUM_BLOCK_SIZE)
{
pxNewBlockLink = (void*)(((uint8_t*)pxBlock) + xWantedSize);
pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
pxBlock->xBlockSize = xWantedSize;
prvInsertBlockIntoFreeList(pxNewBlockLink);
}
else
{
mtCOVERAGE_TEST_MARKER();
}
xFreeBytesRemaining -= pxBlock->xBlockSize;
if (xFreeBytesRemaining < xMinimumEverFreeBytesRemaining)
{
xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
pxBlock->xBlockSize |= xBlockAllocatedBit;
pxBlock->pxNextFreeBlock = NULL;
xNumberOfSuccessfulAllocations++;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
(void)xTaskResumeAll();
return pvReturn;
}
void vPortFree(void* pv)
{
uint8_t* puc = (uint8_t*)pv;
BlockLink_t* pxLink;
if (pv != NULL)
{
puc -= xHeapStructSize;
pxLink = (void*)puc;
if ((pxLink->xBlockSize & xBlockAllocatedBit) != 0)
{
if (pxLink->pxNextFreeBlock == NULL)
{
pxLink->xBlockSize &= ~xBlockAllocatedBit;
vTaskSuspendAll();
{
xFreeBytesRemaining += pxLink->xBlockSize;
prvInsertBlockIntoFreeList(((BlockLink_t*)pxLink));
xNumberOfSuccessfulFrees++;
}
(void)xTaskResumeAll();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
size_t xPortGetFreeHeapSize(void)
{
return xFreeBytesRemaining;
}
size_t xPortGetMinimumEverFreeHeapSize(void)
{
return xMinimumEverFreeBytesRemaining;
}
void vPortInitialiseBlocks(void)
{
}
static void prvHeapInit(void)
{
BlockLink_t* pxFirstFreeBlock;
uint8_t* pucAlignedHeap;
size_t uxAddress;
size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;
uxAddress = (size_t)ucHeap;
if ((uxAddress & portBYTE_ALIGNMENT_MASK) != 0)
{
uxAddress += (portBYTE_ALIGNMENT - 1);
uxAddress &= ~((size_t)portBYTE_ALIGNMENT_MASK);
xTotalHeapSize -= uxAddress - (size_t)ucHeap;
}
pucAlignedHeap = (uint8_t*)uxAddress;
xStart.pxNextFreeBlock = (void*)pucAlignedHeap;
xStart.xBlockSize = (size_t)0;
uxAddress = ((size_t)pucAlignedHeap) + xTotalHeapSize;
uxAddress -= xHeapStructSize;
uxAddress &= ~((size_t)portBYTE_ALIGNMENT_MASK);
pxEnd = (void*)uxAddress;
pxEnd->xBlockSize = 0;
pxEnd->pxNextFreeBlock = NULL;
pxFirstFreeBlock = (void*)pucAlignedHeap;
pxFirstFreeBlock->xBlockSize = uxAddress - (size_t)pxFirstFreeBlock;
pxFirstFreeBlock->pxNextFreeBlock = pxEnd;
xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
xBlockAllocatedBit = ((size_t)1) << ((sizeof(size_t) * heapBITS_PER_BYTE) - 1);
}
static void prvInsertBlockIntoFreeList(BlockLink_t* pxBlockToInsert)
{
BlockLink_t* pxIterator;
uint8_t* puc;
for (pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock)
{
}
puc = (uint8_t*)pxIterator;
if ((puc + pxIterator->xBlockSize) == (uint8_t*)pxBlockToInsert)
{
pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
pxBlockToInsert = pxIterator;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
puc = (uint8_t*)pxBlockToInsert;
if ((puc + pxBlockToInsert->xBlockSize) == (uint8_t*)pxIterator->pxNextFreeBlock)
{
if (pxIterator->pxNextFreeBlock != pxEnd)
{
pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
}
else
{
pxBlockToInsert->pxNextFreeBlock = pxEnd;
}
}
else
{
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
}
if (pxIterator != pxBlockToInsert)
{
pxIterator->pxNextFreeBlock = pxBlockToInsert;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
7.定义port.h
#ifndef __port
#define __port
#include "FreeRTOSMini.h"
void xPortSysTickHandler(void);
__asm void xPortPendSVHandler(void);
__asm void vPortSVCHandler(void);
void vPortRaiseBASEPRI(void);
void vPortClearBASEPRIFromISR(void);
void vPortSetupTimerInterrupt(void);
StackType_t* pxPortInitialiseStack(StackType_t* pxTopOfStack,
TaskFunction_t pxCode,
void* pvParameters);
#define portYIELD() \
{ \
\
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
\
__dsb( portSY_FULL_READ_WRITE ); \
__isb( portSY_FULL_READ_WRITE ); \
}
#endif
8.实现port.c
#include "port.h"
void xPortSysTickHandler(void)
{
vPortRaiseBASEPRI();
{
if (xTaskIncrementTick() != pdFALSE)
{
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
}
}
vPortClearBASEPRIFromISR();
}
__asm void xPortPendSVHandler(void)
{
extern uxCriticalNesting;
extern pxCurrentTCB;
extern vTaskSwitchContext;
PRESERVE8
mrs r0, psp
isb
ldr r3, =pxCurrentTCB
ldr r2, [r3]
stmdb r0 !, { r4 - r11 }
str r0, [r2]
stmdb sp !, { r3, r14 }
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr basepri, r0
dsb
isb
bl vTaskSwitchContext
mov r0, #0
msr basepri, r0
ldmia sp !, { r3, r14 }
ldr r1, [r3]
ldr r0, [r1]
ldmia r0 !, { r4 - r11 }
msr psp, r0
isb
bx r14
nop
}
__asm void vPortSVCHandler(void)
{
extern pxCurrentTCB;
PRESERVE8
ldr r3, = pxCurrentTCB
ldr r1, [r3]
ldr r0, [r1]
ldmia r0 !, { r4 - r11 }
msr psp, r0
isb
mov r0, # 0
msr basepri, r0
orr r14, # 0xd
bx r14
}
void vPortRaiseBASEPRI(void)
{
uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
__asm
{
msr basepri, ulNewBASEPRI
dsb
isb
}
}
void vPortClearBASEPRIFromISR(void)
{
__asm
{
msr basepri, # 0
}
}
void vPortSetupTimerInterrupt(void)
{
portNVIC_SYSTICK_CTRL_REG = 0UL;
portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
portNVIC_SYSTICK_LOAD_REG = (configCPU_CLOCK_HZ / configTICK_RATE_HZ) - 1UL;
portNVIC_SYSTICK_CTRL_REG = (portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT);
}
StackType_t* pxPortInitialiseStack(StackType_t* pxTopOfStack,
TaskFunction_t pxCode,
void* pvParameters)
{
pxTopOfStack--;
*pxTopOfStack = portINITIAL_XPSR;
pxTopOfStack--;
*pxTopOfStack = ((StackType_t)pxCode) & portSTART_ADDRESS_MASK;
pxTopOfStack--;
*pxTopOfStack = (StackType_t)prvTaskExitError;
pxTopOfStack -= 5;
*pxTopOfStack = (StackType_t)pvParameters;
pxTopOfStack -= 8;
return pxTopOfStack;
}
9.实现FreeRTOSMini.c
#include "FreeRTOSMini.h"
#include "heap_4.h"
#include "port.h"
PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = (UBaseType_t)0U;
PRIVILEGED_DATA TCB_t* volatile pxCurrentTCB = NULL;
PRIVILEGED_DATA static List_t pxReadyTasksLists[configMAX_PRIORITIES];
PRIVILEGED_DATA static List_t xDelayedTaskList1;
PRIVILEGED_DATA static List_t xDelayedTaskList2;
PRIVILEGED_DATA static List_t* volatile pxDelayedTaskList;
PRIVILEGED_DATA static List_t* volatile pxOverflowDelayedTaskList;
PRIVILEGED_DATA static List_t xPendingReadyList;
PRIVILEGED_DATA static volatile TickType_t xTickCount = (TickType_t)0;
PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = (TickType_t)0U;
PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = (UBaseType_t)pdFALSE;
PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE;
PRIVILEGED_DATA static volatile BaseType_t xYieldPending = pdFALSE;
PRIVILEGED_DATA static volatile TickType_t xPendedTicks = (TickType_t)0U;
PRIVILEGED_DATA static UBaseType_t uxTaskNumber = (UBaseType_t)0U;
PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = (BaseType_t)0;
PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle = NULL;
PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY;
const volatile UBaseType_t uxTopUsedPriority = configMAX_PRIORITIES - 1U;
#define taskRECORD_READY_PRIORITY(uxPriority) \
{ \
if((uxPriority)>uxTopReadyPriority) \
{ \
uxTopReadyPriority = (uxPriority); \
} \
}
BaseType_t xTaskCreate(TaskFunction_t pxTaskCode,
const char* const pcName,
const configSTACK_DEPTH_TYPE usStackDepth,
void* const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t* const pxCreatedTask)
{
TCB_t* pxNewTCB;
BaseType_t xReturn;
StackType_t* pxStack;
pxStack = pvPortMalloc((((size_t)usStackDepth) * sizeof(StackType_t)));
if (pxStack != NULL)
{
pxNewTCB = (TCB_t*)pvPortMalloc(sizeof(TCB_t));
if (pxNewTCB != NULL)
{
pxNewTCB->pxStack = pxStack;
}
else
{
vPortFree(pxStack);
}
}
else
{
pxNewTCB = NULL;
}
if (pxNewTCB != NULL)
{
prvInitialiseNewTask(pxTaskCode, pcName, (uint32_t)usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB);
prvAddNewTaskToReadyList(pxNewTCB);
xReturn = pdPASS;
}
else
{
xReturn = -1;
}
return xReturn;
}
static void prvInitialiseNewTask(TaskFunction_t pxTaskCode,
const char* const pcName,
const uint32_t ulStackDepth,
void* const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t* const pxCreatedTask,
TCB_t* pxNewTCB)
{
StackType_t* pxTopOfStack;
UBaseType_t x;
pxTopOfStack = &(pxNewTCB->pxStack[ulStackDepth - (uint32_t)1]);
pxTopOfStack = (StackType_t*)(((portPOINTER_SIZE_TYPE)pxTopOfStack) & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK)));
if (pcName != NULL)
{
for (x = (UBaseType_t)0; x < (UBaseType_t)16; x++)
{
pxNewTCB->pcTaskName[x] = pcName[x];
if (pcName[x] == (char)0x00)
{
break;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
pxNewTCB->pcTaskName[16 - 1] = '\0';
}
else
{
pxNewTCB->pcTaskName[0] = 0x00;
}
if (uxPriority >= (UBaseType_t)configMAX_PRIORITIES)
{
uxPriority = (UBaseType_t)configMAX_PRIORITIES - (UBaseType_t)1U;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
pxNewTCB->uxPriority = uxPriority;
pxNewTCB->uxBasePriority = uxPriority;
pxNewTCB->uxMutexesHeld = 0;
vListInitialiseItem(&(pxNewTCB->xStateListItem));
vListInitialiseItem(&(pxNewTCB->xEventListItem));
listSET_LIST_ITEM_OWNER(&(pxNewTCB->xStateListItem), pxNewTCB);
listSET_LIST_ITEM_VALUE(&(pxNewTCB->xEventListItem), (TickType_t)configMAX_PRIORITIES - (TickType_t)uxPriority);
listSET_LIST_ITEM_OWNER(&(pxNewTCB->xEventListItem), pxNewTCB);
pxNewTCB->ucDelayAborted = pdFALSE;
pxNewTCB->pxTopOfStack = pxPortInitialiseStack(pxTopOfStack, pxTaskCode, pvParameters);
if (pxCreatedTask != NULL)
{
*pxCreatedTask = (TaskHandle_t)pxNewTCB;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
void vTaskSuspendAll(void)
{
++uxSchedulerSuspended;
}
void prvTaskExitError(void)
{
vPortRaiseBASEPRI();
for (; ; )
{
}
}
void vPortEnterCritical(void)
{
vPortRaiseBASEPRI();
uxCriticalNesting++;
}
static void prvAddNewTaskToReadyList(TCB_t* pxNewTCB)
{
vPortEnterCritical();
{
uxCurrentNumberOfTasks++;
if (pxCurrentTCB == NULL)
{
pxCurrentTCB = pxNewTCB;
if (uxCurrentNumberOfTasks == (UBaseType_t)1)
{
prvInitialiseTaskLists();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
if (xSchedulerRunning == pdFALSE)
{
if (pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority)
{
pxCurrentTCB = pxNewTCB;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
uxTaskNumber++;
pxNewTCB->uxTCBNumber = uxTaskNumber;
prvAddTaskToReadyList(pxNewTCB);
}
vPortExitCritical();
if (xSchedulerRunning != pdFALSE)
{
if (pxCurrentTCB->uxPriority < pxNewTCB->uxPriority)
{
portYIELD();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
static void prvInitialiseTaskLists(void)
{
UBaseType_t uxPriority;
for (uxPriority = (UBaseType_t)0U; uxPriority < (UBaseType_t)configMAX_PRIORITIES; uxPriority++)
{
vListInitialise(&(pxReadyTasksLists[uxPriority]));
}
vListInitialise(&xDelayedTaskList1);
vListInitialise(&xDelayedTaskList2);
vListInitialise(&xPendingReadyList);
pxDelayedTaskList = &xDelayedTaskList1;
pxOverflowDelayedTaskList = &xDelayedTaskList2;
}
BaseType_t xTaskResumeAll(void)
{
TCB_t* pxTCB = NULL;
BaseType_t xAlreadyYielded = pdFALSE;
vPortEnterCritical();
{
--uxSchedulerSuspended;
if (uxSchedulerSuspended == (UBaseType_t)pdFALSE)
{
if (uxCurrentNumberOfTasks > (UBaseType_t)0U)
{
while (listLIST_IS_EMPTY(&xPendingReadyList) == pdFALSE)
{
pxTCB = listGET_OWNER_OF_HEAD_ENTRY((&xPendingReadyList));
listREMOVE_ITEM(&(pxTCB->xEventListItem));
listREMOVE_ITEM(&(pxTCB->xStateListItem));
prvAddTaskToReadyList(pxTCB);
if (pxTCB->uxPriority >= pxCurrentTCB->uxPriority)
{
xYieldPending = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
if (pxTCB != NULL)
{
prvResetNextTaskUnblockTime();
}
{
TickType_t xPendedCounts = xPendedTicks;
if (xPendedCounts > (TickType_t)0U)
{
do
{
if (xTaskIncrementTick() != pdFALSE)
{
xYieldPending = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
--xPendedCounts;
} while (xPendedCounts > (TickType_t)0U);
xPendedTicks = 0;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
if (xYieldPending != pdFALSE)
{
portYIELD();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
vPortExitCritical();
return xAlreadyYielded;
}
static void prvResetNextTaskUnblockTime(void)
{
if (listLIST_IS_EMPTY(pxDelayedTaskList) != pdFALSE)
{
xNextTaskUnblockTime = portMAX_DELAY;
}
else
{
xNextTaskUnblockTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY(pxDelayedTaskList);
}
}
void vPortExitCritical(void)
{
uxCriticalNesting--;
if (uxCriticalNesting == 0)
{
vPortSetBASEPRI(0);
}
}
static void vPortSetBASEPRI(uint32_t ulBASEPRI)
{
__asm
{
msr basepri, ulBASEPRI
}
}
#define taskSWITCH_DELAYED_LISTS() \
{ \
List_t * pxTemp; \
\
pxTemp = pxDelayedTaskList; \
pxDelayedTaskList = pxOverflowDelayedTaskList; \
pxOverflowDelayedTaskList = pxTemp; \
xNumOfOverflows++; \
prvResetNextTaskUnblockTime(); \
}
BaseType_t xTaskIncrementTick(void)
{
TCB_t* pxTCB;
TickType_t xItemValue;
BaseType_t xSwitchRequired = pdFALSE;
if (uxSchedulerSuspended == (UBaseType_t)pdFALSE)
{
const TickType_t xConstTickCount = xTickCount + (TickType_t)1;
xTickCount = xConstTickCount;
if (xConstTickCount == (TickType_t)0U)
{
taskSWITCH_DELAYED_LISTS();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
if (xConstTickCount >= xNextTaskUnblockTime)
{
for (; ; )
{
if (listLIST_IS_EMPTY(pxDelayedTaskList) != pdFALSE)
{
xNextTaskUnblockTime = portMAX_DELAY;
break;
}
else
{
pxTCB = listGET_OWNER_OF_HEAD_ENTRY(pxDelayedTaskList);
xItemValue = listGET_LIST_ITEM_VALUE(&(pxTCB->xStateListItem));
if (xConstTickCount < xItemValue)
{
xNextTaskUnblockTime = xItemValue;
break;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
listREMOVE_ITEM(&(pxTCB->xStateListItem));
if (listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem)) != NULL)
{
listREMOVE_ITEM(&(pxTCB->xEventListItem));
}
else
{
mtCOVERAGE_TEST_MARKER();
}
prvAddTaskToReadyList(pxTCB);
if (pxTCB->uxPriority >= pxCurrentTCB->uxPriority)
{
xSwitchRequired = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
}
if (listCURRENT_LIST_LENGTH(&(pxReadyTasksLists[pxCurrentTCB->uxPriority])) > (UBaseType_t)1)
{
xSwitchRequired = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
if (xYieldPending != pdFALSE)
{
xSwitchRequired = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
++xPendedTicks;
}
return xSwitchRequired;
}
#define taskSELECT_HIGHEST_PRIORITY_TASK() \
{ \
UBaseType_t uxTopPriority = uxTopReadyPriority; \
\
\
while(listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopPriority ]))) \
{ \
--uxTopPriority; \
} \
\
\
listGET_OWNER_OF_NEXT_ENTRY(pxCurrentTCB, &(pxReadyTasksLists[uxTopPriority])); \
uxTopReadyPriority = uxTopPriority; \
}
void vTaskSwitchContext(void)
{
if (uxSchedulerSuspended != (UBaseType_t)pdFALSE)
{
xYieldPending = pdTRUE;
}
else
{
xYieldPending = pdFALSE;
taskSELECT_HIGHEST_PRIORITY_TASK();
}
}
void vTaskStartScheduler(void)
{
BaseType_t xReturn;
xReturn = xTaskCreate(prvIdleTask,"IDLE",120,(void*)NULL,0,&xIdleTaskHandle);
if (xReturn == pdPASS)
{
vPortRaiseBASEPRI();
xNextTaskUnblockTime = portMAX_DELAY;
xSchedulerRunning = pdTRUE;
xTickCount = (TickType_t)0;
if (xPortStartScheduler() != pdFALSE)
{
}
else
{
}
}
else
{
}
}
static void prvIdleTask(void* pvParameters)
{
(void)pvParameters;
for (; ; )
{
if (listCURRENT_LIST_LENGTH(&(pxReadyTasksLists[tskIDLE_PRIORITY])) > (UBaseType_t)1)
{
portYIELD();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
BaseType_t xPortStartScheduler(void)
{
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
vPortSetupTimerInterrupt();
uxCriticalNesting = 0;
prvStartFirstTask();
return 0;
}
__asm void prvStartFirstTask(void)
{
PRESERVE8
ldr r0, =0xE000ED08
ldr r0, [r0]
ldr r0, [r0]
msr msp, r0
cpsie i
cpsie f
dsb
isb
svc 0
nop
nop
}
void vTaskDelay(const TickType_t xTicksToDelay)
{
BaseType_t xAlreadyYielded = pdFALSE;
if (xTicksToDelay > (TickType_t)0U)
{
vTaskSuspendAll();
{
prvAddCurrentTaskToDelayedList(xTicksToDelay, pdFALSE);
}
xAlreadyYielded = xTaskResumeAll();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
if (xAlreadyYielded == pdFALSE)
{
portYIELD();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
static void prvAddCurrentTaskToDelayedList(TickType_t xTicksToWait,
const BaseType_t xCanBlockIndefinitely)
{
TickType_t xTimeToWake;
const TickType_t xConstTickCount = xTickCount;
pxCurrentTCB->ucDelayAborted = pdFALSE;
if (uxListRemove(&(pxCurrentTCB->xStateListItem)) == (UBaseType_t)0)
{
portRESET_READY_PRIORITY(pxCurrentTCB->uxPriority, uxTopReadyPriority);
}
else
{
mtCOVERAGE_TEST_MARKER();
}
xTimeToWake = xConstTickCount + xTicksToWait;
listSET_LIST_ITEM_VALUE(&(pxCurrentTCB->xStateListItem), xTimeToWake);
if (xTimeToWake < xConstTickCount)
{
vListInsert(pxOverflowDelayedTaskList, &(pxCurrentTCB->xStateListItem));
}
else
{
vListInsert(pxDelayedTaskList, &(pxCurrentTCB->xStateListItem));
if (xTimeToWake < xNextTaskUnblockTime)
{
xNextTaskUnblockTime = xTimeToWake;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
10.定义InitOS.h
#ifndef __INITOS
#define __INITOS
#include "FreeRTOSMini.h"
void InitHardware(void);
#endif
11.实现InitOS.c
#include "InitOS.h"
void InitHardware(void)
{
RCC_DeInit();
RCC_HSEConfig(RCC_HSE_ON);
while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET)
{
}
*((unsigned long*)0x40022000) = 0x02;
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK2Config(RCC_HCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div2);
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
RCC_PLLCmd(ENABLE);
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
}
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while (RCC_GetSYSCLKSource() != 0x08)
{
}
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC
| RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configLIBRARY_KERNEL_INTERRUPT_PRIORITY;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
12.定义led.h
#ifndef __LED
#define __LED
void InitLedEnv(void);
void TestLed(void);
void LED0Task(void *pvParameters);
void LED1Task(void *pvParameters);
void LED2Task(void *pvParameters);
void LED3Task(void *pvParameters);
#endif
13.定义led.c
#include "InitOS.h"
#include "led.h"
void InitLedEnv(void)
{
RCC->APB2ENR|=1<<4;
GPIOC->CRL&=0XFFFFFFF0;
GPIOC->CRL|=0X00000003;
GPIOC->CRL&=0XFFFFFF0F;
GPIOC->CRL|=0X00000030;
GPIOC->CRL&=0XFFFFF0FF;
GPIOC->CRL|=0X00000300;
GPIOC->CRL&=0XFFFF0FFF;
GPIOC->CRL|=0X00003000;
GPIOC->CRL&=0XFFF0FFFF;
GPIOC->CRL|=0X00030000;
GPIOC->CRL&=0XFF0FFFFF;
GPIOC->CRL|=0X00300000;
GPIOC->CRL&=0XF0FFFFFF;
GPIOC->CRL|=0X03000000;
GPIOC->CRL&=0X0FFFFFFF;
GPIOC->CRL|=0X30000000;
GPIOC->ODR|=1<<0;
GPIOC->ODR|=1<<1;
GPIOC->ODR|=1<<2;
GPIOC->ODR|=1<<3;
GPIOC->ODR|=1<<4;
GPIOC->ODR|=1<<5;
GPIOC->ODR|=1<<6;
GPIOC->ODR|=1<<7;
}
void TestLed(void)
{
InitLedEnv();
int curIndex=0;
while(1)
{
for(int i=0;i<8;i++)
{
if(i==curIndex)
{
GPIOC->ODR&=~(1<<i);
}
else
{
GPIOC->ODR|=1<<i;
}
}
curIndex++;
curIndex=curIndex%8;
vTaskDelay(50);
}
}
void LED0Task( void *pvParameters )
{
int statLED0=0;
while(1)
{
if(statLED0==0)
{
statLED0=1;
GPIOC->ODR&=~(1<<0);
}
else
{
statLED0=0;
GPIOC->ODR|=1<<0;
}
vTaskDelay(10);
}
}
void LED1Task( void *pvParameters )
{
int statLED1=0;
while(1)
{
if(statLED1==0)
{
statLED1=1;
GPIOC->ODR&=~(1<<1);
}
else
{
statLED1=0;
GPIOC->ODR|=1<<1;
}
vTaskDelay(20);
}
}
void LED2Task( void *pvParameters )
{
int statLED2=0;
while(1)
{
if(statLED2==0)
{
statLED2=1;
GPIOC->ODR&=~(1<<2);
}
else
{
statLED2=0;
GPIOC->ODR|=1<<2;
}
vTaskDelay(40);
}
}
void LED3Task( void *pvParameters )
{
int statLED3=0;
while(1)
{
if(statLED3==0)
{
statLED3=1;
GPIOC->ODR&=~(1<<3);
}
else
{
statLED3=0;
GPIOC->ODR|=1<<3;
}
vTaskDelay(100);
}
}
14.定义beep.h
#ifndef __BEEP
#define __BEEP
void InitBeepEnv(void);
void TestBeep(void);
void BeepTask(void *pvParameters);
#endif
15.实现beep.c
#include "InitOS.h"
#include "beep.h"
#include "led.h"
void InitBeepEnv(void)
{
RCC->APB2ENR|=1<<3;
GPIOB->CRH&=0XFFFFFFF0;
GPIOB->CRH|=0X00000003;
GPIOB->ODR|=1<<8;
}
void TestBeep(void)
{
InitLedEnv();
InitBeepEnv();
while(1)
{
GPIOB->ODR&=~(1<<8);
GPIOC->ODR&=~(1<<0);
vTaskDelay(50);
GPIOB->ODR|=1<<8;
GPIOC->ODR|=1<<0;
vTaskDelay(50);
}
}
void BeepTask(void *pvParameters)
{
while(1)
{
GPIOB->ODR&=~(1<<8);
vTaskDelay(50);
GPIOB->ODR|=1<<8;
vTaskDelay(500);
}
}
16.实现main.c
#include "InitOS.h"
#include "led.h"
#include "beep.h"
void vTimer2IntHandler( void )
{
TIM2->SR &= (u16)~((u16)0x0001);
}
#define LedTaskPriority (tskIDLE_PRIORITY+3)
#define LedTaskStakSize (170)
#define BeepTaskPriority (tskIDLE_PRIORITY+4)
#define BeepTaskStakSize (170)
int main( void )
{
InitHardware();
InitLedEnv();
InitBeepEnv();
xTaskCreate(LED0Task,"LED0",LedTaskStakSize,NULL,LedTaskPriority,NULL);
xTaskCreate(LED1Task,"LED1",LedTaskStakSize,NULL,LedTaskPriority,NULL);
xTaskCreate(BeepTask,"BEEP",BeepTaskStakSize,NULL,BeepTaskPriority,NULL);
vTaskStartScheduler();
return 0;
}
|