|
一、什么是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接口在哪?
# t! C+ T4 |. D6 i& i; v* w m* l
) B+ U5 X' c5 a1 N$ D
stm32有can总线控制器,以及有库函数stm32f10x_can.c可以驱动该控制器 但stm32只是有can总线控制器,要真正连接can总线,她还要外接can总线收发器,才能分出来can_H ,can_L,例如如下芯片: 这个芯片的主要作用是发送时根据TXD的电平来决定can_H 和can_L的电平,以及接收时根据can_H 和 can_L的电平差来决定RXD的电平。
' v' k' M7 j7 f' a: m0 N! ~5 u# f( e0 |2 G0 W7 h9 f8 |- @/ s4 [( }
/ b4 D7 U7 K# P
& T( O/ `( K: a) {$ f2.can概念入门比较好的文档 https://wenku.baidu.com/view/7701528a6529647d2728520f.html 这个文档比较详细的介绍了can帧的类型,以及各个帧每个字节,每个bit的含义,以及优先级仲裁机制。下面的例程是数据帧。 3.can例程。 ! ]3 z' Y" X! b7 M6 j. v
- #ifndef CAN_H_2 c& j& k7 G8 b8 u5 v0 ~# e
- #define CAN_H_
1 k+ I+ V Z# g& A: d - #include "stm32f10x.h"0 @0 J! H" e ~ P* @
- #define RCC_APBxPeriph_CAN_IO RCC_APB2Periph_GPIOA
. N- R: o# L& D0 R - #define CAN_RXD GPIO_Pin_11' Q) u0 x6 c- G+ }- [& ^. H
- #define CAN_TXD GPIO_Pin_12
$ p, N: Q" J) U C2 ` - #define CAN_IO GPIOA
9 k/ u) ^$ C1 W7 a# g0 h' G
. z* y; y0 F7 T3 X$ R/ |- enum canrate_e
; U$ h3 W! `3 {1 A% V- d* y# S - {
2 T! n. u* ~) O& k; m - CANRATE125K=125,
+ i: q! H/ w2 @) d - CANRATE250K=250,3 o1 Q' S8 N" h6 L; q
- CANRATE500K=500,% Q8 g0 Z- N7 V7 R/ S
- CANNOTLINK," B; n U) o9 p: o
- };
0 G) `( |" }1 W8 P - 6 T. b' }" o; x2 R0 F
- enum canStdExt_e9 A6 z8 l$ D0 Y' h
- {
: ]- T9 ], y$ l% ^6 C9 p - CANSTD=0,
' {7 T9 Z4 p# @; F0 M* C. { - CANEXT=1,# {0 m: n4 a- p) Q" e0 P' c
- };
# S/ b n+ s& s r* R( @; a) d* \8 G - struct canrxtx_s
2 I+ h9 E7 `5 Z" z! @ - {
" h7 S0 o( `* Y' |* @$ B' ?0 l - CanRxMsg rxMessage[3];/ S' M+ Y" Z5 I: x
- u8 rx_newflag;
4 D+ {3 b. b8 b3 |. _( [ - uint32_t f;
5 H1 f q; B% l/ Y3 W6 w5 V: A% J/ | - CanTxMsg txMessage;8 r! R4 C% m5 x
- ( V8 D5 X4 ?7 ^0 z
- };
1 O8 D+ Y6 L/ f5 w
8 L1 ~) C& d# `# E7 M: Z- /*std ID*/
1 c0 b: W' I h2 s# o - #define CAN1_TX_STD_ID 0x7DF //11 Bits ID,Functional$ T l7 c: w8 o0 T
! V9 M3 _8 k, M) [$ T, u3 U- #define CAN1_TX_STD_ID_ECM 0x7E0 //11 Bits ECM ID,physical
& I3 @& e4 @4 D, x - #define CAN1_RX_STD_ID_ECM 0x7E8 //11 Bits ECM ID,physical! U9 X: u3 }7 \1 u7 F$ P0 Y
- #define CAN1_RX_STD_Filter 0x7FF //11 bits ECM Filter
1 T7 @3 h) j% u0 O* E' V - 8 h% F+ \0 y1 V, d
- /*extend ID*/
# X+ @4 F0 d7 y: P( W& L4 a - #define CAN1_TX_EXT_ID 0x18DB33F1 //29 Bits ID,Functional- V& @8 j# ~. @2 W
- #define CAN_Id_Extended_HONDA 0x18DBEFF1 //29 Bits ID,Functional HONDA
3 ~ E1 H( ? i% v! Y- q) J; b - #endif
复制代码- #include "can.h"
5 v( Z% f- W* T# E1 ]) W - #include <string.h>
5 c2 s) Z# l/ v9 H4 ^# F4 F - u8 std_or_ext;) S% l. [$ R( K" p& ^2 g
- struct canrxtx_s canrxtx;" L: C6 a; b0 I! h
- void CAN1_init(enum canrate_e canrate)% f3 ~( m; X7 v
- {* b) J- g) u% z& A) `
7 E$ J5 S" \+ k8 N) t L- GPIO_InitTypeDef GPIO_InitStructure;
% x6 g; X% z: o1 i+ [. o - CAN_InitTypeDef CAN_InitStructure;
2 }( V S8 a/ I( d* {+ s4 l) ? - 1 }. v- t2 z! e* X6 A" I- k& f
- RCC_APB2PeriphClockCmd(RCC_APBxPeriph_CAN_IO | RCC_APB2Periph_AFIO,ENABLE);
" u5 a% [$ P! }8 | - RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);8 b6 \- q c2 {+ L
- GPIO_InitStructure.GPIO_Pin = CAN_RXD;
+ U: o h5 W- u: j+ E - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
4 y3 x/ y, G3 f- @, L0 B - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
7 Q0 y8 P+ w2 c - GPIO_Init(CAN_IO, &GPIO_InitStructure);
3 x6 d) n: }! v, L6 U
6 t H5 T, M( Q, @+ b) x5 i2 M- GPIO_InitStructure.GPIO_Pin = CAN_TXD;
7 p5 _9 m( a8 ?; ?$ }0 k& @$ [% I - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
% A+ B1 b% D; Q( v- q$ J - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;8 A% N8 J) s1 j: ~
- GPIO_Init(CAN_IO, &GPIO_InitStructure);
: |; j; ^1 i7 V9 x# [) r0 O0 u
* A' ?/ [) k4 s! ?3 B1 D4 Y2 R: l) K- CAN_DeInit(CAN1);
d. p8 t4 R ~+ S6 [ - CAN_StructInit(&CAN_InitStructure);# ], e' ]' I2 V9 H k7 [
- 4 F3 \( |) s3 D
- CAN_InitStructure.CAN_TTCM = DISABLE;4 n7 x/ l i; Z. \. m/ f: [0 G2 R
- CAN_InitStructure.CAN_ABOM = DISABLE;
1 A: C# Q2 N6 Q4 O - CAN_InitStructure.CAN_AWUM = DISABLE;# j. ~% |7 {2 @/ w
- CAN_InitStructure.CAN_NART = DISABLE;$ l, m, s$ ~( |5 K: c' e) r$ p
- CAN_InitStructure.CAN_RFLM = DISABLE;' \: K. `. D- P1 v& s
- CAN_InitStructure.CAN_TXFP = DISABLE;
( i5 l/ v( Y! ^6 }! [) x0 Z - CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;# |7 W9 H& g; w9 R) r8 l/ [
- CAN_InitStructure.CAN_SJW = CAN_SJW_1tq; k! s- q2 L; u$ b3 o/ J2 r* p
- CAN_InitStructure.CAN_BS1 = CAN_BS1_3tq;
& ?1 ^, i- B+ Y/ [% h3 O - CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;
1 n" X7 @0 M, [ - //CAN BaudRate = 72MHz/(CAN_SJW+CAN_BS1+CAN_BS2)/CAN_Prescaler+ o- [. J! P, l3 H+ D! l( m$ r
- if(canrate==CANRATE125K) /* 125KBps */6 y0 c9 Z4 A/ r8 D1 ~
- CAN_InitStructure.CAN_Prescaler =96;
$ f8 H2 ?0 d" C$ J/ ]( W* `4 ~ J% ~7 D - else if(canrate==CANRATE250K) /* 250KBps */
8 f$ ]+ v i% [$ A8 I% q4 e$ Y( v - CAN_InitStructure.CAN_Prescaler =48;8 ]. `7 _0 J0 A9 N
- else /* 500KBps */
# R$ a" A8 r8 ]6 M/ y4 D* O - CAN_InitStructure.CAN_Prescaler = 24;
* I" ~* Z- f6 G1 I$ m- X. ] - 8 t8 \4 \2 {/ r3 F. ?
- CAN_Init(CAN1, &CAN_InitStructure);3 `% A: T7 {/ k- q, x7 W% M+ a+ E
- }
' h/ C9 N- N! H& x( e5 O7 @: {' \/ o - ; P6 n- j& ?3 I
- void CAN1_ConfigFilter(u32 id1, u32 id2, u32 mask1, u32 mask2, u8 std_or_ext)/ u: @* ^$ O/ q' S' D
- {( _( g; O" O, j9 D& { e
- CAN_FilterInitTypeDef CAN_FilterInitStructure;7 ^# N; h7 r3 i2 a2 i7 o. P- r7 Q' |; ?2 N
- NVIC_InitTypeDef NVIC_InitStructure;1 l9 X( I7 q, D$ J$ g1 k
- 7 O5 x* {. ~ B' M. c/ F- C3 L
- CAN_FilterInitStructure.CAN_FilterNumber=1; //use which filter,0~13
" G0 V8 `: C6 m1 J. X2 H! [ - CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;& O+ \, i8 `2 c: _5 t3 R# T: Z
- if(std_or_ext == CANSTD)8 u; E. ?8 F' s9 k# D
- {' G6 `" I$ `) Z- z$ L
- CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_16bit;5 T: Q; F; T# ~' X F2 _( D6 J
- CAN_FilterInitStructure.CAN_FilterIdHigh=id1<<5;* E1 a' E/ \4 s9 m4 D
- CAN_FilterInitStructure.CAN_FilterIdLow=id2<<5;+ C) L9 P4 P6 L) W# J. u* ~
- CAN_FilterInitStructure.CAN_FilterMaskIdHigh=mask1<<5;) V4 z4 v3 h, t! Z1 ~, R* }
- CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask2<<5;
2 C9 z l1 r( V0 u& K& y- I! x% h
) E- v: I W2 M7 h# q6 `2 n: F- }- `8 V+ ~" c1 b7 ~. d; n$ A
- else2 G( w' a8 Z5 S8 |0 N
- {
- ~; d( X1 a: K - CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; x7 s( g: o5 r3 q: d
- CAN_FilterInitStructure.CAN_FilterIdHigh=(u16) (id1>>13);
, V8 Y) L+ x# x. F - CAN_FilterInitStructure.CAN_FilterIdLow=(u16) (((id1&0x00001FFF)<<3)|CAN_Id_Extended|CAN_RTR_DATA);* Q0 h9 C# _5 }; i* U
- CAN_FilterInitStructure.CAN_FilterMaskIdHigh=(u16) (mask1>>13);
; w/ q( Q7 `5 {) V6 k0 I - CAN_FilterInitStructure.CAN_FilterMaskIdLow=(u16) ((mask1&0x00001FFF)<<3);9 @& J/ R2 O5 F
- : ?) p1 n, @0 t- x
- }/ `: `$ R; c: X+ l1 F" H8 m/ d
- . N# k9 s; ^( j$ i) b- ~1 q+ g$ u! \
- CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;
r& ^/ B7 d! S1 X4 p5 y3 z - CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;1 w3 o( l+ j; p. v* A
- CAN_FilterInit(&CAN_FilterInitStructure); `+ P; Q$ {6 y- N& S& G
- . @7 o4 P. t, K8 M+ s; A
- NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX1_IRQn;; W7 f+ Z& @% d B. ~' O
. J3 h2 O; ]& k: ~& H- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;4 C; a7 X; v: B( ^ ?8 j
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
* R! O9 {6 C. _5 ^$ S5 N" C5 K - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
5 ~9 i, h4 ?) R& y& E, [" h - NVIC_Init(&NVIC_InitStructure);- _* r( G. ^8 \1 [: h. b
- ; t. Q/ F/ n4 v: Q$ [$ W6 y
- CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);: T) k3 S" N1 |, k% A$ ~' D
- }
5 m5 l9 ~# m2 f6 ^5 c+ h* k, j - /************************init******************************/& y; M2 c' P! P6 k8 e
- void init_demo()
) a3 b, O! [2 w" m - {
1 E1 }: N) ^5 w" N - std_or_ext = CANEXT;9 C6 P( Y' s" g
- CAN1_init(CANRATE500K);/ o; m! s0 e7 q9 l% U
- CAN1_ConfigFilter(0x18DAF110,0x18DAF110,0x1FFFF100,0x1FFFF100,std_or_ext);//extend ID3 g5 y7 ^1 h! b. |/ ?) u
- }
& F1 ], H% ~$ z - /************************tx******************************/
3 u: H& K& U6 x, x+ | - /*datalen<=8*/
8 @* M+ L# s+ h2 w5 v2 j - int CAN1_TransASerialData(u8* pdata,u8 datalen)- B. F4 w3 H+ s; p* i
- {& T/ `" R+ c8 ^: ]( d$ x1 n$ q
- u8 i=0;, I; G2 y: r3 O! Z- P. O
% Y5 y5 l6 u$ q- Delay_ms(20);* f( c p! b2 E% C7 C
: S1 V/ f1 X& p+ z5 ? n- if(std_or_ext == CANEXT)* w* X3 ?* O2 k1 a/ W. P) T
- {( V+ r- W' R! C( T3 d! e
- canrxtx.txMessage.StdId=0x00;
0 G t3 K4 K1 D8 i2 f9 ~ - canrxtx.txMessage.ExtId=CAN_Id_Extended_HONDA;//bentian) U& y4 B* ~& `6 X. z
- canrxtx.txMessage.RTR=CAN_RTR_DATA;
+ U$ q8 o% H: w6 l - canrxtx.txMessage.IDE=CAN_Id_Extended;// 29 bits* v% p8 e; I2 ]+ g* a) h
0 K3 C4 r& V3 J- }0 O7 v% N* |" `) S" b3 s) L0 ^: L
- if(std_or_ext== CANSTD)( X5 D# u5 I' P2 v+ ?: T
- {/ y6 x) u) ?1 a2 H
- canrxtx.txMessage.StdId=CAN1_TX_STD_ID;
" v- N0 D# z7 Q0 x, V( b# t - canrxtx.txMessage.ExtId=0x00;2 a8 O% O: E2 C* }' d% r1 ]
- canrxtx.txMessage.RTR=CAN_RTR_DATA;9 E8 D0 G6 k& T7 a6 N6 S- s
- canrxtx.txMessage.IDE=CAN_Id_Standard;//11 bits
$ L- ?" u- e1 S) g - }
" e* e8 M8 O- a; k7 i - 0 _( s# i+ h) Y: ?- O1 w' K
- canrxtx.txMessage.DLC=0x08;
# y5 a( ^ j& |+ g0 j4 F+ ^ - canrxtx.txMessage.Data[0]=datalen;% M4 ?" R6 T4 E$ X" z% m& u
- memcpy(&(canrxtx.txMessage.Data[1]),pdata,datalen);5 H. c5 t# u( d6 F( O2 D
- 2 k/ l! @8 C; G
5 g( P4 {4 S2 ~1 P% o% c3 O7 v- while(((i++)<3)&&(CAN_TxStatus_NoMailBox==CAN_Transmit( CAN1,&canrxtx.txMessage)))
8 v0 q% D: m' |0 t: y4 _
, c9 @0 p# W( b5 {# y- if(i>=3) //timeout2 D7 N0 M" ~3 ~* K$ F, j o
- {
" n6 y9 B, q% g3 |0 p1 E - return (-1);6 Z# Y! G0 ]+ f" z
- }
% z6 J9 G" x& m/ R& Z% x" e& y - & _! G. C, p% I* C
- canrxtx.rx_newflag=0;
2 |. e- ]) ?! z; |) B - return (0);
2 q T& s4 I/ e0 v
& w# O* n2 b+ {' m- }
# F. Z. Q% f5 q8 P; ] - /************************rx******************************/
+ D, n8 w1 i! {' S- s. X8 |4 ?9 z - void CAN1_RX1_IRQHandler(void)% p" i( ~: F1 H! T K% ]% J# A
- {5 I- ], n% i( [% B
- memset(&canrxtx.rxMessage,0,sizeof(CanRxMsg));/ r- w# k! G6 i. q& ^0 a/ z$ n4 w
- if(CAN_MessagePending(CAN1,CAN_FIFO0))
0 p, Y- l' j! n c - {$ l& f2 q0 R, W. |% q9 Q0 r/ n5 B
- CAN_Receive(CAN1,CAN_FIFO0,&canrxtx.rxMessage[0]);9 e" h; c7 Z7 }$ p- E6 I8 b
- }
& N, d. F7 y$ u0 R1 n4 L" m - canrxtx.rx_newflag=1;7 A0 G$ `/ ?. F, t& o
- }
复制代码
5 {7 A7 N& k u2 N$ W9 }1 y 三、标识符过滤器的解释 过滤器只是用于接收,判断某个报文是否能通过过滤器,过滤器初始化如下: - 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>
复制代码 ( Y8 A, b4 c& O1 f- A' e @
stm32有0~13个过滤器组,每个过滤器组有两个32位的寄存器,通过设置下面两个结构体成员的值可以有四种组合:CAN_FilterMode 和 CAN_FilterScale6 e+ d5 S0 n; z3 k/ O @6 S: C2 O2 @
7 T |- `( O8 A; Z1 {

- H# f8 O. e |: Q' O% L! j. H 四、关于邮箱 如下图,发送3个邮箱,接收每个FIFO 3个邮箱,这是硬件自动管理的,软件不用管,只要判断发送成不成功,中断接收哪个FIFO就行了(要接收过滤器初始化时绑定的那个FIFO)。 每个邮箱都可以存储一个独立的报文,发送调度器(下图红圈)会根据标识符(ID)的优先级来决定先发送哪个报文(比如发送时3个邮箱都有报文,标识符不一样),PS:标识符数值越小,优先级越高,这是由CAN总线仲裁机制决定的(线与,0可以与掉1)。 0 u8 v4 o# q$ j) z
9 Y( A- q0 c% W( B: }7 S0 R. B0 m
五、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位的隐性电平。不管。
8 n1 _1 u% U+ ?. a: j( ^0 z
" ]- [0 ~3 p) d" _9 H3 w
3.位填充的概念 在CAN消息帧中,帧起始,仲裁场。控制场,数据场和CRC段,均以位填充方法进行编码。当发送器在发送流中检测到5个极性相同的连续位时,自动插入一个部补位码。 我觉得这个只要了解就行了,实际编程中库函数已经帮我们做了。 y0 m6 T* F* |
; @# p) z6 Z. d3 S7 E |