zoukankan      html  css  js  c++  java
  • RTCSD2017-2

    解决方案

    任务简述

    本次作业主体由三个任务组成,分别是Sender,Receiver,Monitor。分别完成发送,接收和监控的任务。

    Sender

    Sender作为数据生产者,要求每隔2ms生成一个逐次递增的数。当增加到10000时,返回1继续累加。

    Receiver

    Receiver作为数据消费者,要求每隔1s统计一次生成的数的总和。

    Monitor

    Monitor作为监控者,要求每隔10s检查一次数据是否成功接收。

    思路简述

    1. 由作业一可知,可以用FreeRTOS提供的延时函数vTaskDelay()来完成周期性的任务。
    2. 由上述要求,Receiver执行两次之间,Sender会执行500次,即产生500个数。所以需要缓冲区来承载这些数。
    3. 不妨选择队列来作为缓冲区,即FreeRTOS提供的xQueueCreate()等一系列函数。而且这种队列也支持多任务同时读写。
    4. 之后需要确定监控的方式。可以发现,Receiver产生的数都是依次递增的,前后两个之间相隔1。
    5. 所以Sender可以将当前从队列里取到的数与上一个数比较,将两个的差减一后累加到某个值上去。如果这个值不为0,则出现问题。
    6. 如果后一个数比前一个数小,则将后一个数加上10000再做以上操作。比如当前收到1,上一个收到的是10000:(1+10000)-10000=1,1-1=0
    7. 为了更好地表述,记第5步中所说的值为Diff。当前Diff由Sender累加,但Monitor也会去访问。由于不确定累加和访问这两个操作的原子性,所以需要对这两个加锁。
    8. 不妨选择xSemaphoreCreateMutex()作为锁。

    代码展示

    /**
     * Sender_Task: Product the number
     */
    void SenderTask(void* arg)
    {
        traceString stLogger = xTraceRegisterString("Sender Task");
        uint32_t uiNum = 1;
        TickType_t xLastWakeTime = xTaskGetTickCount();
        while (1)
        {
            if (pdPASS != xQueueSend(g_hNumberBuff, &uiNum, 0))
            {
                vTracePrintF(stLogger, "Send to queue failed.");
                if (pdPASS == xSemaphoreTake(g_uiMutexSL, 1))
                {
                    g_uiFailed++;
                    vTracePrintF(stLogger, "Fail: %d", g_uiFailed);
                    xSemaphoreGive(g_uiMutexSL);
                }
            }
            uiNum += 1;
            if (uiNum > 10000)
            {
                uiNum = 1;
            }
            vTaskDelayUntil(&xLastWakeTime, 2 / portTICK_RATE_MS);
        }
    }
    
    /**
     * Receiver_Task: Produce the number
     */
    void ReceiverTask(void* arg)
    {
        traceString stLogger = xTraceRegisterString("Receiver Task");
        uint64_t ulTmpSum = 0;
        uint32_t uiNumber = 0;
        uint32_t uiLast = 0;
        uint32_t uiTmpDiff;
        uint32_t uiTmpLoopCnt;
        TickType_t xLastWakeTime = xTaskGetTickCount();
        while (1)
        {
            uiTmpDiff = 0;
            uiTmpLoopCnt = 0;
            ulTmpSum = 0;
            while (pdPASS == xQueueReceive(g_hNumberBuff, &uiNumber, 0))
            {
                ulTmpSum += uiNumber;
                if (uiNumber > uiLast)
                {
                    uiTmpDiff += uiNumber - uiLast - 1;
                }
                else
                {
                    uiTmpDiff += uiNumber + 10000 - uiLast - 1;
                    uiTmpLoopCnt += 1;
                }
                uiLast = uiNumber;
            }
            if (pdPASS == xSemaphoreTake(g_uiMutexRML, 10 / portTICK_RATE_MS))
            {
                g_uiDiff += uiTmpDiff;
                g_uiLoopCnt += uiTmpLoopCnt;
                g_ulSum += ulTmpSum;
                xSemaphoreGive(g_uiMutexRML);
            }
            vTracePrintF(stLogger, "The sum of this round is %u
    ", ulTmpSum);
            vTaskDelayUntil(&xLastWakeTime, 1000 / portTICK_RATE_MS);
        }
    }
    
    /**
     * Monitor_Task: Check the task
     */
    void MonitorTask(void* arg)
    {
        traceString stLogger = xTraceRegisterString("Monitor Task");
        uint32_t uiTmpDiff;
        uint32_t uiTmpLoopCnt;
        uint32_t uiTmpState;
        TickType_t xLastWakeTime = xTaskGetTickCount();
        while (1)
        {
            uiTmpState = 0;
            if (pdPASS == xSemaphoreTake(g_uiMutexRML, 10))
            {
                uiTmpDiff = g_uiDiff;
                uiTmpLoopCnt = g_uiLoopCnt;
                g_uiState = (uiTmpDiff != 0);
                xSemaphoreGive(g_uiMutexRML);
            }
    
            if (uiTmpDiff == 0)
            {
                vTracePrintF(stLogger, "OK, %d loops are done.", uiTmpLoopCnt);
            }
            else
            {
                STM_EVAL_LEDOn(LED4);
                STM_EVAL_LEDOff(LED3);
                vTracePrintF(stLogger, "Wrong, difference is %d.", uiTmpDiff);
            }
            vTaskDelayUntil(&xLastWakeTime, 10000 / portTICK_RATE_MS);
        }
    }
    

    成果展示

    GitHub

    https://github.com/89yanyu/STM32F429I-Discovery

    仿真结果

    开始是绿灯,一段时间后变为红灯。
    因为只有在第二次运行Monitor的时候才会检查到有错误,将灯的状态改变。

    1. 初始化(红,绿灯亮)
    2. 正常运行(绿灯亮)
    3. 初始化失败或检查到错误(红灯亮)

    运行结果

    标准模式
    正常运行中:

    出现错误但未被Monitor检测到:

    Monitor检测到错误:

    Record模式
    等待开始指令

    Tracealyzer

    注意事项

    仿真的时候出现LED不亮,LED不变化或者延迟变化。

    因为仿真的时候用的是BSRR寄存器。
    这个寄存器的功能是把要改变的Bit写入,由MCU去改变相应的数据。
    而Qemu在仿真的时候似乎同步没有做好,就出现了以上情况
    将访问BSRR的操作改为ODR,这个寄存器就是直接操作io。
    具体操作比如:
    Set: GPIOx->ODR |= GPIO_Pin_xx;
    ReSet:GPIOx->ODR &= ~GPIO_Pin_xx;

    用Tracealyzer通过SEGGER传输数据时,出现速度不稳定,甚至跳的超过100%

    查看结果时,出现任务执行时长异常,长时间没有任务在工作

    仿真时,将snapshot保存出来,查看时出现未找到时间标签

    原因未知
    在trcConfig.h的151行上方的空格添加
    #define TRC_CFG_ARM_CM_USE_SYSTICK

    仿真或者在板子上运行时,时间长度不正确

    比如,现实生活7s相当于板子里的20s
    因为FreeRTOS设置了MCU的主频,默认是62500000
    而FreeRTOS的定时都是基于MCU主频,即内部是根据MCU主频来确定Tick(可以认为是一个CPU周期),而定时都是将ms转化为Tick。
    比如,20s * 62500000Hz / 180000000Hz = 6.944s
    修改FreeRTOSConfig.h的第98行,改为:
    #define configCPU_CLOCK_HZ ( ( unsigned long ) 180000000 )

    开着Traceanlyzer的流模式运行速度会变慢

    原因未知
    所以提供正常模式和Record模式。
    开机时按住USER_BUTTON(蓝色按钮),或者按住USER_BUTTON,再按RESET(黑色按钮)可以进入Record模式
    此时,会等待Traceanlyzer启动。
    可能需要多点几次Start

    有待改进

    • MCU里的时间和现实时间不一样,可能是config里CPU的主频设置错了。 ↑↑↑
    • 目前这种检查方式只能检查出错误,很大概率知道丢失了几个。但是不能知道丢失了那几个。
      可以用一个O(1)读写的数据结构来存储,但是可能要占一定的空间
  • 相关阅读:
    leetcode 850. Rectangle Area II
    leetcode 699. Falling Squares 线段树的实现
    leetcode 847. Shortest Path Visiting All Nodes 无向连通图遍历最短路径
    leetcode 843. Guess the Word
    javaMail实现收发邮件(三)
    javaMail实现收发邮件(二)
    javaMail实现收发邮件(一)
    springboot整合websocket实现一对一消息推送和广播消息推送
    jieba分词/jieba-analysis(java版)
    java实现两个不同list对象合并后并排序
  • 原文地址:https://www.cnblogs.com/89yanyu/p/7608766.html
Copyright © 2011-2022 走看看