本帖最后由 wind_west 于 2019-9-20 23:08 编辑

     在单片机上进行裸机编程确实非常方便快捷,但是在实际应用中要得到一个非常好的效果还是需要一个嵌入式系统。而FreeRTOS就是一个迷你的实时操作系统内核。作为一个轻量级的操作系统,功能包括:任务管理、时间管理、信号量、消息队列、内存管理、记录功能、软件定时器、协程等,可基本满足较小系统的需要。这些特点还是很符合我们的需要。另外,相对μC/OS-II、embOS等商业操作系统,FreeRTOS操作系统是完全免费的操作系统,具有源码公开、可移植、可裁减、调度策略灵活的特点,可以方便地移植到各种单片机上运行。所以,我就采用这个RTOS来进行移植了。在系统上跑了2个任务,使用串口进行打印,现在截取串口的信息示意图如下
图1.JPG
    可以看到,任务2运行1次,任务1运行3次,大概就是这样一个效果。




1、移植驱动文件
    巧妇难为无米之炊呀,先从官网下载源文件FreeRTOSv9.0.0.zip。这里使用的是版本是v9的,也可以选择最新的版本,这个都没有关系。效果如图:

图2.JPG
    新建一个文件,命名为FreeRTOSv9.0.0_TMPM3Hy。解压文件,找到source文件,拷贝进来。同时,在source的下级文件新建文件夹FreeRTOSConfig用来存放配置文件FreeRTOSConfig.h。FreeRTOSConfig.h这个文件不在source文件的原文件中,是在demo的STM32F103拷贝来的,效果如图:

图3.JPG

    现在仔细讨论 source这个文件夹下的文件。1、portable文件夹下有个keil文件,但是只有个txt文件。移植需要的操作就如这个文件名一样,我们去到RVDS文件夹下将ARM_CM3的内容拷贝过来。因为我们的MCU是arm3的所以拷贝这个文件夹,具体的可以参考数据手册。效果如图:
图4.JPG
2、source文件夹下的MemMang文件里面有内存管理的几个文件,后面会用到heap_4.c,所以比较重要。如果追求简洁,可以删除其他的文件。
现在可以将FreeRTOSv9.0.0_TMPM3Hy文件添加到我们的工程中,然后配置相应的包含路径。配置如图:
图5.JPG

图6.JPG
2、修改启动文件startup_TMPM3HQ.s
    系统在进入main函数之前调用了startup_TMPM3HQ.s,可以看到这里面定义了很多中断函数。这里我们不需要做太大的更改,初步移植只需要修改几个函数,将相关的原函数替换为freeos的函数就行。





    IMPORT vPortSVCHandler
    IMPORT xPortPendSVHandler
    IMPORT xPortSysTickHandler




                DCD      vPortSVCHandler              ; SVCall Handler,SVC_Handler

                DCD      xPortPendSVHandler           ; PendSV Handler,PendSV_Handler
                DCD      xPortSysTickHandler          ; SysTick Handler,SysTick_Handler



效果如图:

图7.JPG

3、在main()中添加业务执行逻辑
    在main函数中添加执行逻辑:
int main(void)
  • {
  •                 prvSetupHardware();
  •     /*----------------------*/
  •     /* Main Processing      */
  •     /*----------------------*/
  •                
  •         /* Start the tasks defined within this file/specific to this demo. */
  •     xTaskCreate( vLEDTask_1, "vLEDTask_1", mainLED1_TASK_STACK_SIZE, NULL, mainLED1_TASK_PRIORITY, NULL );
  •         
  •           xTaskCreate( vLEDTask_2, "vLEDTask_2", mainLED2_TASK_STACK_SIZE, NULL, mainLED2_TASK_PRIORITY, NULL );
  •         /* Start the scheduler. */
  •         vTaskStartScheduler();
  •         /* Will only get here if there was not enough heap space to create the
  •         idle task. */
  •         return 0;
  • }
  • 复制代码



    函数说明:
    1、prvSetupHardware()对硬件进行了初始化。没有太多花里胡哨的内容,就是将先前main函数的初始化移进来的,然后初始化了两个LED的控制引脚。
    /*************************************
    函数名:prvSetupHardware
    作用:对硬件进行初始化
    参数:
    作者:

    **************************************/
    static void prvSetupHardware( void )
    {


      u8 t;
       static gpio_t port;     /*!< Port driver instance. */

        /*----------------------*/
        /* BSP initialize       */
        /*----------------------*/
        bsp_initialize();
        /*----------------------*/
        /* Initialize           */
        /*----------------------*/
        /*--- variable    ---*/
        variable_initialize();

        /*--- driver ---*/
        if (driver_initialize() != TXZ_SUCCESS)
        {
        }

       /*--- application ---*/
        if (application_initialize() != TXZ_SUCCESS)
        {
        }
      
      delay_init();//如果不进行初始化,编译并不报错,但是执行延时函数会宕机
      //我自己进行的IO初始化,这里有个问题,重复初始化会出现什么问题
      
      port.p_pk_instance = TSB_PK;
      /*--- Initialize ---*/
      if (gpio_init(&port, GPIO_PORT_K) != TXZ_SUCCESS)
      {
       // bsp_error();
      }
      /*--- Setting    ---*/
      /*- PJ0 -*/
      if (gpio_func(&port,GPIO_PORT_K, GPIO_PORT_5, (uint32_t)GPIO_PK5_OUTPUT, GPIO_PIN_INOUT) != TXZ_SUCCESS)//原理图:LED1
      {
      //  bsp_error();
      }
      /*--- Setting    ---*/
      /*- PK6 -*/
      if (gpio_func(&port,GPIO_PORT_K, GPIO_PORT_6, (uint32_t)GPIO_PK6_OUTPUT, GPIO_PIN_INOUT) != TXZ_SUCCESS)//原理图:LED2
      {
      //  bsp_error();
      }


    }

    2、vLEDTask_1()这个函数就是平时的main()函数,先定义一个延时的常量,然后就跑起来的while(1)循环。最后,为了能让任务放弃cpu的占有权,用了个系统提供的延时函数。对了,说到这个延时了,因为这款单片机的晶振频率是80mhz,所以在FreeRTOSConfig.h里面一个参数改了一点点。
    /*************************************
    函数名:vLEDTask_1
    作用:对硬件进行初始化
    参数:
    作者:

    **************************************/
    static void vLEDTask_1( void *pvParameters )
    {
    //让LED闪烁的代码
    const TickType_t xDelay = pdMS_TO_TICKS( ( TickType_t ) 1000 );//这是延时1000ms


    while(1){
      
      if (printf("\n vLEDTask_1 !! \n") != -1 ){};

      LED1_OUT(1);
      vTaskDelay( xDelay );
      LED1_OUT(0);
      vTaskDelay( xDelay );

    }

    }

    致此,系统应该是可以跑起来了。

    谢谢大家的阅读,底部奉上一个可串口打印和LED闪烁的附件:
    Freeos_uart.zip (14.07 MB, 下载次数: 0)
    举报
    您需要登录后才可以评论 登录 立即注册
    全部回复 0
    暂无评论,快来抢沙发吧