Avance.Lab

技術紹介

第2回 Vector CAN ライブラリを用いたCAN通信

公開日:2023.12.22 更新日:2023.12.22

tag: ToolCANWindows

こんにちは、OTです。
第1回では、CAN通信開始までの初期設定について説明させていただきました。
今回は、CANメッセージの送信/受信までを説明させていただきます。

第1回と同様、Vector社から提供されているCAN通信ライブラリ「XL Driver Library」を用いて、CAN通信してみます。
通信方法としては、Virtual CAN Bus(PC内でシミュレーションする仮想のCAN BUS)を使用します。

サンプルコード(C++)

以下、CANメッセージの送信/受信を行うサンプルコードを記載させていただきます。
※エラー時の処理は省略。

第1回で作成したサンプルコードに通信テスト用の関数(CanTest)を追加。
ドライバオープン用の関数(CanDriverOpen)の詳細は第1回参照。

#include <iostream>
#include <windows.h>
#include <thread>
#include "vxlapi.h"

// グローバル変数
XLaccess		m_xlChannelMask[2];			// CANチャンネルマスク
XLaccess		m_xlChannelMask_all;		// CANチャンネルマスク(全ポート)
XLportHandle	m_xlPortHandle;				// ポートハンドル
BOOL			m_bRsvCommoActivated;		// 通信FLG

void CanDriverOpen(void);					// ドライバオープン
void CanTest(void);							// CAN通信テスト
void CanTxMsg(void);						// CANメッセージ送信
void ThreadReceiveMain(void);				// CAN受信スレッド

// ---------------------------------------------------
// 機能:メインルーチン
// ---------------------------------------------------
int main()
{
	CanDriverOpen();			// ドライバオープン
	CanTest();					// 通信テスト
}

通信テストの内容:
CAN受信スレッドを用いて、CAN受信処理開始。
その後、CAN Ch1からCAN送信し、CAN Ch2で受信したCANメッセージを画面表示します。

// -----------------------------------
// CAN通信テスト
// -----------------------------------
void CanTest(void)
{
	// CAN受信スレッド開始
	m_bRsvCommoActivated = TRUE;
	std::thread RxThread(ThreadReceiveMain);

	// CAN送信
	CanTxMsg();

	// CAN受信待機
	Sleep(1000);

	// CAN受信スレッド停止
	m_bRsvCommoActivated = FALSE;
	RxThread.join();
}

// -----------------------------------
// CANメッセージ送信
// -----------------------------------
void CanTxMsg(void)
{
	XLevent			xlEvent[1];						// 送信イベント
	unsigned int	eventCount = 1;					// 送信イベント数

	// 送信メッセージ設定
	memset(xlEvent, 0, sizeof(xlEvent));			// 初期化

	xlEvent[0].tag = XL_TRANSMIT_MSG;				// タグ:送信メッセージ
	xlEvent[0].tagData.msg.id = 0x123;				// CAN ID
	xlEvent[0].tagData.msg.flags = 0x00;			// メッセージフラグ
	xlEvent[0].tagData.msg.dlc = 8;					// DLC
	xlEvent[0].tagData.msg.data[0] = 0x01;			// 送信データ 1
	xlEvent[0].tagData.msg.data[1] = 0x02;			// 送信データ 2
	xlEvent[0].tagData.msg.data[2] = 0x03;			// 送信データ 3
	xlEvent[0].tagData.msg.data[3] = 0x04;			// 送信データ 4
	xlEvent[0].tagData.msg.data[4] = 0x05;			// 送信データ 5
	xlEvent[0].tagData.msg.data[5] = 0x06;			// 送信データ 6
	xlEvent[0].tagData.msg.data[6] = 0x07;			// 送信データ 7
	xlEvent[0].tagData.msg.data[7] = 0x08;			// 送信データ 8

	// 送信
	xlCanTransmit(m_xlPortHandle, 					// ポートハンドル
				  m_xlChannelMask[0],				// CANチャンネルマスク:Ch1
				  &eventCount,						// 送信イベント数
				  &xlEvent);						// 送信イベント
}

// -----------------------------------
// CAN受信スレッド
// -----------------------------------
void ThreadReceiveMain(void)
{
	XLstatus		xlStatus;									// ステータス
	XLevent			xlEvent;									// 受信イベント
	unsigned int	eventCount;									// 受信イベント数
	unsigned char	i;											// ループ変数

	while (m_bRsvCommoActivated)
	{
		// 受信イベント確認
		eventCount = 1;
		xlStatus = xlReceive(m_xlPortHandle, 					// ポートハンドル
							 &eventCount,						// 受信イベント数
							 &xlEvent);							// 受信イベント

		if(xlStatus != XL_ERR_QUEUE_IS_EMPTY)					// ステータス:受信イベントあり
		{
			if((xlEvent.tag == XL_RECEIVE_MSG) &&				// タグ:受信メッセージ
			   (xlEvent.tagData.msg.flags == 0))				// メッセージフラグ:なし
			{
				// 受信メッセージ表示
				printf("CAN受信メッセージ\n");
				printf("Ch    :%X\n", xlEvent.chanIndex + 1);	// chanIndex = 0:Virtual CAN Ch1
																// chanIndex = 1:Virtual CAN Ch2
				printf("ID    :%X\n", xlEvent.tagData.msg.id);
				printf("DLC   :%X\n", xlEvent.tagData.msg.dlc);
				printf("DATA  :");
				for (i = 0; i < xlEvent.tagData.msg.dlc; i++)
				{
					printf("%02X ", xlEvent.tagData.msg.data[i]);
				}
			}
		}
	}
}

各ライブラリ関数(概要)

xlCanTransmitCANメッセージを送信します。
引数で指定したCANメッセージが送信されます。
xlReceiveCAN通信の受信イベントを確認します。
受信メッセージがある場合、そのデータは引数に格納されます。
上記サンプルコードでは省略していますが、引数を元にエラーフレームの有無等も確認可能です。

※エラー時の処理を実装する場合、各ライブラリ関数の戻り値を元にエラー判定可能です。

実行結果

以下、上記サンプルプログラムの実行結果となります。
関数 ThreadReceiveMain のCAN受信処理で取得した受信メッセージを画面表示しています。
関数 CanTxMsg のCAN送信処理で送信したメッセージと内容が一致しています。

後がき

CANメッセージの送信/受信処理は以上となります。
次回の記事ではCAN通信終了について記載したいと思います。

OT

組み込み開発をメインに担当しています

関連記事