蜜袋鼯 第⑨贴 基于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:"Microsoft YaHei"">前言</span></span></p>
<p><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">先来回顾下,本项目的整体架构图如下。前面几个帖子,介绍了下运动奖励系统的设计、制作和测试相关内容,本帖将对蜜袋鼯健康监测子系统部分进行介绍</span></span></p>
<p> </p>
<p><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""> </span></span></p>
<p><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""> </span></span></p>
<p><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">正文</span></span></p>
<p><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">在<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:"Microsoft YaHei""> 1、运动健康监测:将RSL10传感器开发套件安装在摩天轮上,通过光照度计收集光照数据,通过空气质量传感器收集温度信息,通过角速度计监测小蜜在摩天轮奔跑的转动速度数据,记录下一晚上的数据,存储在传感器版上。</span></span></p>
<p><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""> </span></span></p>
<p><span style="font-size:14.0pt"><span lang="zh-CN" style="font-family:"Microsoft YaHei"">为了实现如上目标,</span> <span lang="zh-CN" style="font-family:"Microsoft YaHei"">本项目中架构了运动监测系统,该系统主要部署在</span><span lang="en-US" style="font-family:Calibri">RSL10</span><span lang="en-US" style="font-family:"Microsoft YaHei"">-SENSE-GEVK</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">板子上。</span></span></p>
<p><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">依靠开发板上丰富的传感器资源来实现记录环境光照数据、环境温度数据、环境噪声数据和飞鼠滚轮的运动角速度和转动圈数等。</span></span></p>
<p><span style="font-size:14.0pt"><span lang="zh-CN" style="font-family:"Microsoft YaHei"">像下图这样,</span><span lang="en-US" style="font-family:Calibri">RSL10</span><span lang="en-US" style="font-family:"Microsoft YaHei"">-SENSE-GEVK</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">板通过双面胶直接粘在了飞轮的中间,这样经过一晚上的收集,</span></span></p>
<p> </p>
<p><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">第二天早上就可以看到整晚小蜜周围环境和运动数据了。</span></span></p>
<p><span style="font-size:11.0pt"><span style="font-family:Calibri"> </span></span></p>
<p><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">在这个目标中要实现的功能主要有两大块:数据采集和存储。</span></span></p>
<p><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""><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"> </span></span></p>
<p><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""><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"> <span lang="en-US" style="font-family:Calibri">RSL10</span><span lang="en-US" style="font-family:"Microsoft YaHei"">-SENSE-GEVK</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">板上采用的是</span><span lang="en-US" style="font-family:"Microsoft YaHei"">LV0104CS</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">这款传感器,此前,我已经将该传感器的驱动写好,分享到了<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:"Microsoft YaHei""> 光照数据采集方式就相对比较简单,LV0104CS的驱动是按照官方的代码风格实现的,只要在主函数中初始化I2C和传感器,并创建相应的回调函数,在回调函数中就可以定周期获取光照数据了,这里我为了方便数据保存,将真实的光照值除以10,这样就可以存放在一个字节呢了。</span></span></p>
<p><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">代码如下:</span></span></p>
<p><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""> </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(&light_dm,(uint8_t *)&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:"Microsoft YaHei"">、环境温度数据</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:"Microsoft YaHei"">-SENSE-GEVK</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">板上才用的</span><span lang="zh-CN" style="font-family:Calibri">BME680</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">这款芯片,</span><span lang="zh-CN" style="font-family:Calibri">BME680</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">是个多功能的环境空气检测芯片,可以测量温度、湿度、空气质量等,不过我这里仅关心小蜜所在的环境的温度数据,因此只对温度进行了处理,也是为了方便数据保存和传输,将</span><span lang="en-US" style="font-family:Calibri">16</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">位的</span><span lang="en-US" style="font-family:Calibri">x10</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">温度值转化为</span><span lang="en-US" style="font-family:Calibri">8</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">位的室温范围。</span></span></p>
<p><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">代码如下:</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(&bme680_output, output, sizeof(struct BME680_ENV_Data));
//温度数据由x100,转换为x10,并且减掉100,温度起点改为10℃,最大温度35.4℃
int16_t temperature =(output->temperature / 10)-100;
if(temperature>=UINT8_MAX)
{
temperature = UINT8_MAX;
}
else if(temperature <= 0 )
{
temperature = 0;
}
data_write(&temperature_dm,(uint8_t *)&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:"Microsoft YaHei"">、环境噪声数据</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:"Microsoft YaHei"">-SENSE-GEVK</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">板上配有一个</span><span lang="zh-CN" style="font-family:Calibri">inmp522</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">,数字</span><span lang="en-US" style="font-family:"Microsoft YaHei"">mic</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">,可以实时采集环境的声音数据,声音属于实时数据,一般我们会使用分贝计来评估环境噪音的强度,这里我对声音数据进行了一步处理,将其转换成了分贝进行数据保存,具体声音数据转分贝的公式如下:</span></span></p>
<p><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""> </span></span> </p>
<p><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">因为音频采集的中断频率很高,而我要对整晚的环境进行监测,因此我先对音频数据做了均值滤波,并进行分贝计算,然后保留这里最大的分贝值用于存储。</span></span></p>
<p><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">代码如下:</span></span></p>
<p><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""> </span></span></p>
<pre>
<code class="language-cpp">#include <BDK.h>
#include <BSP_Components.h>
#include <BLE_Components.h>
#include <ansi_color.h>
#include <SEGGER_RTT.h>
#include <math.h>
#include <SoftwareTimer.h>
#include <data_manage2.h>
#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->DIV_CFG1 &= ~(AUDIOCLK_PRESCALE_64 | AUDIOSLOWCLK_PRESCALE_4);
CLK->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->DMIC0_GAIN = AUDIO_DMIC0_GAIN;
NVIC_EnableIRQ(DMIC_OUT_OD_IN_IRQn);
SwTimer_Initialize(&inmp522_timer);
SwTimer_AttachScheduled(&inmp522_timer,&INMP522_ContinuousTimerCallback, NULL);
SwTimer_ExpireInMs(&inmp522_timer, period_ms);
}
/*
分贝计算
*/
static float inmp522_process(void)
{
float sum_square_ = 0;
for (size_t i = 0; i < DMIC_BUF_SIZE; ++i) {
sum_square_ += abs(dmic_value<i>);
}
float rms = sum_square_ / (DMIC_BUF_SIZE);
rms = 20.f * log10(rms);
if (rms < kMinLevel)
rms = kMinLevel;
return rms;
}
/*
连续读取定时器回调函数
*/
static void INMP522_ContinuousTimerCallback(void *arg)
{
extern data_manage_t noise_dm;
SwTimer_Advance(&inmp522_timer);
db_value = (float)((_db_max-30.f)*4.f);
uint8_t data = (uint8_t)db_value;
_db_max = 0;
data_write(&noise_dm,(uint8_t *)&data,1);
}
/*
音频中断处理
*/
void DMIC_OUT_OD_IN_IRQHandler(void)
{
if(dmic_index >= DMIC_BUF_SIZE){
_db = inmp522_process();
if(_db > _db_max){
_db_max = _db;
}
dmic_index = 0;
}
dmic_value = (int16_t)AUDIO->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:"Microsoft YaHei"">、角速度及转动圈数数据</span></span></span></i></p>
<p><i><span style="font-size:14.0pt"><span lang="zh-CN" style="font-family:"Microsoft YaHei"">角速度数据和转动圈数数据依靠</span><span lang="zh-CN" style="font-family:Calibri">BHI160</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">进行获取,这里为了减少数据保存的数量,使用了</span><span lang="en-US" style="font-family:Calibri">BHI160</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">的运动模式识别功能,也是为了减少数据存储空间的压力,</span> <span lang="zh-CN" style="font-family:"Microsoft YaHei"">依靠</span><span lang="zh-CN" style="font-family:Calibri">BHI160</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">芯片内部的运动识别功能,识别到运动后,开始记录角速度数据,静止后则停止记录角速度数据,同时芯片内部还自动拟合角度数据,那么通过对角度象限的判断就可以获取转动的完整圈了,所以圈数和角速度记录逻辑具体代码实现如下:</span></span></i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""> </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(&bhy_rotation, &data->data_vector, sizeof(bhy_data_vector_t));
// / 32768 * 2000 * 60 /360= 0.0101725f rpm
float gyro = bhy_rotation.x * 0.0101725f;
if(gyro >= 0 && gyro > sum_gyro)
sum_gyro = gyro;
else if(gyro < 0 && gyro < -sum_gyro)
sum_gyro = -gyro;
ava_gyro = (uint8_t)(sum_gyro + 127 );
uint8_t gyro_u8 = gyro + 127;
data_write(&rotation_dm,(uint8_t *)&gyro_u8,1);
}
// 加速度信息
void BHY_AccelerationCallback(bhy_data_generic_t *data, bhy_virtual_sensor_t sensor)
{
bhy_data_vector_t bhy_acceleration;
memcpy(&bhy_acceleration, &data->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(&bhy_orientation, &data->data_vector, sizeof(bhy_data_vector_t));
angle_back = bhy_orientation.x / 32768.0f * 360.0f;
if((angle_back < 90.f && angle_front >270.f) || (angle_back > 270.f && angle_front < 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(&bhy_Activity, &data->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:"Microsoft YaHei""><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:"Microsoft YaHei"">平时,我们在单片机里对数据进行存储,可以通过</span><span lang="en-US" style="font-family:Calibri">RAM</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">中的变量来进行存储,或者需要掉电保存的数据可以储存在</span><span lang="en-US" style="font-family:Calibri">FLASH/</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">外部</span><span lang="en-US" style="font-family:Calibri">FLASH</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">等介质中,但往往要根据实际情况来决定使用何种方式进行。</span></span></i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""> </span></span></i></p>
<p><i><span style="font-size:14.0pt"><span lang="zh-CN" style="font-family:"Microsoft YaHei"">本项目中要记录蜜袋鼯一天</span><span lang="en-US" style="font-family:Calibri">(</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">我们的一晚上</span><span lang="en-US" style="font-family:Calibri">)</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">的运动量和环境数据,具体包括温度、光照、噪声和运动数据等。每种数据又因为数值范围的不同占用空间也不同。</span></span></i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""> </span></span></i></p>
<p><i><span style="font-size:14.0pt"><span lang="zh-CN" style="font-family:"Microsoft YaHei"">比如温度数据就可以认为室内就</span><span lang="en-US" style="font-family:Calibri">10</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">度</span><span lang="en-US" style="font-family:"Microsoft YaHei"">-35</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">度之间,那么一个</span><span lang="en-US" style="font-family:"Microsoft YaHei"">8</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">位的数据就可以表示</span><span lang="en-US" style="font-family:"Microsoft YaHei"">0.1</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">精度的温度了;</span></span></i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">光照一般室内在0-2000lux不等,那么通过压缩,一个8位数据也可以表示10lux精度的光照了;</span></span></i></p>
<p><i><span style="font-size:14.0pt"><span lang="zh-CN" style="font-family:"Microsoft YaHei"">噪音一般是</span><span lang="en-US" style="font-family:Calibri">30</span><span lang="en-US" style="font-family:"Microsoft YaHei"">-120db</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">不等,也可以通过</span><span lang="en-US" style="font-family:"Microsoft YaHei"">8</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">位数据表示</span><span lang="en-US" style="font-family:"Microsoft YaHei"">1db</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">分辨率的噪音;</span></span></i></p>
<p><i><span style="font-size:14.0pt"><span lang="zh-CN" style="font-family:"Microsoft YaHei"">运动数据包括最大角速度、圈数和运动的波形数据,这里我已</span><span lang="en-US" style="font-family:Calibri">RPM</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">为角速度单位,按照分析小蜜再怎么快也应该超不过</span><span lang="en-US" style="font-family:Calibri">100</span><span lang="en-US" style="font-family:"Microsoft YaHei"">rpm</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">,所以最大角速度和运动波形数据单位值一个字节也够用了,而运动圈数可能一晚上跑个</span><span lang="en-US" style="font-family:"Microsoft YaHei"">10000</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">圈,所以就给个两个字节来存储;</span></span></i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""> </span></span></i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">以上就算都一组数据,如果同时记录一组的话 则需要 7bytes</span></span></i></p>
<p lang="en-US"><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""> </span></span></i></p>
<p><i><span style="font-size:14.0pt"><span lang="zh-CN" style="font-family:"Microsoft YaHei"">一晚上按照</span><span lang="en-US" style="font-family:Calibri">8</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">小时计算的话,那就是</span><span lang="en-US" style="font-family:Calibri">480</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">分钟,那就是</span><span lang="zh-CN" style="font-family:Calibri">28,800</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">秒钟,如果一秒钟一个数据,那就是</span><span lang="en-US" style="font-family:Calibri">28.8</span><span lang="en-US" style="font-family:"Microsoft YaHei"">k * 7 = 201.6Kbytes</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">。</span></span></i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""> </span></span></i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">不过讲实际的,1s中记录一次没啥必要。比如像温度、光照、噪声可以频率低一些,这里我采用5分钟记录一个值;运动数据呢,肯定会有大量的静止状态,所以只记录运动时的数据就好了。</span></span></i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""> </span></span></i></p>
<p><i><span style="font-size:14.0pt"><span lang="zh-CN" style="font-family:"Microsoft YaHei"">那这样的话,</span><span lang="en-US" style="font-family:Calibri">24</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">小时的固定记录的温度、光照、噪声数据的空间占用则可以缩小为</span><span lang="en-US" style="font-family:Calibri">288</span><span lang="en-US" style="font-family:"Microsoft YaHei"">bytes*3</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">,运动数据以</span><span lang="en-US" style="font-family:"Microsoft YaHei"">10hz</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">来记录,按照一小时的活动量,就是</span><span lang="en-US" style="font-family:"Microsoft YaHei"">3.6kbytes</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">的数据。</span></span></i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""> </span></span></i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">我们来看下RSL10的内存资源,如下图所示,基本上用一个RAM块足够够的了。</span></span></i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:Calibri"> </span></span></i></p>
<p><i> </i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""> </span></span></i></p>
<p><i><span style="font-size:14.0pt"><span lang="zh-CN" style="font-family:"Microsoft YaHei"">不过板子上有个</span><span lang="en-US" style="font-family:"Microsoft YaHei"">N</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">24RF64,一个</span><span lang="en-US" style="font-family:"Microsoft YaHei"">NFC</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">芯片带了</span><span lang="en-US" style="font-family:Calibri">8K</span><span lang="en-US" style="font-family:"Microsoft YaHei"">bytes</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">的片外</span><span lang="en-US" style="font-family:"Microsoft YaHei"">flash</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">,我寻思着就把数据放在这里吧,还可以放置掉电丢失,于是就写了一套简单的数据内存管理模块,可以实现为不同类型的数据申请内存空间,利用缓存机制,来实现数据保存到</span><span lang="en-US" style="font-family:"Microsoft YaHei"">flash</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">的操作,并通过读取接口,可以顺序读取</span><span lang="en-US" style="font-family:"Microsoft YaHei"">flash</span><span lang="zh-CN" style="font-family:"Microsoft YaHei"">中的对应数据等功能。</span></span></i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">具体代码如下:</span></span></i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">内存初始化操作:</span></span></i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""> </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 <= BUFFER_SIZE)
p_dm->buf_full_num = 0;
else if(length % BUFFER_SIZE == 0)
p_dm->buf_full_num = length/BUFFER_SIZE;
else
p_dm->buf_full_num = length/BUFFER_SIZE + 1;
if(p_dm->r_buf == NULL && p_dm->w_buf == NULL && p_dm->buf_full_num == 0){
p_dm->w_buf = malloc(length);
p_dm->r_buf = malloc(length);
memset(p_dm->w_buf,0x00,length);
memset(p_dm->r_buf,0x00,length);
}
else if(p_dm->r_buf == NULL && p_dm->w_buf == NULL && p_dm->buf_full_num > 0)
{
p_dm->w_buf = malloc(BUFFER_SIZE);
p_dm->r_buf = malloc(BUFFER_SIZE);
memset(p_dm->w_buf,0x00,BUFFER_SIZE);
memset(p_dm->r_buf,0x00,BUFFER_SIZE);
}
p_dm->buf_r_index = 0;
p_dm->eprom_addr = addr;
p_dm->eprom_len = length;
if(p_dm->buf_full_num == 0)
{
NVIC_DisableIRQ(SW_TIMER_TIMER_IRQN);
I2CEeprom_Write(addr, (uint8_t*)p_dm->w_buf, length , &eeprom);
NVIC_EnableIRQ(SW_TIMER_TIMER_IRQN);
}
else
{
for(uint16_t i = 0;i < p_dm->buf_full_num ;i++ )
{
NVIC_DisableIRQ(SW_TIMER_TIMER_IRQN);
int8_t retval = I2CEeprom_Write(addr + BUFFER_SIZE * i, (uint8_t*)p_dm->w_buf, BUFFER_SIZE , &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:"Microsoft YaHei"">数据写入操作:</span></span></i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""> </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->buf_full_num == 0)
{
if(p_dm->buf_w_index < p_dm->eprom_len)
{
memcpy(p_dm->w_buf + p_dm->buf_w_index ,data , length);
p_dm->buf_w_index += length;
}
else
{
NVIC_DisableIRQ(SW_TIMER_TIMER_IRQN);
I2CEeprom_Write(p_dm->eprom_addr, p_dm->w_buf, p_dm->eprom_len, &eeprom);
NVIC_EnableIRQ(SW_TIMER_TIMER_IRQN);
p_dm->buf_w_index = 0;
}
}
else
{
if(p_dm->buf_w_index < BUFFER_SIZE)
{
memcpy(p_dm->w_buf + p_dm->buf_w_index ,data , length);
p_dm->buf_w_index += length;
}
else
{
NVIC_DisableIRQ(SW_TIMER_TIMER_IRQN);
I2CEeprom_Write(p_dm->eprom_addr + p_dm->buf_w_num * BUFFER_SIZE, p_dm->w_buf, BUFFER_SIZE, &eeprom);
NVIC_EnableIRQ(SW_TIMER_TIMER_IRQN);
p_dm->buf_w_index = 0;
p_dm->buf_w_num++;
if(p_dm->buf_w_num >= p_dm->buf_full_num)
{
p_dm->buf_w_num = 0;
}
}
}
}</code></i></pre>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">数据读取操作:</span></span></i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""> </span></span></i></p>
<pre>
<i>
<code class="language-cpp">//初始化读取索引
void data_read_index_reset(data_manage_t * p_dm)
{
p_dm->buf_r_index = 0;
p_dm->buf_r_num = 0;
}
//读取方法
void data_read(data_manage_t * p_dm,uint8_t * data)
{
if(p_dm->buf_full_num == 0)
{
if(p_dm->buf_r_index == 0)
{
NVIC_DisableIRQ(SW_TIMER_TIMER_IRQN);
I2CEeprom_Read(p_dm->eprom_addr, p_dm->r_buf, p_dm->eprom_len, &eeprom);
NVIC_EnableIRQ(SW_TIMER_TIMER_IRQN);
}
if(p_dm->buf_r_index < p_dm->eprom_len && p_dm->eprom_len < 18)
{
memset(data, 0x00, 18);
memcpy(data, p_dm->r_buf , p_dm->eprom_len);
p_dm->buf_r_index = p_dm->eprom_len;
}
else if(p_dm->buf_r_index < p_dm->eprom_len && p_dm->eprom_len >= 18)
{
if(p_dm->eprom_len - p_dm->buf_r_index >= 18)
{
memset(data, 0x00, 18);
memcpy(data, p_dm->r_buf , 18);
p_dm->buf_r_index += 18;
}
else
{
memset(data, 0x00, 18);
memcpy(data, p_dm->r_buf , p_dm->eprom_len - p_dm->buf_r_index);
p_dm->buf_r_index = p_dm->eprom_len;
}
}
if(p_dm->buf_r_index == p_dm->eprom_len)
{
p_dm->buf_r_index = 0;
}
}
else
{
if(p_dm->buf_r_index == 0)
{
NVIC_DisableIRQ(SW_TIMER_TIMER_IRQN);
I2CEeprom_Read(p_dm->eprom_addr, p_dm->r_buf, BUFFER_SIZE, &eeprom);
NVIC_EnableIRQ(SW_TIMER_TIMER_IRQN);
}
if(BUFFER_SIZE - p_dm->buf_r_index >= 18 )
{
memset(data, 0x00, 18);
memcpy(data, p_dm->r_buf , 18);
p_dm->buf_r_index += 18;
}
else if(BUFFER_SIZE - p_dm->buf_r_index < 18)
{
memset(data, 0x00, 18);
memcpy(data, p_dm->r_buf , BUFFER_SIZE - p_dm->buf_r_index);
p_dm->buf_r_index = BUFFER_SIZE;
}
//此处存在最后一包读取过量的bug
if(p_dm->buf_r_index == BUFFER_SIZE)
{
p_dm->buf_r_index = 0;
p_dm->buf_r_num ++;
if(p_dm->buf_r_num >= p_dm->buf_full_num)
{
p_dm->buf_r_num = 0;
}
}
}
//
}
// 获取数据包数
uint16_t get_data_pkg_cnt(data_manage_t * p_dm)
{
uint16_t cnt = 0;
if(p_dm->buf_full_num == 0)
{
if(p_dm->buf_w_index % 18 != 0)
{
cnt = p_dm->buf_w_index / 18 + 1;
}
else
{
cnt = p_dm->buf_w_index / 18;
}
}
else
{
if((p_dm->buf_w_index + p_dm->buf_w_num * BUFFER_SIZE) % 18 != 0)
{
cnt = (p_dm->buf_w_index + p_dm->buf_w_num * BUFFER_SIZE) / 18 + 1;
}else
{
cnt = (p_dm->buf_w_index + p_dm->buf_w_num * BUFFER_SIZE) / 18;
}
}
return cnt;
}</code></i></pre>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">flash擦除操作:</span></span></i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""> </span></span></i></p>
<pre>
<i>
<code>void data_empty(data_manage_t * p_dm)
{
p_dm->buf_w_index = 0;
p_dm->buf_w_num = 0;
if(p_dm->buf_full_num == 0)
{
memset(p_dm->w_buf,0x00,p_dm->eprom_len);
memset(p_dm->r_buf,0x00,p_dm->eprom_len);
}
else
{
memset(p_dm->w_buf,0x00,BUFFER_SIZE);
memset(p_dm->r_buf,0x00,BUFFER_SIZE);
}
NVIC_DisableIRQ(SW_TIMER_TIMER_IRQN);
I2CEeprom_Write(p_dm->eprom_addr, p_dm->w_buf, p_dm->eprom_len, &eeprom);
NVIC_EnableIRQ(SW_TIMER_TIMER_IRQN);
}
</code></i></pre>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">写完各部分功能代码,进行实验时发现N24RF64的读取写入速度太慢了。。测试了下8K的内容全部擦除需要接近2s的时间…</span></span></i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">于是考虑板子也不会掉电,就吧数据存在RAM里好了。所以改了下内存存储的逻辑,如下所示:</span></span></i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">内存初始化操作:</span></span></i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""> </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->w_buf = buf;
p_dm->r_buf = buf;
p_dm->buf_r_index = 0;
p_dm->eprom_addr = (uint32_t)buf;
p_dm->eprom_len = length;
}</code></i></pre>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">数据写入操作:</span></span></i></p>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei""> </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->buf_w_index < p_dm->eprom_len)
{
memcpy(p_dm->w_buf + p_dm->buf_w_index ,data , length);
p_dm->buf_w_index += length;
}
else
{
p_dm->buf_w_index = 0;
}
}</code></i></pre>
<p><i><span style="font-size:14.0pt"><span style="font-family:"Microsoft YaHei"">数据读取操作:</span></span></i></p>
<pre>
<i>
<code>void data_read_index_reset(data_manage_t * p_dm)
{
p_dm->buf_r_index = 0;
}
void data_read(data_manage_t * p_dm,uint16_t cnt,uint8_t * data)
{
memcpy(data, p_dm->r_buf+(cnt-1)*18 , 18);
}
uint16_t get_data_pkg_cnt(data_manage_t * p_dm)
{
uint16_t cnt = 0;
if(p_dm->buf_w_index % 18 != 0)
{
cnt = p_dm->buf_w_index / 18 + 1;
}
else
{
cnt = p_dm->buf_w_index / 18;
}
return cnt;
}</code></i></pre>
</div>
</div>
</div>
页:
[1]