本帖最后由 yoofs 于 2018-3-14 07:28 编辑
具体移植步骤,请参照如上所述的移植开发文档,这次我们使用的开发环境是 Keil MDK-ARM V5
此处我们认为开发环境已经搭建完毕,我们通过一些简单的例程,具体介绍一下实时操作系统TINIUX在Cortex-M3芯片下的应用。
我们这次使用的芯片是STM32F103ZET6,时钟信号使用的是芯片内部时钟,根据芯片相关信息,我们首先通过头文件OSPreset.h对TINIUX系统进行相关配置/裁剪,配置/裁剪信息如下:
- // !!!注:应用程序可以根据需要调整Tiniux系统API接口函数及相关功能模块的开关 !!!
- #ifndef __OS_PRESET_H_
- #define __OS_PRESET_H_
- /*-----------------------------------------------------------
- * Application specific definitions.
- *
- * These definitions should be adjusted for your particular hardware and
- * application requirements.
- *
- *----------------------------------------------------------*/
- /* Ensure stdint is only used by the compiler, and not the assembler. */
- #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
- #include <stdint.h>
- extern uint32_t SystemCoreClock;
- #endif
- #define SETOS_CPU_CLOCK_HZ ( SystemCoreClock ) //定义CPU运行主频 (如72000000)
- #define SETOS_TICK_RATE_HZ ( 1000 ) //定义TINIUX系统中ticks频率
- #define SETOS_MINIMAL_STACK_SIZE ( 64 ) //定义任务占用的最小Stack空间
- #define SETOS_TOTAL_HEAP_SIZE ( 1024*3 ) //定义系统占用的Heap空间
- #define SETOS_ENABLE_MEMFREE ( 1 ) //是否允许释放内存,允许后可以在系统运行时删除Task MsgQ Semaphone Mutex Timer等
- #define SETOS_LOWPOWER_MODE ( 1 ) //是否开启低功耗模式
- #define SETOS_MAX_NAME_LEN ( 10 ) //定义任务、信号量、消息队列等变量中的名称长度
- #define SETOS_MAX_PRIORITIES ( 8 ) //定义任务最大优先级
- #define SETOS_TASK_SIGNAL_ON ( 1 ) //是否启动轻量级的任务同步信号,功能类似Semaphore MsgQ,内存占用要小于Semaphore MsgQ
- #define SETOS_USE_SEMAPHORE ( 1 ) //是否启用系统信号量功能 0关闭 1启用
- #define SETOS_USE_MUTEX ( 1 ) //是否启用互斥信号量功能 0关闭 1启用
- #define SETOS_USE_MSGQ ( 1 ) //是否启用系统消息队列功能 0关闭 1启用
- #define SETOS_MSGQ_MAX_MSGNUM ( 5 ) //定义消息队列中消息的门限值
- #define SETOS_USE_TIMER ( 1 ) //是否使用系统软件定时器
- #define SETOS_USE_QUICK_SCHEDULE ( 1 ) //是否启动快速调度算法
- #define SETOS_TIME_SLICE_ON ( 1 ) //是否启用时间片轮转(time slice)调度机制
- #define SETOS_PEND_FOREVER_VALUE ( 0xFFFFFFFFUL )//定义信号量及消息队列中永久等待的数值
- /* Cortex-M specific definitions. */
- #ifdef __NVIC_PRIO_BITS
- /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
- #define SETHW_PRIO_BITS __NVIC_PRIO_BITS
- #else
- #define SETHW_PRIO_BITS ( 4 ) /* 15 priority levels */
- #endif
- /* The highest interrupt priority that can be used by any interrupt service
- routine that makes calls to interrupt safe TINIUX API functions. DO NOT CALL
- INTERRUPT SAFE TINIUX API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
- PRIORITY THAN THIS! (higher priorities are lower numeric values. */
- /* !!!! OSMAX_HWINT_PRI must not be set to zero !!!!*/
- #define OSMAX_HWINT_PRI ( 0x5 << (8 - SETHW_PRIO_BITS) ) /* equivalent to 0x50, or priority 5. */
- /* This is the value being used as per the ST library which permits 16
- priority values, 0 to 15. This must correspond to the OSMIN_HWINT_PRI
- setting. Here 15 corresponds to the lowest NVIC value of 255. */
- #define OSMIN_HWINT_PRI ( 0xF << (8 - SETHW_PRIO_BITS) ) /* equivalent to 0xF0, or priority 15. */
- #define FitSVCHandler SVC_Handler
- #define FitPendSVHandler PendSV_Handler
- #define FitOSTickISR SysTick_Handler
- #endif /* __OS_PRESET_H_ */
复制代码
通过上面的代码,我们看到为TINIUX系统配置的Ticks频率为1000Hz,即每个时钟滴答(Tick)为1毫秒。对于内核频率不高芯片,在应用时可适当降低Ticks频率,这样会提高系统的调度效率。
通过TINIUX轻量级同步信号控制LED灯
创建两个任务,一个为LedTask任务,一个为CtrlTask任务,两个任务之间通过轻量级同步信号进行同步交互操作。
相关实现代码如下所示:
- // 包含芯片相关的头文件。
- #include "stm32f1xx_hal.h"
- #include "config.h"
- // 包含嵌入式实时操作系统TINIUX相关的头文件TINIUX.h,在使用TINIUX操作系统时,必须包含此头文件。
- #include "TINIUX.h"
- // 定义空指针
- #ifndef NULL
- #define NULL ( OS_NULL )
- #endif
- // 定义LED任务的句柄,便于对LED任务的具体操作
- OSTaskHandle_t LedTaskHandle = NULL;
- // 定义控制任务的句柄,与LED任务通过轻量级同步信号进行同步交互操作
- OSTaskHandle_t CtrlTaskHandle = NULL;
- // LED任务函数的声明
- static void LedTask( void *pvParameters );
- // Ctrl控制任务函数的声明
- static void CtrlTask( void *pvParameters );
- // LED任务的具体实现函数
- static void LedTask( void *pvParameters )
- {
- // 我们暂时没有用到任务函数的参数pvParameters
- ( void )pvParameters;
- // 任务函数体内一般都是一个死循环,不能通过return语句返回,若任务函数执行完毕后没有必要再继续执行,
- // 则需要调用OSTaskDelete函数进行任务删除操作,便于系统调度,同时把分配给该任务的堆栈空间回收,以供系统再次使用。
- for( ;; )
- {
- // 调用TINIUX的接口函数,让此任务等待接收轻量级的同步信号,等待时间为OSPEND_FOREVER_VALUE,此数值代表永久等待,直至接收到有效的信号为止。
- // 也可以通过参数指定一个具体的数值,代表等待具体的时间,单位为Ticks。若在指定的时间内没有接收到有效信号,则也返回,只是返回值为OS_FALSE;
- // 若在指定的等待时间内接收到有效的信号后,则返回OS_TRUE。此函数与OSTaskSignalEmit()对应使用;
- OSTaskSignalWait( OSPEND_FOREVER_VALUE);
- // 接收到同步信号后,转换LED灯的状态
- // 控制LED等的亮或熄灭,请参照你的板卡进行控制实验。
- HAL_GPIO_TogglePin(LED1_GPIO_PORT, LED1_PIN);
- }
- }
- // 控制任务的具体实现函数
- static void CtrlTask( void *pvParameters )
- {
- // 我们暂时没有用到任务函数的参数pvParameters
- ( void )pvParameters;
- // 任务函数体内一般都是一个死循环,不能通过return语句返回。
- for( ;; )
- {
- // 调用TINIUX的接口函数,让此任务休眠500毫秒,这里调用OSM2T函数,
- // 将500毫秒数值转换为OSTaskSleep函数需要的Ticks数值
- OSTaskSleep( OSM2T(500) );
- //通过任务句柄LedTaskHandle,向LedTask任务发射同步信号。此接口函数与LedTask任务中的OSTaskSignalWait()函数相对应;
- OSTaskSignalEmit(LedTaskHandle);
- }
- }
- int main(void)
- {
- // 对硬件进行配置,包括时钟及Led等.
- SetupHardware();
- GPIO_Configuration();
- // 在使用TINIUX之前,首先对TINIUX相关参数进行初始化
- OSInit();
- // 创建控制LED灯的任务,第一个参数指定具体的任务函数LedTask,第二个参数为LedTask用到的参数,此处我们暂时不用,填写NULL
- // 第三个参数为任务使用的堆栈空间,因为LedTask任务函数中使用的变量较少,我们直接填写OSMINIMAL_STACK_SIZE,
- // 第四个参数填写为LedTask任务分配的优先级,在此例程中,我们使用的任务不多,此处填写比空闲任务大1个的优先级,
- // 第五个参数为任务的名称,任务的名称主要便于调试时分辨任务,此处我们根据任务的功能填写Led
- // 任务创建完毕后,返回任务句柄,保存到LedTaskHandle中,便于后面对此任务进行操作
- LedTaskHandle = OSTaskCreate(LedTask, NULL, OSMINIMAL_STACK_SIZE, OSLOWEAST_PRIORITY+1, "Led");
- // 创建控制任务,参数含义参照main函数中创建LedTask任务时的注释,优先级与LedTask相同,也是OSLOWEAST_PRIORITY+1;
- CtrlTaskHandle = OSTaskCreate(CtrlTask, NULL, OSMINIMAL_STACK_SIZE, OSLOWEAST_PRIORITY+1, "Ctrl");
- // 启动TINIUX操作系统
- OSStart();
- // 如果TINIUX启动正常,则不会执行到这里。
- // 一旦运行到此处,有可能是分配给TINIUX的堆栈空间太小,TINIUX直接退出运行了。
- for( ;; );
- }
复制代码
本例程对应的软件工程如下:
通过TINIUX轻量级同步信号控制LED灯_STM32F103ZET6.rar
(1.53 MB, 下载次数: 14)
|