C#和C 的CAN通信实验

C# 的message与单片机的对比:

    public struct MESSAGESTRUCT
    {
        public string name;            //名称
        public int id;                 //ID
        public string comment;         //说明
        public int dlc;                //字节数
        public string type;            //J1939, 唤醒,标准

        public Dictionary<string, SIGNALSTRUCT> dicsignal;//根据信号名称定位信号
        public Kvadblib.MessageHnd mh; //当前报文的句柄
    }

    u8 Can_Send_Msg(u8* msg, u8 len)
    {
        u8 mbox;
        u16 i = 0;
        CanTxMsg TxMessage;
        TxMessage.StdId = 0x12;         // 标准标识符 
        TxMessage.ExtId = 0x12;         // 设置扩展标示符 
        TxMessage.IDE = CAN_Id_Standard;    // 标准帧
        TxMessage.RTR = CAN_RTR_Data;       // 数据帧
        TxMessage.DLC = len;                // 要发送的数据长度
        for (i = 0; i < len; i++)
            TxMessage.Data[i] = msg[i];
        mbox = CAN_Transmit(CAN1, &TxMessage);
        i = 0;
        while ((CAN_TransmitStatus(CAN1, mbox) == CAN_TxStatus_Failed) && (i < 0XFFF)) i++; //等待发送结束
        if (i >= 0XFFF) return 1;
        return 0;
    }

    typedef struct
    {
      uint32_t StdId;  /*!< Specifies the standard identifier. 标准标识符
                            This parameter can be a value between 0 to 0x7FF. */

    uint32_t ExtId;  /*!< Specifies the extended identifier. 设置扩展标识符
                            This parameter can be a value between 0 to 0x1FFFFFFF. */

    uint8_t IDE;     /*!< Specifies the type of identifier for the message that 
                            will be transmitted. This parameter can be a value 
                            of @ref CAN_identifier_type */

    uint8_t RTR;     /*!< Specifies the type of frame for the message that will 
                            be transmitted. This parameter can be a value of 
                            @ref CAN_remote_transmission_request */

    uint8_t DLC;     /*!< Specifies the length of the frame that will be 
                            transmitted. This parameter can be a value between 
                            0 to 8 */

    uint8_t Data[8]; /*!< Contains the data to be transmitted. It ranges from 0 
                            to 0xFF. */
}
CanTxMsg;
using canlibCLSNET;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using static canlibCLSNET.Canlib;

namespace CanDemon
{
    public partial class FrmMain : Form
    {
        public FrmMain()
        {
            InitializeComponent();

            //Canlib.canInitializeLibrary();//读取信息,初始化
            this.btnRefresh_Click(null, null);  //刷新
            this.cmb_Baud.DataSource = new List<string>() { "125000", "250000", "500000", "1000000" };
            this.cmb_Baud.SelectedIndex = 0;
        }

        private int handle = 0;
        private canStatus canStatus;
        private int chanelCount = 0; //通道数
        CancellationTokenSource cts = new CancellationTokenSource();

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            
            canStatus = Canlib.canGetNumberOfChannels(out chanelCount);//获取can所有通道
            if (canStatus!= canStatus.canOK)
            {
                HandleError("canGetNumberOfChannels", canStatus);
            }

            cmb_Channel.Items.Clear();
            for (int i = 0; i < chanelCount; i++)
            {
                object obj;

                //获取通道名称:canCHANNELDATA_CHANNEL_NAME
                canStatus status = canGetChannelData(i, canCHANNELDATA_CHANNEL_NAME,out obj);//channel号,item号,buffer数据
                string strout = obj.ToString(); //转换成obj类型 获取通道名称

                //产品序列号 canCHANNELDATA_CARD_SERIAL_NO
                status = canGetChannelData(i, canCHANNELDATA_CARD_SERIAL_NO, out obj);
                string strtmp = string.Format(",{0:D6}", obj); //数据长度为6,不够的话前面补0

                strout += strtmp;
                cmb_Channel.Items.Add(strout);

            }
        }

        private void btnOpen_Click(object sender, EventArgs e)
        {
            if (this.btnOpen.Text == "打开")
            {
                //打开
                handle = canOpenChannel(this.cmb_Channel.SelectedIndex, canOPEN_OVERRIDE_EXCLUSIVE + canOPEN_ACCEPT_VIRTUAL);

                //设置波特率
                canStatus = canSetBitrate(handle, Convert.ToInt32(this.cmb_Baud.Text));

                HandleError("canSetBitrate", canStatus);

                //Bus On
                canStatus = canBusOn(handle);
                if (canStatus != canStatus.canOK)
                {
                    HandleError("canBusOn", canStatus);
                    return;
                }
                else
                {
                    //开启线程读取
                    this.btnOpen.Text = "Close";

                    Task.Run(async () =>
                    {
                        while (!cts.IsCancellationRequested)
                        {
                            byte[] buffer = new byte[100];

                            //out 不用在外面定义
                            //dlc长度,flag标志位
                            await Task.Delay(500);
                            canStatus = canRead(handle, out int id, buffer, out int dlc, out int flag, out long time);
                            if (canStatus != canStatus.canOK)
                            {
                                string error = string.Empty;

                                canGetErrorText(canStatus, out error);

                                AddInfo("Receive Error:" + error);
                            }
                            else
                            {
                                //成功读取
                                byte[] result = new byte[dlc];
                                //buffer复制给reslut
                                Array.Copy(buffer, 0, result, 0, dlc);

                                AddInfo("Receive Data:" + time.ToString() + " " + id.ToString() + GetHexStringFromByteArray(result));
                            }
                        }
                    });
                }
            }

            else
            {
                canClose(handle);
                this.btnOpen.Text = "Open";
            }

        }

