CUBEMX+CANOPEN教程二:can機能コード完備

8023 ワード

チュートリアルの基礎の上でcanの機能の完備を行います
主な仕事:
  • canフィルタ構成
  • can受信関連構造体構築
  • を送信する.
  • can送信と受信などの関数構築
  • can festival移植
  • タイマ構成
  • 文書ディレクトリ
  • 1. canフィルタ構成
  • 2. can受信に関するデータ構造構築
  • を送信する.
  • 3. can送信と受信などの関数構築
  • 4. can festival移植
  • 5. タイマ構成
  • 小結
  • 1.canフィルタ構成
    bsp_can.cファイルに追加
    void CAN_Filter_Init(void)
    {
    	CAN_FilterTypeDef CAN_FilterInitStructure;
    
    	CAN_FilterInitStructure.FilterActivation       	= ENABLE; 
    	CAN_FilterInitStructure.FilterBank				= 0;
    	CAN_FilterInitStructure.FilterFIFOAssignment   	= CAN_FILTER_FIFO0;
    	CAN_FilterInitStructure.FilterIdHigh           	= 0x0000;
    	CAN_FilterInitStructure.FilterIdLow           	= 0x0000;
    	CAN_FilterInitStructure.FilterMaskIdHigh        = 0x0000;
    	CAN_FilterInitStructure.FilterMaskIdLow         = 0x0000;
    	CAN_FilterInitStructure.FilterMode				= CAN_FILTERMODE_IDMASK;
    	CAN_FilterInitStructure.FilterScale            	= CAN_FILTERSCALE_32BIT;
    	CAN_FilterInitStructure.SlaveStartFilterBank	= 14;
    	
    	if(HAL_CAN_ConfigFilter(&hcan1, &CAN_FilterInitStructure) != HAL_OK)
    	{
    		_Error_Handler(__FILE__, __LINE__);
    	}
    	if(HAL_CAN_Start(&hcan1) != HAL_OK)
    	{
    		_Error_Handler(__FILE__, __LINE__);
    	}
    	if(HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
    	{
    		_Error_Handler(__FILE__, __LINE__);
    	}
    }
    

    2.can受信に関するデータ構造構築の送信
    CAN 1送信と受信データフレームヘッダ定義は標準ライブラリと異なる
    /* bsp_can.c */
    /* CAN1          */
    CAN_TxHeaderTypeDef				CAN1_TxHeaderMessage;
    CAN_RxHeaderTypeDef				CAN1_RxHeaderMessage;
    
    /* CAN1          */
    CAN_Msgdata can1_tx_msg;
    CAN_Msgdata can1_rx_msg;
    
    /* bsp_can.h */
     typedef struct{
    	Message m;
    }CANOpen_Message;
    
    typedef struct
    {
    	uint8_t Data[8];
    }CAN_Msgdata;
    

    ここでMessageは構造体がcanである.hファイルでの定義
    /* can.h */
    typedef struct {
      UNS16 cob_id;	/**< message's ID */
      UNS8 rtr;		/**< remote transmission request. (0 if not rtr message, 1 if rtr message) */
      UNS8 len;		/**< message's length (0 to 8) */
      UNS8 data[8]; /**< message's datas */
    } Message;
    
    #define Message_Initializer {0,0,0,{0,0,0,0,0,0,0,0}}
    
    typedef UNS8 (*canSend_t)(Message *);
    

    3.can送受信等の関数構築
    送信関数
    /* bsp_can.c */
    u8 canSend(CAN_HandleTypeDef *hcan,Message *m)
    {
    	unsigned char i;
    	CAN_TxHeaderTypeDef TxMessage;
    	
    	TxMessage.StdId = (uint32_t)(m->cob_id);
    	TxMessage.ExtId = 0x00;
    	TxMessage.RTR = m->rtr; 							  
    	TxMessage.IDE = CAN_ID_STD; 						  
    	TxMessage.DLC = 8; 	
    	TxMessage.DLC = m->len; 		
    	for(i=0;ilen;i++)								  
    	{
    		can1_tx_msg.Data[i] = m->data[i];
    	}
    	if(HAL_CAN_AddTxMessage(&hcan1, &TxMessage, can1_tx_msg.Data, (uint32_t*)CAN_TX_MAILBOX0) != HAL_OK)
    	{
    		return 1;
    //	 	printf("    \r
    "); // _Error_Handler(__FILE__, __LINE__); } return 0; }

    can受信キュー保留割込みコールバック関数
    /* bsp_can.c */
    CANOpen_Message CAN1_Rx_m;
    Message RxMSG = Message_Initializer;
    void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
    {
    	if(hcan->Instance == CAN1)
    	{
    		/*   can     */
    		 HAL_CAN_GetRxMessage(hcan,CAN_RX_FIFO0, &CAN1_RxHeaderMessage, can1_rx_msg.Data);
    		
    		/*   can       canDispatch         */
    		 RxMSG.cob_id = CAN1_RxHeaderMessage.StdId;
    		 RxMSG.len = CAN1_RxHeaderMessage.DLC;
    		 RxMSG.rtr = CAN1_RxHeaderMessage.RTR;
    		 memcpy(RxMSG.data,can1_rx_msg.Data,CAN1_RxHeaderMessage.DLC);
    	}
    
    //   AnalysisMessagefromDriver();
    //	SEGGER_RTT_printf(0, "can master revcive data!!!!!!!!!!!!
    "); // canDispatch(CANOpenMasterObject, &(RxMSG)); }

    以上のコードの最後の3行の3つのログアウト関数に注意して、1つ目はcanopenネットワークホストがデータを受信することを分析して、実際のプロジェクトの応用です;2つ目は印刷で、重要ではありません.3つ目はcanopenメッセージ分析で、重要です.
    4.can festival移植
    ソースコードを分析すると、canopen実装の最も重要なのは、canopenネットワークのメッセージの送信と受信タイミングと裁決をタイマで制御することであることがわかる.can festivalを移植した後、主にタイマがfestivalソースコードに融合するためのタイマ機能について話します.
    5.タイマー構成
    タイミングは1 ms
    /* tim.c */
    /* TIM4 init function */
    void MX_TIM4_Init(void)
    {
      TIM_ClockConfigTypeDef sClockSourceConfig;
      TIM_MasterConfigTypeDef sMasterConfig;
      TIM_OC_InitTypeDef sConfigOC;
    
      htim4.Instance = TIM4;
      htim4.Init.Prescaler = 84-1;
      htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
      htim4.Init.Period = 1000-1;
      htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
      if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
      {
        _Error_Handler(__FILE__, __LINE__);
      }
    
      sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
      if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
      {
        _Error_Handler(__FILE__, __LINE__);
      }
    
      if (HAL_TIM_OC_Init(&htim4) != HAL_OK)
      {
        _Error_Handler(__FILE__, __LINE__);
      }
    
      sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
      sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
      if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
      {
        _Error_Handler(__FILE__, __LINE__);
      }
    
      sConfigOC.OCMode = TIM_OCMODE_TIMING;
      sConfigOC.Pulse = 0;
      sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
      sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
      if (HAL_TIM_OC_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
      {
        _Error_Handler(__FILE__, __LINE__);
      }
    
    }
    

    bsp_timer.cではいくつかの関数を実現し、主にfestivalソースコードに呼び出しを提供する.
  • タイマー設定自動リロード値
  • を実現する.
  • 実装タイマは、現在のカウント値
  • を得る.
  • タイマ初期化関数
  • を実現する.
  • タイマ比較出力割り込みコールバック関数
  • を実現する.
    #ifdef CANOPEN_MY
    #include 
    #include "canfestival.h"
    #include "timer.h"
    
    #endif
    
    #ifdef CANOPEN_MY
    static TIMEVAL last_time_set = TIMEVAL_MAX;
    
    /**
      * @brief  setTimer
      * @param  value:Set time value 0x0000-0xffff
      * @retval NONE
      */
    void setTimer(TIMEVAL value)
    {
    	__HAL_TIM_SetAutoreload(&htim4, value);
    }
    /**
      * @brief  getElapsedTime
      * @param  NONE
    	* @retval TIMEVAL:Return current timer value
      */
    TIMEVAL getElapsedTime(void)
    {
    	uint16_t timer = __HAL_TIM_GetCounter(&htim4);
    	
    
    	return timer > last_time_set ? timer - last_time_set : last_time_set - timer; 	
    }
    
    /**
      * @brief  TIM4_start
      * @param  NONE
      * @retval NONE
      */
    void TIM4_start(void)
    {
    		MX_TIM4_Init();
    }
    /**
      * @brief  initTimer
      * @param  NONE
      * @retval NONE
      */
    void initTimer(void)
    {
    		TIM4_start();
    }
    

    そのうち#define CANOPEN_MYはもうmainにいます.hファイルでは、タイマオンはメイン関数ではなくfestivalソースコードでオンタイマを呼び出すように定義されています.
    /* CANOpenObjDictConfig.c */
    void Master_operational(CO_Data* d)
    {
    	UNS32 SyncTimePeriod = 2000;
    	UNS32 size = sizeof(SyncTimePeriod);
    	
    	writeLocalDict( d, /*CO_Data* d*/
    			0x1006, /*UNS16 index*/
    			0x00, /*UNS8 subind*/ 
    			&SyncTimePeriod, /*void * pSourceData,*/ 
    			&size, /* UNS8 * pExpectedSize*/
    			RW);  /* UNS8 checkAccess */
    	stopSYNC(d);
    	startSYNC(d);
    	setTimer(100);
    //	TIM_Cmd(TIM4, ENABLE); //20190408 FreeRTOS    CANopen
    	HAL_TIM_Base_Start_IT(&htim4);
    	SEGGER_RTT_printf(0, "Master_operational
    "); }

    メイン関数の初期化時にcanopenネットワークの初期化を呼び出し、CanopenInit();この関数はfestivalソースコードで定義されており、以下のように定義されています.
    /**
      * @brief  CanopenInit
      * @param  NONE
      * @retval NONE
      */
    void CanopenInit(void)
    {
    	UNS32 i;
    	
    	initTimer();   
    	CANOpenMasterObject->canHandle = CAN1;
    	CANOpenMasterInit(CANOpenMasterObject);
    	setState(CANOpenMasterObject,Initialisation);
    	setNodeId (CANOpenMasterObject, 127);
    //	canInit(CAN1,CAN_BAUD_1M);      
    	canInit(); //20190408 FreeRTOS    CANopen	
    	for(i=0; i<65536; i++);
    	for(i=0; i<65536; i++);
    	for(i=0; i<65536; i++);
    	for(i=0; i<65536; i++);
    	for(i=0; i<65536; i++);
    }
    

    ソースコードのcan初期化はボーレートを構成することができ、cubemxでボーレートが構成されているべきであるため、canInit(CAN1,CAN_BAUD_1M);関数をログアウトし、canInit();関数を自主的に実現し、この関数は以下のように定義される.
    u8 canInit(void)
    {
    	MX_CAN1_Init();
    	CAN_Filter_Init();
    	return 0;
    }
    

    この関数はcubemxで生成されたcan初期化関数を呼び出し,自分で実現したcanフィルタ初期化関数を加える.
    これでcan festival移植が完了し、canopen通信ネットワークホスト機能が実現しました.
    小結