CanFestival移植STM32F103
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 <inttypes.h>
#include <avr\io.h>
#include <avr\interrupt.h>
#include <avr/pgmspace.h>
#include <avr\sleep.h>
#include <avr\wdt.h>
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 <stdio.h>
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主機的移植完成。