一、什么是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 T! |3 e, ^5 ?1 I% H
: ~% Q1 C- X: f4 s' U
stm32有can总线控制器,以及有库函数stm32f10x_can.c可以驱动该控制器 但stm32只是有can总线控制器,要真正连接can总线,她还要外接can总线收发器,才能分出来can_H ,can_L,例如如下芯片: 这个芯片的主要作用是发送时根据TXD的电平来决定can_H 和can_L的电平,以及接收时根据can_H 和 can_L的电平差来决定RXD的电平。
& G- Q' C+ m8 O5 D( a' Y9 [3 H- U q4 E1 ]5 o0 L
2 v: V1 e/ c$ B& T1 i
9 B) j8 P; q1 h9 ~1 z" @/ C! y2.can概念入门比较好的文档 https://wenku.baidu.com/view/7701528a6529647d2728520f.html 这个文档比较详细的介绍了can帧的类型,以及各个帧每个字节,每个bit的含义,以及优先级仲裁机制。下面的例程是数据帧。 3.can例程。
; m1 d- f Q1 o* d9 O- #ifndef CAN_H_
" [! _: K2 A2 X5 k - #define CAN_H_
9 s/ _. K: j A1 U - #include "stm32f10x.h"' y/ g' y4 j6 `0 c/ p8 F# V8 Y
- #define RCC_APBxPeriph_CAN_IO RCC_APB2Periph_GPIOA Z* c# H. U% K* M) ~. [
- #define CAN_RXD GPIO_Pin_11
+ I6 ?8 T! H0 G- A4 t: Y& h5 T - #define CAN_TXD GPIO_Pin_12( ? q+ _/ D+ S; u: F
- #define CAN_IO GPIOA! r2 v6 ]( F+ q+ {# |
# t4 m W% S$ X' J( R- enum canrate_e
5 z# _! S! L; N% ^7 U' ^! c/ P - {
7 X6 U, P' |7 h2 q! C - CANRATE125K=125,# v4 ], R' V9 j- H
- CANRATE250K=250,0 y, s" B/ d, A1 a) T1 Q; j
- CANRATE500K=500,
! h. H* {& S7 ?7 u5 e - CANNOTLINK,
p( n6 _/ Z3 N( Z9 w" | - };' ~$ }" ~! S- T! N) r- \4 ~- g
& R- @# x" x' b- enum canStdExt_e/ H) N5 C" Q' l5 U) d, _/ K
- {
/ @# M$ l; w- k2 P$ ^ - CANSTD=0,9 T) J8 E5 d4 W% t. U$ _
- CANEXT=1,4 d# T3 K$ ^/ a% d$ Y) s
- };
( y/ ]: h0 M& G2 _$ ?% z2 y3 x1 ~ - struct canrxtx_s
. k+ P8 N) @0 R' s- ~9 F1 ` - {( j. v5 v g" ^* D9 g
- CanRxMsg rxMessage[3];+ v1 x4 P! O7 I
- u8 rx_newflag;
5 w' ~, g5 \" P4 w0 @5 b. t6 \: z - uint32_t f;$ L& H3 l/ b( e; c
- CanTxMsg txMessage;
8 i# |- _# \6 w1 s - 9 I, z8 g) Z q4 q7 r6 d2 C
- };# ?2 {% D: u0 _6 m& i. h
- 5 q" j" R9 X( r: D! \
- /*std ID*/
9 t( R1 l- X- G1 \: e2 D' u+ ` - #define CAN1_TX_STD_ID 0x7DF //11 Bits ID,Functional" f5 [) u8 A+ r; X
- $ n! s; }$ D2 J, d
- #define CAN1_TX_STD_ID_ECM 0x7E0 //11 Bits ECM ID,physical% z& b6 D) r2 n# [( }8 ]$ p) Q
- #define CAN1_RX_STD_ID_ECM 0x7E8 //11 Bits ECM ID,physical) G& k1 v) c/ w* |5 P7 S
- #define CAN1_RX_STD_Filter 0x7FF //11 bits ECM Filter
8 p/ M( X5 R, I
3 A( \% K& g4 }& ?; l& t- /*extend ID*/
. x g/ E/ P! Z" ^ - #define CAN1_TX_EXT_ID 0x18DB33F1 //29 Bits ID,Functional1 l/ ?+ Y$ t/ D. N+ S" v
- #define CAN_Id_Extended_HONDA 0x18DBEFF1 //29 Bits ID,Functional HONDA
, B( V) v; d) Z: O) J - #endif
复制代码- #include "can.h"
# w. I+ [' G5 l; y - #include <string.h>" E$ b: b. N% {5 u9 W
- u8 std_or_ext;, a* m/ u- Q1 q+ b6 Z9 ~$ {: N
- struct canrxtx_s canrxtx;
/ U5 R8 d: V# ]" T" @# H - void CAN1_init(enum canrate_e canrate)& B8 z4 M% l8 T' C H
- {
7 H; u, z- g) o! G! @1 s
2 U- [5 Z* f; \/ [$ k0 q/ R- GPIO_InitTypeDef GPIO_InitStructure;/ d2 }: u/ x0 W1 [7 E3 A& h
- CAN_InitTypeDef CAN_InitStructure;9 r) p. T0 H c; Z
- 4 U! q; K3 e' D4 g+ p: E
- RCC_APB2PeriphClockCmd(RCC_APBxPeriph_CAN_IO | RCC_APB2Periph_AFIO,ENABLE);
1 Z% ?4 h! x5 d. W) X" ~* ^ - RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);
/ ^1 b2 r7 J" i r - GPIO_InitStructure.GPIO_Pin = CAN_RXD;2 N, n3 x! F/ N" g' j3 s
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;- x/ g9 V* I/ T; l
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;( [; l. c" k6 K8 ?+ l( G- u# d
- GPIO_Init(CAN_IO, &GPIO_InitStructure);! I* a1 D& V! S- H$ a
+ i# @6 a% v4 {% o; S; Z- GPIO_InitStructure.GPIO_Pin = CAN_TXD;
5 t$ \' S" K% |) j! _6 R: ` - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;9 f1 v3 i! e) Q/ \& o |
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;2 J5 l- p/ v- H' `( e% `: @7 y
- GPIO_Init(CAN_IO, &GPIO_InitStructure);1 o/ \# M& A% C- {" R
- 0 O3 i' o4 O/ T/ R6 _2 c* S
- CAN_DeInit(CAN1);
5 ?' Q/ I& U0 @! V7 F. T - CAN_StructInit(&CAN_InitStructure);0 U4 L4 J2 y! j8 j9 y7 W5 e
- 2 p6 k4 \4 D" }1 y
- CAN_InitStructure.CAN_TTCM = DISABLE;% X7 R, O/ [; A0 g$ w
- CAN_InitStructure.CAN_ABOM = DISABLE;
7 J) @+ n6 p' a& w - CAN_InitStructure.CAN_AWUM = DISABLE; [' W/ Y; Z* `: e& X2 x9 M) l# _
- CAN_InitStructure.CAN_NART = DISABLE;7 l& ]6 z* n, F4 Y/ M( _$ ~& ~
- CAN_InitStructure.CAN_RFLM = DISABLE;
8 n) I5 t2 }3 w" Y4 b4 Z - CAN_InitStructure.CAN_TXFP = DISABLE;! Z; M. S0 h5 G% ]; @6 K# Z6 I
- CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
/ ^( O; u1 n! M - CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
, n. P1 N; q4 v3 p8 J( p - CAN_InitStructure.CAN_BS1 = CAN_BS1_3tq;( m Y: f) S; y5 l% B/ W
- CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;
+ U% O! K+ S# P6 X Q - //CAN BaudRate = 72MHz/(CAN_SJW+CAN_BS1+CAN_BS2)/CAN_Prescaler& A8 y8 y7 p$ u& `( i- m
- if(canrate==CANRATE125K) /* 125KBps */
7 r6 ]+ T% a3 v3 r' Z; K3 i - CAN_InitStructure.CAN_Prescaler =96;
$ |4 p9 n* k6 i$ c2 i& j - else if(canrate==CANRATE250K) /* 250KBps */$ l0 G" {* ]7 x- z, g+ D% {5 ]
- CAN_InitStructure.CAN_Prescaler =48;8 D( P; c# M* D0 n3 _% E- M h
- else /* 500KBps */9 v3 F2 n' o) T, x6 v
- CAN_InitStructure.CAN_Prescaler = 24;6 I& u* _; r# w* L- Q1 @8 V# n8 a
7 P1 Q# L) E F7 Y1 _( a- CAN_Init(CAN1, &CAN_InitStructure);
Z. v) d, F6 X3 o: ^! @$ V; l - }$ \2 m2 [& q Y/ L/ ^+ p' d
- & P: k$ u% K; K
- void CAN1_ConfigFilter(u32 id1, u32 id2, u32 mask1, u32 mask2, u8 std_or_ext)3 G2 O2 t) u8 T! k) @) S
- {5 d; e, m7 {5 ~2 K5 u
- CAN_FilterInitTypeDef CAN_FilterInitStructure;" \/ f3 V7 T$ L1 M7 y$ g- o
- NVIC_InitTypeDef NVIC_InitStructure;
9 u9 } u& E% c5 P+ H! j
- W3 H: k9 L( f; O- CAN_FilterInitStructure.CAN_FilterNumber=1; //use which filter,0~13
0 ^' W6 y; l" h - CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;1 z1 X, c3 a3 s, s! E& z; {2 e
- if(std_or_ext == CANSTD)
0 F8 R u$ j8 Z& I - {
% d# T$ }- P- u% r0 J* L - CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_16bit;
' _: o) o" z9 W7 y+ Y1 f - CAN_FilterInitStructure.CAN_FilterIdHigh=id1<<5;
- a# C, q' m3 x - CAN_FilterInitStructure.CAN_FilterIdLow=id2<<5;/ `! M- k" @1 L q u8 z
- CAN_FilterInitStructure.CAN_FilterMaskIdHigh=mask1<<5;. ?9 C- K j4 g/ o9 v
- CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask2<<5;
5 K2 A) \' a# ~3 y8 y+ u
" k2 N( w3 \9 X0 G* k- }
0 i1 P* T" u1 L& \2 N% i' g7 J J! [ - else& P8 C* ]1 Z+ s: `8 h, n ^+ O9 M* d
- {9 R U# s+ w$ \$ u
- CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;# c$ k) X3 s: z" Z
- CAN_FilterInitStructure.CAN_FilterIdHigh=(u16) (id1>>13); L3 {0 D/ G0 Z6 q- O; m
- CAN_FilterInitStructure.CAN_FilterIdLow=(u16) (((id1&0x00001FFF)<<3)|CAN_Id_Extended|CAN_RTR_DATA);) |) Q: F9 X1 N
- CAN_FilterInitStructure.CAN_FilterMaskIdHigh=(u16) (mask1>>13);
' o4 ?8 L& F4 O0 k! A* Z - CAN_FilterInitStructure.CAN_FilterMaskIdLow=(u16) ((mask1&0x00001FFF)<<3);8 }* w) o( w. J
- , a+ G9 W L. V Z G
- }) x& T* n+ ] s9 d' ]9 T
- & H( d7 ]5 k+ L
- CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;
2 H* K% x- R6 F8 L/ E- D8 S' r' m2 M - CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
& N; P8 [* A, a3 e - CAN_FilterInit(&CAN_FilterInitStructure);0 Z; M8 @3 t: g# c5 X, ~: J2 o! F
- 5 ~- e' Y8 |3 W$ o* F# M- W1 ^- E
- NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX1_IRQn;! U) t, U$ ^, P
4 G; i: k* M K8 J' L v" n- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;- H! q2 ?/ A. i" S+ G- e
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;, _+ Z' y# C) V+ _+ J" `4 X; a
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
: K1 V% {. x$ j% Z+ { - NVIC_Init(&NVIC_InitStructure);
4 o6 |$ E: i* q- M* D4 r - 7 E, F( U: M- o/ h8 R# `6 g
- CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);, {/ D% ^' B- @! B
- }
9 O& a; [0 {3 y; c! E3 e( G - /************************init******************************/) p# W9 G' k+ o: } X
- void init_demo()- N- r: c3 {" b T
- {2 Z) B2 V; X5 {8 L
- std_or_ext = CANEXT;
, N! f! O- X: F+ @9 d - CAN1_init(CANRATE500K);
# Y, }& H- N2 s' I/ j; ? - CAN1_ConfigFilter(0x18DAF110,0x18DAF110,0x1FFFF100,0x1FFFF100,std_or_ext);//extend ID4 v: m8 O' P5 q( q+ q
- }; a" `7 \# h5 ^) {" m, F
- /************************tx******************************/
. u, G; }6 L# P - /*datalen<=8*/7 f( {( `( e* ?, ^6 g/ l; \. g
- int CAN1_TransASerialData(u8* pdata,u8 datalen)& ?. F5 z( \& [4 g/ ]; o1 l1 G
- {
4 {, K/ {; v8 i0 q9 n - u8 i=0; S4 F' x0 o- B* Q# ]* O a4 Y
- , x, {- e$ }& R
- Delay_ms(20);, N0 V# p8 |# X9 D# l
- B% ^- E. I E2 k- if(std_or_ext == CANEXT)
: S5 t" [6 Y8 _$ A - {' [, Z' I/ c- p3 h8 a* M
- canrxtx.txMessage.StdId=0x00;
0 g- }% O- a6 ]/ W* ^4 x: T - canrxtx.txMessage.ExtId=CAN_Id_Extended_HONDA;//bentian0 l$ j y7 |7 A8 i# ?5 J. y+ [& G- u/ {
- canrxtx.txMessage.RTR=CAN_RTR_DATA;# m. G5 q1 A+ U6 t Q/ F4 i; F
- canrxtx.txMessage.IDE=CAN_Id_Extended;// 29 bits; r4 J7 F) `! b
1 r* y* T6 `- K l+ ^1 H6 U- }# f3 q/ U7 ?6 v
- if(std_or_ext== CANSTD)
9 a/ u- W: l4 m O( q9 } - {
g! W k. M' e - canrxtx.txMessage.StdId=CAN1_TX_STD_ID;8 Q6 V1 V; j0 {* V; y6 `" |
- canrxtx.txMessage.ExtId=0x00;$ Z! `5 R. d; e1 `' l5 ]" q3 t
- canrxtx.txMessage.RTR=CAN_RTR_DATA;
2 N7 V5 @) w9 }. h& N - canrxtx.txMessage.IDE=CAN_Id_Standard;//11 bits+ W; F: D# y4 r
- }
+ `- m' M/ K; `& `2 G8 m
. e& u% f! b3 ~/ F- canrxtx.txMessage.DLC=0x08;" e! F) g7 k9 |! } V5 S5 E
- canrxtx.txMessage.Data[0]=datalen;
% a, d9 l- f1 T# d% X - memcpy(&(canrxtx.txMessage.Data[1]),pdata,datalen);# o, g8 ]: U$ f/ A( Y# K6 y
& U6 }' T5 Z7 G, R9 Z- / e% k2 h1 U7 R1 L& @8 J
- while(((i++)<3)&&(CAN_TxStatus_NoMailBox==CAN_Transmit( CAN1,&canrxtx.txMessage)))* S( N' h6 {8 w5 e0 t/ X
- 3 h8 ?7 g* a1 \5 i) d1 k+ `" I# i: f
- if(i>=3) //timeout8 Y* s. t; N! h' b) ]; ]
- {
) e( |; s' G/ h2 [6 ]6 b - return (-1);0 k" T/ t5 E! p% i0 _
- }0 |3 u1 E: \+ p% `6 V, n3 |4 W
2 Y6 E5 ~( n) I+ u$ M+ n: x- canrxtx.rx_newflag=0;
6 K% c4 o( q. L2 n, I5 L8 Q - return (0);' ?( O& q% T: A8 ^- w: M
- 5 h' \: N. }% N/ A, d
- }1 x ]% V$ s& ]% {. I9 k3 V
- /************************rx******************************/) M9 X5 E2 p! K5 Q0 w1 O/ a
- void CAN1_RX1_IRQHandler(void)+ R+ n! i9 L9 s% c" j3 T3 Q
- {% J a5 d5 z$ \7 R2 Y
- memset(&canrxtx.rxMessage,0,sizeof(CanRxMsg));
5 v7 U9 A( n# j0 m, O, U - if(CAN_MessagePending(CAN1,CAN_FIFO0))
5 P) O) z2 Y' F8 t) `# l, U$ g - {
6 X8 I' C/ @# u; J8 K, h6 ~2 I - CAN_Receive(CAN1,CAN_FIFO0,&canrxtx.rxMessage[0]);
" x- A9 C& @6 g5 H: w - }9 b1 D0 t$ p! P/ t
- canrxtx.rx_newflag=1;5 X( P% l9 @9 b4 l$ E4 w
- }
复制代码
U& Z. ]8 P, T" x; A$ r$ {- ~" k& ] 三、标识符过滤器的解释 过滤器只是用于接收,判断某个报文是否能通过过滤器,过滤器初始化如下: - 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>
复制代码
+ p% e. Q: Z( O. p6 L# ~stm32有0~13个过滤器组,每个过滤器组有两个32位的寄存器,通过设置下面两个结构体成员的值可以有四种组合:CAN_FilterMode 和 CAN_FilterScale K% y; @# C2 I3 l5 o& W
8 S" b( S. N G# Z! J0 ^$ }
: \2 |% u) Z0 U- o7 y: U 四、关于邮箱 如下图,发送3个邮箱,接收每个FIFO 3个邮箱,这是硬件自动管理的,软件不用管,只要判断发送成不成功,中断接收哪个FIFO就行了(要接收过滤器初始化时绑定的那个FIFO)。 每个邮箱都可以存储一个独立的报文,发送调度器(下图红圈)会根据标识符(ID)的优先级来决定先发送哪个报文(比如发送时3个邮箱都有报文,标识符不一样),PS:标识符数值越小,优先级越高,这是由CAN总线仲裁机制决定的(线与,0可以与掉1)。
! L6 O; c1 \* h; e, f O
6 t% {. Y+ I, f% e- J1 C! t
五、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位的隐性电平。不管。
# X) H' B7 g$ @* \5 X
' g2 u6 r* z* I7 v! W* x
3.位填充的概念 在CAN消息帧中,帧起始,仲裁场。控制场,数据场和CRC段,均以位填充方法进行编码。当发送器在发送流中检测到5个极性相同的连续位时,自动插入一个部补位码。 我觉得这个只要了解就行了,实际编程中库函数已经帮我们做了。
9 A% T4 }1 I6 ]# U7 M# n1 f6 W2 t2 k% E0 H& m* W: x
|