justd0 发表于 2021-7-18 23:48

蜜袋鼯 第⑨贴 基于RSL10的蜜袋鼯数据监测子系统-设计与实现

本帖最后由 justd0 于 2021-7-19 00:17 编辑

<div style="border-width:100%">
<div style="width:8.5125in">
<div style="width:8.5125in">
<p><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">前言</span></span></p>

<p><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">先来回顾下,本项目的整体架构图如下。前面几个帖子,介绍了下运动奖励系统的设计、制作和测试相关内容,本帖将对蜜袋鼯健康监测子系统部分进行介绍</span></span></p>

<p> &nbsp;</p>

<p><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;</span></span></p>

<p><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;</span></span></p>

<p><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">正文</span></span></p>

<p><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">在<a href="https://bbs.eeworld.com.cn/thread-1170825-1-1.html"> 蜜袋鼯 第⑤贴 基于RSL10的蜜袋鼯健康监测系统--项目简介</a>贴中,我介绍了本项目的功能目标,其中第一条是</span></span></p>

<p><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;1、运动健康监测:将RSL10传感器开发套件安装在摩天轮上,通过光照度计收集光照数据,通过空气质量传感器收集温度信息,通过角速度计监测小蜜在摩天轮奔跑的转动速度数据,记录下一晚上的数据,存储在传感器版上。</span></span></p>

<p><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;</span></span></p>

<p><span style="font-size:14.0pt"><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">为了实现如上目标,</span> <span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">本项目中架构了运动监测系统,该系统主要部署在</span><span lang="en-US" style="font-family:Calibri">RSL10</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">-SENSE-GEVK</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">板子上。</span></span></p>

<p><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">依靠开发板上丰富的传感器资源来实现记录环境光照数据、环境温度数据、环境噪声数据和飞鼠滚轮的运动角速度和转动圈数等。</span></span></p>

<p><span style="font-size:14.0pt"><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">像下图这样,</span><span lang="en-US" style="font-family:Calibri">RSL10</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">-SENSE-GEVK</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">板通过双面胶直接粘在了飞轮的中间,这样经过一晚上的收集,</span></span></p>

<p> &nbsp;</p>

<p><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">第二天早上就可以看到整晚小蜜周围环境和运动数据了。</span></span></p>

<p><span style="font-size:11.0pt"><span style="font-family:Calibri">&nbsp;</span></span></p>

<p><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">在这个目标中要实现的功能主要有两大块:数据采集和存储。</span></span></p>

<p><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;"><span lang="zh-CN" style="font-weight:bold">一</span> <span lang="zh-CN" style="font-weight:bold">、数据采集</span></span></span></p>

<p lang="en-US"><span style="font-size:14.0pt"><span style="font-family:Calibri">&nbsp;</span></span></p>

<p><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;"><span lang="en-US" style="font-weight:bold">1</span><span lang="zh-CN" style="font-weight:bold">、光照采集</span></span></span></p>

<p><span style="font-size:14.0pt">&nbsp;&nbsp;&nbsp; <span lang="en-US" style="font-family:Calibri">RSL10</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">-SENSE-GEVK</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">板上采用的是</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">LV0104CS</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">这款传感器,此前,我已经将该传感器的驱动写好,分享到了<a href="https://bbs.eeworld.com.cn/thread-1169973-1-1.html">蜜袋鼯 第③贴 RSL10-SENSE-GEVK 光照传感器驱动 写好了 分享给大家</a></span></span></p>

<p><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;&nbsp;&nbsp; 光照数据采集方式就相对比较简单,LV0104CS的驱动是按照官方的代码风格实现的,只要在主函数中初始化I2C和传感器,并创建相应的回调函数,在回调函数中就可以定周期获取光照数据了,这里我为了方便数据保存,将真实的光照值除以10,这样就可以存放在一个字节呢了。</span></span></p>

<p><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">代码如下:</span></span></p>

<p><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;</span></span></p>

<pre>
<code class="language-cpp">main.c

int main(void)
{

.......
    /** Initialize LV0104CS. */
    LV0104CS_LUX_Initialize();
    LV0104CS_LUX_StartContinuous(1000, LV0104CS_Callback);
.......

}