        private void HandleError(string cmd, canStatus status)
        {
            if (status != canStatus.canOK) //错误状态
            {
                string error = string.Empty;
                canGetErrorText(status, out error);
                AddInfo($"{cmd} Error: {error}");
            }
        }

        private void AddInfo(string info)
        {
            if (this.listInfo.InvokeRequired)
            {
                this.Invoke(new Action(() =>
                {
                    this.listInfo.Items.Add(info);
                }));
                //this.listInfo.Invoke
            }
            else
            {
                this.listInfo.Items.Add(info);
            }
        }

        private string GetHexStringFromByteArray(byte[] b)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var item in b)
            {
                sb.Append(item.ToString("X") + " ");
            }

            return sb.ToString().Trim();
        }


    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Kvaser.Kvadblib;

namespace CanDemon
{
    public enum canMSGFlag
    {
        canMsg_Mask = 0x00FF,
        canMsg_RTR = 0x0001,
        canMsg_STD = 0x0002,
        canMsg_EXT = 0x0004,
        canMsg_WAKEUP = 0x0008,
        canMsg_NERR = 0x0010,
        canMsg_ERROR_FRAME = 0x0020,
        canMsg_TXACK = 0x0040,
        canMsg_TXRQ = 0x0080F,
    }


    public struct SIGNALSTRUCT
    {
        public string name;            //名称
        public string comment;         //注释
        public string unit;            //单位
        public string encooding;       //编码
        public string type;            //类型
        public double minvaluelimit;   //最小值
        public double maxvaluelimit;   //最大值
        public double factor;          //系数
        public double offset;          //偏移量
        public int startbit;           //起始位
        public int bitlength;          //位长度
        public Kvadblib.SignalHnd sh;  //当前信号的句柄
    }
    public struct MESSAGESTRUCT
    {
        public string name;            //名称
        public int id;                 //ID
        public string comment;         //说明
        public int dlc;                //字节数
        public string type;            //J1939, 唤醒,标准

        public Dictionary<string, SIGNALSTRUCT> dicsignal;//根据信号名称定位信号 一对多,有多个signnal
        public Kvadblib.MessageHnd mh; //当前报文的句柄
    }
    public class canDbcReader
    {
        Kvadblib.Hnd dh = new Kvadblib.Hnd();
        Kvadblib.MessageHnd mh = new Kvadblib.MessageHnd();
        Kvadblib.SignalHnd sh = new Kvadblib.SignalHnd();
        Kvadblib.Status status;

        //08
        public Dictionary<int, MESSAGESTRUCT> dicMessage = new Dictionary<int, MESSAGESTRUCT>(); //canDbcReader中有多个Message

        public Dictionary<string, int> dicSigNameID = new Dictionary<string, int>();

        public canDbcReader()
        {
            dh = new Kvadblib.Hnd();
            status = Kvadblib.Open(out dh);
        }

        #region 导入dbc文件,相关的数据保存在字典的结构体中
        public bool ImportDbc(string strDbc)
        {
            #region 清除原有的数据

            foreach (MESSAGESTRUCT item in dicMessage.Values)
            {
                item.dicsignal.Clear();
            }
            dicMessage.Clear();

            dicSigNameID.Clear();

            #endregion

            try
            {
                //打开dbc文件
                status = Kvadblib.ReadFile(dh, strDbc);

                if (status != Kvadblib.Status.OK)
                    return false;


                status = Kvadblib.GetFirstMsg(dh, out mh);
                while (status == Kvadblib.Status.OK)//循环遍历报文,以及报文下面的信号
                {
                    MESSAGESTRUCT message = new MESSAGESTRUCT();
                    message.dicsignal = new Dictionary<string, SIGNALSTRUCT>();

                    if (!GetMessageInfo(mh, out message))

                        return false;

                    dicMessage.Add(message.id, message);

                    status = Kvadblib.GetNextMsg(dh, out mh);
                }
                return true;
            }
            catch
            {
                return false;
            }
        }
        #endregion

