|
一、什么是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接口在哪?
- H/ F; W/ o" F; J2 i6 B% t' O0 U
. a% s& Z, z. R7 P
stm32有can总线控制器,以及有库函数stm32f10x_can.c可以驱动该控制器 但stm32只是有can总线控制器,要真正连接can总线,她还要外接can总线收发器,才能分出来can_H ,can_L,例如如下芯片: 这个芯片的主要作用是发送时根据TXD的电平来决定can_H 和can_L的电平,以及接收时根据can_H 和 can_L的电平差来决定RXD的电平。 4 C& n v: \5 h( w" J' [. |7 o [
% Q, c% E( g1 V A8 d
C7 H* E& j% a
" R* }; W: d6 [ g5 R2.can概念入门比较好的文档 https://wenku.baidu.com/view/7701528a6529647d2728520f.html 这个文档比较详细的介绍了can帧的类型,以及各个帧每个字节,每个bit的含义,以及优先级仲裁机制。下面的例程是数据帧。 3.can例程。
% n0 X: _* a$ N0 g- #ifndef CAN_H_: l, s/ j2 {1 q/ p
- #define CAN_H_
" Y0 ^) i/ I0 I - #include "stm32f10x.h"
2 O) x+ g: D$ Z9 @6 g7 k/ ^/ p1 R: a - #define RCC_APBxPeriph_CAN_IO RCC_APB2Periph_GPIOA
+ a& F/ L; U! i; E- \ - #define CAN_RXD GPIO_Pin_11
$ ~+ Z* s6 h3 j7 ~ - #define CAN_TXD GPIO_Pin_126 n, G( w/ U6 ~9 H* i
- #define CAN_IO GPIOA
* Q9 ^- k* i" `% q - , L4 D* a" R8 v# R0 `, z" s# j2 N
- enum canrate_e. M$ N8 r% O% F2 x9 ]' g" q5 P' O
- {
" H ~2 v' |4 f! F - CANRATE125K=125,4 ?4 N) T' P. f1 K' `
- CANRATE250K=250,
8 G# p* ^ j) r( g' F# j) ]& b - CANRATE500K=500,: ^$ L0 v2 J( K+ v7 a# p
- CANNOTLINK,
9 O' }9 C" l0 g6 r4 L0 N& j - };
' ] w' @/ H/ j U( h - 2 _1 Y9 J2 U- ~/ U- S! y% K
- enum canStdExt_e/ }2 W) Y8 p/ M6 |) `. |9 d& h
- {8 q7 @' F* c" N1 Z9 d
- CANSTD=0,
# {0 { n* D" K1 ~6 C9 B2 f - CANEXT=1,6 Z" A: U/ o/ l+ ~0 l2 X
- };
) V' C h3 }5 i/ g - struct canrxtx_s
9 O& n; }0 h2 K% s) q6 F5 G - {* h2 s( _# S+ |0 N* ?/ h/ @! p: N
- CanRxMsg rxMessage[3];% C' q4 E* O$ Q f) b; H6 A% |
- u8 rx_newflag;5 v5 z( r2 C$ t f
- uint32_t f;" ~1 }% j3 K# [3 q5 j
- CanTxMsg txMessage;
1 \ r( ~8 U" ?' K - 9 r! I# ^- a7 [9 ?. m: G$ K) L
- };
4 e- N( z3 ?& P - * `" w! o6 s# ?1 A% V( O
- /*std ID*/
- B4 \+ q) B8 p6 A5 @ - #define CAN1_TX_STD_ID 0x7DF //11 Bits ID,Functional. u5 o }0 m" O: H; g
- , ?) |6 [) s& d7 e2 e
- #define CAN1_TX_STD_ID_ECM 0x7E0 //11 Bits ECM ID,physical
, H" e3 {* _% H2 X9 b - #define CAN1_RX_STD_ID_ECM 0x7E8 //11 Bits ECM ID,physical
: B, h6 t$ a4 { - #define CAN1_RX_STD_Filter 0x7FF //11 bits ECM Filter
, F+ x, R0 K( h; D
4 M& e- [, L, {6 ~8 `- /*extend ID*/
( k8 R& ~% m/ P/ C( P" x! E% s - #define CAN1_TX_EXT_ID 0x18DB33F1 //29 Bits ID,Functional
+ e) S. n+ _( T8 b/ y# q v - #define CAN_Id_Extended_HONDA 0x18DBEFF1 //29 Bits ID,Functional HONDA. h% k# K7 v- _0 X! \9 |5 g
- #endif
复制代码- #include "can.h"
3 G5 y" g' V* i" k; i - #include <string.h> F5 c+ }3 \4 I @3 d$ W' P
- u8 std_or_ext;2 T. g8 q) g* S3 Q) O9 X( Q
- struct canrxtx_s canrxtx;
0 n. u) M, F3 [: ?; R - void CAN1_init(enum canrate_e canrate)6 g/ a5 m g0 t3 j% {& q$ I
- {8 y6 C7 v# b& p2 M
- 4 M2 L7 t8 p8 i3 o b
- GPIO_InitTypeDef GPIO_InitStructure;
6 r0 j- g/ m5 C4 s" N - CAN_InitTypeDef CAN_InitStructure;
" X" m# B* q. @( a) c8 |7 N
) v9 R% m8 |5 }& p9 O; A0 {- RCC_APB2PeriphClockCmd(RCC_APBxPeriph_CAN_IO | RCC_APB2Periph_AFIO,ENABLE);
: z7 _" L7 J& O' B- F - RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);. x$ [; p4 l- T2 F+ M
- GPIO_InitStructure.GPIO_Pin = CAN_RXD;
: {- M7 w# p, G' N ?% f - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;2 b8 X4 C ^. j2 G, C% q/ I
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
* g: |$ V" \- Y+ F, O - GPIO_Init(CAN_IO, &GPIO_InitStructure);1 d" H) o/ M, P2 ^9 |9 _
% r5 P5 S- b: U& H, C3 z! D- GPIO_InitStructure.GPIO_Pin = CAN_TXD;
; w4 R# b4 y. U3 F7 e - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;( e: \# r* i+ G D7 ^5 n% J
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;& r; o- L% n# d8 K. T8 A" W
- GPIO_Init(CAN_IO, &GPIO_InitStructure);& w1 s7 ~# _4 V+ _$ t5 _9 J5 a* y
# ?1 ?4 ^1 H6 S6 l6 W- CAN_DeInit(CAN1);7 q% T3 N2 u. @3 l$ T: ~
- CAN_StructInit(&CAN_InitStructure);( {/ ~+ F" J" p0 I
0 @6 F1 r, _; B" U. z1 E- CAN_InitStructure.CAN_TTCM = DISABLE;: P) u) p! a5 B4 y2 }$ s' }
- CAN_InitStructure.CAN_ABOM = DISABLE;
* }7 }. B+ Y) o: O/ c! X3 } - CAN_InitStructure.CAN_AWUM = DISABLE;
+ l. r" V6 Z# d } - CAN_InitStructure.CAN_NART = DISABLE;
& D, N, J7 M6 B - CAN_InitStructure.CAN_RFLM = DISABLE;
( y; R2 i* D& K0 w( H' G Q+ o) u - CAN_InitStructure.CAN_TXFP = DISABLE;& \' ]8 F9 R4 e2 `+ z
- CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;8 c \: k$ l. W5 [- ^
- CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
+ t6 V5 G2 s9 u$ w2 I. g$ D - CAN_InitStructure.CAN_BS1 = CAN_BS1_3tq;8 p. t7 w6 u0 Z( U- t
- CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;
0 W% U$ A" v: O2 K/ R; [4 T - //CAN BaudRate = 72MHz/(CAN_SJW+CAN_BS1+CAN_BS2)/CAN_Prescaler
$ z9 w; \* }- V5 ~, M: D* d) z - if(canrate==CANRATE125K) /* 125KBps */1 A6 Z4 Y ?9 J
- CAN_InitStructure.CAN_Prescaler =96;
1 A" r1 t, U( { - else if(canrate==CANRATE250K) /* 250KBps */
0 F/ r% S: E2 ` T - CAN_InitStructure.CAN_Prescaler =48;" C. t2 e0 S& O8 _5 w
- else /* 500KBps */
5 |: `9 }0 d5 B n - CAN_InitStructure.CAN_Prescaler = 24;
! i3 X3 v2 Z4 s - ) z# A. c& E8 n5 C; N0 v0 V/ E
- CAN_Init(CAN1, &CAN_InitStructure);
3 w- H% \4 S4 J - }: `, ~7 I9 h1 }( z; e
0 g' N2 ]7 [2 ~- void CAN1_ConfigFilter(u32 id1, u32 id2, u32 mask1, u32 mask2, u8 std_or_ext)# y* ?- Z. B2 Y' u* b4 a5 r
- {
: {& W' r% i1 Y7 y' k. H- l( X4 x& m1 p - CAN_FilterInitTypeDef CAN_FilterInitStructure;. \$ o ^5 _% x6 U
- NVIC_InitTypeDef NVIC_InitStructure;
' z' ^; Q! }, Q% I2 u2 _3 t8 O
' V7 c* l: L1 l6 V7 t- CAN_FilterInitStructure.CAN_FilterNumber=1; //use which filter,0~133 |3 v3 ]. I# L: D
- CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
, I* W B9 i4 D a6 J( d) V( _ - if(std_or_ext == CANSTD)
. s% K S* T/ g6 s% r - {* G% ]) A$ X/ H
- CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_16bit;
: f* b9 h1 z& n% y7 z6 M: {/ y5 m m9 n - CAN_FilterInitStructure.CAN_FilterIdHigh=id1<<5;
8 [- Q% Y/ E# S5 q - CAN_FilterInitStructure.CAN_FilterIdLow=id2<<5;
% c0 G) L4 ]: j* o& g+ e \ - CAN_FilterInitStructure.CAN_FilterMaskIdHigh=mask1<<5;
; D7 |1 r" ]" P( Z4 I7 i8 A - CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask2<<5;& _; I$ B" S% T+ x, p7 x
* V+ n: Y1 Y8 `& N6 Y+ `- }
# N; Q: j! g7 T$ G* ` - else
$ e0 f8 [ G$ R. e/ ~ - {
/ V5 D! R/ t: U2 J5 a - CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;1 |1 j9 K5 |+ C
- CAN_FilterInitStructure.CAN_FilterIdHigh=(u16) (id1>>13);6 Q2 F) g5 g4 Q
- CAN_FilterInitStructure.CAN_FilterIdLow=(u16) (((id1&0x00001FFF)<<3)|CAN_Id_Extended|CAN_RTR_DATA);3 H2 g( v4 k) g. r
- CAN_FilterInitStructure.CAN_FilterMaskIdHigh=(u16) (mask1>>13);! Q2 o2 f G l& a; U% M
- CAN_FilterInitStructure.CAN_FilterMaskIdLow=(u16) ((mask1&0x00001FFF)<<3);
7 m7 O/ \; I$ g0 k& D3 D" |
; M' h1 Q Z6 l4 E' X/ x4 e x- }
4 ?0 W; J+ E5 o9 v8 t0 |) g7 r - 2 x) }" z( E0 G6 P& ^3 M
- CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;# W! ~/ N6 n/ |: d
- CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;& g* u9 s/ b* K* I" c) T
- CAN_FilterInit(&CAN_FilterInitStructure);
8 ~; S# p. j% x - . e8 o( b! |1 Y- j$ P! N0 X
- NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX1_IRQn;% I" K9 F4 ^* x: J; V
- , p5 ~/ I) {6 l
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;- B5 Q; g* U# t+ {
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
# n+ O' W- E! A - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;4 |- }! [. ^% x& S9 A. E9 }
- NVIC_Init(&NVIC_InitStructure);/ C2 B7 G$ ]+ q w/ ` n9 f; `' o
) m4 M5 p$ j: \7 J# y2 D& D- CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
8 F, {" B& O! u: ]* o. r - }" d0 \! W4 h" J* C8 g
- /************************init******************************/
# A8 P/ A7 i" | - void init_demo()
% s! r4 G' f0 B6 H* x: L - {$ a) e. F4 S K& y3 I
- std_or_ext = CANEXT;. Y6 j ^, O! X) L0 P9 f6 v. F
- CAN1_init(CANRATE500K);- ?* U' `/ M9 M
- CAN1_ConfigFilter(0x18DAF110,0x18DAF110,0x1FFFF100,0x1FFFF100,std_or_ext);//extend ID
0 r2 K$ B9 C6 {0 a' N2 T - }& F0 g. J$ U& A. `' L7 G% R
- /************************tx******************************/0 l* e% J1 I- h$ R5 `
- /*datalen<=8*/" Y0 \6 u- c3 I" C# Z( d6 |
- int CAN1_TransASerialData(u8* pdata,u8 datalen)6 s6 _! Z$ u) {* s& P! _3 `
- {
9 S1 m, n& _$ @, e" C" j8 X - u8 i=0;
$ E' ~& {+ G) g# E2 ^ - 3 N, Q0 Y) N8 ]; S/ g
- Delay_ms(20);; t3 t; D% u s! ^1 |
9 G- I# B7 |9 y9 w- E. Y$ C- if(std_or_ext == CANEXT)
+ U$ E0 D. i! g* ]4 V2 ] - {1 M L0 d& V5 j( W, a
- canrxtx.txMessage.StdId=0x00;
v j! X4 b/ ^1 O" M: V4 u! y - canrxtx.txMessage.ExtId=CAN_Id_Extended_HONDA;//bentian
7 B4 g; C2 w# F1 k# h8 K1 j" Q. N - canrxtx.txMessage.RTR=CAN_RTR_DATA;2 k9 N3 _0 z" W* H
- canrxtx.txMessage.IDE=CAN_Id_Extended;// 29 bits
2 p5 \. f/ h2 ]1 m4 ]. n
; L* J1 ]; t* n/ X- }
$ }* a* [: ?, F$ ?( j - if(std_or_ext== CANSTD)
+ Z' u% \4 ]# i% Z0 b$ a2 X( h8 f - {& y, y' P. N6 @' V, c
- canrxtx.txMessage.StdId=CAN1_TX_STD_ID;7 c/ K7 o8 ~8 k( c8 g
- canrxtx.txMessage.ExtId=0x00;, b+ B4 V! a- [: h& a0 H1 A4 ^
- canrxtx.txMessage.RTR=CAN_RTR_DATA;
4 r0 O' h9 n! I9 _! e6 b: p - canrxtx.txMessage.IDE=CAN_Id_Standard;//11 bits7 d$ w# A: H* f6 g5 s
- }
) \: O, \" q& V N1 }$ ` - 5 M& _& c( E2 e: L$ S, [
- canrxtx.txMessage.DLC=0x08;/ @" f8 |) f2 d' \2 }$ `
- canrxtx.txMessage.Data[0]=datalen;
2 N* y6 ^/ H3 G+ O# F - memcpy(&(canrxtx.txMessage.Data[1]),pdata,datalen);
6 K7 A9 t/ G, a
1 {: r+ C, f7 f5 z+ f; z3 U+ x) x
9 y! f5 Z9 d; S/ R) L9 j- while(((i++)<3)&&(CAN_TxStatus_NoMailBox==CAN_Transmit( CAN1,&canrxtx.txMessage)))1 ?6 X- O1 a6 |5 l K; z0 m
4 X& J6 C. Y: W2 N. q7 q5 a: T- if(i>=3) //timeout
! ` W! Y; I+ z7 Z# D - {# M0 n% d' {/ d) U3 C- r
- return (-1);0 y7 q3 M2 p1 q
- }' l1 ?+ p, p5 W/ q- }1 j2 Y" z
& U$ o7 N( Q9 Q/ d: E4 m9 T: m) A- canrxtx.rx_newflag=0;! j( H' ~6 l L! t' X% w( o8 [% N* F
- return (0);
% ?& ~. o) k c6 l0 r/ o3 S3 e
" K* {/ D4 F4 O" c7 A- }5 M6 i$ w: S* Q( Y* ]. [) [! P
- /************************rx******************************/' C5 f: H- E# {6 @# h
- void CAN1_RX1_IRQHandler(void) V. }$ |2 |. r4 I
- {2 V6 T( x( f% z* w
- memset(&canrxtx.rxMessage,0,sizeof(CanRxMsg));/ |1 x& m0 {4 t' Z; q3 M
- if(CAN_MessagePending(CAN1,CAN_FIFO0))0 R- {6 E5 ~2 a
- {
/ i* q% D' w, Y; A - CAN_Receive(CAN1,CAN_FIFO0,&canrxtx.rxMessage[0]);
7 f1 O( q; w) h& P# C - }
2 z$ O6 Y" D7 U, Q - canrxtx.rx_newflag=1;
' _7 H) k6 [- i1 Y% A: u% d - }
复制代码
8 @4 j, R f' ? 三、标识符过滤器的解释 过滤器只是用于接收,判断某个报文是否能通过过滤器,过滤器初始化如下: - 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>
复制代码 5 d+ `( }2 y* C
stm32有0~13个过滤器组,每个过滤器组有两个32位的寄存器,通过设置下面两个结构体成员的值可以有四种组合:CAN_FilterMode 和 CAN_FilterScale
. {. J/ B# H& K2 [
' f1 b; T L! X' L
8 P. a+ v1 M9 R0 l
四、关于邮箱 如下图,发送3个邮箱,接收每个FIFO 3个邮箱,这是硬件自动管理的,软件不用管,只要判断发送成不成功,中断接收哪个FIFO就行了(要接收过滤器初始化时绑定的那个FIFO)。 每个邮箱都可以存储一个独立的报文,发送调度器(下图红圈)会根据标识符(ID)的优先级来决定先发送哪个报文(比如发送时3个邮箱都有报文,标识符不一样),PS:标识符数值越小,优先级越高,这是由CAN总线仲裁机制决定的(线与,0可以与掉1)。
# a& ?' ^# y9 U1 N7 ?2 S9 M \: ^
7 ?' `" P5 c5 Q v+ x u! B
五、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位的隐性电平。不管。
, e! K0 J8 Y5 }6 y Y0 ` C( S
/ ?; I) H/ S4 P
3.位填充的概念 在CAN消息帧中,帧起始,仲裁场。控制场,数据场和CRC段,均以位填充方法进行编码。当发送器在发送流中检测到5个极性相同的连续位时,自动插入一个部补位码。 我觉得这个只要了解就行了,实际编程中库函数已经帮我们做了。
( D& x3 l7 u/ s1 T( X M k4 g* b! k: W9 { [
|