plc接收CAN总线上的信息,程序怎么写?

plc接收CAN总线上的信息,程序怎么写?,第1张

plc接收CAN总线上的信息,可以配置成CANopen基本协议进行9针口程序编写。

CAN协议用于汽车中各种不同元件之间的通信,以喊模则此取代昂贵而笨重的配电线束。该协议的健壮性使其用途延伸到其他自动化码档和工业应用。

CAN协议的特性包括完整性的串行数据通讯、提供实时支持、传输速率高达1Mb/s、同时具有11位的寻址以及检错能力。

CAN总线使用串行数据传输方式,可以1Mb/s的速率在40m的双绞线上运行,也可以使用光缆连接,而且在这种总线上总线协议支持多主控制器。

扩展资料:

CAN协议总线的工作原理:

CAN与I2C总线的许多细节很类似,但也有一些明显的区别。当CAN总线上的一个节点(站)发送数据时,它以报文形式广播给网络中所有节点。对每个节点来说,无论数据是否是发给自己的,都对其进行接收。

每组报文开头的11位字符为标识符,定义了报文的优先级,这种报文格式称为面向内容的编址方案。

在同一系统中标识符是唯一的,不可能有两个站发送具有相同标识符的报文。当几个站同时竞争总线读取时,这种配置十分重要。

参考资料来源:百度百科—可编程逻辑控制器 (可编程控制器件)

参考郑棚资料来源:百度百科—CAN总线协议

CAN协议基础知识

I2C.SPI总线多用于短距离传输,协议简单,数据量少,主要用于IC之间的通讯,而 CAN 总线则不同,CAN(Controller Area Network) 总线定义了更为优秀的物理层、数据链路层,并且拥有种类丰富、简繁不一的上层协议。与I2C、SPI有时钟信号的同步通讯方式不同,CAN通讯并不是以时钟信号来进行同步的,它是一种异步通讯,只具有CAN_High和CAN_Low两条信号线,共同构成一组差分信号线,以差分信号的形式进行通讯。

CAN物理层的形式主要分为闭环总线及开环总线网络两种,一个适合于高速通讯,一个适合于远距离通讯。CAN闭环通讯网络是一种遵循ISO11898标准的高速、短距离网络,它的总线最大长度为40m,通信速度最高为1Mbps,总线的两端各要求有一个

“120欧”的电阻。来做阻抗匹配,以减少回波反射。

 闭环总线网络

CAN开环总线网络是遵循ISO11519-2标准的低速、远距离网络,它的最大传输距离为1km,最高通讯速率为125kbps,两根总线是独立的、不形成闭环,要求每根总线上各串联有一个“2.2千欧”的电阻

开环总线网络

CAN总线上可以挂载多个通讯节点,节点之间的信号经过总线传输,实现节点间通讯。由于CAN通讯协议不对节点进行地址编码,而是对数据内容进行编码,所以网络中的节点个数理论上不受限制,只要总线的负载足够即可,可以通过中继器增强负载。

CAN通讯节点由一个CAN控制器及CAN收发器组成,控制器与收发器之间通过CAN_Tx及CAN_Rx信号线相连,收发器与CAN总线之间使用CAN_High及CAN_Low信号线相连。其中CAN_Tx及CAN_Rx使用普通的类似TTL逻辑信号,而CAN_High及CAN_Low是一对差分信号线,使用比较特别的差分信号首销。当CAN节点需要发送数据时,控制器把要发送的二进制编码通过CAN_Tx线发送到收发器,然后由收发器把这个普通的逻辑电平信号转化成差分信号,通过差分线CAN_High和CAN_Low线输出到CAN总线网络。而通过收发器接收总线上的数据到控制器时,则是相反的过程,收发器把总线上收到的CAN_High及CAN_Low信号转化成普通的逻辑电平信号,通过CAN_Rx输出到控制器中。

差分信号

差分信号又称差模信号,与传统使用单根信号线电压表示逻辑的方式有区别,使用差分信号传输时,需要两根信号线,这两个信号线的振幅相等,相位相反,通过两根信号线的电压差值来表示逻辑0和逻辑1。相对于单信号线传输的方式,使用差分信号传输具有如下优点:

• 抗干扰能力强,当外界存在噪声干扰时,几乎会同时耦合到两条信号线上,而接收端只关心两个信号的差值,所以外界的共模噪声可以被完全抵消。

• 能有效抑制它对外部的电磁干扰,同样的道理,由于两根信号搜芹唤的极性相反,他们对外辐射的电磁场可以相互抵消,耦合的越紧密,泄放到外界的电磁能量越少。

• 时序定位精确,由于差分信号的世凯开关变化是位于两个信号的交点,而不像普通单端信号依靠高低两个阈值电压判断,因而受工艺,温度的影响小,能降低时序上的误差,同时也更适合于低幅度信号的电路。