        #region 根据信号句柄sh获取信号信息
        private void GetSignalInfo(Kvadblib.SignalHnd sh, out SIGNALSTRUCT sig)
        {
            SIGNALSTRUCT signal = new SIGNALSTRUCT();
            signal.sh = sh;                                             //信号句柄
            status = Kvadblib.GetSignalName(sh, out signal.name);       //信号名称
            status = Kvadblib.GetSignalComment(sh, out signal.comment); //信号说明
            status = Kvadblib.GetSignalUnit(sh, out signal.unit);       //信号单位
            Kvadblib.SignalEncoding se;                                 //编码方式,inter或 motorola
            status = Kvadblib.GetSignalEncoding(sh, out se);
            if (se == Kvadblib.SignalEncoding.Intel)
                signal.encooding = "Inter";
            else if (se == Kvadblib.SignalEncoding.Motorola)
                signal.encooding = "Motorola";
            Kvadblib.SignalType st;                                     //信号数据类型            
            status = Kvadblib.GetSignalRepresentationType(sh, out st);
            switch (st)
            {
                case Kvadblib.SignalType.Signed:
                    signal.type = "Signed";
                    break;
                case Kvadblib.SignalType.Unsigned:
                    signal.type = "Unsigned";
                    break;
                case Kvadblib.SignalType.Double:
                    signal.type = "Double";
                    break;
                case Kvadblib.SignalType.Float:
                    signal.type = "Float";
                    break;
                case Kvadblib.SignalType.Invalid:
                    signal.type = "Invalid";
                    break;
            }
            status = Kvadblib.GetSignalValueLimits(sh, out signal.minvaluelimit, out signal.maxvaluelimit);//最大最小信号值范围
            status = Kvadblib.GetSignalValueScaling(sh, out signal.factor, out signal.offset);//因数和偏移量
            status = Kvadblib.GetSignalValueSize(sh, out signal.startbit, out signal.bitlength);//起始位,位长度
            sig = signal;
        }
        #endregion

        #region 根据报文句柄mh获取报文信息
        private bool GetMessageInfo(Kvadblib.MessageHnd mh, out MESSAGESTRUCT msg)
        {
            MESSAGESTRUCT message = new MESSAGESTRUCT();
            message.dicsignal = new Dictionary<string, SIGNALSTRUCT>();
            try
            {
                Kvadblib.MESSAGE km;
                status = Kvadblib.GetMsgId(mh, out message.id, out km);//ID和帧类型

                switch (km)
                {
                    case Kvadblib.MESSAGE.EXT:
                        message.type = "扩展";
                        message.id = message.id & 0x1FFFFFFF;
                        break;
                    case Kvadblib.MESSAGE.J1939:
                        message.type = "J1939";
                        break;
                    case Kvadblib.MESSAGE.WAKEUP:
                        message.type = "唤醒帧";
                        break;
                    default:
                        message.type = "标准";
                        message.id = message.id & 0x1FFFFFFF;
                        break;
                }
                status = Kvadblib.GetMsgName(mh, out message.name);//报文名称
                status = Kvadblib.GetMsgDlc(mh, out message.dlc);//报文长度
                status = Kvadblib.GetMsgComment(mh, out message.comment);//报文说明
                message.mh = mh;//当前的句柄

                SIGNALSTRUCT signal = new SIGNALSTRUCT();
                Kvadblib.SignalHnd sh = new Kvadblib.SignalHnd();
                status = Kvadblib.GetFirstSignal(message.mh, out sh);
                while (status == Kvadblib.Status.OK)
                {

                    GetSignalInfo(sh, out signal);
                    dicSigNameID.Add(signal.name, message.id);
                    message.dicsignal.Add(signal.name, signal);
                    status = Kvadblib.GetNextSignal(mh, out sh);
                }
                msg = message;
                return true;
            }
            catch
            {
                msg = message;
                return false;
            }
        }
        #endregion

        #region 物理量或原始值填充报文
        //将信号的原始值填充到报文中
        public bool StoreSignalValueRaw(SIGNALSTRUCT signal, byte[] candata, int length, int raw)
        {
            status = Kvadblib.StoreSignalValueRaw(signal.sh, candata, candata.Length, raw);
            if (status != Kvadblib.Status.OK) return false;
            return true;
        }
        //将信号的物理值填充到报文中

        public bool StoreSignalValuePhys(SIGNALSTRUCT signal, byte[] candata, int length, double phys)
        {
            status = Kvadblib.StoreSignalValuePhys(signal.sh, candata, candata.Length, phys);
            if (status != Kvadblib.Status.OK) return false;
            return true;
        }

        #endregion

        #region 根据信号和原始值获取物理量
        //转换CAN数据到浮点的物理值
        public bool GetSignalValueFloat(SIGNALSTRUCT signal, byte[] candata, int length, out double value)
        {
            status = Kvadblib.GetSignalValueFloat(signal.sh, out value, candata, candata.Length);
            if (status != Kvadblib.Status.OK) return false;
            return true;
        }

