1. 程式人生 > >stm32f103 學習筆記 —— 07 CAN通訊協議

stm32f103 學習筆記 —— 07 CAN通訊協議

1.報文種類

  1. 資料幀 :用於節點向外傳送資料

  2. 遙控幀 :用於向遠端節點請求資料

  3. 錯誤幀 :用於向遠端節點通知校驗錯誤,請求重新發送上一個資料

  4. 過載幀 :用於通知遠端節點本節點尚未做好接受準備

  5. 幀間隔 :用於將資料幀及遙控幀與前面的幀分離開來

2.報文結構(以資料幀為例)

  1. 以一個顯性位(邏輯0)開始,以7個連續的隱性位(邏輯1)結束
  2. 幀起始(Start Of Frame):只有一個數據位(顯性電平,邏輯0)
  3. 仲裁段 :決定傳送優先順序(通過“線與”的方式,即同時出現顯性和隱形電平時匯流排狀態被置為顯性);CAN控制器根據ID過濾報文
  4. 遠端傳輸請求位(Remote Transmission Request Bit):資料幀為顯性,遙控幀為隱性
  5. 識別符號擴充套件位(Identifier Extension Bit):顯性表示標準格式,隱性表示擴充套件格式
  6. SRR :只存在於擴充套件格式,它用於替代標準格式中的RTR位(由於擴充套件幀中的SRR位為隱性位,RTR在資料幀為顯性位,所以在兩  個ID相同的標準格式報文與擴充套件格式報文中,標準格式的優先順序較高)
  7. 資料長度碼(Data Length Code):由4個數據位組成,但只能表示0~8個位元組,用於表示報文中的資料段包含多少個位元組
  8. CRC :為了保證報文的正確傳輸,CAN的報文包含了一段15位的CRC校驗碼,一旦接收節點算出的CRC碼跟接收到的CRC碼不同,則它會向傳送節點反饋出錯資訊,利用錯誤幀請求它重新發送。
    CRC部分的計算一般由CAN控制器硬體完成,出錯時的處理則由軟體控制最大重發數。CRC校驗碼之後,有一個CRC界定符,它為隱性位,主要作用是把CRC校驗碼與後面的ACK段間隔起來。
  9. ACK段 :包括一個ACK槽位,和ACK界定符位。ACK槽位中,傳送節點發送的是隱性位,而接收節點則在這一位中傳送顯性位以示應答。在ACK槽和幀結束之間由ACK界定符間隔開。

  10. 幀結束(End Of Frame):7個連續的隱性位

3.CAN的相關配置

1.main.c


#include "stm32f10x.h"
#include "./usart/bsp_usart.h"
#include "./led/bsp_led.h"
#include "./can/bsp_can.h"
#include "./key/bsp_key.h"  

CanRxMsg  CAN_Rece_Data;
CanTxMsg  CAN_Tran_Data;

uint8_t flag = 0;
 
 
void Delay(__IO uint32_t nCount); 


int main(void)
{ 	
	
	
	CAN_Config()	;   
	
	Key_GPIO_Config();
	
	while(1)
	{
		if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON  )
		
		{
			uint8_t box;
			
			CAN_Tran_Data.StdId = 0;
			CAN_Tran_Data.ExtId = PASS_ID;
			CAN_Tran_Data.RTR = CAN_RTR_Data;
			CAN_Tran_Data.IDE = CAN_Id_Extended ;
			CAN_Tran_Data.DLC = 1;
			CAN_Tran_Data.Data[0] = 10;
			
			box = CAN_Transmit(CAN1,&CAN_Tran_Data);
			
			while(CAN_TransmitStatus(CAN1,box) == CAN_TxStatus_Failed);
						
					
			
		} 		
		
		
		if(flag == 1)
		{
			
			  flag = 0;
		}
		else
		{
		
		}
	}
}


2.bsp_can.c

#include "./can/bsp_can.h"

//1.初始化CAN外設、波特率,位的組成
//2.配置篩選器,方便接收資料
//3.傳送資料,並接收,使用迴環模式測試