/** 中断保存亮度数据,调用datamanager的write方法. */
void LV0104CS_Callback(uint32_t lux)
{
        uint8_t lux_data = lux/10;
        data_write(&amp;light_dm,(uint8_t *)&amp;lux_data,1);
}</code></pre>

<p><span style="font-size:14.0pt"><span lang="en-US" style="font-weight:bold"><span style="font-family:Calibri">2</span></span><span lang="zh-CN" style="font-weight:bold"><span style="font-family:&quot;Microsoft YaHei&quot;">、环境温度数据</span></span></span></p>

<p><span style="font-size:14.0pt">&nbsp; <span lang="en-US" style="font-family:Calibri">RSL10</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">-SENSE-GEVK</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">板上才用的</span><span lang="zh-CN" style="font-family:Calibri">BME680</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">这款芯片,</span><span lang="zh-CN" style="font-family:Calibri">BME680</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">是个多功能的环境空气检测芯片,可以测量温度、湿度、空气质量等,不过我这里仅关心小蜜所在的环境的温度数据,因此只对温度进行了处理,也是为了方便数据保存和传输,将</span><span lang="en-US" style="font-family:Calibri">16</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">位的</span><span lang="en-US" style="font-family:Calibri">x10</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">温度值转化为</span><span lang="en-US" style="font-family:Calibri">8</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">位的室温范围。</span></span></p>

<p><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">代码如下:</span></span></p>

<pre>
<code class="language-cpp">main.c

int main(void)
{
......
    /** Initialize BME680 */
    BME680_ENV_Initialize();
    BME680_ENV_StartPeriodic(BME680_Callback, 1000);
......

}

void BME680_Callback(struct BME680_ENV_Data *output)
{
//    memcpy(&amp;bme680_output, output, sizeof(struct BME680_ENV_Data));
        //温度数据由x100,转换为x10,并且减掉100,温度起点改为10℃,最大温度35.4℃
        int16_t temperature =(output-&gt;temperature / 10)-100;
        if(temperature&gt;=UINT8_MAX)
        {
                temperature = UINT8_MAX;
        }
        else if(temperature &lt;= 0 )
        {
                temperature = 0;
        }
        data_write(&amp;temperature_dm,(uint8_t *)&amp;temperature,1);

}</code></pre>

<p><span style="font-size:14.0pt"><span lang="en-US" style="font-weight:bold"><span style="font-family:Calibri">3</span></span><span lang="zh-CN" style="font-weight:bold"><span style="font-family:&quot;Microsoft YaHei&quot;">、环境噪声数据</span></span></span></p>

<p><span style="font-size:14.0pt"><span lang="en-US" style="font-family:Calibri">RSL10</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">-SENSE-GEVK</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">板上配有一个</span><span lang="zh-CN" style="font-family:Calibri">inmp522</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">,数字</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">mic</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">,可以实时采集环境的声音数据,声音属于实时数据,一般我们会使用分贝计来评估环境噪音的强度,这里我对声音数据进行了一步处理,将其转换成了分贝进行数据保存,具体声音数据转分贝的公式如下:</span></span></p>

<p><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;</span></span> &nbsp;</p>

<p><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">因为音频采集的中断频率很高,而我要对整晚的环境进行监测,因此我先对音频数据做了均值滤波,并进行分贝计算,然后保留这里最大的分贝值用于存储。</span></span></p>

<p><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">代码如下:</span></span></p>

<p><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;</span></span></p>

<pre>
<code class="language-cpp">#include &lt;BDK.h&gt;
#include &lt;BSP_Components.h&gt;
#include &lt;BLE_Components.h&gt;
#include &lt;ansi_color.h&gt;
#include &lt;SEGGER_RTT.h&gt;
#include &lt;math.h&gt;
#include &lt;SoftwareTimer.h&gt;

#include &lt;data_manage2.h&gt;

#define AUDIO_DMIC0_GAIN                0x800
#define AUDIO_DMIC1_GAIN                0x800
#define AUDIO_OD_GAIN                   0x800