        //转换CAN数据到整型物理值
        public bool GetSignalValueInteger(SIGNALSTRUCT signal, byte[] candata, int length, out int value)
        {
            status = Kvadblib.GetSignalValueInteger(signal.sh, out value, candata, candata.Length);
            if (status != Kvadblib.Status.OK) return false;
            return true;
        }

        //2转换CAN数据到枚举的物理值
        public bool GetSignalValueEnum(SIGNALSTRUCT signal, byte[] candata, int length, out string value)
        {
            status = Kvadblib.GetSignalValueEnum(signal.sh, out value, candata, candata.Length);
            if (status != Kvadblib.Status.OK) return false;
            return true;
        }
        #endregion
    }
}

namespace AXEBMSPro
{
    public enum canMSGFlag
    {
        canMsg_Mask = 0x00FF,
        canMsg_RTR = 0x0001,
        canMsg_STD = 0x0002,
        canMsg_EXT = 0x0004,
        canMsg_WAKEUP = 0x0008,
        canMsg_NERR = 0x0010,
        canMsg_ERROR_FRAME = 0x0020,
        canMsg_TXACK = 0x0040,
        canMsg_TXRQ = 0x0080F,
    }


    public struct SIGNALSTRUCT
    {
        public string name;            //名称
        public string comment;         //注释
        public string unit;            //单位
        public string encooding;       //编码
        public string type;            //类型
        public double minvaluelimit;   //最小值
        public double maxvaluelimit;   //最大值
        public double factor;          //系数
        public double offset;          //偏移量
        public int startbit;           //起始位
        public int bitlength;          //位长度
        public Kvadblib.SignalHnd sh;  //当前信号的句柄
    }
    public struct MESSAGESTRUCT
    {
        public string name;            //名称
        public int id;                 //ID
        public string comment;         //说明
        public int dlc;                //字节数
        public string type;            //J1939, 唤醒,标准

        public Dictionary<string, SIGNALSTRUCT> dicsignal;//根据信号名称定位信号
        public Kvadblib.MessageHnd mh; //当前报文的句柄
    }
    public class canDbcReader
    {
        Kvadblib.Hnd dh = new Kvadblib.Hnd();
        Kvadblib.MessageHnd mh = new Kvadblib.MessageHnd();
        Kvadblib.SignalHnd sh = new Kvadblib.SignalHnd();
        Kvadblib.Status status;

        public Dictionary<int, MESSAGESTRUCT> dicMessage = new Dictionary<int, MESSAGESTRUCT>();

        public Dictionary<string, int> dicSigNameID = new Dictionary<string, int>();

        public canDbcReader()
        {
            dh = new Kvadblib.Hnd();
            status = Kvadblib.Open(out dh);
        }

        #region 导入dbc文件,相关的数据保存在字典的结构体中
        public bool ImportDbc(string strDbc)
        {
            #region 清除原有的数据

            foreach (MESSAGESTRUCT item in dicMessage.Values)
            {
                item.dicsignal.Clear();
            }
            dicMessage.Clear();

            dicSigNameID.Clear();

            #endregion

            try
            {
                //打开dbc文件
                status = Kvadblib.ReadFile(dh, strDbc);

                if (status != Kvadblib.Status.OK)
                    return false;


                status = Kvadblib.GetFirstMsg(dh, out mh);
                while (status == Kvadblib.Status.OK)//循环遍历报文,以及报文下面的信号
                {
                    MESSAGESTRUCT message = new MESSAGESTRUCT();
                    message.dicsignal = new Dictionary<string, SIGNALSTRUCT>();

                    if (!GetMessageInfo(mh, out message))

                        return false;

                    dicMessage.Add(message.id, message);

                    status = Kvadblib.GetNextMsg(dh, out mh);
                }
                return true;
            }
            catch
            {
                return false;
            }
        }
        #endregion