void CAN_GPIO_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
	
	/* 使能CAN時鐘 */
	RCC_APB1PeriphClockCmd (RCC_APB1Periph_CAN1 , ENABLE );
	
	/* 使能CAN引腳相關的時鐘 */
 	RCC_APB2PeriphClockCmd ( CAN_GPIO_CLK|RCC_APB2Periph_AFIO, ENABLE );
	
	//使用PA8 9引腳的第二功能
	GPIO_PinRemapConfig (GPIO_Remap1_CAN1 ,ENABLE);
	
  /* 配置CAN的 引腳,普通IO即可 */
  GPIO_InitStructure.GPIO_Pin = CAN_TX_GPIO_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(CAN_TX_GPIO_PROT, &GPIO_InitStructure);
	
	  /* 配置CAN的 引腳,普通IO即可 */
  GPIO_InitStructure.GPIO_Pin = CAN_RX_GPIO_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(CAN_RX_GPIO_PORT, &GPIO_InitStructure);
	
}


void CAN_Mode_Config(void)	
{

	CAN_InitTypeDef CAN_InitTypeStruct;
	
	CAN_InitTypeStruct.CAN_ABOM = ENABLE;//自動離線管理功能
	CAN_InitTypeStruct.CAN_AWUM = ENABLE;//自動喚醒功能
	CAN_InitTypeStruct.CAN_Mode = CAN_Mode_LoopBack;//CAN_Mode_Normal;//工作模式
	CAN_InitTypeStruct.CAN_NART = ENABLE;//錯誤重傳
	CAN_InitTypeStruct.CAN_RFLM = ENABLE;//是否鎖定FIFO
	CAN_InitTypeStruct.CAN_TTCM = DISABLE;//是否使能時間觸發功能
	CAN_InitTypeStruct.CAN_TXFP = DISABLE; //按ID優先順序傳送
	
	//配置成1Mbps
	CAN_InitTypeStruct.CAN_BS1 = CAN_BS1_5tq;
	CAN_InitTypeStruct.CAN_BS2 = CAN_BS2_3tq;
	CAN_InitTypeStruct.CAN_SJW = CAN_SJW_2tq;
	CAN_InitTypeStruct.CAN_Prescaler = 4;
	
	
	CAN_Init(CAN1,&CAN_InitTypeStruct);

}



void CAN_Filter_Config(void)
{
	CAN_FilterInitTypeDef CAN_FilterInitTypeStruct;
	
	CAN_FilterInitTypeStruct.CAN_FilterActivation = ENABLE;
	CAN_FilterInitTypeStruct.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0  ;
	CAN_FilterInitTypeStruct.CAN_FilterNumber = 0;//篩選器編號
	CAN_FilterInitTypeStruct.CAN_FilterScale = CAN_FilterScale_32bit;//篩選器尺度
	CAN_FilterInitTypeStruct.CAN_FilterMode = CAN_FilterMode_IdMask  ;//篩選器模式
	
	CAN_FilterInitTypeStruct.CAN_FilterIdHigh = ((PASS_ID<<3 |CAN_Id_Extended |CAN_RTR_Data)&0xFFFF0000)>>16;
	CAN_FilterInitTypeStruct.CAN_FilterIdLow = ((PASS_ID<<3 |CAN_Id_Extended |CAN_RTR_Data)&0xFFFF);
	
	CAN_FilterInitTypeStruct.CAN_FilterMaskIdHigh = 0xFFFF;
	CAN_FilterInitTypeStruct.CAN_FilterMaskIdLow =0xFFFF;	

	CAN_FilterInit(&CAN_FilterInitTypeStruct);
	
	CAN_ITConfig (CAN1,CAN_IT_FMP0,ENABLE);
	
}	

void CAN_NVIC_Config(void)
{

	NVIC_InitTypeDef NVIC_InitStructure;
  
  /* 配置NVIC為優先順序組1 */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  
  NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
  /* 配置搶佔優先順序 */
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  /* 配置子優先順序 */
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  /* 使能中斷通道 */
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

void CAN_Config(void)	
{
	CAN_GPIO_Config();
  CAN_Mode_Config();
	CAN_Filter_Config();
	CAN_NVIC_Config();
	
}
   

3.bsp_can.h

#ifndef __BSP_CAN_H
#define __BSP_CAN_H

#include "stm32f10x.h"


#define PASS_ID   ((uint32_t)0x1314)


#define CAN_TX_GPIO_PROT  		GPIOB
#define CAN_TX_GPIO_PIN   		GPIO_Pin_9

#define  CAN_RX_GPIO_PORT     GPIOB
#define  CAN_RX_GPIO_PIN      GPIO_Pin_8

#define CAN_GPIO_CLK					RCC_APB2Periph_GPIOB



void CAN_Config(void)	;     


#endif /* __BSP_CAN_H */