|
一、什么是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接口在哪? 0 p6 [+ U2 u9 _) d+ `, t. @
- p# A7 D* p9 p! d W( K
stm32有can总线控制器,以及有库函数stm32f10x_can.c可以驱动该控制器 但stm32只是有can总线控制器,要真正连接can总线,她还要外接can总线收发器,才能分出来can_H ,can_L,例如如下芯片: 这个芯片的主要作用是发送时根据TXD的电平来决定can_H 和can_L的电平,以及接收时根据can_H 和 can_L的电平差来决定RXD的电平。 % q4 {6 J4 {4 v& A
1 w+ C) M5 @7 f8 r; I& g- f! f
, S+ S% R1 `2 ]( N/ E# h
4 d& t4 d7 h# R6 B. V' |4 @
2.can概念入门比较好的文档 https://wenku.baidu.com/view/7701528a6529647d2728520f.html 这个文档比较详细的介绍了can帧的类型,以及各个帧每个字节,每个bit的含义,以及优先级仲裁机制。下面的例程是数据帧。 3.can例程。 : b' R1 }9 D% P- Q2 N1 c7 h
- #ifndef CAN_H_
: F y% O; D4 z: F - #define CAN_H_% c6 c1 A0 y5 r6 E5 R
- #include "stm32f10x.h"
* n3 B# i9 J) s- F" L9 I$ | - #define RCC_APBxPeriph_CAN_IO RCC_APB2Periph_GPIOA/ q) g# m4 H; h) _# ^& }0 I5 F
- #define CAN_RXD GPIO_Pin_11
; x6 Z k1 k# ? - #define CAN_TXD GPIO_Pin_12) T$ B# Z: f. ~1 v9 P, K: D0 { u
- #define CAN_IO GPIOA; L4 E. {' B/ k' ?4 T
- 3 J$ k, \5 o& B
- enum canrate_e+ X4 I& d! Y+ a2 C t4 {# R+ {
- {* z* J% C# s, i* e% A* N
- CANRATE125K=125,
1 c* i) X8 U6 R$ ~7 W4 \ - CANRATE250K=250,
/ y7 ]- X6 p' u3 t( i+ S - CANRATE500K=500,* g0 j1 e- |& C
- CANNOTLINK,! a! x4 S$ r5 j# F: Z }% M
- };
! i4 o7 M6 T0 a" v - : m8 F* i3 x& Y: U! ~7 F7 N$ @
- enum canStdExt_e: Q6 s4 |7 z: q0 j, t6 X
- {) l, z" D# G0 p/ h
- CANSTD=0,) X. H) y9 U4 X1 n+ e5 o
- CANEXT=1,
: y, c( q2 ]. V- ?5 k6 v( l2 I - };7 k! i3 u1 I1 B% R$ N
- struct canrxtx_s
* f7 _% Y/ U4 c6 F - {
& ?2 O# P) T* n. Y) H! n; V - CanRxMsg rxMessage[3];/ I4 b6 [; ]! @+ E
- u8 rx_newflag;
+ u: V$ O& E$ }2 n0 _/ `& {. Y - uint32_t f;
. v, e0 C7 h. ~9 s% S- D) f8 M - CanTxMsg txMessage;2 M8 T5 i8 A; J3 I
/ ~5 K1 c* p7 {3 q- }; N8 A0 l: ^ Q2 o: z( g
- + O8 a2 D+ _. [- l1 L
- /*std ID*/
1 w2 V/ i, o* X! I# y6 D+ P - #define CAN1_TX_STD_ID 0x7DF //11 Bits ID,Functional
7 }- z7 v' z0 n
* {: @) d) P) k6 L( K+ s( g- #define CAN1_TX_STD_ID_ECM 0x7E0 //11 Bits ECM ID,physical! p3 V# m: |( A! C% ^
- #define CAN1_RX_STD_ID_ECM 0x7E8 //11 Bits ECM ID,physical" j& _* |" p) {. ]. K* b3 h! q
- #define CAN1_RX_STD_Filter 0x7FF //11 bits ECM Filter
3 G+ ?* Z# }* y9 V1 N U/ B9 A3 F) p& I - & Q. d, x# `2 e* }2 o
- /*extend ID*/: U+ Z" g5 T: @5 S6 e: v
- #define CAN1_TX_EXT_ID 0x18DB33F1 //29 Bits ID,Functional
: U- H2 x& V" o) H; C& j) W - #define CAN_Id_Extended_HONDA 0x18DBEFF1 //29 Bits ID,Functional HONDA& S5 L3 [$ |; q* {5 Q
- #endif
复制代码- #include "can.h"1 @# F8 Y: P c! V: A o6 r5 m
- #include <string.h>: p* d1 e" a9 a* }) a7 o
- u8 std_or_ext;6 t% p9 n$ |# M9 ^* s
- struct canrxtx_s canrxtx;
; U# H' |9 Z/ r0 q - void CAN1_init(enum canrate_e canrate)
* f: e' L; y& b" l- w0 p* b - {
" \6 Q# v) t$ f. X+ G2 l
! d7 Q7 C( Q0 P8 s- GPIO_InitTypeDef GPIO_InitStructure;4 \9 x# C1 |5 t. I& \" N' A( N6 O
- CAN_InitTypeDef CAN_InitStructure;
! O4 u' U7 [1 M+ `2 X! _" }; }4 `% j
. t l9 S" c5 H2 V3 M/ V- RCC_APB2PeriphClockCmd(RCC_APBxPeriph_CAN_IO | RCC_APB2Periph_AFIO,ENABLE);
/ |1 U3 J0 w' u2 U - RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);2 I2 _& X1 d9 J
- GPIO_InitStructure.GPIO_Pin = CAN_RXD;
* e7 Y& G' X5 [6 s( H' ]; `3 | - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
4 j9 ^5 P1 C3 u/ A. z2 h9 O$ g - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;0 ]. O/ T1 y4 N) N- P
- GPIO_Init(CAN_IO, &GPIO_InitStructure);
6 B# ? l) f4 _9 b; f& ]5 g1 b
, {' H& _4 \) T" H) U5 R9 K0 I; T- GPIO_InitStructure.GPIO_Pin = CAN_TXD;1 @0 N7 l, ^3 x% B$ }6 N' |
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;/ }0 x1 ]3 l; Z9 C2 x! {, y# [
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;( ~# s8 Y" k0 s( i
- GPIO_Init(CAN_IO, &GPIO_InitStructure);( I3 O; t1 ^% z. A6 @
- - _5 @* s+ u' K6 q |
- CAN_DeInit(CAN1);6 K/ I. j! q S' G8 g0 H* T: N
- CAN_StructInit(&CAN_InitStructure);
, D5 b8 R$ o% {+ A) O - * w& ^2 n3 k+ k: {/ n0 i
- CAN_InitStructure.CAN_TTCM = DISABLE;, A! R, z q Q3 w
- CAN_InitStructure.CAN_ABOM = DISABLE;& y8 _' h3 o0 |; C
- CAN_InitStructure.CAN_AWUM = DISABLE;' R# v k9 O* g v
- CAN_InitStructure.CAN_NART = DISABLE;
( ]) f* C' \( \3 M6 [! d% b u9 k - CAN_InitStructure.CAN_RFLM = DISABLE;+ y5 R! U7 k9 s/ @9 \: m
- CAN_InitStructure.CAN_TXFP = DISABLE;
7 W: [% x# B$ w - CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;9 X- Q! Z3 p2 c+ z
- CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
1 }3 @/ i. q; M& a7 E6 m/ _, ^0 H - CAN_InitStructure.CAN_BS1 = CAN_BS1_3tq;
. C' @0 ?2 s: m2 v M9 n9 I! s& D - CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;8 w3 g) q! S' D, N1 X) W
- //CAN BaudRate = 72MHz/(CAN_SJW+CAN_BS1+CAN_BS2)/CAN_Prescaler
- ~- p6 C9 J! N3 [# P4 _4 x) ^ - if(canrate==CANRATE125K) /* 125KBps */
0 e2 ]8 b0 x! z$ y8 ^+ w - CAN_InitStructure.CAN_Prescaler =96;
3 A) q V3 H, X/ S; O* w2 [ - else if(canrate==CANRATE250K) /* 250KBps */8 t' G3 y; c- L0 z
- CAN_InitStructure.CAN_Prescaler =48;
) C! r, x* A- n* V - else /* 500KBps */6 p" K: a* `. B( _" V+ x3 q, a
- CAN_InitStructure.CAN_Prescaler = 24;
/ d, G0 |! U- Q+ h0 Z8 L6 l
) j' W+ W) V% G9 z* l% C+ K- CAN_Init(CAN1, &CAN_InitStructure);3 n6 a! L0 M* K
- }
1 S& E+ g" O$ O( c1 \0 C - " g+ M7 B2 Y7 a% ?2 s
- void CAN1_ConfigFilter(u32 id1, u32 id2, u32 mask1, u32 mask2, u8 std_or_ext)
, k) ]. X/ F" v O; Y. E- W i - {6 |9 O2 x& L) L+ I7 d
- CAN_FilterInitTypeDef CAN_FilterInitStructure;
9 `4 c/ V/ A, ]' a+ u - NVIC_InitTypeDef NVIC_InitStructure;+ M# v' ?* \, O: e* q4 [! c+ `. v
- ! a& \% _0 b N$ E' Z8 y
- CAN_FilterInitStructure.CAN_FilterNumber=1; //use which filter,0~13
9 u6 G0 d$ A! i5 d/ J$ _ - CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
- N- ]; F3 ]( r - if(std_or_ext == CANSTD)
, Z0 w2 k: ^% h- w, S$ ]5 [ - {
2 p4 ~* p. P, Y6 Y. g- E, o - CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_16bit;1 P$ o" R/ ]& s) V
- CAN_FilterInitStructure.CAN_FilterIdHigh=id1<<5;: [' Y9 B# {- O( V# O! U6 a- [1 x
- CAN_FilterInitStructure.CAN_FilterIdLow=id2<<5;
3 W2 }, X1 k. _* s1 C; F/ M( P2 B - CAN_FilterInitStructure.CAN_FilterMaskIdHigh=mask1<<5;3 z0 e6 z- q1 j& a
- CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask2<<5;
6 }7 ^/ ?# Q+ \& Y, V - : E6 Z a/ Y8 Q; K( L* T
- } ?0 U9 P1 V: d$ Y
- else* c7 Z/ n4 x9 G" [9 n1 l1 Y# s5 _
- {+ o" r/ C0 W4 G* ~) }3 ]7 d, B
- CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;
! z7 F- k* W3 x6 s# w - CAN_FilterInitStructure.CAN_FilterIdHigh=(u16) (id1>>13);( q( M1 f) p, f( L7 L! M! I
- CAN_FilterInitStructure.CAN_FilterIdLow=(u16) (((id1&0x00001FFF)<<3)|CAN_Id_Extended|CAN_RTR_DATA);( ~" p4 `% ?7 s, @0 T. i
- CAN_FilterInitStructure.CAN_FilterMaskIdHigh=(u16) (mask1>>13);5 B7 _3 E3 ^# m7 l3 e
- CAN_FilterInitStructure.CAN_FilterMaskIdLow=(u16) ((mask1&0x00001FFF)<<3);
$ W; S/ m$ Q. G- E1 G& z; T
' i6 v- P& d& d. A: e0 B# b! y. I& |- }* E' b; z7 K7 G5 l& f& ?& z
- { T: Z* K% b9 O2 k3 O4 B
- CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;' Y, X* K$ l2 P) }' o, K" @
- CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
5 L. y/ n- ]6 \2 n - CAN_FilterInit(&CAN_FilterInitStructure);
( ~8 L0 ^4 A. o$ a - ( b8 A; n# k2 f+ k
- NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX1_IRQn;
* t4 W& T& }8 N
. E! c+ |& ~1 O1 l- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;& p& y7 K, L: a y5 j7 X1 S
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;* b0 a( m' n0 o& t5 @
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
3 n; e- t0 ^9 r- Y - NVIC_Init(&NVIC_InitStructure);
$ b5 O4 L* n; ^1 Z' J/ I( a
) }* L+ T# Z# D6 p( }. n" y- CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
- u2 I* M+ n' c% k }) N F - }
, c. |1 S$ }! i" x - /************************init******************************/5 g- I# w9 p9 i8 X k
- void init_demo()
$ F( B: k( P2 Y) a) h/ F - {7 m, @% l/ O4 l7 o6 |0 P
- std_or_ext = CANEXT;& _: e' F* l+ F2 Y2 F. }
- CAN1_init(CANRATE500K);
* I/ o. ^2 Z5 h# `! t1 \ - CAN1_ConfigFilter(0x18DAF110,0x18DAF110,0x1FFFF100,0x1FFFF100,std_or_ext);//extend ID3 L& @: o* ~0 e% j0 Y! ?$ ~
- }
- m- W3 j$ n( Y& I$ m) O - /************************tx******************************/1 d* P& t v- s
- /*datalen<=8*/
& m( @! ?7 O# L3 R% \/ b - int CAN1_TransASerialData(u8* pdata,u8 datalen) l9 B2 W0 s# Z6 c" J- k5 k
- {
& f& M' h2 K( B( ? - u8 i=0;% A8 Y L. G4 Z! |2 S
& g1 Q, [: r6 A; \. L7 D6 @/ m- Delay_ms(20);
: K! B* B% o( y( S, E) L - 8 M4 s( \" B' [) @4 Y* n
- if(std_or_ext == CANEXT)- A0 G! |% J: u9 L7 C
- {" l+ X O$ d; Z. |% ^) h/ U+ ^0 G- P3 j
- canrxtx.txMessage.StdId=0x00;* d4 V4 p+ d- T. R" a5 a
- canrxtx.txMessage.ExtId=CAN_Id_Extended_HONDA;//bentian' v$ _( a) J. S6 y
- canrxtx.txMessage.RTR=CAN_RTR_DATA;
# {) W, i1 R) O- T2 ` - canrxtx.txMessage.IDE=CAN_Id_Extended;// 29 bits
1 [: a. |" h N3 m - % w+ H. M$ n8 c2 n/ M
- } w. E; X d( ~* x& f, k
- if(std_or_ext== CANSTD)! S$ s9 r' H. j3 u
- {% X4 G5 x `. M
- canrxtx.txMessage.StdId=CAN1_TX_STD_ID;
; P' N9 W$ k( ]3 B4 V, e - canrxtx.txMessage.ExtId=0x00;9 T7 T6 z8 @) }( y7 R1 s
- canrxtx.txMessage.RTR=CAN_RTR_DATA;
5 x* I7 _% @% r% T - canrxtx.txMessage.IDE=CAN_Id_Standard;//11 bits
- K; ?: b3 n1 N. A6 C - }, Q4 s7 D1 b- _1 L- E% g
- 4 k. A6 ~6 d+ {) n5 q. W! C! _# ]# O
- canrxtx.txMessage.DLC=0x08;: ], F5 o: |" O0 T# @( n+ i
- canrxtx.txMessage.Data[0]=datalen;
+ ?* c, r, {- S# _2 L1 \3 \% J - memcpy(&(canrxtx.txMessage.Data[1]),pdata,datalen);, U2 j4 @4 w# U/ @" m
8 l% V9 X: n) [* S
$ h+ V9 C& z; \' ^; F- while(((i++)<3)&&(CAN_TxStatus_NoMailBox==CAN_Transmit( CAN1,&canrxtx.txMessage)))* ?7 R6 H; i, Z( A3 A3 d/ j2 u7 c K
. y" h2 L+ Z7 k! v- if(i>=3) //timeout
6 A! ?! Z8 \+ b6 e. x3 C$ V - {
/ i; }2 g3 c+ \; u( z+ f/ N% l - return (-1);
x T/ G3 J! b& r% f - }
) g2 E$ p+ Z- G! |* I
0 [; B+ l& m1 b4 r- X% ~7 s- canrxtx.rx_newflag=0;
3 T6 E$ K$ t7 K {& q7 `3 |$ W - return (0);
$ p8 ]& i; q# G- j' f
5 P, e, l7 o$ @+ ^) g [- }
+ H, e1 l; b( L. S( K: S - /************************rx******************************/( Z; ]6 ]9 f0 P: C- C
- void CAN1_RX1_IRQHandler(void)
9 @9 J2 k, }; Q! Q7 q5 s: T5 R - {
) g# N+ `1 W1 E) h8 h; D - memset(&canrxtx.rxMessage,0,sizeof(CanRxMsg));
5 \0 E0 o0 C! j. m7 R$ V - if(CAN_MessagePending(CAN1,CAN_FIFO0))
9 ~( v5 D( U& n - {
3 A+ H- e$ a; | Z0 R - CAN_Receive(CAN1,CAN_FIFO0,&canrxtx.rxMessage[0]);
9 `& K4 u1 { u* N" F2 n. `6 o - }
) H" f) X1 g* q5 m; F - canrxtx.rx_newflag=1;
3 G4 _9 J% X6 L; c6 e k/ @; m - }
复制代码 " i0 ], o0 H" O& u% D N0 G
三、标识符过滤器的解释 过滤器只是用于接收,判断某个报文是否能通过过滤器,过滤器初始化如下: - CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
复制代码- <font face="Tahoma" color="#000000">CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_16bit; </font><div><font face="Tahoma" color="#000000">CAN_FilterInitStructure.CAN_FilterIdHigh=id1<<5; CAN_FilterInitStructure.CAN_FilterIdLow=id2<<5; CAN_FilterInitStructure.CAN_FilterMaskIdHigh=mask1<<5; CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask2<<5; </font></div>
复制代码
+ T4 L+ C7 D8 i. Q5 N" J* jstm32有0~13个过滤器组,每个过滤器组有两个32位的寄存器,通过设置下面两个结构体成员的值可以有四种组合:CAN_FilterMode 和 CAN_FilterScale* _! q& V q3 j' S
6 u" d0 D) K# J; t3 s
, g) Q( k3 B& Y2 W9 |* [1 p
四、关于邮箱 如下图,发送3个邮箱,接收每个FIFO 3个邮箱,这是硬件自动管理的,软件不用管,只要判断发送成不成功,中断接收哪个FIFO就行了(要接收过滤器初始化时绑定的那个FIFO)。 每个邮箱都可以存储一个独立的报文,发送调度器(下图红圈)会根据标识符(ID)的优先级来决定先发送哪个报文(比如发送时3个邮箱都有报文,标识符不一样),PS:标识符数值越小,优先级越高,这是由CAN总线仲裁机制决定的(线与,0可以与掉1)。 3 }, N" o, \) d- m
: X' t4 L* @+ ^' [. Q: A, w0 y9 N
五、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位的隐性电平。不管。 ; s, P: q* D' T. d; w0 v& |
! D: D/ S: u: W6 N
3.位填充的概念 在CAN消息帧中,帧起始,仲裁场。控制场,数据场和CRC段,均以位填充方法进行编码。当发送器在发送流中检测到5个极性相同的连续位时,自动插入一个部补位码。 我觉得这个只要了解就行了,实际编程中库函数已经帮我们做了。
8 T8 d. R/ U8 X+ R
: O+ Y f5 X" j" W, T" H4 }1 X Z |