• 由于差分信号线具有这些优点,所以在USB协议、485协议、以太网协议及CAN协议的物理层中,都使用了差分信号传输。

CAN协议中的差分信号

CAN协议中对它使用的CAN_High及CAN_Low表示的差分信号做了规定。以高速CAN协议为例,当表示逻辑1时(隐性电平),CAN_High和CAN_Low线上的电压均为2.5v,即它们的电压差V H -V L =0V;而表示逻辑0时(显性电平),CAN_High的电平为3.5V,CAN_Low线的电平为1.5V,即它们的电压差为V H -V L =2V。

这是我从书上拷下来的程序,我自己试过是可以的,就是CAN的自测试,有发送和接收,你可以仿照着根据自己想要的结果来改。端口腔指随便定义就行了。不知道符不符合你的要求。

/**************************************************************************

**功能描述: ECAN自测试程序,CAN模块工作在自测试模式。MBX0发送到MBX16***

**MBX1发送到MBX17。该程序不停地高速背靠背传输数据,检查接数据的正确性**

**************************************************************************/

#include "DSP28_Device.h"

void mailbox_check(int32 T1, int32 T2, int32 T3)

void mailbox_read(int16 i)

/////////////芦返///////////////////////

Uint32 ErrorCount = 0

Uint32 MessageReceivedCount = 0

Uint32 TestMbox1 = 0

Uint32 TestMbox2 = 0

Uint32 TestMbox3 = 0

void CAN_INIT()

{

struct ECAN_REGS ECanaShadow

EALLOW

GpioMuxRegs.GPFMUX.bit.CANTXA_GPIOF6 = 1// 设置GPIOF6为CANTX

GpioMuxRegs.GPFMUX.bit.CANRXA_GPIOF7 = 1// 设置GPIOF7为CANRX

EDIS

/*eCAN 控制寄存器需要32位访问。如果想向一个单独位进行写 *** 作,编译器可能会使其进入16位访问。这儿引用了一种解决方法,就是用影子寄存器迫使进行32位访问。 把整个寄存器读入一个影子寄存器。 这个访问将是32位的。用32位写 *** 作改变需要改的位,然后把该值拷贝回eCAN寄存器*/

EALLOW

ECanaShadow.CANTIOC.all = ECanaRegs.CANTIOC.all// 把CANTIOC读入影子寄存器

ECanaShadow.CANTIOC.bit.TXFUNC = 1 // 外部引脚I/O使能标志位。

// TXFUNC=1 CANTX引脚被用于CAN发送功能。

// TXFUNC=0 CANTX引脚被作为通用I/O引脚被使用

ECanaRegs.CANTIOC.all = ECanaShadow.CANTIOC.all// 把配置好的寄存器值回写

ECanaShadow.CANRIOC.all = ECanaRegs.CANRIOC.all // 把CANRIOC读影子寄存器

ECanaShadow.CANRIOC.bit.RXFUNC = 1 // 外部引脚I/O使能标志位。

// RXFUNC=1 CANRX引脚被用于CAN接收功能。

// RXFUNC=0 CANRX引脚被作为通用I/O引脚被使用。

ECanaRegs.CANRIOC.all = ECanaShadow.CANRIOC.all // 把配置好的寄存器值回写

EDIS

// 在配置邮箱ID值之前,CANME对应的位必须复位,

// 如果CANME寄存器中对应的位被置位,则ID写入 *** 作无效。

ECanaRegs.CANME.all = 0// 复位所有的邮箱

ECanaMboxes.MBOX0.MID.all = 0x9555AAA0 // 配置发送邮箱0的ID:扩展标识符29位

ECanaMboxes.MBOX1.MID.all = 0x9555AAA1 // 配置发送邮箱1的ID:扩展标识符29位

ECanaMboxes.MBOX16.MID.all = 0x9555AAA0//伍哗配 确定接收邮箱16的ID

ECanaMboxes.MBOX17.MID.all = 0x9555AAA1// 确定接收邮箱17的ID

// 把邮箱0~15 配置为发送邮箱 , 把邮箱16~31 配置为接收邮箱

ECanaRegs.CANMD.all = 0xFFFF0000

ECanaRegs.CANME.all = 0xFFFFFFFF// CAN模块使能对应的邮箱,

ECanaMboxes.MBOX0.MCF.bit.DLC = 8

ECanaMboxes.MBOX1.MCF.bit.DLC = 8 // 把发送,接收数据的长度定义为8位

ECanaMboxes.MBOX0.MCF.bit.RTR = 0 // 无远程帧请求

// 因为RTR位在复位后状态不定,因此在程序进行初始化的时候必须对该位赋值。

ECanaMboxes.MBOX1.MCF.bit.RTR = 0

// 把待发送的数据写入发送邮箱

ECanaMboxes.MBOX0.MDRL.all = 0x00112233

ECanaMboxes.MBOX0.MDRH.all = 0x44556677

ECanaMboxes.MBOX1.MDRL.all = 0x8899AABB

ECanaMboxes.MBOX1.MDRH.all = 0xCCDDEEFF

EALLOW

// 邮箱中断屏蔽寄存器。上电后所有的中断屏蔽位都清零且停止中断使能。

// 这些位允许独立屏蔽任何邮箱中断。

ECanaRegs.CANMIM.all = 0xFFFFFFFF

// CANMIM .BIT.X=1 邮箱中断被使能(X=1~31)

// CANMIM .BIT.X=0 邮箱中断被禁止(X=1~31)

ECanaShadow.CANMC.all = ECanaRegs.CANMC.all// 把CANMC读入影子寄存器

ECanaShadow.CANMC.bit.CCR = 1 // 改变配置请求位

ECanaRegs.CANMC.all = ECanaShadow.CANMC.all// 把配置好的寄存器值回写

EDIS

/*CPU要求对配置寄存器CANBTC和SCC的接收屏蔽寄存器(CANGAM,LAM[0]和LAM[3])进行写 *** 作。对该位置位后,CPU必须等待,直到CANES寄存器的CCE标志位在送入CANBTC寄存器之前为1 */

do

{

ECanaShadow.CANES.all = ECanaRegs.CANES.all

} while(ECanaShadow.CANES.bit.CCE != 1 ) // 当CCE=1时可以对CANBTC进行 *** 作。

// 配置波特率

EALLOW

ECanaShadow.CANBTC.all = ECanaRegs.CANBTC.all// 把CANBTC读入影子寄存器

ECanaShadow.CANBTC.bit.BRP = 149 // (BRP+1)=150, 最小时间单位TQ=1us

ECanaShadow.CANBTC.bit.TSEG2 = 2 // 位定时bit-time=(TSEG1+1)+(TSEG1+1)+1

ECanaShadow.CANBTC.bit.TSEG1 = 3 // bit-time=8us, 所以波特率为125Kpbs

ECanaRegs.CANBTC.all = ECanaShadow.CANBTC.all // 把配置好的寄存器值回写

ECanaShadow.CANMC.all = ECanaRegs.CANMC.all // 把CANMC读入影子寄存器

ECanaShadow.CANMC.bit.CCR = 0 // 设置CCR=0, CPU请求正常模式

ECanaRegs.CANMC.all = ECanaShadow.CANMC.all // 把配置好的寄存器值回写

EDIS

do

{

ECanaShadow.CANES.all = ECanaRegs.CANES.all

} while(ECanaShadow.CANES.bit.CCE != 0 ) // 等待 CCE 位被清零

// 配置eCAN为自测试模式,使能eCAN的增强特性

EALLOW

ECanaShadow.CANMC.all = ECanaRegs.CANMC.all

ECanaShadow.CANMC.bit.STM = 1 // 配置CAN 为自测试模式

// CANMC.bit.STM=0,正常模式,CANMC.bit.STM=1,自测试模式

ECanaShadow.CANMC.bit.SCM = 1 // 选择HECC工作模式

ECanaRegs.CANMC.all = ECanaShadow.CANMC.all

EDIS

}

