本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站。作者:汪阳
CANopen在工业使用广泛,正好测试CAN于是乎就移植一个canfestival试试吧。
1.在网上下载canfestival源码,取出src和include目录,参考example的移植,一定要打开keil的C99模式。文件结构如下图:
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 @bruce
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。