#define AUDIO_CONFIG                  (OD_AUDIOSLOWCLK            | \
                                       DMIC_AUDIOCLK            | \
                                       DECIMATE_BY_64             | \
                                       OD_UNDERRUN_PROTECT_ENABLE | \
                                       OD_DATA_MSB_ALIGNED      | \
                                       DMIC0_DATA_LSB_ALIGNED   | \
                                       DMIC1_DATA_LSB_ALIGNED   | \
                                       OD_DMA_REQ_DISABLE         | \
                                       DMIC0_DMA_REQ_DISABLE      | \
                                       DMIC1_DMA_REQ_DISABLE      | \
                                       OD_INT_GEN_DISABLE         | \
                                       DMIC0_INT_GEN_ENABLE       | \
                                       DMIC1_INT_GEN_DISABLE      | \
                                       OD_DISABLE               | \
                                       DMIC0_ENABLE               | \
                                       DMIC1_DISABLE)
#define DMIC_BUF_SIZE                                        10


static const float kMinLevel = 30.f;
float _db = 0.f;
float _db_max = 0.f;
static int16_t dmic_value = {0};
static int16_t dmic_index = 0;
static struct SwTimer inmp522_timer;
static void INMP522_ContinuousTimerCallback(void *arg);

float db_value;

void inmp522_init(uint32_t period_ms)
{
    /** Configure DMIC input to test INMP522 microphone. */

    /* Configure AUDIOCLK to 2 MHz and AUDIOSLOWCLK to 1 MHz. */
    CLK-&gt;DIV_CFG1 &amp;= ~(AUDIOCLK_PRESCALE_64 | AUDIOSLOWCLK_PRESCALE_4);
    CLK-&gt;DIV_CFG1 |= AUDIOCLK_PRESCALE_4 | AUDIOSLOWCLK_PRESCALE_2;

    /* Configure OD, DMIC0 and DMIC1 */
    Sys_Audio_Set_Config(AUDIO_CONFIG);

    Sys_Audio_Set_DMICConfig(DMIC0_DCRM_CUTOFF_20HZ | DMIC1_DCRM_CUTOFF_20HZ |
                           DMIC1_DELAY_DISABLE | DMIC0_FALLING_EDGE |
                           DMIC1_RISING_EDGE, 0);

    Sys_Audio_DMICDIOConfig(DIO_6X_DRIVE | DIO_LPF_DISABLE | DIO_NO_PULL,
                            10, 6, DIO_MODE_AUDIOCLK);

    /* Configure Gains for DMIC0, DMIC1 and OD */
    AUDIO-&gt;DMIC0_GAIN = AUDIO_DMIC0_GAIN;
    NVIC_EnableIRQ(DMIC_OUT_OD_IN_IRQn);


        SwTimer_Initialize(&amp;inmp522_timer);
        SwTimer_AttachScheduled(&amp;inmp522_timer,&amp;INMP522_ContinuousTimerCallback, NULL);
        SwTimer_ExpireInMs(&amp;inmp522_timer, period_ms);


}

/*
    分贝计算
*/
static float inmp522_process(void)
{
    float sum_square_ = 0;
    for (size_t i = 0; i &lt; DMIC_BUF_SIZE; ++i) {
      sum_square_ += abs(dmic_value<i>);
    }
    float rms = sum_square_ / (DMIC_BUF_SIZE);

    rms = 20.f * log10(rms);
    if (rms &lt; kMinLevel)
      rms = kMinLevel;
    return rms;
}


/*
    连续读取定时器回调函数
*/
static void INMP522_ContinuousTimerCallback(void *arg)
{
        extern data_manage_t noise_dm;

    SwTimer_Advance(&amp;inmp522_timer);

    db_value = (float)((_db_max-30.f)*4.f);
    uint8_t data = (uint8_t)db_value;
    _db_max = 0;
    data_write(&amp;noise_dm,(uint8_t *)&amp;data,1);
}

/*
    音频中断处理
*/
void DMIC_OUT_OD_IN_IRQHandler(void)
{

        if(dmic_index &gt;= DMIC_BUF_SIZE){
                _db = inmp522_process();
                if(_db &gt; _db_max){
                        _db_max = _db;
                }
                dmic_index = 0;
        }
        dmic_value = (int16_t)AUDIO-&gt;DMIC0_DATA;
        dmic_index++;

}
</i></code></pre>

<p><i><span style="font-size:14.0pt"><span lang="en-US" style="font-weight:bold"><span style="font-family:Calibri">4</span></span><span lang="zh-CN" style="font-weight:bold"><span style="font-family:&quot;Microsoft YaHei&quot;">、角速度及转动圈数数据</span></span></span></i></p>