        #region 根据信号句柄sh获取信号信息
        private void GetSignalInfo(Kvadblib.SignalHnd sh, out SIGNALSTRUCT sig)
        {
            SIGNALSTRUCT signal = new SIGNALSTRUCT();
            signal.sh = sh;                                             //信号句柄
            status = Kvadblib.GetSignalName(sh, out signal.name);       //信号名称
            status = Kvadblib.GetSignalComment(sh, out signal.comment); //信号说明
            status = Kvadblib.GetSignalUnit(sh, out signal.unit);       //信号单位
            Kvadblib.SignalEncoding se;                                 //编码方式,inter或 motorola
            status = Kvadblib.GetSignalEncoding(sh, out se);
            if (se == Kvadblib.SignalEncoding.Intel)
                signal.encooding = "Inter";
            else if (se == Kvadblib.SignalEncoding.Motorola)
                signal.encooding = "Motorola";
            Kvadblib.SignalType st;                                     //信号数据类型            
            status = Kvadblib.GetSignalRepresentationType(sh, out st);
            switch (st)
            {
                case Kvadblib.SignalType.Signed:
                    signal.type = "Signed";
                    break;
                case Kvadblib.SignalType.Unsigned:
                    signal.type = "Unsigned";
                    break;
                case Kvadblib.SignalType.Double:
                    signal.type = "Double";
                    break;
                case Kvadblib.SignalType.Float:
                    signal.type = "Float";
                    break;
                case Kvadblib.SignalType.Invalid:
                    signal.type = "Invalid";
                    break;
            }
            status = Kvadblib.GetSignalValueLimits(sh, out signal.minvaluelimit, out signal.maxvaluelimit);//最大最小信号值范围
            status = Kvadblib.GetSignalValueScaling(sh, out signal.factor, out signal.offset);//因数和偏移量
            status = Kvadblib.GetSignalValueSize(sh, out signal.startbit, out signal.bitlength);//起始位,位长度
            sig = signal;
        }
        #endregion

        #region 根据报文句柄mh获取报文信息
        private bool GetMessageInfo(Kvadblib.MessageHnd mh, out MESSAGESTRUCT msg)
        {
            MESSAGESTRUCT message = new MESSAGESTRUCT();
            message.dicsignal = new Dictionary<string, SIGNALSTRUCT>();
            try
            {
                Kvadblib.MESSAGE km;
                status = Kvadblib.GetMsgId(mh, out message.id, out km);//ID和帧类型

                switch (km)
                {
                    case Kvadblib.MESSAGE.EXT:
                        message.type = "扩展";
                        message.id = message.id & 0x1FFFFFFF;
                        break;
                    case Kvadblib.MESSAGE.J1939:
                        message.type = "J1939";
                        break;
                    case Kvadblib.MESSAGE.WAKEUP:
                        message.type = "唤醒帧";
                        break;
                    default:
                        message.type = "标准";
                        message.id = message.id & 0x1FFFFFFF;
                        break;
                }
                status = Kvadblib.GetMsgName(mh, out message.name);//报文名称
                status = Kvadblib.GetMsgDlc(mh, out message.dlc);//报文长度
                status = Kvadblib.GetMsgComment(mh, out message.comment);//报文说明
                message.mh = mh;//当前的句柄

                SIGNALSTRUCT signal = new SIGNALSTRUCT();
                Kvadblib.SignalHnd sh = new Kvadblib.SignalHnd();
                status = Kvadblib.GetFirstSignal(message.mh, out sh);
                while (status == Kvadblib.Status.OK)
                {
                  
                    GetSignalInfo(sh, out signal);
                    dicSigNameID.Add(signal.name, message.id);
                    message.dicsignal.Add(signal.name, signal);
                    status = Kvadblib.GetNextSignal(mh, out sh);
                }
                msg = message;
                return true;
            }
            catch
            {
                msg = message;
                return false;
            }
        }
        #endregion

        #region 物理量或原始值填充报文
        //将信号的原始值填充到报文中
        public bool StoreSignalValueRaw(SIGNALSTRUCT signal, byte[] candata, int length, int raw)
        {
            status = Kvadblib.StoreSignalValueRaw(signal.sh, candata, candata.Length, raw);
            if (status != Kvadblib.Status.OK) return false;
            return true;
        }
        //将信号的物理值填充到报文中

        public bool StoreSignalValuePhys(SIGNALSTRUCT signal, byte[] candata, int length, double phys)
        {
            status = Kvadblib.StoreSignalValuePhys(signal.sh, candata, candata.Length, phys);
            if (status != Kvadblib.Status.OK) return false;
            return true;
        }

        #endregion

        #region 根据信号和原始值获取物理量
        //转换CAN数据到浮点的物理值
        public bool GetSignalValueFloat(SIGNALSTRUCT signal, byte[] candata, int length, out double value)
        {
            status = Kvadblib.GetSignalValueFloat(signal.sh, out value, candata, candata.Length);
            if (status != Kvadblib.Status.OK) return false;
            return true;
        }

        //转换CAN数据到整型物理值
        public bool GetSignalValueInteger(SIGNALSTRUCT signal, byte[] candata, int length, out int value)
        {
            status = Kvadblib.GetSignalValueInteger(signal.sh, out value, candata, candata.Length);
            if (status != Kvadblib.Status.OK) return false;
            return true;
        }

        //2转换CAN数据到枚举的物理值
        public bool GetSignalValueEnum(SIGNALSTRUCT signal, byte[] candata, int length, out string value)
        {
            status = Kvadblib.GetSignalValueEnum(signal.sh, out value, candata, candata.Length);
            if (status != Kvadblib.Status.OK) return false;
            return true;
        }
        #endregion
    }
}

