发 帖  
原厂入驻New

[经验] stm32 开发CANOPEN 协议 命令字

2020-7-24 16:43:37  463 STM32
分享
4

下面是CAN协议与OSI网络模型的一个对比。CAN的物理层分了三层分别是MDI,PMA和PLS,数据链路层分了两层:MAC与LLC。这五层就是最原始的CAN协议,标准是ISO11898。也就是说CAN协议一开始是没有应用层的。后来有一种叫CANOpen的基于CAN的应用层协议被开发出来,标准是CiA301。

在实际开发CAN器件的时候不一定要用CANOpen,你可以根据自己的需要定制自己的应用层协议。






CANOpen协议共有6种通讯对象,分别是:PDO、SDO、SYNC、tiME、EMCY、NMT。这6种通讯对象完成了CANOpen协议的所有通讯功能。其中我们只介绍使用较多的PDO、SDO、NMT(4.4)。


通信对象ID(COB-ID)
CANOpen协议的通讯对象主要利用了CAN协议中的数据帧和远程帧。为了区分不同的通讯对象,CANOpen协议利用数据帧/远程帧中的ID。其中第7位到第10位为功能代码。第0位到第6位为节点ID,用以区分不同节点的相同功能。这样就允许最多127个从节点与主节点通讯。



下面是预定义的各通讯对象的COB-ID





其中绿色部分为广播的通讯对象,蓝色部分为点对点的通讯对象。


COB-ID的大小也决定了通讯对象的优先级,其中NMT的优先级最高,PDO的优先级高于SDO。





CANOpen的网络管理使用了master/slave结构。Master通过模块控制服务,可以控制slave的状态:{STOPPED, PRE-OPERATIONAL, OPERATIONAL, INITIALISING}.模块控制服务可以只针对一个节点,也可以是所有节点同时改变。






