ARM技术论坛
直播中

刘满贵

7年用户 1460经验值
私信 关注
[经验]

CANopen通讯之移植canfestival试验

CANopen在工业使用广泛,正好测试CAN于是乎就移植一个canfestival试试吧。

1.在网上下载canfestival源码,取出src和include目录,参考example的移植,一定要打开keil的C99模式。文件结构如下图:

CAN-01.png

CAN-02.png

CAN-03.png

2.打开对象字典编辑器,因为我的电脑装有python3,默认会用py3打开,就会闪退,所以使用cmd打开:py -2 objdictedit.py

使用测试的OD文件,我用的新版本canfestival,所以增加100C和100D,防止编译出错,生成头文件和.C文件

3.移植定时器,主要代码如下:

void setTimer(TIMEVAL value)  
 {  
  // TIMER\_CAR(TIMER1) = TIMER\_CNT(TIMER1) + value;  
     TIMER\_CAR(TIMER1) =  value;  
 }  
 TIMEVAL getElapsedTime(void)  
 {  
      return TIMER\_CNT(TIMER1);  
 }  
  
 //定时器初始化 8us  
 void time1\_init(void)  
 {  
  
  timer\_parameter\_struct timer\_initpara;//定时器结构体  
  rcu\_periph\_clock\_enable(RCU\_TIMER1);//开启定时器时钟  
  //因为APB1是AHB的4分频,因此定时器时钟CK\_TIMERx = CK\_AHB = 200m  
   rcu\_timer\_clock\_prescaler\_config(RCU\_TIMER\_PSC\_MUL4);//配置定时器时钟等于CK\_AHB  
  
  timer\_struct\_para\_init(&timer\_initpara);//将定时器结构体内参数配置成默认参数  
    timer\_deinit(TIMER1); //复位定时器  
  
  /\* TIMER1 configuration \*/  
  //200M/200/10 = 10us  
    timer\_initpara.prescaler         = 200\*8-1;//预分频  
    timer\_initpara.alignedmode       = TIMER\_COUNTER\_EDGE; //边缘对齐  
    timer\_initpara.counterdirection  = TIMER\_COUNTER\_UP; //向上计数方式  
    timer\_initpara.period            = TIMEVAL\_MAX-1; //计数值 //8-1  
    timer\_initpara.clockdivision     = TIMER\_CKDIV\_DIV1;  
    timer\_initpara.repetitioncounter = 0; //每次溢出都产生更新是件  
    timer\_init(TIMER1,&timer\_initpara);  
  
    /\* auto-reload preload enable \*/  
    timer\_auto\_reload\_shadow\_enable(TIMER1);//使能自动重加载  
  
  timer\_interrupt\_enable(TIMER1,TIMER\_INT\_UP);//使能溢出中断  
  
  nvic\_irq\_enable(TIMER1\_IRQn, 0, 1);//配置中断优先级  
  
    /\* TIMER1 enable \*/  
    timer\_enable(TIMER1);//使能定时器  
  
 }  
  
  
 //中断函数  
 //static int testtimer = 0;  
 void TIMER1\_IRQHandler(void)  
 {  
     if(SET == timer\_interrupt\_flag\_get(TIMER1,TIMER\_INT\_UP)){  
  
     TimeDispatch();  
     /\* clear TIMER interrupt flag \*/  
     timer\_interrupt\_flag\_clear(TIMER1,TIMER\_INT\_UP);  
    }       
 }

4.can驱动,接收采用中断

//Can 接收中断实现:  
  void CAN0\_RX0\_IRQpro(void)  
  {  
   m.cob\_id=receive\_message.rx\_sfid;  
   if(receive\_message.rx\_ft == CAN\_FT\_REMOTE)  
         m.rtr=1;  
   else if(receive\_message.rx\_ft == CAN\_FT\_DATA)  
      m.rtr=0;  
   m.len = receive\_message.rx\_dlen;  
  for(int i = 0; i < receive\_message.rx\_dlen; i++)  
                 m.data\[i\]=receive\_message.rx\_data\[i\];  
    canDispatch(&TestSlave\_Data, &m);  
  }  
 can发送函数:  
 /\*canSend函数实现如下:\*/  
 unsigned char canSend(CAN\_PORT notused, Message \*m)  
 {  
        uint32\_t        i;  
      transmit\_message.tx\_sfid = m->cob\_id;  
        if(m->rtr)  
              transmit\_message.tx\_ft = CAN\_FT\_REMOTE;  
        else  
             transmit\_message.tx\_ft = CAN\_FT\_DATA;  
        transmit\_message.tx\_ff = CAN\_FF\_STANDARD;  
        transmit\_message.tx\_dlen = m->len;  
        for(i = 0; i < m->len; i++)  
               transmit\_message.tx\_data\[i\] = m->data\[i\];  
       can\_message\_transmit(CAN1, &transmit\_message);  
      return 0;  
 }

5.初始化canopen进入操作模式

void InitNodes(CO\_Data\* d, UNS32 id)  
 {  
     static unsigned char deviceid=0;  
     setNodeId(&TestSlave\_Data, id);  //set node id [url=home.php?mod=space&uid=55329]@bruce[/url]  
     deviceid=\*(TestSlave\_Data.bDeviceNodeId);  
    /\* init \*/  
    /\* boot-up该节点 进入Pre-optional状态 \*/  
    setState(&TestSlave\_Data, Initialisation);     
    deviceid=\*(TestSlave\_Data.bDeviceNodeId);  
    setState(&TestSlave\_Data, Operational);  
    printf(" device ID is 0x\[%x\]\r\n",deviceid);  
 }

6.修改对象字典1017的心跳时间为1000,编译下载,开发板每隔1s发出心跳报文,一切OK。

原作者:兆易创新GD32 MCU 汪阳

更多回帖

发帖
×
20
完善资料,
赚取积分