0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何通过IPC通信玩转传感器数据?

RTThread物联网操作系统 来源:RTThread物联网操作系统 作者:RTThread物联网操作 2021-01-15 13:39 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

1、rt-smart的第一个应用程序,imx6ull用户态点灯

简介

首先纠正一下上一篇文章中,在我的仓库中,1月11日的代码会出现系统崩溃。原因在于我的驱动中内存物理地址映射到虚拟地址的操作有问题,我已经把这个bug解决了,如果有兴趣,欢迎拉取最新的代码。

这一篇来介绍我在rt-smart的第二个应用。这个应用将加入rt-smart与rt-thread区别之处--进程间的通信

功能主要是在用户态读取传感器数据,传感器是100ASK_imx6ull板载的ap3216c,它是采用I2C总线进行通信。

为啥这次会先对接I2C呢?因为接下来想把屏幕在rt-smart跑起来,但是屏幕的触摸芯片采用I2C,所以就把他先跑起来。

目前屏幕已经在rt-thread上跑起来,但是在rt-smart没有跑起来,目前在研究LCD的缓存是一个什么样一个形式。

100ask_imx6ull驱动对接情况:

rt-threadrt-smart

GPIO√√

I2C√√

lcd√×

100ask_imx6ull的rtt仓库:

rt-thread的仓库:https://gitee.com/RiceChen0/imx6ull_rt_rthread

rt-smart的厂库:https://gitee.com/RiceChen0/imx6ull_rt_smart

环境

100ask_imx6ull开发板。

两条micro USB线。

电源

windows电脑一台。

I2C驱动适配

在imx6ull中,我适配的是硬件I2C,imx6ull有4组I2C接口。软件I2C后续不会进行适配,因为在这颗芯片上,软件I2C的必要性不大。

如果你要了解RT-Thread的I2C设备驱动框架,可以看一下我之前的文章《rt-thread驱动框架分析》-i2c驱动

在上一篇文章中《rt-smart的第一个应用程序,imx6ull用户态点灯》讲到,rt-smart不能直接使用物理地址访问硬件,而需要采用虚拟地址。所以需要进行地址映射(rtt提供的API:rt_hw_kernel_phys_to_virt)。

首先需要查看imx6ull的芯片手册,需要将I2C相关的物理地址找到。为了不要重复造轮子,定义了一个结构体:struct i2c_addr_config,并把4组I2C相关的地址作为一个表格。如下:

#define I2C1_SCL_MUX_BASE 0x020E00B4U

#define I2C2_SCL_MUX_BASE 0x020E00BCU

#define I2C3_SCL_MUX_BASE 0x020E00E4U

#define I2C4_SCL_MUX_BASE 0x020E00ECU

#define I2C1_SCL_CFG_BASE 0x020E0340U

#define I2C2_SCL_CFG_BASE 0x020E0348U

#define I2C3_SCL_CFG_BASE 0x020E0370U

#define I2C4_SCL_CFG_BASE 0x020E0378U

#define I2C1_SCL_INPUT_BASE 0x020E05A4U

#define I2C2_SCL_INPUT_BASE 0x020E05ACU

#define I2C3_SCL_INPUT_BASE 0x020E05B4U

#define I2C4_SCL_INPUT_BASE 0x020E05BCU

#define I2C1_SDA_MUX_BASE 0x020E00B8U

#define I2C2_SDA_MUX_BASE 0x020E00C0U

#define I2C3_SDA_MUX_BASE 0x020E00E8U

#define I2C4_SDA_MUX_BASE 0x020E00F0U

#define I2C1_SDA_CFG_BASE 0x020E0344U

#define I2C2_SDA_CFG_BASE 0x020E034CU

#define I2C3_SDA_CFG_BASE 0x020E0374U

#define I2C4_SDA_CFG_BASE 0x020E037CU

#define I2C1_SDA_INPUT_BASE 0x020E05A8U

#define I2C2_SDA_INPUT_BASE 0x020E05B0U