<p><i><span style="font-size:14.0pt"><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">角速度数据和转动圈数数据依靠</span><span lang="zh-CN" style="font-family:Calibri">BHI160</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">进行获取,这里为了减少数据保存的数量,使用了</span><span lang="en-US" style="font-family:Calibri">BHI160</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">的运动模式识别功能,也是为了减少数据存储空间的压力,</span> <span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">依靠</span><span lang="zh-CN" style="font-family:Calibri">BHI160</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">芯片内部的运动识别功能,识别到运动后,开始记录角速度数据,静止后则停止记录角速度数据,同时芯片内部还自动拟合角度数据,那么通过对角度象限的判断就可以获取转动的完整圈了,所以圈数和角速度记录逻辑具体代码实现如下:</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;</span></span></i></p>

<pre>
<i>
<code class="language-cpp">main.c

int main(void)
{

......
    /** Initialize BHI160 + load BMM150 RAM patch */
    BHI160_NDOF_Initialize();
    BHI160_NDOF_EnableSensor(BHI160_NDOF_S_ACTIVITY_RECOGNITION, BHY_ActivityCallback, 1);
......

}





// 角速度信息
void BHY_RateOfRotationCallback(bhy_data_generic_t *data, bhy_virtual_sensor_t sensor)
{
        bhy_data_vector_t bhy_rotation;
//        uint16_t dyn_range = BHI160_NDOF_GetGyroDynamicRange();
    memcpy(&amp;bhy_rotation, &amp;data-&gt;data_vector, sizeof(bhy_data_vector_t));
//   / 32768 * 2000 * 60 /360= 0.0101725f rpm
    float gyro = bhy_rotation.x * 0.0101725f;
    if(gyro &gt;= 0 &amp;&amp; gyro &gt; sum_gyro)
            sum_gyro = gyro;
    else if(gyro &lt; 0 &amp;&amp; gyro &lt; -sum_gyro)
            sum_gyro = -gyro;
    ava_gyro = (uint8_t)(sum_gyro + 127 );
    uint8_t gyro_u8 = gyro + 127;
    data_write(&amp;rotation_dm,(uint8_t *)&amp;gyro_u8,1);
}

// 加速度信息
void BHY_AccelerationCallback(bhy_data_generic_t *data, bhy_virtual_sensor_t sensor)
{
        bhy_data_vector_t bhy_acceleration;
    memcpy(&amp;bhy_acceleration, &amp;data-&gt;data_vector, sizeof(bhy_data_vector_t));


}

// 角度信息
void BHY_OrientationCallback(bhy_data_generic_t *data, bhy_virtual_sensor_t sensor)
{
        bhy_data_vector_t bhy_orientation;
    memcpy(&amp;bhy_orientation, &amp;data-&gt;data_vector, sizeof(bhy_data_vector_t));
    angle_back = bhy_orientation.x / 32768.0f * 360.0f;
    if((angle_back &lt; 90.f &amp;&amp; angle_front &gt;270.f) || (angle_back &gt; 270.f &amp;&amp; angle_front &lt; 90.f))
    {
            round_count++;
    }
    angle_front = angle_back;

}


//当运动状态改变时,启动角速度、角度、加速度数据获取
void BHY_ActivityCallback(bhy_data_generic_t *data, bhy_virtual_sensor_t sensor)
{
        bhy_data_scalar_u16_t bhy_Activity;
        static uint16_t last_bhy_Activity = 0;
        memcpy(&amp;bhy_Activity, &amp;data-&gt;data_scalar_u16, sizeof(bhy_data_scalar_u16_t));
        if(bhy_Activity.data == 0x0001 ||bhy_Activity.data == 0x0100)
        {
                if(bhy_Activity.data != last_bhy_Activity){
                        switch(bhy_Activity.data)
                        {
                        case 0x0001:        //still ended
//                          BHI160_NDOF_EnableSensor(BHI160_NDOF_S_LINEAR_ACCELERATION, BHY_AccelerationCallback, 100);
                          BHI160_NDOF_EnableSensor(BHI160_NDOF_S_RATE_OF_ROTATION, BHY_RateOfRotationCallback, 1);
                          BHI160_NDOF_EnableSensor(BHI160_NDOF_S_ORIENTATION, BHY_OrientationCallback, 100);
                                break;
                        case 0x0100://still start

//                                BHI160_NDOF_DisableSensor(BHI160_NDOF_S_LINEAR_ACCELERATION);
                                BHI160_NDOF_DisableSensor(BHI160_NDOF_S_RATE_OF_ROTATION);
                                BHI160_NDOF_DisableSensor(BHI160_NDOF_S_ORIENTATION);
                                break;
                        }
                }
                last_bhy_Activity = bhy_Activity.data;
        }

}
</code></i></pre>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;"><span style="font-weight:bold">二、数据存储</span></span></span></i></p>

