如何通過IPC通信玩轉傳感器數據?

2021-01-18 電子發燒友

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),如下:

RT_Thread的傳感器框架很貼心,提供了測試命令(sensor_polling li_ap),這樣就可以初步驗證傳感器是否正常工作,通過驗證,傳感器和I2C適配都能正常工作:

上面的驗證都是在內核態中測試的,而這篇文章的目的是要在用戶態中讀取傳感器數據,為了進一步了解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

打開APP閱讀更多精彩內容

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容圖片侵權或者其他問題,請聯繫本站作侵刪。 侵權投訴

相關焦點

  • 讓進程間通信更容易 - Pandora.js 的 IPC-Hub
    我們在淘寶業務中也是這樣實踐的,有一個問題也越發明顯,進程間如何通信呢?起初我們有一個比較簡單的 IPC 實現,通過 Domain Socket 進行通信。也是傳統的 C/S 架構的,兩個進程間進行比較基礎的消息通信(比較類似 Node-IPC 這個包)。不過實在是太基礎了,時不時地在想:在同一臺計算機上的同一個語言,為什麼要搞得這麼痛苦?
  • 如何接入IPC的GB28181平臺
    上篇文章我們講解如何通過onvif協議對接IPC,本文接下來介紹如何接入通過國內最主流的GB28181協議對接IPC。對於GB28181協議內容細節不多介紹,他是國家公安部定義的安防設備互通的協議,細節詳見《GBT28181-2016 公共安全視頻監控聯網系統信息傳輸、交換、控制技術要求.pdf》。目前城市街道,公共場所,社區等各個安防設備基本都是通過GB28181在協議互通。
  • Electron使用指南——IPC 通信
    IPC 通信1、index.html<!args) => { console.log(args)})ipcRenderer.on( &39;, (e, args) => { console.log(args)})3、main.js// Modulesconst {app, BrowserWindow, ipcMain
  • IPC國際線上研討會推薦:IPC-CFX 電子製造商的工業4.0標準
    電子行業通過使用更好的設計和效率更高的組件,與各種物聯網和其他頂尖數位技術一同進行創新。正處於建設中的互聯生態系統具有許多良好的效益,並用此來產生競爭優勢。IPC-CFX對機器與機器之間的通信進行了簡化和標準化,同時也促進了機器對企業/企業對機器的解決方案。
  • 實例:S7-200 SMART通過Modbus-RTU讀取溫溼度傳感器數據
    本實例我們介紹下西門子S7-200 SMART PLC如何通過Modbus-RTU協議讀取溫溼度傳感器的數值。本文包括如下幾個主題:1、溫溼度傳感器外觀、接線及通信參數介紹2、CPU ST20與溫溼度傳感器的接線;3、CPU ST20的編程;1、溫溼度傳感器外觀、
  • 即時通訊小程序-IPC之消息隊列
    消息隊列上次說到了進程間通信的管道,不過匿名管道有個缺點就是,只能做到有親緣關係的進程間通信,所以今天學習一個新的進程間通信方式——消息隊列。消息隊列提供了一個從一個進程向另外一個進程發送一塊數據的方法每個數據塊都被認為是有一個類型,接收者進程接收的數據塊可以有不同的類型值消息隊列也有管道一樣的不足,就是每個數據塊的最大長度是有上限的,系統上全體隊列的最大總長度也有一個上限
  • LabVIEW編程實例:如何通過TCP協議進行數據通信
    對於網絡通信來說,LabVIEW平臺本身提供了多種方法加以實現,如可以通過TCP協議、UDP協議、DataSocket技術、甚至遠程面板通信技術等方式進行通信。下面通過一個簡單的例子,演示在LabVIEW中如何通過TCP協議實現兩個程序之間的數據通信功能。
  • IPC標準委員會把AMQP定為互聯工廠的通信傳輸協議
    2-17標準分委會主席Aegis Software公司歐洲市場總監Michael Ford帶領團隊成員正著手為數據定義構建數據模型。 9月18日將在伊利諾州羅斯蒙特會展中心IPC標準開發委員會會議期間召開CFX面對面會議。更多CFX信息,請點擊www.ipc.org.cn。
  • 使用Boost 的 IPC 和 MPI 庫進行並發編程
    本文中將學習如何使用 Boost IPC 庫實現共享內存對象、消息隊列和同步文件鎖。通過使用 Boost MPI 庫,了解 environment 和 communicator 類,以及如何實現分布式通信。 注意:本文中的代碼已經用 gcc-4.3.4 和 boost-1.45 包測試過了。
  • Electron IPC 渲染線程和主線程通訊
    今天我們就看一看在 electron 中主線程是如何同渲染線程進行通訊的。那麼我們需要先了解一下什麼是主線程,什麼又是渲染線程。const {ipcRenderer} = require('electron');<p data-line="46" class="sync-line" style="margin:0;"></p>引入 ipc
  • 百步穿楊之IPC
    使用命令建立IPC$空連接:net use \\10.xxx.xxx.xxx\ipc$如果能獲取SMB的user和passwrod,則可以使用以下命令建立完整的用戶名,密碼連接:net user \\10.xxx.xxx.xxx
  • 數據是如何通過網絡傳輸的(NAT、P2P通信)
    主要是限制內網和公網的通信,通常丟棄未經許可的數據包,防火牆會檢查但是不去修改試圖進入內網的數據包的IP位址和TPC/UDP的埠信息網絡地址轉換器,NATNAT不僅檢查進入數據包的頭部中繼(Relaying)這是最可靠但也是最低效的一種P2P通信實現,其原理就是通過一個公網的IP伺服器中間人對兩個內網的客戶端的通信數據進行中繼和轉發此方法會增加伺服器的負擔,完全沒有體現出P2P的優勢,但是此方法的好處能夠保證成功,因此實踐中也常作為一種備選的方案
  • 數據通信中的模擬數據和數字數據
    ,才能真正地掌握數據通信的意義。 模擬數據在時間上和幅度取值上都是連續的,其電平隨時間連續變化。例如,語音是典型的模擬信號,其他由模擬傳感器接收到的信號如溫度、壓力、流量等也是模擬信號。數字數據在時間上離散的,在幅值上是經過量化的,它一般是由0、1的二進位代碼組成的數字序列。在通信系統中,模擬數據表示的信號稱做模擬信號,由數字數據表示的信號稱做數位訊號。二者是可以相互轉化的。
  • 開放式數控系統中IPC與PLC通信技術
    PLC在數控系統中處於協調自身所在的數控系統和外部的控制指令的位置,一方面它需要能夠執行IPC傳達的控制命令和發送數據信息,一方面也需要通過DMP接收工具機操作命令,根據這些接收到的命令輸入工具機的各個電機環節進行操作。
  • USB如何通過兩根數據線完成通信?
    USB通信格式USB接口最少有四根線連接,其中有兩根是數據線,而所有的USB數據傳輸都是通過這兩根線完成的,那麼它是怎麼做到的?那麼USB應該也有相應的通信格式要求才對,那它的格式是怎麼樣的?串口中高電平代表1,低電平代表0,並且是全雙工通信,即可以同時發送和接收數據。而 USB 有所不同,它雖然也有兩根數據線,但它們卻是採用差分傳輸,即需要兩根數據線配合才能傳輸一個bit,因此是半雙工通信,同一時間只能發送或者接收。
  • IPC 啟動「未來工廠計劃」 推動電子產業合作、轉型、現代化
    該計劃旨在通過推進和加速現代化來推動行業發展,幫助更好地製造電子產品。 基於20年來傳統技術的進步和新興/顛覆性技術(例如數位化,3D列印,機器人技術,雲計算和設備數據通信)的發展,IPC將「未來工廠計劃」解決方案供應商與原始設備製造商,EMS公司和
  • 千餘種傳感器數據如何上傳雲平臺 GSI傳感器統一接入技術助力物聯...
    傳感器是信息的重要來源,可用於傳統機械和設備工程以外的應用,以優化流程、節約資源。航空、電力、醫療、教育各個行業的傳感器形成大規模的工業物聯網,傳感器已經大量部署於實際生產中,各式各樣的傳感器產生了大量的數據,如何獲取全部數據,如何集中的存儲、管理、分析和共享這些數據,實現生產加工標準化、公共服務高效化、社會治理精準化、城市決策科學化,成為人們越來越關注的問題。
  • 那些來自傳感器的數據是如何上傳至雲端的?
    如果你在中西部地區的大型農場監控土壤數據,那麼實時視頻監控對你來說就沒什麼意義,你需要的是遠程無線連接。如果你要為犯罪高發區域安裝監控,那麼高帶寬才是王道。在第二個例子中,你可以使用不同的方式來完成視頻數據傳輸,你可以在攝像頭上安裝大功率發射機,然後直接通過移動基站獲取視頻信息,也可以通過電線桿上的少量Wi-Fi路由器將視頻數據通過超高帶寬連結直接發射給基站。
  • 如何通過USB通信來升級傳統設計
    如何通過USB通信來升級傳統設計 電子工程網 發表於 2019-10-21 16:08:01 設計具有通用串行總線(USB)通信功能的應用可使系統能夠通過各種USB主機設備進行通信,並通過USB連接提供方便的電源選擇方案
  • 由傳感器生成的數據,人工智慧要如何搞定?
    由傳感器生成的數據,人工智慧要如何搞定?比如,通過結合數據挖掘和深度學習的優勢,如今可以利用人工智慧來分析各種來源的大量數據,識別各種模式、提供交互式理解和進行智能預測。 這種創新發展的一個例子就是將人工智慧應用於由傳感器生成的數據,尤其是通過智慧型手機和其他消費者設備所收集的數據。運動傳感器數據以及其他信息比如GPS地址,可提供大量不同的數據集。因此,問題在於:「如何使用人工智慧才能充分發揮這些協同作用?」