一、项目介绍
本项目是一个以 NXP FRDM-MCXN236 开发板为平台,基于zephyr实现 环境数据的采集与显示 :通过 I2C 总线采集三轴加速度、温度、湿度等环境数据,经处理后实时显示在 OLED 屏上,并可通过按键切换显示界面。
二、硬件部分
FRDM-MCXN236:FRDM-MCXN236是一款紧凑且可扩展的开发板,可让您快速基于MCX N23x MCU开展原型设计。它们提供行业标准的接口,可轻松访问MCU的I/O、集成的开放标准串行接口、外部闪存和板载MCU-Link调试器。

0.96寸OLED:OLED是有机发光二极管,又称为有机电激光显示(Organic Electroluminescence Display, OLED)。OLED由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为是下一代的平面显示器新兴应用技术

sht45:SHT45 传感器是第四代产品(从 SHT10 起步,一路发展至巅峰)。SHT45 在 20% 至 70% 的相对湿度范围内具有出色的 ±1.0% 典型精度,在 5°C 至 60°C 范围内具有 ±0.1°C 的典型精度。

FXLS8974CFR3:FXLS8974CF是一款紧凑型3轴MEMS加速度计,适用于多种需要超低功耗运动唤醒的工业和医疗物联网应用,支持高性能和低功耗两种工作模式,可最大程度灵活满足不同应用场景对分辨率和功耗的需求。多种先进的集成数字功能可帮助设计人员降低整体系统功耗,简化主机数据采集工作。该产品采用2mm×2mm×0.95mm 10引脚DFN封装,引脚间距0.4mm,带可润湿侧翼,符合工业标准,可在-40℃至+105℃的扩展温度范围内工作,结合传感器性能、系统节能功能与宽温工作性能,适合物联网领域的运动感应应用。

三、软件部分
软件流程图

软件部分
开启了一个线程进行温湿度数据的获取,通过互斥锁保护数据的存储
static void env_thread(void *p1, void *p2, void *p3)
{
ARG_UNUSED(p1);
ARG_UNUSED(p2);
ARG_UNUSED(p3);
while (1) {
struct sensor_value temp;
struct sensor_value hum;
if (sensor_sample_fetch(sht45) < 0) {
printf("SHT45 sample fetch failed\n");
} else if (sensor_channel_get(sht45, SENSOR_CHAN_AMBIENT_TEMP,
&temp) < 0 ||
sensor_channel_get(sht45, SENSOR_CHAN_HUMIDITY, &hum) < 0) {
printf("SHT45 channel get failed\n");
} else {
/* sensor_value_to_centi() 来自 sensor.h,返回 0.01 单位的 int64_t */
int64_t t = sensor_value_to_centi(&temp);
int64_t rh = sensor_value_to_centi(&hum);
/* 串口打印:手工拆出整数位和两位小数,避免用 %f */
int t_int = (int)(t / 100);
int t_frac = (int)(t % 100);
if (t_frac < 0) {
t_frac = -t_frac;
}
printf("[env] T=%d.%02d C RH=%d.%02d %%\n",
t_int, t_frac, (int)(rh / 100), (int)(rh % 100));
k_mutex_lock(&state_lock, K_FOREVER);
state.temp_c = (int16_t)CLAMP(t, (int64_t)INT16_MIN,
(int64_t)INT16_MAX);
state.rh_pct = (uint16_t)CLAMP(rh, (int64_t)0,
(int64_t)UINT16_MAX);
state.env_valid = true;
k_mutex_unlock(&state_lock);
}
k_msleep(ENV_PERIOD_MS);
}
}
创建一个线程先进行加速度计的初始化,然后通过i2c获取加速度数据,同样通过互斥锁存储数据
static void accel_thread(void *p1, void *p2, void *p3)
{
ARG_UNUSED(p1);
ARG_UNUSED(p2);
ARG_UNUSED(p3);
while (1) {
struct sensor_value x;
struct sensor_value y;
struct sensor_value z;
if (sensor_sample_fetch(accel) < 0) {
printf("accel sample fetch failed\n");
} else if (sensor_channel_get(accel, SENSOR_CHAN_ACCEL_X, &x) < 0 ||
sensor_channel_get(accel, SENSOR_CHAN_ACCEL_Y, &y) < 0 ||
sensor_channel_get(accel, SENSOR_CHAN_ACCEL_Z, &z) < 0) {
printf("accel channel get failed\n");
} else {
int x_mg = accel_to_mg(&x);
int y_mg = accel_to_mg(&y);
int z_mg = accel_to_mg(&z);
/* 串口打印:printf 未开浮点支持,这里用整数 mg 输出 */
printf("[accel] X=%+5d mg Y=%+5d mg Z=%+5d mg\n",
x_mg, y_mg, z_mg);
k_mutex_lock(&state_lock, K_FOREVER);
state.x_mg = x_mg;
state.y_mg = y_mg;
state.z_mg = z_mg;
state.accel_valid = true;
k_mutex_unlock(&state_lock);
}
k_msleep(ACCEL_PERIOD_MS);
}
}
下面代码把获取到的x,y,z数据映射到屏幕的圆点,达到倾斜开发板,对应屏幕上的小球也会进行相应的运动
static void draw_bubble_screen(const struct sensor_state *st)
{
const struct cfb_position center = { .x = CENTER_X, .y = CENTER_Y };
const struct cfb_position h_start = { .x = CENTER_X - BUBBLE_RADIUS, .y = CENTER_Y };
const struct cfb_position h_end = { .x = CENTER_X + BUBBLE_RADIUS, .y = CENTER_Y };
const struct cfb_position v_start = { .x = CENTER_X, .y = CENTER_Y - BUBBLE_RADIUS };
const struct cfb_position v_end = { .x = CENTER_X, .y = CENTER_Y + BUBBLE_RADIUS };
int limit = BUBBLE_RADIUS - DOT_RADIUS - 1;
/* +X 向右、+Y 向上,屏幕坐标 y 轴朝下所以要取反 */
int dx = CLAMP(st->x_mg * BUBBLE_RADIUS / TILT_FULL_SCALE_MG, -limit, limit);
int dy = CLAMP(-st->y_mg * BUBBLE_RADIUS / TILT_FULL_SCALE_MG, -limit, limit);
cfb_print(oled, "BUBBLE 1/3", 0, 0);
cfb_draw_circle(oled, ¢er, BUBBLE_RADIUS);
cfb_draw_line(oled, &h_start, &h_end);
cfb_draw_line(oled, &v_start, &v_end);
draw_filled_dot(CENTER_X + dx, CENTER_Y + dy, DOT_RADIUS);
}
四、项目展示
可以通过sw2按键进行界面的切换
水平仪界面:倾斜开发板,中间的小球会随着移植

加速度界面:会实时显示获取的加速度

温湿度数据界面,通过iic获取sht45的温湿度数据,然后显示再oled屏幕上面

串口输出数据

五、心得体会
通过这次活动让我更加深入的体会到了zephyr的便捷性,不需要更改上层代码,只需要更改对应的设备树就能完成项目的移植,也让体会到mcxn236这颗芯片的性能。