C:

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "lcd.h"
#include "usart.h"	 
#include "can.h" 
 
  


 int main(void)
 {	 
		u8 key;
	u8 i=0,t=0;
	u8 cnt=0;
	u8 canbuf[8];
	u8 res;
	u8 mode=CAN_Mode_LoopBack;//CAN工作模式;CAN_Mode_Normal(0):普通模式,CAN_Mode_LoopBack(1):环回模式

	delay_init();	    	 //延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 	//串口初始化为115200
	LED_Init();		  		//初始化与LED连接的硬件接口
	LCD_Init();			   	//初始化LCD	
	KEY_Init();				//按键初始化		 	
   
	CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_LoopBack);//CAN初始化环回模式,波特率500Kbps    

 	POINT_COLOR=RED;//设置字体为红色 
	LCD_ShowString(60,50,200,16,16,"WarShip STM32");	
	LCD_ShowString(60,70,200,16,16,"CAN TEST");	
	LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
	LCD_ShowString(60,110,200,16,16,"2015/1/15");
	LCD_ShowString(60,130,200,16,16,"LoopBack Mode");	 
	LCD_ShowString(60,150,200,16,16,"KEY0:Send WK_UP:Mode");//显示提示信息		
	POINT_COLOR=BLUE;//设置字体为蓝色	  
	LCD_ShowString(60,170,200,16,16,"Count:");			//显示当前计数值	
	LCD_ShowString(60,190,200,16,16,"Send Data:");		//提示发送的数据	
	LCD_ShowString(60,250,200,16,16,"Receive Data:");	//提示接收到的数据		
 	while(1)
	{
		key=KEY_Scan(0);
		if(key==KEY0_PRES)//KEY0按下,发送一次数据
		{
			for(i=0;i<8;i++)
			{
				canbuf[i]=cnt+i;//填充发送缓冲区
				if(i<4)LCD_ShowxNum(60+i*32,210,canbuf[i],3,16,0X80);	//显示数据
				else LCD_ShowxNum(60+(i-4)*32,230,canbuf[i],3,16,0X80);	//显示数据
 			}
			res=Can_Send_Msg(canbuf,8);//发送8个字节 
			if(res)LCD_ShowString(60+80,190,200,16,16,"Failed");		//提示发送失败
			else LCD_ShowString(60+80,190,200,16,16,"OK    ");	 		//提示发送成功								   
		}else if(key==WKUP_PRES)//WK_UP按下,改变CAN的工作模式
		{	   
			mode=!mode;
  			CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,mode);//CAN普通模式初始化, 波特率500Kbps 
			POINT_COLOR=RED;//设置字体为红色 
			if(mode==0)//普通模式,需要2个开发板
			{
				LCD_ShowString(60,130,200,16,16,"Nnormal Mode ");	    
			}else //回环模式,一个开发板就可以测试了.
			{
 				LCD_ShowString(60,130,200,16,16,"LoopBack Mode");
			}
 			POINT_COLOR=BLUE;//设置字体为蓝色 
		}		 
		key=Can_Receive_Msg(canbuf);
		if(key)//接收到有数据
		{			
			LCD_Fill(60,270,130,310,WHITE);//清除之前的显示
 			for(i=0;i<key;i++)
			{									    
				if(i<4)LCD_ShowxNum(60+i*32,270,canbuf[i],3,16,0X80);	//显示数据
				else LCD_ShowxNum(60+(i-4)*32,290,canbuf[i],3,16,0X80);	//显示数据
 			}
		}
		t++; 
		delay_ms(10);
		if(t==20)
		{
			LED0=!LED0;//提示系统正在运行	
			t=0;
			cnt++;
			LCD_ShowxNum(60+48,170,cnt,3,16,0X80);	//显示数据
		}		   
	}
}


=========C=

#ifndef __CAN_H
#define __CAN_H	 
#include "sys.h"	    

 
//CAN接收RX0中断使能
#define CAN_RX0_INT_ENABLE	0		//0,不使能;1,使能.								    
//tsjw:重新同步跳跃时间单元.范围:CAN_SJW_1tq~ CAN_SJW_4tq	
//tbs2:时间段 2 的时间单元. 范围:CAN_BS2_1tq~CAN_BS2_8tq;
//tbs1:时间段 1 的时间单元. 范围:CAN_BS1_1tq ~CAN_BS1_16tq
//brp :波特率分频器.范围:1~1024; tq=(brp)*tpclk1
//波特率=Fpclk1/((tbs1+1+tbs2+1+1)*brp);
//mode:CAN_Mode_Normal,普通模式;CAN_Mode_LoopBack,回环模式;

//Fpclk1 的时钟在初始化的时候设置为 36M,如果设置
//CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_LoopBack);
//则波特率为:36M/((8+9+1)*4)=500Kbps
//返回值:0,初始化 OK;
// 其他,初始化失败; u8 CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)
u8 CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode);//CAN初始化

u8 Can_Send_Msg(u8* msg,u8 len);						//发送数据