<p><i><span style="font-size:14.0pt"><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">平时,我们在单片机里对数据进行存储,可以通过</span><span lang="en-US" style="font-family:Calibri">RAM</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">中的变量来进行存储,或者需要掉电保存的数据可以储存在</span><span lang="en-US" style="font-family:Calibri">FLASH/</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">外部</span><span lang="en-US" style="font-family:Calibri">FLASH</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">等介质中,但往往要根据实际情况来决定使用何种方式进行。</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">本项目中要记录蜜袋鼯一天</span><span lang="en-US" style="font-family:Calibri">(</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">我们的一晚上</span><span lang="en-US" style="font-family:Calibri">)</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">的运动量和环境数据,具体包括温度、光照、噪声和运动数据等。每种数据又因为数值范围的不同占用空间也不同。</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">比如温度数据就可以认为室内就</span><span lang="en-US" style="font-family:Calibri">10</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">度</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">-35</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">度之间,那么一个</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">8</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">位的数据就可以表示</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">0.1</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">精度的温度了;</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">光照一般室内在0-2000lux不等,那么通过压缩,一个8位数据也可以表示10lux精度的光照了;</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">噪音一般是</span><span lang="en-US" style="font-family:Calibri">30</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">-120db</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">不等,也可以通过</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">8</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">位数据表示</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">1db</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">分辨率的噪音;</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">运动数据包括最大角速度、圈数和运动的波形数据,这里我已</span><span lang="en-US" style="font-family:Calibri">RPM</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">为角速度单位,按照分析小蜜再怎么快也应该超不过</span><span lang="en-US" style="font-family:Calibri">100</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">rpm</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">,所以最大角速度和运动波形数据单位值一个字节也够用了,而运动圈数可能一晚上跑个</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">10000</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">圈,所以就给个两个字节来存储;</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">以上就算都一组数据,如果同时记录一组的话 则需要 7bytes</span></span></i></p>

<p lang="en-US"><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">一晚上按照</span><span lang="en-US" style="font-family:Calibri">8</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">小时计算的话,那就是</span><span lang="en-US" style="font-family:Calibri">480</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">分钟,那就是</span><span lang="zh-CN" style="font-family:Calibri">28,800</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">秒钟,如果一秒钟一个数据,那就是</span><span lang="en-US" style="font-family:Calibri">28.8</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">k * 7 = 201.6Kbytes</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">。</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">不过讲实际的,1s中记录一次没啥必要。比如像温度、光照、噪声可以频率低一些,这里我采用5分钟记录一个值;运动数据呢,肯定会有大量的静止状态,所以只记录运动时的数据就好了。</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">那这样的话,</span><span lang="en-US" style="font-family:Calibri">24</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">小时的固定记录的温度、光照、噪声数据的空间占用则可以缩小为</span><span lang="en-US" style="font-family:Calibri">288</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">bytes*3</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">,运动数据以</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">10hz</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">来记录,按照一小时的活动量,就是</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">3.6kbytes</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">的数据。</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">我们来看下RSL10的内存资源,如下图所示,基本上用一个RAM块足够够的了。</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:Calibri">&nbsp;</span></span></i></p>

<p><i> &nbsp;</i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">不过板子上有个</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">N</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">24RF64,一个</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">NFC</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">芯片带了</span><span lang="en-US" style="font-family:Calibri">8K</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">bytes</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">的片外</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">flash</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">,我寻思着就把数据放在这里吧,还可以放置掉电丢失,于是就写了一套简单的数据内存管理模块,可以实现为不同类型的数据申请内存空间,利用缓存机制,来实现数据保存到</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">flash</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">的操作,并通过读取接口,可以顺序读取</span><span lang="en-US" style="font-family:&quot;Microsoft YaHei&quot;">flash</span><span lang="zh-CN" style="font-family:&quot;Microsoft YaHei&quot;">中的对应数据等功能。</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">具体代码如下:</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">内存初始化操作:</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;</span></span></i></p>

