2. STM32CubeMX移植OSAL

本文详细介绍了在STM32平台上使用STM32CubeMX工具移植OSAL(操作系统抽象层)的过程,包括创建工程、配置时钟和外设、添加OSAL代码、解决编译错误、移植定时器和中断接口,以及理解和使用OSAL的基本运行逻辑。
摘要由CSDN通过智能技术生成

2. STM32CubeMX移植OSAL

  • 在STM32平台(或者任何平台)移植分为如下的步骤
    1. 创建基本的工程,初始化系统时钟、Systick定时器(或者其他定时器)、初始化基本外设(串口、LED)
    2. 将OSAL代码添加到工程,将头文件添加到工程。本文移植的OSAL源代码为GitHub - hotsauce1861/gcc-stm32-osal: ARM-GCC下STM32F1工程模板,运行OSAL操作系统。
    3. 运行工程,排除基本的错误。
    4. 移植OSAL定时器接口,移植全局中断接口,移植内存管理相关配置。
    5. 了解OSAL基本的运行逻辑,完成基本外设的运行操作(串口、LED)。
  • 移植完成的代码如下:
    https://gitee.com/Pencil888/osal-stm32

2.1 创建基本的工程

  1. 打开STM32CubeMx,选择需要配置的芯片,创建工程。
    在这里插入图片描述
  2. 选择RCC(时钟配置),选择外部时钟。
    在这里插入图片描述
  3. 选择SYS(系统配置),选择调试接口为Serial Write,也可以其他调试接口。
    在这里插入图片描述
  4. 选择 Clock Configuration ,按照下图完成时钟配置。
    在这里插入图片描述
  5. 配置LED外设
    在这里插入图片描述
  6. 配置UART1外设
    在这里插入图片描述
  7. 输出工程
    在这里插入图片描述
    在这里插入图片描述

2.2 将OSAL代码添加到工程

  1. 下载OSAL移植代码 git close https://github.com/hotsauce1861/gcc-stm32-osal.git,或者直接访问 https://github.com/hotsauce1861/gcc-stm32-osal.git 进行下载。
  2. 打开Keil工程,将 OSAL 文件夹拷贝的 上方创建的工程目录下,并将osal 、hal 中的文件添加到keil工程中。
    在这里插入图片描述
    在这里插入图片描述
  3. 将 include 文件夹添加到C++头文件
    在这里插入图片描述

2.3 解决基本的错误

  1. SysTick_Handler(void) 重复定义,将 time.h 中的 Systick_Handler(void) 注释掉,在Stm32f1xx_it.cSystick_Handler(void)中添加osal_update_timers();
#include "osal_timer.h"
void SysTick_Handler(void)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */
      // 代码要卸载BEGIN 和 END之间,不然就会被清除掉。
        osal_update_timers();
  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */

  /* USER CODE END SysTick_IRQn 1 */
}
  1. 发现好多重复定义,将 type.h 中的 #include "stm32f10x.h" 注释掉
  2. type.hSUCCESSERROR 有重复定义,将这两个宏定义修改名称,并且在OSAL 中也进行修改。(这里表达的不太详细,但是实际操作一下就会了。很简单)
  3. 再次运行,已经没有错误。

2.4 移植OSAL接口

  1. 移植定时器接口,在上方解决基本的错误中第一点已经完成。
  2. 打开和关闭全局中断,打开type.h ,修改如下的代码
#define CLI()         __disable_irq();             // Disable Interrupts
#define SEI()         __enable_irq();              // Enable Interrupts
  1. 移植内存相关配置,在32位的单片机。不用修改,具体其中配置的含义在第三个章节有具体分析。

2.5 了解OSAL基本的运行逻辑,完成基本外设的运行操作

  1. 创建osal_main.c 文件,添加如下的代码
#include "application.h"

int osal_main(void)
{    
        //系统硬件、外设等初始化
        
    //禁止中断
    HAL_DISABLE_INTERRUPTS();

    //osal操作系统初始化
    osal_init_system();

     /*
         添加任务
             Serial_Task_Init             任务初始化函数
             Serial_Task_EventProcess     任务循环函数
             1                            任务优先级,数值越大,优先级越高
     */
    osal_add_Task(Serial_Task_Init,Serial_Task_EventProcess,1);   
         
    //任务初始化,在这个函数中会调用添加到任务中的初始化函数
    osal_Task_init();
    // 内存相关函数
    osal_mem_kick();

    //允许中断
    HAL_ENABLE_INTERRUPTS();        
    
    /*
        osal_start_reload_timer 设置任务的定时周期
        Serial_TaskID     任务ID,在任务函数中有创建
        PRINTF_STR        任务事件号,在任务头文件中自己定义
        500               循环的周期,单位为ms
    */
    osal_start_reload_timer( Serial_TaskID, PRINTF_STR, 500);

    //启动osal系统,不会再返回,逻辑在其中处理
    osal_start_system();
    
    return AERROR;
}
  1. 创建serial_task.c文件,这是任务的初始化、循环函数的文件。