u8 Can_Receive_Msg(u8 *buf);							//接收数据
#endif
#include "can.h"
#include "led.h"
#include "delay.h"
#include "usart.h"
 
 
//CAN初始化
//tsjw:重新同步跳跃时间单元.范围:CAN_SJW_1tq~ CAN_SJW_4tq
//tbs2:时间段2的时间单元.   范围:CAN_BS2_1tq~CAN_BS2_8tq;
//tbs1:时间段1的时间单元.   范围:CAN_BS1_1tq ~CAN_BS1_16tq
//brp :波特率分频器.范围:1~1024;  tq=(brp)*tpclk1
//波特率=Fpclk1/((tbs1+1+tbs2+1+1)*brp);
//mode:CAN_Mode_Normal,普通模式;CAN_Mode_LoopBack,回环模式;
//Fpclk1的时钟在初始化的时候设置为36M,如果设置CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_LoopBack);
//则波特率为:36M/((8+9+1)*4)=500Kbps
//返回值:0,初始化OK;
//    其他,初始化失败; 
u8 CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)
{ 
	GPIO_InitTypeDef 		GPIO_InitStructure; 
	CAN_InitTypeDef        	CAN_InitStructure;
	CAN_FilterInitTypeDef  	CAN_FilterInitStructure;
#if CAN_RX0_INT_ENABLE 
	NVIC_InitTypeDef  		NVIC_InitStructure;
#endif

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PORTA时钟	                   											 

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟	

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽
	GPIO_Init(GPIOA, &GPIO_InitStructure);			//初始化IO

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;	//上拉输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);			//初始化IO

	//CAN单元设置
	CAN_InitStructure.CAN_TTCM=DISABLE;			//非时间触发通信模式  
	CAN_InitStructure.CAN_ABOM=DISABLE;			//软件自动离线管理	 
	CAN_InitStructure.CAN_AWUM=DISABLE;			//睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
	CAN_InitStructure.CAN_NART=ENABLE;			//禁止报文自动传送 
	CAN_InitStructure.CAN_RFLM=DISABLE;		 	//报文不锁定,新的覆盖旧的  
	CAN_InitStructure.CAN_TXFP=DISABLE;			//优先级由报文标识符决定 
	CAN_InitStructure.CAN_Mode= mode;	        //模式设置: mode:0,普通模式;1,回环模式; 
	//设置波特率
	CAN_InitStructure.CAN_SJW=tsjw;				//重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位  CAN_SJW_1tq	 CAN_SJW_2tq CAN_SJW_3tq CAN_SJW_4tq
	CAN_InitStructure.CAN_BS1=tbs1; 			//Tbs1=tbs1+1个时间单位CAN_BS1_1tq ~CAN_BS1_16tq
	CAN_InitStructure.CAN_BS2=tbs2;				//Tbs2=tbs2+1个时间单位CAN_BS2_1tq ~	CAN_BS2_8tq
	CAN_InitStructure.CAN_Prescaler=brp;        //分频系数(Fdiv)为brp+1	
	CAN_Init(CAN1, &CAN_InitStructure);        	//初始化CAN1 

	CAN_FilterInitStructure.CAN_FilterNumber=0;	//过滤器0
	CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; 	//屏蔽位模式
	CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; 	//32位宽 
	CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;	//32位ID
	CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32位MASK
	CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
	CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;//激活过滤器0

	CAN_FilterInit(&CAN_FilterInitStructure);			//滤波器初始化
	
#if CAN_RX0_INT_ENABLE 
	CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);				//FIFO0消息挂号中断允许.		    

	NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;     // 主优先级为1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;            // 次优先级为0
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
#endif
	return 0;
}   
 
#if CAN_RX0_INT_ENABLE	//使能RX0中断
//中断服务函数			    
void USB_LP_CAN1_RX0_IRQHandler(void)
{
  	CanRxMsg RxMessage;
	int i=0;
    CAN_Receive(CAN1, 0, &RxMessage);
	for(i=0;i<8;i++)
	printf("rxbuf[%d]:%d\r\n",i,RxMessage.Data[i]);
}
#endif