单片机源码如下
  1. /* Includes ------------------------------------------------------------------*/
  2. #include "STM32f10x.h"
  3. #include "SysTick/systick.h"
  4. #include "GeneralTim.h"
  5. #include "stmflash.h"
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include <string.h>


  9. /* Private variables ---------------------------------------------------------*/
  10. uint8_t CAN1_RxRdy,CAN2_RxRdy;
  11. uint16_t CAN1_Val_Tx,CAN1_Val_Rx,CAN2_Val_Tx,CAN2_Val_Rx;
  12. CanTxMsg Can1TxMessage;
  13. CanTxMsg Can2TxMessage;
  14. CanRxMsg Can1RxMessage;
  15. CanRxMsg Can2RxMessage;
  16. /* Private function prototypes -----------------------------------------------*/

  17. void GPIO_Configuration(void);
  18. void NVIC_Configuration(void);
  19. void CAN_Configuration(void);
  20. void CanWriteData( CAN_TypeDef* CANx ,CanTxMsg *TxMessage );

  21.   

  22. u8 CAN1_TX_data[128],CAN1_RX_data[128];
  23. u16 CAN1_Tx_Counter,CAN1_Rx_Counter,CAN1_TX_flag,CAN1_RX_flag,CAN1_TX_status,CAN1_RX_status;
  24. u8 CAN2_TX_data[128],CAN2_RX_data[128];
  25. u16 CAN2_Tx_Counter,CAN2_Rx_Counter,CAN2_TX_flag,CAN2_RX_flag,CAN2_TX_status,CAN2_RX_status;


  26. char KEY1_up,KEY2_up,KEY3_up,KEY4_up,KEY5_up,KEY6_up;
  27. char canopen_ID=0x01;
  28. char canopen_start,canopen_reset,canopen_pretreatment;
  29. char canopen_RSDO,canopen_RPDO;
  30. /*******************************************************************************
  31. * Function Name  : main
  32. * Description    : Main program
  33. * Input          : None
  34. * Output         : None
  35. * Return         : None
  36. * Attention                 : None
  37. *******************************************************************************/
  38. int main(void)
  39. {
  40.         CAN_Configuration();
  41.        
  42.         CAN2_RxRdy = DISABLE;
  43.         Can2TxMessage.StdId=0x0700+canopen_ID;            //地址
  44.         Can2TxMessage.DLC=3;
  45.         Can2TxMessage.RTR = CAN_RTR_DATA; /* 设置为数据帧 */
  46.         Can2TxMessage.IDE = CAN_ID_STD;   /* 使用标准id        */
  47.         Can2TxMessage.Data[0] = 0x00;                       
  48.         CAN_Transmit(CAN2,&Can2TxMessage);
  49.        
  50.         while (1)
  51.         {               
  52.                
  53.                 IF(canopen_pretreatment==1)                            //高压恢复
  54.                 {
  55.                         canopen_pretreatment=0;
  56.                         CAN2_RxRdy = DISABLE;
  57.                         Can2TxMessage.StdId=0x0180+canopen_ID;            //地址
  58.                         Can2TxMessage.DLC=8;
  59.                         Can2TxMessage.RTR = CAN_RTR_DATA; /* 设置为数据帧 */
  60.                         Can2TxMessage.IDE = CAN_ID_STD;   /* 使用标准id        */
  61.                         Can2TxMessage.Data[0] = GPIO_ReadOutputDataBit(GPIOE,GPIO_Pin_0);
  62.                         Can2TxMessage.Data[1] = GPIO_ReadOutputDataBit(GPIOE,GPIO_Pin_1);              
  63.                         Can2TxMessage.Data[2] = GPIO_ReadOutputDataBit(GPIOE,GPIO_Pin_2);
  64.                         Can2TxMessage.Data[3] = GPIO_ReadOutputDataBit(GPIOE,GPIO_Pin_3);
  65.                         Can2TxMessage.Data[4] = GPIO_ReadOutputDataBit(GPIOE,GPIO_Pin_4);
  66.                         Can2TxMessage.Data[5] = GPIO_ReadOutputDataBit(GPIOE,GPIO_Pin_5);              
  67.                         Can2TxMessage.Data[6] = GPIO_ReadOutputDataBit(GPIOE,GPIO_Pin_6);
  68.                         Can2TxMessage.Data[7] = GPIO_ReadOutputDataBit(GPIOE,GPIO_Pin_7);
  69.                                                        
  70.                         CAN_Transmit(CAN2,&Can2TxMessage);       
  71.                 }
  72.                 if(CAN1_RX_flag==1)
  73.                 {
  74.                         CAN1_RX_flag=0;
  75.                         if((Can1RxMessage.StdId==0x0000)&&(Can1RxMessage.Data[0]==0x10)&&(Can1RxMessage.Data[1]==0x00))
  76.                         {
  77.                                 canopen_start=1;
  78.                         }
  79.                         if((Can1RxMessage.StdId==0x0000)&&(Can1RxMessage.Data[0]==0x10)&&(Can1RxMessage.Data[1]==canopen_ID))
  80.                         {
  81.                                 canopen_start=1;
  82.                         }
  83.                         if(canopen_start==1)
  84.                         {
  85.                                 if((Can1RxMessage.StdId==0x0000)&&(Can1RxMessage.Data[0]==0x20)&&(Can1RxMessage.Data[1]==0x00))
  86.                                 {
  87.                                         canopen_start=0;
  88.                                 }
  89.                                 if((Can1RxMessage.StdId==0x0000)&&(Can1RxMessage.Data[0]==0x20)&&(Can1RxMessage.Data[1]==canopen_ID))
  90.                                 {
  91.                                         canopen_start=0;
  92.                                 }
  93.                                 if((Can1RxMessage.StdId==0x0000)&&(Can1RxMessage.Data[0]==0x82)&&(Can1RxMessage.Data[1]==0x00))
  94.                                 {
  95.                                         canopen_reset=1;
  96.                                 }
  97.                                 if((Can1RxMessage.StdId==0x0000)&&(Can1RxMessage.Data[0]==0x81)&&(Can1RxMessage.Data[1]==canopen_ID))
  98.                                 {
  99.                                         canopen_reset=1;
  100.                                 }
  101.                                 if((Can1RxMessage.StdId==0x0000)&&(Can1RxMessage.Data[0]==0x80)&&(Can1RxMessage.Data[1]==0x00))
  102.                                 {
  103.                                         canopen_pretreatment=1;
  104.                                 }
  105.                                 if((Can1RxMessage.StdId==0x0000)&&(Can1RxMessage.Data[0]==0x80)&&(Can1RxMessage.Data[1]==canopen_ID))
  106.                                 {
  107.                                         canopen_pretreatment=1;
  108.                                 }
  109.                                 if((Can1RxMessage.StdId-0x0600)==canopen_ID)
  110.                                 {
  111.                                         canopen_RSDO=1;
  112.                                         if(canopen_RSDO==1)
  113.                                         {
  114.                                                 canopen_RSDO=0;
  115.                                                 if((Can1RxMessage.Data[0]==0x2F)&&(Can1RxMessage.Data[1]==0x00)&&(Can1RxMessage.Data[2]==0x20)&&(Can1RxMessage.Data[3]==0x00))
  116.                                                 {
  117.                                                         canopen_ID=Can1RxMessage.Data[4];
  118.                                                 }
  119.                                         }
  120.                                 }
  121.                                 if((Can1RxMessage.StdId-0x0200)==canopen_ID)
  122.                                 {
  123.                                         canopen_RPDO=1;
  124.                                         if(canopen_RPDO==1)
  125.                                         {
  126.                                                 canopen_RPDO=0;
  127.                                                 if(Can1RxMessage.Data[0]==0x31)
  128.                                                 {
  129.                                                         GPIO_WriteBit(GPIOB,GPIO_Pin_0,1);
  130.                                                 }
  131.                                                 if(Can1RxMessage.Data[0]==0x30)
  132.                                                 {
  133.                                                         GPIO_WriteBit(GPIOB,GPIO_Pin_0,0);
  134.                                                 }
  135.                                                 if(Can1RxMessage.Data[1]==0x31)
  136.                                                 {
  137.                                                         GPIO_WriteBit(GPIOB,GPIO_Pin_1,1);
  138.                                                 }
  139.                                                 if(Can1RxMessage.Data[1]==0x30)
  140.                                                 {
  141.                                                         GPIO_WriteBit(GPIOB,GPIO_Pin_1,0);
  142.                                                 }
  143.                                         }
  144.                                 }
  145.                         }
  146.                 }       
  147.         }
  148. }

  149. /*******************************************************************************
  150. * Function Name  : GPIO_Configuration
  151. * Description    : Configures the different GPIO ports.
  152. * Input          : None
  153. * Output         : None
  154. * Return         : None
  155. * Attention                 : None
  156. *******************************************************************************/
  157. void GPIO_Configuration(void)
  158. {
  159.   GPIO_InitTypeDef GPIO_InitStructure;

  160.   RCC_APB2PeriphclockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO ,ENABLE);
  161.   /* CAN1 and CAN2 periph clock enable */
  162.   RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1 | RCC_APB1Periph_CAN2, ENABLE);                                                 
  163.          
  164.   /* Configure CAN1 RX pin */
  165.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  166.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  167.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  168.   GPIO_Init(GPIOA, &GPIO_InitStructure);
  169.   /* Configure CAN1 pin: TX */
  170.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
  171.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  172.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  173.   GPIO_Init(GPIOA, &GPIO_InitStructure);
  174.   /* Configure CAN2 RX pin */
  175.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
  176.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  177.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  178.   GPIO_Init(GPIOB, &GPIO_InitStructure);
  179.   /* Configure CAN2 pin: TX */
  180.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
  181.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  182.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  183.   GPIO_Init(GPIOB, &GPIO_InitStructure);  

  184.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
  185.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  186.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  187.   GPIO_Init(GPIOB, &GPIO_InitStructure);        

  188.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
  189.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  190.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  191.   GPIO_Init(GPIOE, &GPIO_InitStructure);
  192. }

  193. /*******************************************************************************
  194. * Function Name  : NVIC_Configuration
  195. * Description    : Configures the nested vectored interrupt controller.
  196. * Input          : None
  197. * Output         : None
  198. * Return         : None
  199. * Attention                 : None
  200. *******************************************************************************/
  201. void NVIC_Configuration(void)
  202. {
  203.   NVIC_InitTypeDef NVIC_InitStructure;

  204.   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

  205.   /* Enable CAN1 RX0 interrupt IRQ channel */
  206.   NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
  207.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  208.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  209.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  210.   NVIC_Init(&NVIC_InitStructure);

  211.   /* Enable CAN2 RX0 interrupt IRQ channel */
  212.   NVIC_InitStructure.NVIC_IRQChannel = CAN2_RX0_IRQn;
  213.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  214.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  215.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  216.   NVIC_Init(&NVIC_InitStructure);
  217. }

  218. /*******************************************************************************
  219. * Function Name  : CAN_Configuration
  220. * Description    : Configures the CAN
  221. * Input          : None
  222. * Output         : None
  223. * Return         : None
  224. * Attention                 : None
  225. *******************************************************************************/
  226. void CAN_Configuration(void)
  227. {
  228.   CAN_InitTypeDef        CAN_InitStructure;
  229.   CAN_FilterInitTypeDef  CAN_FilterInitStructure;

  230.   NVIC_Configuration();
  231.   GPIO_Configuration();
  232.   /* CAN register init */
  233.   CAN_DeInit(CAN1);
  234.   CAN_DeInit(CAN2);
  235.   CAN_StructInit(&CAN_InitStructure);

  236.   CAN1_RxRdy = CAN2_RxRdy = DISABLE;
  237.   CAN1_Val_Tx = CAN1_Val_Rx = CAN2_Val_Tx = CAN2_Val_Rx = 0;

  238.   /* CAN cell init */
  239.   CAN_InitStructure.CAN_TTCM = DISABLE; /* 时间触发禁止, 时间触发:CAN硬件的内部定时器被激活,并且被用于产生时间戳 */
  240.   CAN_InitStructure.CAN_ABOM = DISABLE; /* 自动离线禁止,自动离线:一旦硬件监控到128次11个隐性位,就自动退出离线状态。在这里要软件设定后才能退出 */
  241.   CAN_InitStructure.CAN_AWUM = DISABLE; /* 自动唤醒禁止,有报文来的时候自动退出休眠        */
  242.   CAN_InitStructure.CAN_NART = DISABLE; /* 报文重传, 如果错误一直传到成功止,否则只传一次 */
  243.   CAN_InitStructure.CAN_RFLM = DISABLE; /* 接收FIFO锁定, 1--锁定后接收到新的报文摘不要,0--接收到新的报文则覆盖前一报文        */
  244.   CAN_InitStructure.CAN_TXFP = ENABLE;  /* 发送优先级  0---由标识符决定  1---由发送请求顺序决定        */
  245.   CAN_InitStructure.CAN_Mode = CAN_Mode_Normal; /* 模式        */
  246.   CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;      /* 重新同步跳宽,只有can硬件处于初始化模式时才能访问这个寄存器 */
  247.   CAN_InitStructure.CAN_BS1 = CAN_BS1_9tq;      /* 时间段1 */
  248.   CAN_InitStructure.CAN_BS2 = CAN_BS2_8tq;      /* 时间段2 */
  249.   CAN_InitStructure.CAN_Prescaler = 8;          /* 波特率预分频数 */  

  250.   /* 波特率计算方法 */
  251.   /* CANbps= FPClk/((BRP+1)*((Tseg1+1)+(Tseg2+1)+1)  此处计算为  CANbps=36000000/(45*(4+3+1))=1200kHz */                                                                                                                     //此处Tseg1+1 = CAN_BS1_8tp
  252.   /* 配置大方向: Tseg1>=Tseg2  Tseg2>=tq; Tseg2>=2TSJW */                                               

  253.   /*Initializes the CAN1  and CAN2 */
  254.   CAN_Init(CAN1, &CAN_InitStructure);
  255.   CAN_Init(CAN2, &CAN_InitStructure);

  256.   /* CAN1 filter init */
  257.   /* 配置CAN过滤器 */
  258.   /* 32位对应的id */
  259.   /* stdid[10:0],extid[17:0],ide,rtr        */
  260.   /* 16位对应的id */
  261.   /* stdid[10:0],ide,rtr,extid[17:15] */
  262.   /* 一般使用屏蔽模式        */
  263.   /* 要注意的是fifo接收存满了中断,还有就是fifo的概念,即取的一直是最早那一个数据, 要释放才能取下一个数据 */
  264.   /* 常使用的中断有 */
  265.   /* 1,有信息中断,即fifo挂号中断 */
  266.   /* 2,fifo满中断        */
  267.   /* 3,fifo满之后又有信息来则中断,即fifo溢出中断        */
  268.   CAN_FilterInitStructure.CAN_FilterNumber = 0;     /* 过滤器1 */
  269.   CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;  /* 屏敝模式 */
  270.   CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; /* 32位 */
  271.   CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;  /* 以下四个都为0, 表明不过滤任何id */
  272.   CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
  273.   CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;
  274.   CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
  275.   CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0;  
  276.   CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
  277.   CAN_FilterInit(&CAN_FilterInitStructure);

  278.   /* CAN2 filter init */
  279.   CAN_FilterInitStructure.CAN_FilterNumber = 14;
  280.   CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0;
  281.   CAN_FilterInit(&CAN_FilterInitStructure);

  282.   /* IT Configuration for CAN1 */  
  283.   CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);

  284.   /* IT Configuration for CAN2 */  
  285.   CAN_ITConfig(CAN2, CAN_IT_FMP0, ENABLE);
  286. }

  287. /*******************************************************************************
  288. * Function Name  : CanWriteData
  289. * Description    : Can Write Date to CAN-BUS
  290. * Input          : None
  291. * Output         : None
  292. * Return         : None
  293. * Attention                 : None
  294. *******************************************************************************/
  295. void CanWriteData( CAN_TypeDef* CANx ,CanTxMsg *TxMessage )
  296. {
  297.   /* transmit */
  298. //  TxMessage->StdId = 0xA5A5;     /* 设置标准id  注意标准id的最高7位不能全是隐性(1)。共11位 */
  299. //TxMessage->ExtId = 0x00;       //设置扩展id  扩展id共18位
  300.   TxMessage->RTR = CAN_RTR_DATA; /* 设置为数据帧 */
  301.   TxMessage->IDE = CAN_ID_STD;   /* 使用标准id        */
  302. //  TxMessage->DLC = 8;            /* 数据长度, can报文规定最大的数据长度为8字节 */

  303.   CAN_Transmit(CANx,TxMessage);  /* 返回这个信息请求发送的邮箱号0,1,2或没有邮箱申请发送no_box */       
  304. }

  305. /*******************************************************************************
  306. * Function Name  : CAN1_RX0_IRQHandler
  307. * Description    : This function handles CAN1 RX0 interrupts
  308. * Input          : None
  309. * Output         : None
  310. * Return         : None
  311. * Attention                 : None
  312. *******************************************************************************/
  313. void CAN1_RX0_IRQHandler(void)
  314. {
  315.   int i;
  316.         CAN_Receive(CAN1,CAN_FIFO0, &Can1RxMessage);  /* 此函数包含释放提出报文了的,在非必要时,不需要自己释放 */
  317.   CAN1_RxRdy = ENABLE;
  318.         CAN1_RX_flag=1;
  319. }

  320. /*******************************************************************************
  321. * Function Name  : CAN2_RX0_IRQHandler
  322. * Description    : This function handles CAN2 RX0 interrupts
  323. * Input          : None
  324. * Output         : None
  325. * Return         : None
  326. * Attention                 : None
  327. *******************************************************************************/
  328. void CAN2_RX0_IRQHandler(void)
  329. {
  330.   CAN_Receive(CAN2,CAN_FIFO0, &Can2RxMessage);  /* 此函数包含释放提出报文了的,在非必要时,不需要自己释放 */
  331.   CAN2_RxRdy = ENABLE;
  332.         CAN2_RX_flag=1;
  333. }

  334. /*********************************************************************************************************
  335.       END FILE
  336. *********************************************************************************************************/
复制代码



长弓128828 2020-7-26 20:45:29
这么好的帖子没人看吗
回复

举报

评论

高级模式
您需要登录后才可以回帖 登录 | 注册

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
发经验
关闭

站长推荐 上一条 /8 下一条

快速回复 返回顶部 返回列表