<pre>
<i>
<code class="language-cpp">void data_manage_init(data_manage_t * p_dm,uint32_t addr,uint32_t length)
{

        if(length &lt;= BUFFER_SIZE)
                p_dm-&gt;buf_full_num = 0;
        else if(length % BUFFER_SIZE == 0)
                p_dm-&gt;buf_full_num = length/BUFFER_SIZE;
        else
                p_dm-&gt;buf_full_num = length/BUFFER_SIZE + 1;


        if(p_dm-&gt;r_buf == NULL &amp;&amp; p_dm-&gt;w_buf == NULL &amp;&amp; p_dm-&gt;buf_full_num == 0){
                p_dm-&gt;w_buf = malloc(length);
                p_dm-&gt;r_buf = malloc(length);
                memset(p_dm-&gt;w_buf,0x00,length);
                memset(p_dm-&gt;r_buf,0x00,length);
        }

        else if(p_dm-&gt;r_buf == NULL &amp;&amp; p_dm-&gt;w_buf == NULL &amp;&amp; p_dm-&gt;buf_full_num &gt; 0)
        {
                p_dm-&gt;w_buf = malloc(BUFFER_SIZE);
                p_dm-&gt;r_buf = malloc(BUFFER_SIZE);
                memset(p_dm-&gt;w_buf,0x00,BUFFER_SIZE);
                memset(p_dm-&gt;r_buf,0x00,BUFFER_SIZE);
        }

        p_dm-&gt;buf_r_index = 0;
        p_dm-&gt;eprom_addr = addr;
        p_dm-&gt;eprom_len = length;


        if(p_dm-&gt;buf_full_num == 0)
        {
                NVIC_DisableIRQ(SW_TIMER_TIMER_IRQN);
                I2CEeprom_Write(addr, (uint8_t*)p_dm-&gt;w_buf, length , &amp;eeprom);
                NVIC_EnableIRQ(SW_TIMER_TIMER_IRQN);
        }
        else
        {
                for(uint16_t i = 0;i &lt; p_dm-&gt;buf_full_num ;i++ )
                {
                        NVIC_DisableIRQ(SW_TIMER_TIMER_IRQN);
                        int8_t retval = I2CEeprom_Write(addr + BUFFER_SIZE * i, (uint8_t*)p_dm-&gt;w_buf, BUFFER_SIZE , &amp;eeprom);
                        NVIC_EnableIRQ(SW_TIMER_TIMER_IRQN);
                        if(retval != I2C_EEPROM_OK)
                                break;
                }
        }

}</code></i></pre>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">数据写入操作:</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;</span></span></i></p>

<pre>
<i>
<code class="language-cpp">void data_write(data_manage_t * p_dm,uint8_t* data,uint32_t length)
{

        if(p_dm-&gt;buf_full_num == 0)
        {
                if(p_dm-&gt;buf_w_index &lt; p_dm-&gt;eprom_len)
                {
                        memcpy(p_dm-&gt;w_buf + p_dm-&gt;buf_w_index ,data , length);
                        p_dm-&gt;buf_w_index += length;
                }
                else
                {
                        NVIC_DisableIRQ(SW_TIMER_TIMER_IRQN);
                  I2CEeprom_Write(p_dm-&gt;eprom_addr, p_dm-&gt;w_buf, p_dm-&gt;eprom_len, &amp;eeprom);
                  NVIC_EnableIRQ(SW_TIMER_TIMER_IRQN);
                  p_dm-&gt;buf_w_index = 0;
                }
        }
        else
        {
                if(p_dm-&gt;buf_w_index &lt; BUFFER_SIZE)
                {
                        memcpy(p_dm-&gt;w_buf + p_dm-&gt;buf_w_index ,data , length);
                        p_dm-&gt;buf_w_index += length;
                }
                else
                {
                        NVIC_DisableIRQ(SW_TIMER_TIMER_IRQN);
                        I2CEeprom_Write(p_dm-&gt;eprom_addr + p_dm-&gt;buf_w_num * BUFFER_SIZE, p_dm-&gt;w_buf, BUFFER_SIZE, &amp;eeprom);
                        NVIC_EnableIRQ(SW_TIMER_TIMER_IRQN);
                        p_dm-&gt;buf_w_index = 0;

                        p_dm-&gt;buf_w_num++;
                        if(p_dm-&gt;buf_w_num &gt;= p_dm-&gt;buf_full_num)
                        {
                                p_dm-&gt;buf_w_num = 0;
                        }
                }
        }
}</code></i></pre>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">数据读取操作:</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;</span></span></i></p>

