CANopen从站协议在stm32f103zet6单片机上的实现摘要:本文对CANopen从站协议在stm32f103zet6单片机上的实现做了分析和说明。
介绍了CANopen协议的SDO(服务数据对象),PDO(过程数据对象)等报文处理的工作和实现原理,实现了向主站发送数据及处理主站报文等功能。
本文中,做了一个从站与一个主站进行数据交互的实现,实验表明CANopen从站协议可以正常使用在stm32f103zet6单片机上,并且可以与CANopen主站进行数据传输等交互操作。
关键词:CANopen;从站协议;服务数据对象;过程数据对象;单片机1引言(STM32F103ZET6)(STM32F103ZET6)(STM32F103ZET6)从站设备(STM32F103ZET6)图1 CANOPEN连接示意图CANopen是一种架构在控制局域网路(Control Area Network, CAN)上的高层通讯协定,其协议在嵌入式系统及单片机上广泛使用,是工业控制常用到的一种现场总线。
依靠CANopen协议集的支持,可以对不同的从站设备通过总线进行配置和系统重构。
相信在不久的将来随着国内对CANo pen协议的研究深入,CANopen协议会在各个领域有广泛的应用。
CANopen 是OSI模型中的网络层以上(包括网络层)的协定。
CANopen 支持网络管理、设备监控及节点间的通讯,其中包括一个简易的传输层,可处理资料的传送。
数据的传输和接收都基于CAN总线。
如图1,通常多个从站设备靠CANopen网络传输数据给一个CANopen主站设备。
CANopen需要有对象字典,SDO(服务数据对象)处理功能,PDO(过程数据对象)处理功能,定时器,NMT(网络管理)处理功能等。
本文着重介绍了CANopen协议的各个功能以及CANopen协议在单片机上stm32f103zet6的设计与实现。
2 CANopen对象字典介绍及设计对象字典(od:object dictionary)是CAN open协议的核心。
对象字典(od:object dict ionary)是一个有序的对象组;每个对象采用一个16位的索引值来寻址,为了允许访问数据结构中的单个元素,同时定义了一个8位的子索引。
通过接收主站发送的SDO(服务数据对象)报文,可以设置从站的对象字典,主要对象字典请参见表1。
从站在做事件处理时通常会读取对象字典,根据对象字典里的数据进行事件处理。
譬如从站的1017索引是记录从站发送心跳包的时间间隔。
当从站程序运行时并且从站是准备、停止、运行状态时,程序会查找1017索引的0号子索引里的数据进行处理。
如果里面有数据的话(假设数据为2000),程序则会根据数据所设置的时间通过定时器判断来每2000毫秒发送心跳包。
表1 从站主要对象字典介绍索引:对象16 位元的位址。
数据的类型:一个代表对象的类型,可以是阵列、纪录或只是一个变量。
类型:变量的类型。
属性:提供此是否可读/可写的资料,有下列四种:可读/写、只读、唯写、只读常数。
以下是建立6003索引的代码案例,并且里面的数据是(2.78593)*100000的代码片段:UNS32 AIdata=(2.78593)*100000;//要写入索引数据static UNS8 highestSubIndex_6003 = 0; // 子索引为:1个(从0开始计数)subindex Index6003[] ={{RW,uint32,sizeof(UNS32),(void*)&AIdata} };//建立索引的读写属性,数据类型,数据大小,索引数据3 NMT节点管理介绍及设计NMT(网络管理, Network management)会定义(设备内部)从站的状态变更命令(如启动设备或停止设备)、侦测远端设备故障情形等。
通常从站都由主机通过NMT报文来启动、停止和重启。
每一个从站还必须配有一个单独的设备标识符,即从站节点ID。
(从站节点ID一般在程序启动后,节点初始化状态时设置。
)节点可分为4种状态,初始化状态(Init ialisatio),预操作状态(Pre_operational),操作状态(Operational)和停止状态(Stoppe d)。
主站发送来的NMT格式一般为00 00 01 05,其中00 00是NMT功能码,代表主站发来的是NMT报文,01是要将从站节点设定为操作状态(参考表2),05是从站节点的ID。
表2 状态码表置从站节点ID及一些索引数据的初始化,完成这些操作后,程序进入预操作状态,在预操作状态下,主站通常会通过SDO报文设置从站对象字典,包括心跳时间的设定,同步功能设置,数据存储映射设置等,当设置完毕后,会发送NMT节点管理报文将从站设为操作状态,此时从站节点如果已经设置了同步功能,当从站节点收到主站发送过来的同步报文后(通常是收到的报文是00 80 ,需要从站根据1005对象字典内的数据来确定可识别的同步报文ID,若数据为00 80,那么收到00 80的报文后发送从站状态数据)会返回目前从站的状态数据。
NMT主要涉及的代码为:proceedNMTstateChange(Message *m)函数:此函数主要功能是根据主站发送的设定状态码来设置从站节点的状态,代码片段如下:if( ( (*m).data[1] == 0 ) || ( (*m).dat a[1] == bDeviceNodeId ) ){//判断报文是否是发给本从站switch( (*m).data[0]){ //解析报文case NMT_Start_Node:if ( (nodeState == Pre_operat ional) || (nodeState == Stopped) )nodeState = Operational;break;case NMT_Stop_Node:if ( nodeState == Pre_operati onal ||nodeState == Operational )nodeState = Stopped;break;case NMT_Enter_PreOperationa l:if ( nodeState == Operational || nodeState == Stopped )nodeState= Pre_operational;break;case NMT_Reset_Node:nodeState = Initialisation;break;4 心跳功能介绍及设计所谓“心跳”,指的是主站/从站之间的一种通信。
采用心跳机制的好处在于,如果从站设备发生故障(如断电,重启等),会停止发送心跳报文,若主站一段时间内没有收到心跳报文,主站设备就会检测到从站发生了故障。
(心跳报文:CANopen设备将根据主站给从站设置心跳时间间隔参数(索引1 017h)的周期发送心跳报文。
)Stm32f103zet6单片机内置定时器用于计算心跳报文发送间隔,假设对象字典设置的数据报文发送间隔为2000毫秒,就可以将定时器设定为每500毫秒累计一次数值5 01,当累加数值大于2000时则发送心跳报文。
心跳报文数据格式为07 05 7F。
07 05根据协议计算可以知道是从站节点ID为5。
(根据CANopen协议设定,心跳报文格式为”Communication Object Identifier”COB-I D+NODE-ID+1位状态码,心跳报文的COB -ID为0x700,0705等于0x700+0x05,则N ODE-ID等于0x05),7F代表从站状态为预操作状态(详见表3)。
当发送心跳报文后,数值清0,数值再次每500毫秒累加一次数值501,当累加到大于2000数值时则发送心跳报文,以此无限循环。
图2 心跳报文及定时器工作流程图表3 心跳报文状态码对照表心跳功能主要涉及的函数代码为:定时器设置函数TIM3_Configuration:此函数主要功能为每500毫秒触发一次定时器函数,代码片段:void TIM3_Configuration(void){TIM_TimeBaseInitTypeDef TIM_Time BaseStructure;TIM_TimeBaseStructure.TIM_Period = 9999;TIM_TimeBaseStructure.TIM_Prescaler = 3599;//公式(1+3599)/72M*(1+9999)=0.5 TIM_TimeBaseStructure.TIM_ClockDivi sion = 0;TIM_TimeBaseStructure.TIM_CounterM ode = TIM_CounterMode_Up;TIM_TimeBaseInit(TIM3, &TIM_Time BaseStructure);触发的定时器函数则进行数值累加,代码片段:void TIM3_IRQHandler(void){if (TIM_GetITStatus(TIM3, TIM_IT_U pdate) != RESET) {/* Clear TIM3 update interrupt */TIM_ClearITPendingBit(TIM3, TIM _IT_Update);GPIOF->ODR ^= GPIO_Pin_7;//每次让连接PF7管脚的LED灯亮进行状态切换a=a+501;//每次累加数值501}}另外涉及的heartbeatMGR心跳函数:此函数功能是对定时器累加的数值做判断,当累加的数值达到对象字典内的数值时则发送心跳报文,代码片段:if ( should_time )//这个变量为1017索引内的值,通过读取对象字典函数getODen try()获取{if( ( a >= should_time ) ){msg.cob_id.w= bDeviceNod eId+ 0x700;msg.len = (UNS8)0x01;msg.rtr = 0;msg.data[0] = nodeState;can_send(&msg);//发送心跳报文a=0;//发送完毕后将定时器累加的数值清0}}5 SDO服务数据对象介绍及设计SDO服务数据对象可用来设置及读取远端节点的对象字典其中的资料。
当主站要设置从站的对象字典的数据时,需要先发送一个SDO报文,当从站(stm32f103zet6)接收到报文后,会进行报文解析进而形成一个响应报文反馈给主站。
参考以下流程图:图3 从站处理主站SDO流程图CANopen发送的SDO报文包括11 位元的ID、远端传输请求(RTR)位元及大小不超过8位元的资料。