#define I2C3_SDA_INPUT_BASE 0x020E05B8U

#define I2C4_SDA_INPUT_BASE 0x020E05C0U

struct i2c_addr_config

{

I2C_Type *i2c;

size_t i2c_scl_mux_base;

size_t i2c_scl_config_base;

size_t i2c_scl_input_base;

size_t i2c_sda_mux_base;

size_t i2c_sda_config_base;

size_t i2c_sda_input_base

};

static struct i2c_addr_config addr_config[] =

{

{I2C1, I2C1_SCL_MUX_BASE, I2C1_SCL_CFG_BASE, I2C1_SCL_INPUT_BASE, I2C1_SDA_MUX_BASE, I2C1_SDA_CFG_BASE, I2C1_SDA_INPUT_BASE},

{I2C2, I2C2_SCL_MUX_BASE, I2C2_SCL_CFG_BASE, I2C2_SCL_INPUT_BASE, I2C2_SDA_MUX_BASE, I2C2_SDA_CFG_BASE, I2C2_SDA_INPUT_BASE},

{I2C3, I2C3_SCL_MUX_BASE, I2C3_SCL_CFG_BASE, I2C3_SCL_INPUT_BASE, I2C3_SDA_MUX_BASE, I2C3_SDA_CFG_BASE, I2C3_SDA_INPUT_BASE},

{I2C4, I2C4_SCL_MUX_BASE, I2C4_SCL_CFG_BASE, I2C4_SCL_INPUT_BASE, I2C4_SDA_MUX_BASE, I2C4_SDA_CFG_BASE, I2C4_SDA_INPUT_BASE},

};

将物理地址转为虚拟地址,代码如下:

for(i = 0; i 《 sizeof(addr_config) / sizeof(addr_config[0]); i++)

{

addr_config[i].i2c = (I2C_Type *)rt_hw_kernel_phys_to_virt((void*)(addr_config[i].i2c), 0x1000);

addr_config[i].i2c_scl_mux_base = (size_t)rt_hw_kernel_phys_to_virt((void*)(addr_config[i].i2c_scl_mux_base), 0x1000);

addr_config[i].i2c_scl_config_base = (size_t)rt_hw_kernel_phys_to_virt((void*)(addr_config[i].i2c_scl_config_base), 0x1000);

addr_config[i].i2c_scl_input_base = (size_t)rt_hw_kernel_phys_to_virt((void*)(addr_config[i].i2c_scl_input_base), 0x1000);

addr_config[i].i2c_sda_mux_base = (size_t)rt_hw_kernel_phys_to_virt((void*)(addr_config[i].i2c_sda_mux_base), 0x1000);

addr_config[i].i2c_sda_config_base = (size_t)rt_hw_kernel_phys_to_virt((void*)(addr_config[i].i2c_sda_config_base), 0x1000);

addr_config[i].i2c_sda_input_base = (size_t)rt_hw_kernel_phys_to_virt((void*)(addr_config[i].i2c_sda_input_base), 0x1000);

}

在imx6ull中,I2C需要的步骤,引脚初始化为I2C,然后I2C总线初始化便可以了。

目前imx6ull上,rt-thread和rt-smart都适配I2C,所以可以先看一下rt-thread的仓库,然后再看rt-smart的仓库,可能更加理解它的区别。

I2C的应用:

100ask_imx6ull中,板载有ap3216c传感器,挂载在I2C1总线上。而且RT-Thread中有相应的软件包,对接了RT-Thread的传感器设备框架,这给我验证代码提供便携。不过要在用户态中使用该软件包,还需要做一点操作,需要注册该传感器设备。

int ap3216c_test()

{

struct rt_sensor_config cfg;

cfg.intf.dev_name = “i2c1”;

cfg.mode = RT_SENSOR_MODE_POLLING;

rt_hw_ap3216c_init(“ap”, &cfg);

return RT_EOK;

}

INIT_DEVICE_EXPORT(ap3216c_test);