<pre>
<i>
<code class="language-cpp">//初始化读取索引
void data_read_index_reset(data_manage_t * p_dm)
{
        p_dm-&gt;buf_r_index = 0;
        p_dm-&gt;buf_r_num = 0;
}
//读取方法
void data_read(data_manage_t * p_dm,uint8_t * data)
{
        if(p_dm-&gt;buf_full_num == 0)
        {
                if(p_dm-&gt;buf_r_index == 0)
                {
                        NVIC_DisableIRQ(SW_TIMER_TIMER_IRQN);
                  I2CEeprom_Read(p_dm-&gt;eprom_addr, p_dm-&gt;r_buf, p_dm-&gt;eprom_len, &amp;eeprom);
                  NVIC_EnableIRQ(SW_TIMER_TIMER_IRQN);
                }
                if(p_dm-&gt;buf_r_index &lt; p_dm-&gt;eprom_len &amp;&amp; p_dm-&gt;eprom_len &lt; 18)
                {
                        memset(data, 0x00, 18);
                        memcpy(data, p_dm-&gt;r_buf , p_dm-&gt;eprom_len);
                        p_dm-&gt;buf_r_index = p_dm-&gt;eprom_len;
                }
                else if(p_dm-&gt;buf_r_index &lt; p_dm-&gt;eprom_len &amp;&amp; p_dm-&gt;eprom_len &gt;= 18)
                {
                        if(p_dm-&gt;eprom_len - p_dm-&gt;buf_r_index &gt;= 18)
                        {
                                memset(data, 0x00, 18);
                                memcpy(data, p_dm-&gt;r_buf , 18);
                                p_dm-&gt;buf_r_index += 18;
                        }
                        else
                        {
                                memset(data, 0x00, 18);
                                memcpy(data, p_dm-&gt;r_buf , p_dm-&gt;eprom_len - p_dm-&gt;buf_r_index);
                                p_dm-&gt;buf_r_index = p_dm-&gt;eprom_len;
                        }
                }
                if(p_dm-&gt;buf_r_index == p_dm-&gt;eprom_len)
                {
                        p_dm-&gt;buf_r_index = 0;
                }
        }
        else
        {
                if(p_dm-&gt;buf_r_index == 0)
                {
                        NVIC_DisableIRQ(SW_TIMER_TIMER_IRQN);
                  I2CEeprom_Read(p_dm-&gt;eprom_addr, p_dm-&gt;r_buf, BUFFER_SIZE, &amp;eeprom);
                  NVIC_EnableIRQ(SW_TIMER_TIMER_IRQN);
                }
                if(BUFFER_SIZE - p_dm-&gt;buf_r_index &gt;= 18 )
                {
                        memset(data, 0x00, 18);
                        memcpy(data, p_dm-&gt;r_buf , 18);
                        p_dm-&gt;buf_r_index += 18;
                }
                else if(BUFFER_SIZE - p_dm-&gt;buf_r_index &lt; 18)
                {
                        memset(data, 0x00, 18);
                        memcpy(data, p_dm-&gt;r_buf , BUFFER_SIZE - p_dm-&gt;buf_r_index);
                        p_dm-&gt;buf_r_index = BUFFER_SIZE;
                }
                //此处存在最后一包读取过量的bug
                if(p_dm-&gt;buf_r_index == BUFFER_SIZE)
                {
                        p_dm-&gt;buf_r_index = 0;
                        p_dm-&gt;buf_r_num ++;
                        if(p_dm-&gt;buf_r_num &gt;= p_dm-&gt;buf_full_num)
                        {
                                p_dm-&gt;buf_r_num = 0;
                        }
                }
        }
//
}
// 获取数据包数
uint16_t get_data_pkg_cnt(data_manage_t * p_dm)
{
        uint16_t cnt = 0;
        if(p_dm-&gt;buf_full_num == 0)
        {
                if(p_dm-&gt;buf_w_index % 18 != 0)
                {
                        cnt = p_dm-&gt;buf_w_index / 18 + 1;
                }
                else
                {
                        cnt = p_dm-&gt;buf_w_index / 18;
                }
        }
        else
        {
                if((p_dm-&gt;buf_w_index + p_dm-&gt;buf_w_num * BUFFER_SIZE) % 18 != 0)
                {
                        cnt = (p_dm-&gt;buf_w_index + p_dm-&gt;buf_w_num * BUFFER_SIZE) / 18 + 1;
                }else
                {
                        cnt = (p_dm-&gt;buf_w_index + p_dm-&gt;buf_w_num * BUFFER_SIZE) / 18;
                }
        }
        return cnt;
}</code></i></pre>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">flash擦除操作:</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;</span></span></i></p>

