当前位置:网站首页>C#和C 的CAN通信实验
C#和C 的CAN通信实验
2022-06-24 20:01:00 【罗迪尼亚的熔岩】
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,"[email protected]");
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;
边栏推荐
- 傳輸層 以字節為單比特的滑動窗口技術
- [interview question] what is a transaction? What are dirty reads, unrepeatable reads, phantom reads, and how to deal with several transaction isolation levels of MySQL
- 腾讯云国际云服务器网络访问丢包问题解决办法
- Android SQLite database
- linux 系统redis常用命令
- Microsoft won the title of "leader" in the magic quadrant of Gartner industrial Internet of things platform again!
- Helm chart仓库操作
- Fuxin Kunpeng joins in, and dragon lizard community welcomes a new partner in format document technical service
- Interesting checkbox counters
- JDBC —— 数据库连接
猜你喜欢
Do280openshift access control -- encryption and configmap
Related operations of ansible and Playbook
UE4 WebBrowser chart cannot display problems
Dynamic effect of canvas lines
Go crawler framework -colly actual combat (4) -- Zhihu answer crawl (2) -- visual word cloud
Use coordinatorlayout+appbarlayout+collapsingtoolbarlayout to create a collapsed status bar
Decoupling pages and components using lifecycle
Discrete mathematics and its application detailed explanation of exercises in the final exam of spring and summer semester of 2018-2019 academic year
Outer screen and widescreen wasted? Harmonyos folding screen design specification teaches you to use it
Signal integrity (SI) power integrity (PI) learning notes (XXV) differential pair and differential impedance (V)
随机推荐
vim使用命令
ServerSocket and socket connection
How can I persuade leaders to use DDD to construct the liver project?
Use coordinatorlayout+appbarlayout+collapsingtoolbarlayout to create a collapsed status bar
Realization of MNIST handwritten numeral recognition
傳輸層 以字節為單比特的滑動窗口技術
Current situation and development prospect forecast report of global and Chinese tetrahydrofurfuryl alcohol acetate industry from 2022 to 2028
Collection of software testing and game testing articles
不重要的token可以提前停止计算!英伟达提出自适应token的高效视觉Transformer网络A-ViT,提高模型的吞吐量!...
Registration method of native method in JNI
传输层 以字节为单位的滑动窗口技术
Related operations of ansible and Playbook
融合模型权限管理设计方案
I suddenly find that the request dependent package in NPM has been discarded. What should I do?
Signal integrity (SI) power integrity (PI) learning notes (XXV) differential pair and differential impedance (V)
Domain Driven Design and coding
Svg line animation background JS effect
linux 系统redis常用命令
UE4 WebBrowser chart cannot display problems
Helm chart仓库操作