//can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)	
//len:数据长度(最大为8)				     
//msg:数据指针,最大为8个字节.
//返回值:0,成功;
//		 其他,失败;
u8 Can_Send_Msg(u8* msg,u8 len)
{	
	u8 mbox;
	u16 i=0;
	CanTxMsg TxMessage;
	TxMessage.StdId=0x12;			// 标准标识符 
	TxMessage.ExtId=0x12;			// 设置扩展标示符 
	TxMessage.IDE=CAN_Id_Standard; 	// 标准帧
	TxMessage.RTR=CAN_RTR_Data;		// 数据帧
	TxMessage.DLC=len;				// 要发送的数据长度
	for(i=0;i<len;i++)
	TxMessage.Data[i]=msg[i];			          
	mbox= CAN_Transmit(CAN1, &TxMessage);   
	i=0; 
	while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++;	//等待发送结束
	if(i>=0XFFF)return 1;
	return 0;	 
}
//can口接收数据查询
//buf:数据缓存区;	 
//返回值:0,无数据被收到;
//		 其他,接收的数据长度;
u8 Can_Receive_Msg(u8 *buf)
{		   		   
 	u32 i;
	CanRxMsg RxMessage;
    if( CAN_MessagePending(CAN1,CAN_FIFO0)==0)return 0;		//没有接收到数据,直接退出 
    CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);//读取数据	
    for(i=0;i<8;i++)
    buf[i]=RxMessage.Data[i];  
	return RxMessage.DLC;	
}
typedef struct
{
  uint32_t StdId;  /*!< Specifies the standard identifier.
                        This parameter can be a value between 0 to 0x7FF. */

  uint32_t ExtId;  /*!< Specifies the extended identifier.
                        This parameter can be a value between 0 to 0x1FFFFFFF. */

  uint8_t IDE;     /*!< Specifies the type of identifier for the message that 
                        will be transmitted. This parameter can be a value 
                        of @ref CAN_identifier_type */

  uint8_t RTR;     /*!< Specifies the type of frame for the message that will 
                        be transmitted. This parameter can be a value of 
                        @ref CAN_remote_transmission_request */

  uint8_t DLC;     /*!< Specifies the length of the frame that will be 
                        transmitted. This parameter can be a value between 
                        0 to 8 */

  uint8_t Data[8]; /*!< Contains the data to be transmitted. It ranges from 0 
                        to 0xFF. */
} CanTxMsg;

/** 
  * @brief  CAN Rx message structure definition  
  */

typedef struct
{
  uint32_t StdId;  /*!< Specifies the standard identifier.
                        This parameter can be a value between 0 to 0x7FF. */

  uint32_t ExtId;  /*!< Specifies the extended identifier.
                        This parameter can be a value between 0 to 0x1FFFFFFF. */

  uint8_t IDE;     /*!< Specifies the type of identifier for the message that 
                        will be received. This parameter can be a value of 
                        @ref CAN_identifier_type */

  uint8_t RTR;     /*!< Specifies the type of frame for the received message.
                        This parameter can be a value of 
                        @ref CAN_remote_transmission_request */

  uint8_t DLC;     /*!< Specifies the length of the frame that will be received.
                        This parameter can be a value between 0 to 8 */

  uint8_t Data[8]; /*!< Contains the data to be received. It ranges from 0 to 
                        0xFF. */

  uint8_t FMI;     /*!< Specifies the index of the filter the message stored in 
                        the mailbox passes through. This parameter can be a 
                        value between 0 to 0xFF */
} CanRxMsg;
  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C#中实现CAN总线通信需要使用CAN总线适配器和相应的库文件。以下是一些具体的步骤: 1. 确定CAN总线适配器的型号和接口类型(如USB、PCI等)。 2. 下载并安装相应的驱动程序,以确保计算机可以与CAN总线适配器进行通信。 3. 选择一个合适的库文件(如PCAN-Basic或Kvaser CANlib)并集成到C#项目中。 4. 在代码中实现CAN总线通信操作,例如发送和接收CAN消息。 以下是一个示例代码,使用PCAN-Basic库实现CAN总线通信的示例: ```csharp using System; using System.Threading.Tasks; using Peak.Can.Basic; namespace CANCommunication { class Program { static void Main(string[] args) { // 初始化CAN总线适配器 TPCANHandle h = PCANBasic.PCAN_USBBUS1; TPCANBaudrate baudrate = TPCANBaudrate.PCAN_BAUD_500K; if (PCANBasic.Initialize(h, baudrate) != TPCANStatus.PCAN_ERROR_OK) { Console.WriteLine("Failed to initialize CAN adapter."); return; } // 发送CAN消息 TPCANMsg msg = new TPCANMsg { ID = 0x123, MSGTYPE = TPCANMessageType.PCAN_MESSAGE_STANDARD, LEN = 8 }; msg.DATA = new byte[] { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 }; if (PCANBasic.Write(h, ref msg) != TPCANStatus.PCAN_ERROR_OK) { Console.WriteLine("Failed to send CAN message."); return; } // 接收CAN消息 TPCANMsg receivedMsg = new TPCANMsg(); TPCANTimestamp timestamp = new TPCANTimestamp(); while (true) { if (PCANBasic.Read(h, out receivedMsg, out timestamp) == TPCANStatus.PCAN_ERROR_OK) { Console.WriteLine($"Received CAN message: ID=0x{receivedMsg.ID:x}, Data=[{string.Join(",", receivedMsg.DATA)}]"); } } } } } ``` 需要注意的是,CAN总线通信操作需要在一个独立的线程中执行,以允许程序同时进行其他操作。可以使用`Task`类或`Thread`类来创建新线程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

潘诺西亚的火山

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值