英创Linux主板的Python, C#实例之四 CAN总线

本文主要介绍在英创Linux工控主板(ESM8000、ESM7000和ESM6800H)上,采用Python和C#编程,实现对CAN总线接口的访问。Python和C#实例,均采用Visual Studio Code作为基本的编程工具,其代码可在主板 + ESMARC评估底板上运行,其基本的硬件环境采用采用ESM8000工控主板 + 评估底板构成,如下图所示:

 

在Linux平台,CAN总线接口设备已纳入网络的socket架构。英创的Linux主板有两路CAN接口,网络名称为”can0”和”can1”。在本文后面的实例代码中使用can0接口,评估底板上有相应的CAN驱动电路,与开发主机的CAN适配器连接,就可进行测试了。

可选择任何一款CAN调试模块,如PCAN,作为CAN总线测试的对端,通过其APP可看到CAN数据帧的收发情况。

Python应用实例

Python支持can接口操作库文件Python-CAN已经安装在ESM8000板卡文件系统中,调用import can 即可调用API函数对于can接口进行读写操作。对于socketcan的操作模式,一般需要调用ip 命令来激活can接口,并设置相应的波特率。

#>ip link set can0 type can bitrate 2500000

#>ip link set can0 up

Python CAN实例代码如下:

import can
import os

print( "Step9_CAN v1.0\n" )

# ip can0 up
os.system( "ifconfig can0 down" )
os.system( "ip link set can0 type can bitrate 250000" )
os.system( "ifconfig can0 up" )
print( "ifconfig can0 up" )

bus = can.interface.Bus(bustype='socketcan', channel='can0', bitrate=250000)

#send one message first
msg = can.Message(arbitration_id=0x80, data=[0, 20, 8, 1, 3, 1, 4, 1], is_extended_id=False)

bus.send(msg)

while True:
    msg = bus.recv()
    if msg:
        str="rcv: "+msg.data
        print(str)
        #send message back
        try:
            msg:arbitration_id=0x80
            bus.send(msg)
            print("Message sent on {}".format(bus.channel_info))
        except can.CanError:
            print("Message NOT sent")

C#应用实例

C#的网络通讯功能需要System.Net.Sockets类库,.NET Core已包含该库,也认可从NuGet下载最新版本的库。在NuGet上的CAN总线类库已经很久未更新,可能与新近的.NET 5有兼容性问题,故选择了一个第三方的开源案例:

GitHub - jormenjanssen/netcore-can-example: SocketCan example on dotnet-core。实例通过C#的InteropServices机制,直接调用Linux socket相关函数,并不依赖于libsocketcan库。

运行程序前,需要通过Linux命令ifconfig,让can0接口up。

鉴于本程序代码较多(包含6个C#文件),仅例出main函数。感兴趣的客户可与英创技术部门联系,获取完整代码。

using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Riwo.Rimote.VirtualCan;
using Riwo.Rimote.VirtualCan.Linux;

namespace Step9_Can
{
    class Program
    {
        //static void Main(string[] args)
        static async Task Main(string[] args)
        {
            Console.WriteLine("Step9_CAN V1.0");
            // This is an example application for .Net Core 3+ to support SocketCAN with CAN 2.0B.
            // For CAN-FD (Flexible data rate) some small changes are required which are not included in this example.

            // To run this example make sure your CANBus is up and running (for testing i used network interface can0 (FlexCan interface off) an NXP Imx6 processor for testing but X86/X64/ARM64 should definitely work)
            // You also could use VCAN software emulation see: https://elinux.org/Bringing_CAN_interface_up#Virtual_Interfaces
            // For testing i recommend using the linux can-utils (candump, cansend, etc.), they should be available in modern distro's otherwise: https://github.com/linux-can/can-utils 
            // I tested this application with .Net Core 3 Preview 7 on a Poky (Thud) based Yocto image on an Toradex Colibri IMX6 DL and Colibri Imx6ULL SOM

            // First configure the bitrate (I used 250K for testing): "ip link set can0 type can bitrate 250000"
            // Then set the canbus up: "ip link set can0 up"
            // Last but not least verify it's up and running by: "ip link show can0" this gives me the following result on my test system:
            // 3: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 10 link / ca

            await SimpleLoopBackAsync("can0", CancellationToken.None).ConfigureAwait(false);
        }

        static async Task SimpleLoopBackAsync(string adapter, CancellationToken cancellationToken)
        {
            var factory = new SocketCanFactory();
            var incomingBuffer = new byte[CanFrame.FrameLength];

            using var socket = factory.CreateSocket(adapter);
            {
                Console.WriteLine($"Created adapter: {adapter}");

                while (true)
                {
                    await socket.ReceiveAsync(incomingBuffer, SocketFlags.None, CancellationToken.None).ConfigureAwait(false);

                    var incomingFrame = new CanFrame(incomingBuffer);
                    Console.WriteLine($"Received {nameof(CanFrame)} Id: {incomingFrame.Id} IsRtr: {incomingFrame.IsRemoteTransmissionRequest} Length: {incomingFrame.DataLength} IsError: {incomingFrame.IsErrorMessage} Data: {ByteArrayToString(incomingFrame.Data)}");

                    try
                    {
                        var sendFrame = new CanFrame {IsExtendedFrame = true, Id = incomingFrame.Id - 1, DataLength = 4};

                        sendFrame.Data[0] = 1;
                        sendFrame.Data[1] = 2;
                        sendFrame.Data[2] = 3;
                        sendFrame.Data[3] = 4;

                        await socket.SendAsync(sendFrame.FrameBytes, SocketFlags.None).ConfigureAwait(false);
                    }
                    catch (SocketException se) when (se.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
                    {
                        // Default the buffer space is only 10 message you can extend this on Linux or wait a while before retransmitting.
                        // RUN: "ip link set can0 txqueuelen 1000" to increase size to 1000 messages where can0 is the name of the SocketCAN interface in Linux

                        Console.WriteLine("No buffer space available waiting a few ms");
                        await Task.Delay(TimeSpan.FromMilliseconds(10), cancellationToken).ConfigureAwait(false);
                    }
                }
            }
        }

        private static string ByteArrayToString(Span<byte> ba)
        {
            var hex = new StringBuilder(ba.Length * 2);
            foreach (var b in ba)
                hex.AppendFormat("{0:x2}", b);
            return hex.ToString();
        }    
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值