然后编译烧录,通过list_device就可以看到相对应的设备(pr_ap和li_ap),如下:

29be56fa-56f1-11eb-8b86-12bb97331649.png

RT_Thread的传感器框架很贴心,提供了测试命令(sensor_polling li_ap),这样就可以初步验证传感器是否正常工作,通过验证,传感器和I2C适配都能正常工作:

29dbdc34-56f1-11eb-8b86-12bb97331649.png

上面的验证都是在内核态中测试的,而这篇文章的目的是要在用户态中读取传感器数据,为了进一步了解rt-smart和RT-Thread的区别,我这个应用采用进程通信(IPC)做了例子,该例子将上一篇文章例子结合起来:

有两个进程, 进程1和进程2

进程1,通过接收等待进程2读取的传感器数据是否超标的状态,来进行闪灯。

进程2,通过读取ap3216c传感器光强度数据,判断是否超过50lux,如果超过则通知进程1进行闪灯提示。

IPC通信,详情可以查看官网:https://www.rt-thread.org/document/site/rt-smart/architecture/architecture/。

进程1,等待接收通道发来的“warning”信息,然后进行闪灯操作:

int main(int argc, char **argv)

{

struct rt_device_pin_mode pin_mode;

struct rt_device_pin_status pin_status;

int server_ch;

int shmid;

struct rt_channel_msg msg_text;

char *str;

printf(“RiceChen rt-smart first app

”);

/* create the IPC channel for ‘server’ */

server_ch = rt_channel_open(“server”, O_CREAT);

if (server_ch == -1) {

printf(“Error: rt_channel_open: fail to create the IPC channel for server!

”);

return -1;

}

printf(“

server: wait on the IPC channel: %d

”, server_ch);

pin_dev = rt_device_find(“pin”);

if(pin_dev == RT_NULL)

{

printf(“not find pin device

”);

return RT_ERROR;

}

rt_device_open(pin_dev, RT_DEVICE_OFLAG_RDWR);

pin_mode.pin = LED_PIN;

pin_mode.mode = 0; //OUTPUT

rt_device_control(pin_dev, 0, (void *)&pin_mode);

pin_status.pin = LED_PIN;

while(1)

{

rt_channel_recv(server_ch, &msg_text); //接收通道信息

shmid = (int)msg_text.u.d;

if (shmid 《 0 || !(str = (char *)lwp_shmat(shmid, NULL)))

{

msg_text.u.d = (void *)-1;

printf(“server: receive an invalid shared-memory page.

”);

rt_channel_reply(server_ch, &msg_text); /* send back -1 */

continue;

}

if(strcmp(str, “warning”) == 0) //判断是否接收到“warning”信息

{

printf(“light warning.

”);

pin_status.status = 1;

rt_device_write(pin_dev, 0, (void *)&pin_status, sizeof(pin_status));

rt_thread_mdelay(200);

pin_status.status = 0;

rt_device_write(pin_dev, 0, (void *)&pin_status, sizeof(pin_status));

rt_thread_mdelay(200);

pin_status.status = 1;

rt_device_write(pin_dev, 0, (void *)&pin_status, sizeof(pin_status));

rt_thread_mdelay(200);

pin_status.status = 0;

rt_device_write(pin_dev, 0, (void *)&pin_status, sizeof(pin_status));

rt_thread_mdelay(200);

}

lwp_shmdt(str);

msg_text.type = RT_CHANNEL_RAW;

msg_text.u.d = (void *)1;

rt_channel_reply(server_ch, &msg_text);

}

return 0;

}

进程2,间隔两面读取一次传感器光强度数据,然后判断是否操作50lux,超过则通过通道通知进程1进行闪灯:

int main(int argc, char **argv)