void main(void)

{

Uint16 j

InitSysCtrl()// 系统初始化程序,该子程序在DSP28_sysctrl.c中

DINT // 关闭总中断

IER = 0x0000 // 关闭外设中断

IFR = 0x0000 // 请中断标志

CAN_INIT()

// 开始循环发送数据

while(1)

{

ECanaRegs.CANTRS.all = 0x00000003

while(ECanaRegs.CANTA.all != 0x00000003 ) {}

ECanaRegs.CANTA.all = 0x0000FFFF

MessageReceivedCount++

for(j = 0j<32)

{

mailbox_read(j) // 把邮箱j(j=0~31)的数据读出来

j++

// mailbox_check(TestMbox1,TestMbox2,TestMbox3)// 测试程序是否正确

}

}

}

// 该函数读出邮箱序号(MBXnbr)指示的邮箱内容.

void mailbox_read(int16 MBXnbr)

{

volatile struct MBOX *Mailbox

Mailbox = &ECanaMboxes.MBOX0 + MBXnbr

TestMbox1 = Mailbox->MDRL.all// 读出当前邮箱数据低4字节

TestMbox2 = Mailbox->MDRH.all // 读出当前邮箱数据高4字节

TestMbox3 = Mailbox->MID.all// 读出当前邮箱ID

}

// 接收邮箱MBX的 MID作为MDRL 数据传输data

void mailbox_check(int32 T1,int32 T2,int32 T3)

{

if((T1 != T3) || ( T2 != 0x89ABCDEF))

ErrorCount++

}


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/12444337.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-25
下一篇 2023-05-25

发表评论

登录后才能评论

评论列表(0条)

保存