Can通信介质是屏蔽双绞线,通过差分信号进行信号的传输,属于OSI七层网络结构的物理层和数据链路层。CanOpen是基于Can通信的上层协议,是属于网络层协议。需要用到CanOpen则需要根据下载的文档进行移植。
移植环境:
1、移植包 CanFestival-3-8bfe0ac00cdb
2、Keil开发工具
3、STM32F103系列新品(带收发器) 最小ROM 40K RAM 2K
4、Python2.7
5、wxPython2.8
移植步骤:
1、新建一个STM32工程文件,添加源文件和对应头文件
2、在工程目录文件下新建CanFestival文件夹,在CanFestival文件夹新建Src、Inc、Driver三个文件夹。
3、复制CanFestival-3-8bfe0ac00cdb包下的src文件夹内的全部源文件到工程文件的Src目录
4、复制CanFestival-3-8bfe0ac00cdb包下的include文件夹内的头文件到工程文件的Inc目录下,并且将CanFestival-3-8bfe0ac00cdb下的example/AVR/Slave文件夹下的ObjDict.h复制到工程文件Inc文件夹内。
5、复制CanFestival-3-8bfe0ac00cdb/include/AVR目录下applicfg.h、canfestival.h、config.h、timerscfg.h到工程文件夹Driver目录下,并在该目录下新建stm32文件夹。
6、将CanFestival-3-8bfe0ac00cdb/examples/TestMasterSlave文件夹下的TestMaster.c、TestMaster.h、TestSlave.c 、TestSlave.h、TestMasterSlave.h复制到工程目录Driver/stm32目录下,并在该目录下新建stm32_festival.c。
注:在CanFestival-3-8bfe0ac00cdb/examples/TestMasterSlave文件夹下并未发现上述的源文件和头文件,但可以发现有TestMaster.od、TestSlave.od文件。该文件为通讯对象字典,通过python解析可生成源文件。
Python安装: Win10在Windows图标鼠标右键,打开管理员权限命令行,找到Python下载路径,会车可自动安装。
wxPython2.8安装:一路Next,选择安装项最后一项原本为空,下拉选择第二项,然后开始安装成功。
CanFestival-3-8bfe0ac00cdb/objdictgen目录下解压Gnosis_Utils-current.tar到当前目录,复制gnosis文件夹到CanFestival-3-8bfe0ac00cdb/objdictgen目录下,找到该目录下objdictedit.py,点击启动,有对象字典配置界面显示,环境成功安装。
7、将所有的源码和头文件添加进工程,若是实现CanOpen主机,添加TestMaster.c,否则添加TestMaster.c。
8、为stm32_festival.c源文件添加内容
#include "canfestival.h"
#include "stm32f10x.h"
unsigned int TimeCNT = 0 ; //时间计数
unsigned int NextTime = 0 ; //下一次触发时间计数
unsigned int TIMER_MAX_COUNT = 70000; //最大时间计数
static TIMEVAL last_time_set = TIMEVAL_MAX ; //上一次的时间计数
CanTxMsg TxMessage;
CanRxMsg RxMessage;
extern CO_Data TestMaster_Data;
//主要被源码用来定时的,时间到了就需要调用一下函数TimeDispatch()
void setTimer(TIMEVAL value)
{
NextTime=(TimeCNT+value)%TIMER_MAX_COUNT;
}
//查询距离下一个定时触发还有多少时间
TIMEVAL getElapsedTime(void)
{
int ret=0;
ret = TimeCNT> last_time_set ? TimeCNT - last_time_set : TimeCNT + TIMER_MAX_COUNT - last_time_set;
last_time_set = TimeCNT;
return ret;
}
//发一个CAN包的,需要调用驱动来将一个CAN包发出去
unsigned char canSend(CAN_PORT notused, Message *m)
{
uint32_t i;
CanTxMsg *ptx_msg = &TxMessage;
ptx_msg->StdId = m->cob_id;
if(m->rtr)
{
ptx_msg->RTR = CAN_RTR_REMOTE;
}
else
{
ptx_msg->RTR = CAN_RTR_DATA;
}
ptx_msg->IDE = CAN_ID_STD;
ptx_msg->DLC = m->len;
for(i = 0; i < m->len; i++)
{
ptx_msg->Data[i] = m->data[i] ;
}
if( CAN_Transmit( CAN1, ptx_msg )==CAN_NO_MB)
{
return 0xff;
}
else
{
return 0x00;
}
}
//1ms定时
void timerForCan(void)
{
TimeCNT ++ ;
if(TimeCNT >= TIMER_MAX_COUNT)
{
TimeCNT = 0 ;
}
if(TimeCNT == NextTime)
{
TimeDispatch();
}
}
/* TIM4 configure */
static void TIM4_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure ;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Prescaler =72-1; //72000 - 1;
TIM_TimeBaseInitStructure.TIM_Period =0x03e8;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStructure);
TIM_ITConfig(TIM4, TIM_IT_CC1, ENABLE);
TIM_Cmd(TIM4, ENABLE);
}
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
static void RCC_Configuration(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA ,ENABLE);
}
void TIM4_Start(void)
{
RCC_Configuration();
NVIC_Configuration();
TIM4_Configuration();
}
void TIM4_IRQHandler(void)
{
if(TIM_GetITStatus(TIM4,TIM_IT_CC1)!= RESET)
{
TIM_ClearITPendingBit(TIM4,TIM_IT_CC1);
timerForCan();
}
}
void CAN_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
CAN_InitTypeDef CAN_InitStructure ;
CAN_FilterInitTypeDef CAN_FilterInitStructure ;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PORTA时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化IO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化IO
/* CAN register init */
CAN_DeInit(CAN1);
CAN_StructInit(&CAN_InitStructure);
/* CAN1 cell init */
CAN_InitStructure.CAN_TTCM = DISABLE;
CAN_InitStructure.CAN_ABOM = DISABLE;
CAN_InitStructure.CAN_AWUM = DISABLE;
CAN_InitStructure.CAN_NART = ENABLE;
CAN_InitStructure.CAN_RFLM = DISABLE;
CAN_InitStructure.CAN_TXFP = DISABLE;
CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
//Fpclk=72M/2/CAN_Prescaler
//BitRate=Fpclk/((CAN_SJW+1)*((CAN_BS1+1)+(CAN_BS2+1)+1));
//1M
/*CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
CAN_InitStructure.CAN_BS1 = CAN_BS1_3tq;
CAN_InitStructure.CAN_BS2 = CAN_BS2_5tq;
CAN_InitStructure.CAN_Prescaler = 4;*/
//125K
CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
CAN_InitStructure.CAN_BS1 = CAN_BS1_8tq;
CAN_InitStructure.CAN_BS2 = CAN_BS2_7tq;
CAN_InitStructure.CAN_Prescaler = 18;
CAN_Init(CAN1, &CAN_InitStructure);
/* CAN1 filter init */
CAN_FilterInitStructure.CAN_FilterNumber = 0;
CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;
CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment = 0;
CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
CAN_FilterInit(&CAN_FilterInitStructure);
CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE); //FIFO0消息挂号中断允许.
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 主优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 次优先级为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void USB_LP_CAN1_RX0_IRQHandler(void)
{
u8 i ;
Message m ;
CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
//接收处理
m.cob_id=RxMessage.StdId;
if(RxMessage.RTR == CAN_RTR_REMOTE)
m.rtr=1;
else if(RxMessage.RTR == CAN_RTR_DATA)
m.rtr=0;
m.len=RxMessage.DLC;
for(i = 0; i < RxMessage.DLC; i++)
{
m.data[i] = RxMessage.Data[i];
printf("%x ",m.data[i]);
}
canDispatch(&TestMaster_Data, &m);
}
9、编译,肯定会报错。注释掉config.h下的包含文件
#include
#include
#include
#include
#include
#include
10、修改dcf.c中的函数前修饰inline
inline void start_node(CO_Data* d, UNS8 nodeId)
修改为
static __inline void start_node(CO_Data* d, UNS8 nodeId)
10、主函数内添加如下代码:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "TestSlave.h"
#include "canfestival.h"
#include
unsigned char nodeID=0x21;
extern CO_Data TestMaster_Data;
int main(void)
{
u8 i = 0 ;
u8 res = 0 ;
u8 mes[8] = {0x2f,0x00,0x14,0x02,0xfd,0x00,0x00,0x00};
void* st ;
Message mesg ;
mesg.cob_id = 0x607; // SDO服务器地址
mesg.rtr = 0 ;
mesg.len = 8 ;
for(i=0;i<8;i++)
mesg.data[i] = mes[i] ;
delay_init(); //延时函数初始化
uart_init(115200);
LED_Init(); //初始化与LED连接的硬件接口
KEY_Init();
CAN_Config();
setNodeId(&TestMaster_Data, nodeID);
setState(&TestMaster_Data, Initialisation); // Init the state
TIM4_Start();
while(1)
{
res = KEY_Scan(0);
if(res == 1)
{
printf("KEY1 Press\r\n");
canSend((void*)0x607,&mesg);
}
else if(res == 2)
{
}
LED0=0;
LED1=1;
delay_ms(300); //延时300ms
LED0=1;
LED1=0;
delay_ms(300); //延时300ms
}
}
CanOpen主机的移植完成。