can总线-stm32
一、什么是can总线?
can总线因为使用电压差表示逻辑1和0,所以抗干扰性强,传播距离远(500kbps 时130M),比特率越小越远
1.can有几根线?
2根,can_H ,can_L
2.can怎么表示1,0?
can_H - can_L > 0.9V ,为逻辑 0,也称为显性电平。
can_H - can_L < 0.5v ,为逻辑1,也称为隐性电平。
一般can_H为3.5V , 2.5V
一般can_L为2.5V ,1.5V
二、stm32 怎么使用can总线
1.can接口在哪?
stm32有can总线控制器,以及有库函数stm32f10x_can.c可以驱动该控制器
但stm32只是有can总线控制器,要真正连接can总线,她还要外接can总线收发器,才能分出来can_H ,can_L,例如如下芯片:
这个芯片的主要作用是发送时根据TXD的电平来决定can_H 和can_L的电平,以及接收时根据can_H 和 can_L的电平差来决定RXD的电平。
2.can概念入门比较好的文档
https://wenku.baidu.com/view/7701528a6529647d2728520f.html
这个文档比较详细的介绍了can帧的类型,以及各个帧每个字节,每个bit的含义,以及优先级仲裁机制。下面的例程是数据帧。
3.can例程。
1 #ifndef CAN_H_ 2 #define CAN_H_ 3 #include "stm32f10x.h" 4 #define RCC_APBxPeriph_CAN_IO RCC_APB2Periph_GPIOA 5 #define CAN_RXD GPIO_Pin_11 6 #define CAN_TXD GPIO_Pin_12 7 #define CAN_IO GPIOA 8 9 enum canrate_e 10 { 11 CANRATE125K=125, 12 CANRATE250K=250, 13 CANRATE500K=500, 14 CANNOTLINK, 15 }; 16 17 enum canStdExt_e 18 { 19 CANSTD=0, 20 CANEXT=1, 21 }; 22 struct canrxtx_s 23 { 24 CanRxMsg rxMessage[3]; 25 u8 rx_newflag; 26 uint32_t f; 27 CanTxMsg txMessage; 28 29 }; 30 31 /*std ID*/ 32 #define CAN1_TX_STD_ID 0x7DF //11 Bits ID,Functional 33 34 #define CAN1_TX_STD_ID_ECM 0x7E0 //11 Bits ECM ID,physical 35 #define CAN1_RX_STD_ID_ECM 0x7E8 //11 Bits ECM ID,physical 36 #define CAN1_RX_STD_Filter 0x7FF //11 bits ECM Filter 37 38 /*extend ID*/ 39 #define CAN1_TX_EXT_ID 0x18DB33F1 //29 Bits ID,Functional 40 #define CAN_Id_Extended_HONDA 0x18DBEFF1 //29 Bits ID,Functional HONDA 41 #endif
1 #include "can.h" 2 #include <string.h> 3 u8 std_or_ext; 4 struct canrxtx_s canrxtx; 5 void CAN1_init(enum canrate_e canrate) 6 { 7 8 GPIO_InitTypeDef GPIO_InitStructure; 9 CAN_InitTypeDef CAN_InitStructure; 10 11 RCC_APB2PeriphClockCmd(RCC_APBxPeriph_CAN_IO | RCC_APB2Periph_AFIO,ENABLE); 12 RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE); 13 GPIO_InitStructure.GPIO_Pin = CAN_RXD; 14 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; 15 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 16 GPIO_Init(CAN_IO, &GPIO_InitStructure); 17 18 GPIO_InitStructure.GPIO_Pin = CAN_TXD; 19 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 20 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 21 GPIO_Init(CAN_IO, &GPIO_InitStructure); 22 23 CAN_DeInit(CAN1); 24 CAN_StructInit(&CAN_InitStructure); 25 26 CAN_InitStructure.CAN_TTCM = DISABLE; 27 CAN_InitStructure.CAN_ABOM = DISABLE; 28 CAN_InitStructure.CAN_AWUM = DISABLE; 29 CAN_InitStructure.CAN_NART = DISABLE; 30 CAN_InitStructure.CAN_RFLM = DISABLE; 31 CAN_InitStructure.CAN_TXFP = DISABLE; 32 CAN_InitStructure.CAN_Mode = CAN_Mode_Normal; 33 CAN_InitStructure.CAN_SJW = CAN_SJW_1tq; 34 CAN_InitStructure.CAN_BS1 = CAN_BS1_3tq; 35 CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq; 36 //CAN BaudRate = 72MHz/(CAN_SJW+CAN_BS1+CAN_BS2)/CAN_Prescaler 37 if(canrate==CANRATE125K) /* 125KBps */ 38 CAN_InitStructure.CAN_Prescaler =96; 39 else if(canrate==CANRATE250K) /* 250KBps */ 40 CAN_InitStructure.CAN_Prescaler =48; 41 else /* 500KBps */ 42 CAN_InitStructure.CAN_Prescaler = 24; 43 44 CAN_Init(CAN1, &CAN_InitStructure); 45 } 46 47 void CAN1_ConfigFilter(u32 id1, u32 id2, u32 mask1, u32 mask2, u8 std_or_ext) 48 { 49 CAN_FilterInitTypeDef CAN_FilterInitStructure; 50 NVIC_InitTypeDef NVIC_InitStructure; 51 52 CAN_FilterInitStructure.CAN_FilterNumber=1; //use which filter,0~13 53 CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; 54 if(std_or_ext == CANSTD) 55 { 56 CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_16bit; 57 CAN_FilterInitStructure.CAN_FilterIdHigh=id1<<5; 58 CAN_FilterInitStructure.CAN_FilterIdLow=id2<<5; 59 CAN_FilterInitStructure.CAN_FilterMaskIdHigh=mask1<<5; 60 CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask2<<5; 61 62 } 63 else 64 { 65 CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; 66 CAN_FilterInitStructure.CAN_FilterIdHigh=(u16) (id1>>13); 67 CAN_FilterInitStructure.CAN_FilterIdLow=(u16) (((id1&0x00001FFF)<<3)|CAN_Id_Extended|CAN_RTR_DATA); 68 CAN_FilterInitStructure.CAN_FilterMaskIdHigh=(u16) (mask1>>13); 69 CAN_FilterInitStructure.CAN_FilterMaskIdLow=(u16) ((mask1&0x00001FFF)<<3); 70 71 } 72 73 CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0; 74 CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; 75 CAN_FilterInit(&CAN_FilterInitStructure); 76 77 NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX1_IRQn; 78 79 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; 80 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; 81 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 82 NVIC_Init(&NVIC_InitStructure); 83 84 CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE); 85 } 86 /************************init******************************/ 87 void init_demo() 88 { 89 std_or_ext = CANEXT; 90 CAN1_init(CANRATE500K); 91 CAN1_ConfigFilter(0x18DAF110,0x18DAF110,0x1FFFF100,0x1FFFF100,std_or_ext);//extend ID 92 } 93 /************************tx******************************/ 94 /*datalen<=8*/ 95 int CAN1_TransASerialData(u8* pdata,u8 datalen) 96 { 97 u8 i=0; 98 99 Delay_ms(20); 100 101 if(std_or_ext == CANEXT) 102 { 103 canrxtx.txMessage.StdId=0x00; 104 canrxtx.txMessage.ExtId=CAN_Id_Extended_HONDA;//bentian 105 canrxtx.txMessage.RTR=CAN_RTR_DATA; 106 canrxtx.txMessage.IDE=CAN_Id_Extended;// 29 bits 107 108 } 109 if(std_or_ext== CANSTD) 110 { 111 canrxtx.txMessage.StdId=CAN1_TX_STD_ID; 112 canrxtx.txMessage.ExtId=0x00; 113 canrxtx.txMessage.RTR=CAN_RTR_DATA; 114 canrxtx.txMessage.IDE=CAN_Id_Standard;//11 bits 115 } 116 117 canrxtx.txMessage.DLC=0x08; 118 canrxtx.txMessage.Data[0]=datalen; 119 memcpy(&(canrxtx.txMessage.Data[1]),pdata,datalen); 120 121 122 while(((i++)<3)&&(CAN_TxStatus_NoMailBox==CAN_Transmit( CAN1,&canrxtx.txMessage))) 123 124 if(i>=3) //timeout 125 { 126 return (-1); 127 } 128 129 canrxtx.rx_newflag=0; 130 return (0); 131 132 } 133 /************************rx******************************/ 134 void CAN1_RX1_IRQHandler(void) 135 { 136 memset(&canrxtx.rxMessage,0,sizeof(CanRxMsg)); 137 if(CAN_MessagePending(CAN1,CAN_FIFO0)) 138 { 139 CAN_Receive(CAN1,CAN_FIFO0,&canrxtx.rxMessage[0]); 140 } 141 canrxtx.rx_newflag=1; 142 }
三、标识符过滤器的解释
过滤器只是用于接收,判断某个报文是否能通过过滤器,过滤器初始化如下:
53 CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
56 CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_16bit;
57 CAN_FilterInitStructure.CAN_FilterIdHigh=id1<<5;
58 CAN_FilterInitStructure.CAN_FilterIdLow=id2<<5;
59 CAN_FilterInitStructure.CAN_FilterMaskIdHigh=mask1<<5;
60 CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask2<<5;
stm32有0~13个过滤器组,每个过滤器组有两个32位的寄存器,通过设置下面两个结构体成员的值可以有四种组合:
CAN_FilterMode 和 CAN_FilterScale
四、关于邮箱
如下图,发送3个邮箱,接收每个FIFO 3个邮箱,这是硬件自动管理的,软件不用管,只要判断发送成不成功,中断接收哪个FIFO就行了(要接收过滤器初始化时绑定的那个FIFO)。
每个邮箱都可以存储一个独立的报文,发送调度器(下图红圈)会根据标识符(ID)的优先级来决定先发送哪个报文(比如发送时3个邮箱都有报文,标识符不一样),PS:标识符数值越小,优先级越高,这是由CAN总线仲裁机制决定的(线与,0可以与掉1)。
五、can中容易理解错的概念
1.CAN总线中是没有地址这个概念的,每个报文都是群发。
所有节点都可以发送和接收,先发送的有优先权,此时其它节点处于监听模式,看是否有能通过自己过滤器的报文。
当同时有多个节点需要同时发送时,can总线将实行仲裁,标识符小的优先发送,被仲裁下去想要发送的节点立即转入监听状态,等待下次机会。
标识符是报文的一部分,如下图所示:
2.不管是标准帧或者扩展帧,最多只能携带8字节数据,用户可以根据这8个字节私立协议。
SOF:帧起始信号,显性电平,即can_H和can_L相差很小,小于0.5V,库函数做了赋值,不管。
标识符:11bit或者29bits,代表着本条报文的优先级
RTR:帧类型,是远程帧还是数据帧
IDE:标准帧还是扩展帧
R0:保留位,库函数做了,不管
DLC:数据域长度
数据域:具体携带的数据,最长8字节
CRC:对CRC前所有字节进行校验,得到的结果,库函数进行了这一步,不需要我们自己计算,不管。
CRC分隔符:1个隐性电平,库函数做了,不管
ACK Field:库函数做了,
EOF:帧结束标志,至少连续7位的隐性电平。不管。
3.位填充的概念
在CAN消息帧中,帧起始,仲裁场。控制场,数据场和CRC段,均以位填充方法进行编码。当发送器在发送流中检测到5个极性相同的连续位时,自动插入一个部补位码。
我觉得这个只要了解就行了,实际编程中库函数已经帮我们做了。