FreeRTOS多任务同步和通信机制的掌握

本周课堂任务为:

  • 在github上,Fork例程项目(https://github.com/cbhust/

  • STM32F429_Discovery_FreeRTOS_9.git) 到自己的个人账号。

  • clone项目到本地电脑的Ubuntu虚拟机中(虚拟机环境在第一次作业中已搭建)。

  • 按照/Projects/Demo1/README.md中的提示编译Demo1例程并通过Qemu运行例程。

  • 在Demo1的框架基础上完成自己的本次编程作业(具体要求见第3点)。

  • 代码完成后提交到自己的github账号上,确保助教可以正常的clone并编译运行。

  • 在作业博客上给出代码的github链接、代码说明以及运行结果展示。

clone项目并初运行

参考第一次作业的内容,按照指示,fork老师的代码后,在终端输入:
git clone https://github.com/czphappy/STM32F429_Discovery_FreeRTOS_9.git
获得相应编程环境。如图

根据老师的提示,按照README.md中的流程,安装QEMU(如图)

接着是为qemu加入环境变量,在终端输入: (这一步每次重启终端都需要重新输入,谢谢老师的提醒,少走许多弯路)

#cd ~/work
#tar xvf gnuarmeclipse-qemu-debian64-2.8.0-201612271623-dev.tgz
#chmod -R -w ./qemu
#export PATH=~/work/qemu/2.8.0-201612271623-dev/bin/:$PATH
#qemu-system-gnuarmeclipse --version

结果如图,配置成功。

接着按照指示,在Demo1下make之后,在终端输入:
#./qemu.sh
运行结果如下,验证完毕,环境已经建好。:

GDB调试

继续依照指示,在终端输入:
#./qemu_gdb.sh
开启UI后,新开一个终端,输入:

#arm-none-eabi-gdb  
(gdb)target remote localhost:1234 
(gdb)continue

得到如下结果(验证完毕)

新建通信任务

这个问题我想主要难点在于Monitor_Task的书写,由于三个任务同步进行,Monitor_Task如果设置不恰当很有可能错误判断,因为最常见的结果是Sender_Task已经把数据传出,只是 Receiver_Task还没有接收,但我发现sender每次传输的值和其传输的次数是相同的(或者具体说是除10000的余数),所以我就设置两个全局变量,一个用于存储Receiver_Task最新接收的值,另外一个用于存储传输次数,通过比较两者是否相等,就可以直接进行判断。

以下是具体实现流程,在老师给的main.c的框架下,我设置的全局变量

void Hardware_Init(void);
void Monitor_Task( void *pvParameters );
void Sender_Task( void *pvParameters );
void Receiver_Task( void *pvParameters );
void Red_LED_On(void);
void Red_LED_Off(void);
void Green_LED_On(void);
void Green_LED_Off(void);
extern unsigned long ReceiverFlag =0;
extern unsigned long nflag=0;

ReceiverFlag用于存储Receiver_Task最新接收的值,nflag存储传输次数,以下是我新建的三个任务:

      
       xTaskCreate(                                                                                  
	   Sender_Task,                 /* Function pointer */
		  ( signed portCHAR * )"Sender_Task", /* Task name - for debugging only*/
		  configMINIMAL_STACK_SIZE,         /* Stack depth in words */
		  (void*) NULL,                     /* Pointer to tasks arguments ````(parameter) */
		  tskIDLE_PRIORITY + 2UL,           /* Task priority*/
		  NULL                              /* Task handle */
       );

      xTaskCreate(
		  Receiver_Task,                 /* Function pointer */
		  ( signed portCHAR * )"Receiver_Task",  /* Task name - for debugging only*/
		  configMINIMAL_STACK_SIZE,         /* Stack depth in words */
		  (void*) NULL,                     /* Pointer to tasks arguments (parameter) */
		  tskIDLE_PRIORITY + 4UL,           /* Task priority*/
		  NULL                              /* Task handle */
       );
       xTaskCreate(
		  Monitor_Task,                 /* Function pointer */
		   ( signed portCHAR * )"Monitor_Task", /* Task name - for debugging only*/
		  configMINIMAL_STACK_SIZE,         /* Stack depth in words */
		  (void*) NULL,                     /* Pointer to tasks arguments (parameter) */
		  tskIDLE_PRIORITY + 3UL,           /* Task priority*/
		  NULL                              /* Task handle */
       );

其中优先级取为Sender_Task<Receiver_Task<Monitor_Task(其实后两者可以一样) ,结果是一致的。

void Sender_Task(void *pvParameters)
     {    
       unsigned long  SendNum = 1;     
       unsigned long SenderSum =0;    
       for( ;; )  
      {  
        vTaskDelay(2);  
        /* 向队列中填充内容 */  
        xQueueSend( MsgQueue, ( void* )&SendNum, 0 );  
        SenderSum=SendNum+SenderSum;
        SendNum=(SendNum+1)%10000;
      }  
      }

sender_Task的任务比较简单,只需要有个累加值以及一个基数即刻,优先级较低。

void Receiver_Task(void *pvParameters)
{
    unsigned long ReceiverSum = 0;
    unsigned long ReceiverNum =1;
    for( ;; )
    {  
        
        vTaskDelay(1000);
        /* 从队列中获取内容 */  
        for( ;xQueueReceive( MsgQueue,&ReceiverNum, 0 ) == pdPASS;)  
        {  
            ReceiverSum = ReceiverNum+ReceiverSum; 
            nflag++;
            ReceiverFlag=ReceiverNum;
        }  
    }  
}

Receiver_Task的任务相对复杂,除了两个累加值之外,还需要设置两个全局变量,取出值和累加值

void Monitor_Task(void *pvParameters)
{  
    for( ;; )  
    {  
        vTaskDelay(10000);
        if( ReceiverFlag == (nflag % 10000))  
        {  
             Green_LED_On();
             vTaskDelay(1000);
             Green_LED_Off();
        }  
        else 
        {
            Red_LED_On();
            vTaskDelay(1000);
            Red_LED_Off();
        }
    }  
}

正如前面所说,Monitor_Task就是简单判断两个全局变量是否相等,正确则绿灯亮,错误则红灯亮。

结果是绿灯持续闪烁,说明传输没有问题。
完成后将我的代码push到远程仓库。
以下是我的github链接
https://github.com/czphappy/STM32F429_Discovery_FreeRTOS_9


此次实验,我的进度把握不是很好,师兄也是一在把时间延后,从一开始什么都不知道,到现在的任务完成,期间遇到各种问题,多谢师兄和同学们也耐心讲解,让我完成这个作业,对于GitHub和FreeRTOS也有了一定的认识。谢谢!