{

rt_device_t ap3216c_dev;

struct rt_sensor_data sensor_data;

int res;

int server_ch;

char warning_msg[256] = { 0 };

size_t len = 0;

/* channel messages to send and return back */

struct rt_channel_msg ch_msg, ch_msg_ret;

printf(“RiceChen rt-smart second app

”);

/* open the IPC channel created by ‘pong’ */

server_ch = rt_channel_open(“server”, 0);

if (server_ch == -1)

{

printf(“Error: rt_channel_open: could not find the ‘server’ channel!

”);

return -1;

}

ap3216c_dev = rt_device_find(SENSOR_NAME);

if (ap3216c_dev == RT_NULL)

{

rt_kprintf(“Can‘t find device:%s”, SENSOR_NAME);

return -1;

}

if (rt_device_open(ap3216c_dev, RT_DEVICE_FLAG_RDWR) != RT_EOK)

{

rt_kprintf(“open device failed!”);

return -1;

}

rt_device_control(ap3216c_dev, RT_SENSOR_CTRL_SET_ODR, (void *)100);

while(1)

{

res = rt_device_read(ap3216c_dev, 0, &sensor_data, 1); //读取传感器数值

if (res != 1)

{

rt_kprintf(“read data failed!size is %d

”, res);

}

else

{

rt_kprintf(“light:%5d lux, timestamp:%5d

”, sensor_data.light, sensor_data.timestamp);

}

if(sensor_data.light 》 50) //判断阈值

{

ch_msg.type = RT_CHANNEL_RAW;

snprintf(warning_msg, 255, “%s”, “warning”);

len = strlen(warning_msg) + 1;

warning_msg[len] = ’‘;

int shmid = prepare_data(warning_msg, len);

if (shmid 《 0)

{

printf(“clent: fail to prepare the clent message.

”);

continue;

}

ch_msg.u.d = (void *)shmid;

rt_channel_send_recv(server_ch, &ch_msg, &ch_msg_ret); //发送警报信息

lwp_shmrm(shmid);

}

rt_thread_mdelay(2000);

}

rt_device_close(ap3216c_dev);

rt_channel_close(server_ch);

return 0;

}

演示

原文标题:rt-smart用户态通过IPC通信玩转传感器数据

文章出处:【微信公众号:RTThread物联网操作系统】欢迎添加关注!文章转载请注明出处。

责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 传感器
    +关注

    关注

    2573

    文章

    54363

    浏览量

    785861
  • 通信
    +关注

    关注

    18

    文章

    6314

    浏览量

    139541
  • 操作系统
    +关注

    关注

    37

    文章

    7328

    浏览量

    128611
  • IPC
    IPC
    +关注

    关注

    3

    文章

    375

    浏览量

    54546

原文标题:rt-smart用户态通过IPC通信玩转传感器数据

