|
一、什么是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接口在哪?
! I+ B- v9 S C% M" ~
3 b8 _. k1 |3 b
stm32有can总线控制器,以及有库函数stm32f10x_can.c可以驱动该控制器 但stm32只是有can总线控制器,要真正连接can总线,她还要外接can总线收发器,才能分出来can_H ,can_L,例如如下芯片: 这个芯片的主要作用是发送时根据TXD的电平来决定can_H 和can_L的电平,以及接收时根据can_H 和 can_L的电平差来决定RXD的电平。
/ ]+ Y: L* T4 h* k6 _! a1 a
% W3 h, q( K5 g, R) m W( m! t
+ r5 ]6 R$ g+ I9 {. D
0 t. w' w- p2 V- I: |1 D) I2.can概念入门比较好的文档 https://wenku.baidu.com/view/7701528a6529647d2728520f.html 这个文档比较详细的介绍了can帧的类型,以及各个帧每个字节,每个bit的含义,以及优先级仲裁机制。下面的例程是数据帧。 3.can例程。
; u2 Z0 J" t5 H( G: }, Y/ h* ~- #ifndef CAN_H_% n: O3 S' P/ Y; F" B# g
- #define CAN_H_6 U5 L* E9 q7 E
- #include "stm32f10x.h"
{( _# y. t$ ^: b2 k" q2 E - #define RCC_APBxPeriph_CAN_IO RCC_APB2Periph_GPIOA
3 @$ m9 H! Q& e2 x. O- o - #define CAN_RXD GPIO_Pin_11
3 l- k3 B5 R# l1 W% z - #define CAN_TXD GPIO_Pin_12& e+ W9 ^5 D( M1 I
- #define CAN_IO GPIOA5 z* \: c) _3 E% Z, W- [
4 Y9 J4 C- {3 _1 W. X* i7 C( k, B5 q- enum canrate_e
, i0 Q7 o8 m* p - {
+ F: a: `8 U5 g" N - CANRATE125K=125,$ J2 c- }0 J: ?9 {. Q3 S
- CANRATE250K=250,$ p% x8 v$ b6 O3 E4 {/ E! ?) Z% Y
- CANRATE500K=500,
& ]& N9 Z) t) L - CANNOTLINK,$ ?. I, u+ x3 V7 _
- };2 ^* Q1 I6 K1 N' i+ d4 f
, w4 N5 T8 f$ i. h- enum canStdExt_e* ?# l) I! W! w) R* ]
- {
- @0 l) ~2 B1 J$ O! @ - CANSTD=0,
& q' y4 u* I. N9 P1 b- a% Y* Q - CANEXT=1,
9 l- C" u& g; l. d6 R - };( g6 a; T0 Y( {4 ?
- struct canrxtx_s
; Z# s# A* d* q - {
% v, u; q1 U2 |! T1 Q' Q, G& k - CanRxMsg rxMessage[3];2 a y2 v: E5 K
- u8 rx_newflag;2 O, r' e$ P; s( Y2 W3 N
- uint32_t f;; _6 [/ z2 f w% L8 |0 A) a7 v
- CanTxMsg txMessage;0 z; g8 g# [, t% d
- ' V' D$ m2 {; H9 Q2 k6 ]: i
- };
( r+ i5 r3 ?4 I; m3 U# {, G5 R
0 H+ k3 h0 v: h- /*std ID*/
- ?, ~ ~/ O5 r0 I2 p - #define CAN1_TX_STD_ID 0x7DF //11 Bits ID,Functional
6 n6 [( L j8 q- B. D8 o' Y# G: S* Z- B - 6 D, g6 G" n/ d3 k# w, n/ f- Y c
- #define CAN1_TX_STD_ID_ECM 0x7E0 //11 Bits ECM ID,physical
' ?4 O9 u$ t# I- g8 b - #define CAN1_RX_STD_ID_ECM 0x7E8 //11 Bits ECM ID,physical; F# S% J* {/ G! k7 U' B- X
- #define CAN1_RX_STD_Filter 0x7FF //11 bits ECM Filter
9 g9 }, k( V) ]! a" G- D - # E6 T; |' J6 z3 E! h' D
- /*extend ID*/0 d d! u" l$ p
- #define CAN1_TX_EXT_ID 0x18DB33F1 //29 Bits ID,Functional
* ?" a8 e( D5 S; L8 Z3 H5 I - #define CAN_Id_Extended_HONDA 0x18DBEFF1 //29 Bits ID,Functional HONDA G' d* V8 _1 s) }1 D( F9 }
- #endif
复制代码- #include "can.h"
5 J+ P2 ]# E; x# a1 Q- O( m2 ? - #include <string.h>! j' Y- z4 j. B5 A+ W
- u8 std_or_ext;* m- l: h1 K+ S8 A9 G% C9 l
- struct canrxtx_s canrxtx;2 R( q2 V ^1 U3 A
- void CAN1_init(enum canrate_e canrate)4 v3 @! Y E! w: W; W: _
- {
H- o1 G0 V2 W9 ~
" y( \: R5 \( E/ ?, H1 @ a$ D- GPIO_InitTypeDef GPIO_InitStructure;; o4 \1 t: K6 l, v7 G3 w# l3 s
- CAN_InitTypeDef CAN_InitStructure;3 {7 |$ }6 y. \* V: ]5 w
- # {' N! j" Y# Q$ L/ Z7 b% q
- RCC_APB2PeriphClockCmd(RCC_APBxPeriph_CAN_IO | RCC_APB2Periph_AFIO,ENABLE);
, g1 }. n1 A: S) ^' W - RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);
$ w! w- b6 f- H - GPIO_InitStructure.GPIO_Pin = CAN_RXD;' ^; ^$ D6 o( X T1 L
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
7 Y1 a7 r0 e9 N S+ C - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
D) P+ J# w! \! f; p+ k - GPIO_Init(CAN_IO, &GPIO_InitStructure);
" ~' |/ Y" u# u) A( a3 Y
( j, p, E+ \/ d8 {/ Q b- GPIO_InitStructure.GPIO_Pin = CAN_TXD;1 n% Y6 s' x% }' Z
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;8 i" s* n6 d8 ^, e# n
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/ x8 D) L% W& I0 U9 ^# l" O - GPIO_Init(CAN_IO, &GPIO_InitStructure);
0 o9 b; W" d) Q: ~9 t, p, Z8 L
- y- i7 T: R+ b) j. n$ m- CAN_DeInit(CAN1);: |5 E0 D+ G+ z
- CAN_StructInit(&CAN_InitStructure);/ \4 Q7 R6 I/ a" i
- 8 K) G# t1 D1 z2 [3 J
- CAN_InitStructure.CAN_TTCM = DISABLE;
0 h: {3 P4 d. \9 E+ v - CAN_InitStructure.CAN_ABOM = DISABLE;7 |% \0 f1 H. @
- CAN_InitStructure.CAN_AWUM = DISABLE;
: h% C' |/ {; K" U4 G - CAN_InitStructure.CAN_NART = DISABLE;' k' l5 n4 i+ \& @& B; P0 n
- CAN_InitStructure.CAN_RFLM = DISABLE;
: w# \+ R% ~- @. Q: D - CAN_InitStructure.CAN_TXFP = DISABLE;6 C* t" G# j2 Q+ H+ u# l
- CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;3 i, F1 b5 T% g: i% y7 A
- CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
1 L3 n+ R! b* z$ j - CAN_InitStructure.CAN_BS1 = CAN_BS1_3tq;
+ _1 c, T, o5 A* J" ` - CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;% {1 c# W& X L6 x5 W$ S
- //CAN BaudRate = 72MHz/(CAN_SJW+CAN_BS1+CAN_BS2)/CAN_Prescaler
2 ^1 Y5 f; ^: G) o; g+ ~- q - if(canrate==CANRATE125K) /* 125KBps */
( r8 g ] V5 ~9 y5 Y6 T - CAN_InitStructure.CAN_Prescaler =96;+ r/ p6 T5 O+ W& s# l1 e
- else if(canrate==CANRATE250K) /* 250KBps */& H& o& o1 `- Y
- CAN_InitStructure.CAN_Prescaler =48;
" W/ C9 x2 `4 c3 ^! ~# X6 [ - else /* 500KBps */
8 |; W9 M. ^5 S - CAN_InitStructure.CAN_Prescaler = 24;$ Y1 u& y8 ~. y4 z5 P3 [0 l
- & M) u. s9 | y) T+ Y( A+ |5 D
- CAN_Init(CAN1, &CAN_InitStructure);
# p7 J& N+ p5 X1 Y$ G - }
3 |7 \( p/ Q6 d& ? - $ Z5 C! J3 Q4 O J' S) Q8 i
- void CAN1_ConfigFilter(u32 id1, u32 id2, u32 mask1, u32 mask2, u8 std_or_ext) f2 ]# k8 H3 n2 `9 G
- {
% |+ B) e) h; j% ?4 L- ` - CAN_FilterInitTypeDef CAN_FilterInitStructure;7 i$ `6 O4 Q7 D8 ^, u N! q, _# }& J
- NVIC_InitTypeDef NVIC_InitStructure;- b3 m4 b; C, I" u$ P
4 P0 A4 q0 ^& o- CAN_FilterInitStructure.CAN_FilterNumber=1; //use which filter,0~136 f5 X: u6 {$ P y7 T
- CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;$ g( o/ d. Z7 t) D
- if(std_or_ext == CANSTD)
* A* N$ U; S% p2 }) O - {
1 n. T) M7 D" E8 e) k - CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_16bit;
+ u, Q/ ^3 z% [( q# w. s - CAN_FilterInitStructure.CAN_FilterIdHigh=id1<<5;
% P$ z' V0 d0 C. R - CAN_FilterInitStructure.CAN_FilterIdLow=id2<<5;+ m7 g$ d9 l( [3 l" u1 P* m4 |6 L
- CAN_FilterInitStructure.CAN_FilterMaskIdHigh=mask1<<5;9 H1 c8 r/ C/ D5 [ @
- CAN_FilterInitStructure.CAN_FilterMaskIdLow=mask2<<5;
& o1 A5 H3 c; j" x- n0 d
: `% c/ |% M) `! ^; I- }
; L7 D9 g8 i. V# z |/ R+ G, m& m - else
2 c7 \, b5 u3 b8 I& m - {
9 I) }% q! {5 F( w" B. ] - CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;
* w' O0 l$ v, V - CAN_FilterInitStructure.CAN_FilterIdHigh=(u16) (id1>>13); V" }, b6 P& k d4 a, v; L
- CAN_FilterInitStructure.CAN_FilterIdLow=(u16) (((id1&0x00001FFF)<<3)|CAN_Id_Extended|CAN_RTR_DATA);2 m1 f" _( V8 x% u( n Z
- CAN_FilterInitStructure.CAN_FilterMaskIdHigh=(u16) (mask1>>13); ^5 ], V- A$ J9 K7 H) _0 d
- CAN_FilterInitStructure.CAN_FilterMaskIdLow=(u16) ((mask1&0x00001FFF)<<3);( A9 H) X! [- {
8 f; v- y/ M1 R3 n3 W, N- }
3 L7 U8 C6 J- Y8 @1 I - ) w8 I% @/ K1 Q4 R1 m( o- w8 N
- CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;
3 b$ `$ p( z5 @$ `- l$ M - CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;) \2 I3 a& @$ n5 {6 J) V4 V
- CAN_FilterInit(&CAN_FilterInitStructure);. x4 Y+ ]) w+ ]( t$ \
' O( f+ ~: l3 k' A- NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX1_IRQn;
" A0 ~7 Z/ g$ \+ y. k
* u. I6 ]! j u" y" N; p- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
# C# P; _& k7 b# `7 R5 c - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
$ ]. r* ?! I. f+ Y k2 |& N Z - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;* Z* J7 Z: p. n* Q' {
- NVIC_Init(&NVIC_InitStructure);
! D# t7 |! e& _! [+ i - / r0 b Z8 V% x; h
- CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);: F0 s, x$ R0 y1 ~
- }3 }: M% ?) I: S1 ~1 o% c- e
- /************************init******************************/
) y: H3 D2 G) r0 o8 m - void init_demo()0 N7 c; h S$ X0 Z; w
- {+ c2 A/ q" ~7 U; t
- std_or_ext = CANEXT;: _4 E' B& u0 L4 j1 \$ D4 R
- CAN1_init(CANRATE500K);9 _' L r1 e5 _; `5 o( S: Q
- CAN1_ConfigFilter(0x18DAF110,0x18DAF110,0x1FFFF100,0x1FFFF100,std_or_ext);//extend ID* q7 w! N Q w5 u4 I
- }# J* l2 W7 G- @. J+ w, Q; U
- /************************tx******************************/
# ^7 I% o- l/ ^. \- F* e# o$ m! { - /*datalen<=8*/
6 t2 \2 f5 i/ a- ^; } ~1 v - int CAN1_TransASerialData(u8* pdata,u8 datalen)
Q# P. z! M9 @. [5 n8 L - {3 }" c8 H3 W) a8 u5 C( W+ A* Q- b7 d3 J
- u8 i=0;, X! p* l" u1 F% s1 ?
) z& N# _6 v- E8 A/ C- Delay_ms(20);( f% b9 B& E; {/ U9 h: N
$ c5 k4 X T1 J0 {: {9 q- if(std_or_ext == CANEXT)
- ]' V; e4 f" `* A* {6 Z, w - {, i- I- L+ L. ?& r0 ?7 s
- canrxtx.txMessage.StdId=0x00;+ \7 `2 E% p/ ^: Y! U
- canrxtx.txMessage.ExtId=CAN_Id_Extended_HONDA;//bentian
. ]/ w. f3 b# f9 G - canrxtx.txMessage.RTR=CAN_RTR_DATA;
/ `4 A6 g" n" Q" W3 x - canrxtx.txMessage.IDE=CAN_Id_Extended;// 29 bits9 X- ?6 {' v3 U7 o( m1 ^
. @# u% i7 w4 R/ J- }, q/ U: R, `. ^2 o
- if(std_or_ext== CANSTD): [' N4 T, e5 ^
- {' G# q: X3 _0 u3 f* Z* z. \
- canrxtx.txMessage.StdId=CAN1_TX_STD_ID;' U0 n6 r& l3 u6 L+ ~
- canrxtx.txMessage.ExtId=0x00;- C. v" [! r/ Y l! k
- canrxtx.txMessage.RTR=CAN_RTR_DATA;
, {# o& Y0 e: D% I3 Y) C; X - canrxtx.txMessage.IDE=CAN_Id_Standard;//11 bits1 @# N; z4 P4 V
- }
1 e9 z* U, s- o - 0 I( O" \2 F! V# r- p
- canrxtx.txMessage.DLC=0x08;
. s6 x5 u6 F* r# r* @* T - canrxtx.txMessage.Data[0]=datalen;
- `& l1 \* {# @/ u& T! s# M" u6 `% x - memcpy(&(canrxtx.txMessage.Data[1]),pdata,datalen);5 T" `- Q/ X# l! P) M9 E$ R
' w4 z! }: Y6 i3 \0 s9 a
! O- A7 x' e- J# l" K6 k7 ^2 R- while(((i++)<3)&&(CAN_TxStatus_NoMailBox==CAN_Transmit( CAN1,&canrxtx.txMessage)))# f" u! Q6 w- o# [
! i8 l( w2 {7 ^" d- if(i>=3) //timeout
$ x2 ]% C! X3 D" e6 s$ s' h - {
. t6 M [* d8 k( H% j+ U - return (-1);) n1 \/ u) W8 P3 v+ a
- }
0 Y, z. C) @: G
1 W/ I8 J/ k& d: H: K- N- canrxtx.rx_newflag=0;) _ e4 K- e2 ^. N
- return (0);
. X$ r2 W9 N6 x |) P; C - . E& h; z: r. ~0 i8 Y
- }
% v1 f' W$ M' O9 z6 _: G% E7 O - /************************rx******************************/
) z/ S1 m6 v; U( u6 e. C - void CAN1_RX1_IRQHandler(void)
/ C6 E( @- D; n% F - {
5 _( T8 g& k1 D! }! j; j - memset(&canrxtx.rxMessage,0,sizeof(CanRxMsg));; g; w M* ` K9 E
- if(CAN_MessagePending(CAN1,CAN_FIFO0))
' ~! G% ~* w( U/ @$ c F* _, o: [ - {
3 K3 o4 s; b# H& ?* q+ E - CAN_Receive(CAN1,CAN_FIFO0,&canrxtx.rxMessage[0]);5 z( n0 |* C+ S! Q' n+ n# G! B
- }' c5 d3 T1 c! C) m% I
- canrxtx.rx_newflag=1;
5 _9 S! J& O9 A6 o* i& A- m/ I0 c - }
复制代码 1 z' a5 Z6 D% 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>
复制代码 & g' b; m' J0 q6 j& T
stm32有0~13个过滤器组,每个过滤器组有两个32位的寄存器,通过设置下面两个结构体成员的值可以有四种组合:CAN_FilterMode 和 CAN_FilterScale
! ^, J% j9 m4 q. J9 G3 h0 [. w
: l5 ^5 W% n; S- A! k. K2 ?7 |1 i# x: D$ m
# ~* L4 s1 {& q x- |& e 四、关于邮箱 如下图,发送3个邮箱,接收每个FIFO 3个邮箱,这是硬件自动管理的,软件不用管,只要判断发送成不成功,中断接收哪个FIFO就行了(要接收过滤器初始化时绑定的那个FIFO)。 每个邮箱都可以存储一个独立的报文,发送调度器(下图红圈)会根据标识符(ID)的优先级来决定先发送哪个报文(比如发送时3个邮箱都有报文,标识符不一样),PS:标识符数值越小,优先级越高,这是由CAN总线仲裁机制决定的(线与,0可以与掉1)。
8 T( O4 ^- Y( D$ {: G9 E, `/ j/ u
' C& _+ b6 m+ o9 n6 X/ T% J
五、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位的隐性电平。不管。 9 u' I2 `# ^8 Q% M" r
) B. w+ ~' y- d0 A7 x8 x3 |
3.位填充的概念 在CAN消息帧中,帧起始,仲裁场。控制场,数据场和CRC段,均以位填充方法进行编码。当发送器在发送流中检测到5个极性相同的连续位时,自动插入一个部补位码。 我觉得这个只要了解就行了,实际编程中库函数已经帮我们做了。 ! E: y4 @$ H% j+ k$ n% U2 o
E7 n( H3 Y6 Y- N: W7 X$ y# D' t |