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;
本文探讨了C#中MESSAGESTRUCT结构与单片机CAN通信的异同,涉及消息格式、数据发送与接收函数,以及使用Kvaser.Kvadblib库解析DBC文件的示例。展示了C#中的字典用于信号映射和报文句柄管理,与单片机CAN的帧结构进行对比。
1万+

被折叠的 条评论
为什么被折叠?