文章出处:【微信号:RTThread,微信公众号:RTThread物联网操作系统】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    有哪些常见的传感器数据失真原因?

      传感器数据失真的本质是 “ 传感器输出信号与被测量的真实值偏离超出允许范围 ”,其原因可按 “ 传感器自身硬件、安装与接线、外部环境、使用维护、信号处理 ” 五大维度分类,覆盖从元
    的头像 发表于 09-24 11:53 1039次阅读

    传感器如何实现数据采集联网通信

    传感器实现数据采集与联网通信是一个涉及硬件设计、协议选择、数据处理和云平台集成的系统化过程。其核心目标是将传感器采集的物理量(如温度、湿度、
    的头像 发表于 09-23 17:30 738次阅读

    雷达传感器和红外传感器的区别

    雷达传感器和红外传感器都可以进行测距,能够辅助设备进行“感知世界”的行为,虽然说功能看起来是一样的,但是实现的方式却是大有不同,红外测距是通过发射红外线,雷达测距是通过发射电磁波,从本
    的头像 发表于 08-28 17:48 725次阅读

    霍尔传感器在智慧小区燃气联网监测中的应用方案与解析

    一、核心功能设计 ‌燃气流量计量与数据采集‌ 霍尔传感器通过检测燃气表内部叶轮或涡轮上磁铁的旋转频率,将机械运动转换为电脉冲信号,实现燃气流量的精确计量(精度达±1%以内)‌。例如,全极性霍尔
    发表于 08-13 11:05

    如何选择酒精传感器

    鉴于可用技术、其应用及其性能特征的细微差别,选择适合您的特定需求的酒精传感器可能是一个复杂的过程。本指南将通过探索酒精传感器的类型、其原理、应用以及表格格式的比较分析,帮助您浏览选项并做出明智的决定
    的头像 发表于 07-21 11:37 948次阅读
    如何选择酒精<b class='flag-5'>传感器</b>

    TLE9879 SSC模块与传感器进行三线SPI通信问题求解

    我咨询一下,我在用TLE9879芯片SSC模块与MT6501传感器进行SPI通信时,我现在遇到了一个问题: 在发出读取指令和寄存地址后,MTSR发常高进行读取传感器
    发表于 07-15 07:42

    传感器数据采集的应用场景有哪些

    传感器数据采集的应用场景广泛覆盖工业、农业、医疗、交通、环保、消费电子等多个领域,其核心是通过实时感知物理世界的数据,为决策、控制或优化提供依据。以下是具体的应用场景分类及案例: 一、
    的头像 发表于 07-14 15:54 1402次阅读

    如何使用 CYW20829 将获得的传感器数据发送到广播中?

    我计划使用外部传感器将原始数据输出到蓝牙模块的闪存中,然后通过蓝牙发送原始数据,与我个人笔记本电脑的蓝牙配对,并在我的个人电脑中获取这些原始数据
    发表于 07-02 07:16

    可以通过 slavefifo 接口建立 FX3 和传感器通信吗?

    需要在CYUSB2014和AR0144c之间建立通信。 我们不采用 UVC 框架。 我们可以通过 slavefifo 接口建立 FX3 和传感器通信吗? 我已将“slfifosync”
    发表于 05-19 08:30

    STM32F103RCT6采集不同采样率传感器数据发送到位机数据不完整

    你好,我用STM32F103RCT6对2个传感器实时采集数据传感器1:SPI通信,采样率1000HZ,TIM2中断判断并通过串口1发送
    发表于 04-23 01:22

    数据采集卡与压力传感器

    本文介绍了拉压力传感器的测量原理,并使用数据采集卡,采集传感器所传递的压力信号。
    的头像 发表于 03-27 15:50 3163次阅读
    <b class='flag-5'>数据</b>采集卡与压力<b class='flag-5'>传感器</b>

    无线传感器网络:智能监测的未来

    节点通过无线通信方式连接而成的网络。这些传感器节点能够实时感知、采集、处理和传输环境参数,如温度、湿度、光照、压力、声音等。通过将这些数据
    的头像 发表于 02-25 08:34 841次阅读

    位移传感器的工作原理详解

    1. 位移传感器的定义 位移传感器是一种能够将物体的位移量转换为电信号的传感器。它可以检测物体的线性或旋转位移,并将其转换为电压、电流或数字信号输出,以便于后续的数据处理和控制。 2.
    的头像 发表于 01-19 09:45 3160次阅读

    使用DM368通过PCA9306与一个5V逻辑的传感器通信,获取数据时,应答信号始终收不到,为什么?

    我在使用DM368通过PCA9306与一个5V逻辑的传感器通信,但是获取数据时,应答信号始终收不到,而且应答的时钟与前面的地址时钟周期有一个间隔,请帮忙分析一下原因。谢谢。VREF
    发表于 01-15 07:42

    1分钟,实现传感器通过串口服务接入ZWS云

    导读本文介绍如何在1分钟内,将传感器通过串口服务GCOM80接入ZWS云平台,实现数据上云。本文以光照传感器为例,介绍
    的头像 发表于 01-10 11:37 923次阅读
    1分钟,实现<b class='flag-5'>传感器</b><b class='flag-5'>通过</b>串口服务<b class='flag-5'>器</b>接入ZWS云