#include "application.h"

#include <string.h>
#include <stdarg.h>
#include <stdio.h>

#include "main.h"
#include "usart.h"
#include "gpio.h"


uint8 Serial_TaskID;                                        //系统串口通信任务ID

// 任务的初始化,必须按照 void xxx (uint8 task_id) 来定义,在这个函数中完成外设、变量的初始化
// 会传入一个任务ID,由系统分配,需要将其存储
void Serial_Task_Init(uint8 task_id)
{
        Serial_TaskID = task_id;

        //串口配置初始化
//        Usart_Init(COM1,115200,STOP_1_B,WROD_LEN_8B,PARITY_NO,HARD_NO);
//        LED_Init();
}

// 任务的循环函数,周期性运转,必须按照 uint16 xxx(uint8 task_id,uint16 task_event)定义
// 传入参数为任务ID,和任务事件,在完成处理之后必须消除任务事件
uint16 Serial_Task_EventProcess(uint8 task_id,uint16 task_event)
{
        // 系统消息事件,OSAL系统默认会调用,可以不写此判断内
        if ( task_event & SYS_EVENT_MSG )           //判断系统消息事件
          {
                  osal_sys_msg_t *MSGpkt;                            //定义一个指向接受系统消息结构体的指针
            //从消息队列获取消息  
            MSGpkt = (osal_sys_msg_t *)osal_msg_receive( task_id ); 
    
            while ( MSGpkt )
            {
                      switch ( MSGpkt->hdr.event )          //判断消息事件
                      {
                          case OSAL_PRINTF:
                                  break;

                        default:
                                  break;
                      }

                      // Release the memory
                      osal_msg_deallocate( (uint8 *)MSGpkt );

                      // Next  获取下一个消息
                      MSGpkt = (osal_sys_msg_t *)osal_msg_receive( task_id );
            }

            // return unprocessed events
            return (task_event ^ SYS_EVENT_MSG);
          }
        // 用户实现的处理,判断是否为 PRINTF_STR
        if(task_event & PRINTF_STR)
        {
                // 反转LED
                static int dir = 1;

                if(dir)
                {
                        dir = 0;
                        HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_SET);
                }
                else
                {
                        dir = 1;
                        HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_RESET);
                }
                // 打印消息
                HAL_UART_Transmit(&huart1, "Hello World!", sizeof("Hello World!")-1, 1000);
                // 清除事件
                return task_event ^ PRINTF_STR;
        }

        return 0;
}
  1. application.h 其中实现了一些消息队列和任务的定义
#ifndef APPLICATION_H
#define APPLICATION_H

#include "osal.h"
#include "osal_timer.h"
#include "osal_event.h"
#include "osal_memory.h"
#include "osal_msg.h"

//全局变量声明
/*****************************************************************************/

typedef struct
{
        osal_event_hdr_t  hdr;          //操作系统事件结构
        unsigned char *Data;                        //命令帧操作数
} General_SerialData_t;             //OSAL中通用串口打印消息的格式结构体

/*****************************************************************************/

//所有任务的任务ID、初始化函数、事件处理函数、任务事件都统一在此文件声明或定义
/*****************************************************************************/

//任务ID声明
extern uint8 Serial_TaskID;

//任务初始化函数声明
extern void Serial_Task_Init(uint8 task_id);

//任务事件处理函数声明
extern uint16 Serial_Task_EventProcess(uint8 task_id,uint16 task_event);

extern void osal_printf(char *format, ...);                //打印通用串口数据

//任务事件定义
//系统消息事件
#define SYS_EVENT_MSG                0x8000

//串口通信任务事件定义
#define        PRINTF_STR                        0X0001                 //打印字符串事件
//串口通信任务系统消息事件定义
#define OSAL_PRINTF                        0X01                //系统打印

/*****************************************************************************/

#endif
  1. main() 函数中调用osal_main();
  2. 观察代码运行结果:
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值