<pre>
<i>
<code>void data_empty(data_manage_t * p_dm)
{
        p_dm-&gt;buf_w_index = 0;
        p_dm-&gt;buf_w_num = 0;

        if(p_dm-&gt;buf_full_num == 0)
        {
                memset(p_dm-&gt;w_buf,0x00,p_dm-&gt;eprom_len);
                memset(p_dm-&gt;r_buf,0x00,p_dm-&gt;eprom_len);
        }
        else
        {
                memset(p_dm-&gt;w_buf,0x00,BUFFER_SIZE);
                memset(p_dm-&gt;r_buf,0x00,BUFFER_SIZE);
        }
        NVIC_DisableIRQ(SW_TIMER_TIMER_IRQN);
        I2CEeprom_Write(p_dm-&gt;eprom_addr, p_dm-&gt;w_buf, p_dm-&gt;eprom_len, &amp;eeprom);
        NVIC_EnableIRQ(SW_TIMER_TIMER_IRQN);
}
</code></i></pre>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">写完各部分功能代码,进行实验时发现N24RF64的读取写入速度太慢了。。测试了下8K的内容全部擦除需要接近2s的时间&hellip;</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">于是考虑板子也不会掉电,就吧数据存在RAM里好了。所以改了下内存存储的逻辑,如下所示:</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">内存初始化操作:</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;</span></span></i></p>

<pre>
<i>
<code>void data_manage_init(data_manage_t * p_dm,uint8_t* buf,uint32_t length)
{
        memset(buf, 0x00, length);
        p_dm-&gt;w_buf = buf;
        p_dm-&gt;r_buf = buf;

        p_dm-&gt;buf_r_index = 0;
        p_dm-&gt;eprom_addr = (uint32_t)buf;
        p_dm-&gt;eprom_len = length;

}</code></i></pre>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">数据写入操作:</span></span></i></p>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">&nbsp;</span></span></i></p>

<pre>
<i>
<code class="language-cpp">void data_write(data_manage_t * p_dm,uint8_t* data,uint32_t length)
{
        if(p_dm-&gt;buf_w_index &lt; p_dm-&gt;eprom_len)
        {
                memcpy(p_dm-&gt;w_buf + p_dm-&gt;buf_w_index ,data , length);
                p_dm-&gt;buf_w_index += length;
        }
        else
        {
                p_dm-&gt;buf_w_index = 0;
        }
}</code></i></pre>

<p><i><span style="font-size:14.0pt"><span style="font-family:&quot;Microsoft YaHei&quot;">数据读取操作:</span></span></i></p>

<pre>
<i>
<code>void data_read_index_reset(data_manage_t * p_dm)
{
        p_dm-&gt;buf_r_index = 0;
}

void data_read(data_manage_t * p_dm,uint16_t cnt,uint8_t * data)
{
        memcpy(data, p_dm-&gt;r_buf+(cnt-1)*18 , 18);
}

uint16_t get_data_pkg_cnt(data_manage_t * p_dm)
{
        uint16_t cnt = 0;
        if(p_dm-&gt;buf_w_index % 18 != 0)
        {
                cnt = p_dm-&gt;buf_w_index / 18 + 1;
        }
        else
        {
                cnt = p_dm-&gt;buf_w_index / 18;
        }
        return cnt;
}</code></i></pre>
</div>
</div>
</div>
页: [1]
查看完整版本: 蜜袋鼯 第⑨贴 基于RSL10的蜜袋鼯数据监测子系统-设计与实现