CAN通信
) s( _2 c" u0 t% H CAN 是Controller Area Network 的缩写(以下称为CAN),该通信使用的是ISO11898标准,该标准的物理层特征如下图所示。
/ W6 W" q5 d3 H; _( G+ E. I7 t% @$ c1 W$ |
9 n( |0 Z% q& ?, K+ K/ j+ E
}- K0 f L) o1 _" }
CAN协议是通过以下5种类型的帧进行的:- t* |( y/ E6 O
数据帧
9 f. q" k( g# f) m" o7 c7 V摇控帧" X+ P& @/ c4 c, c9 W6 `* X; Y
错误帧
( b! K6 h/ t3 R, S- [/ T过载帧
- ?; w" e1 r* f帧间隔! q+ I4 ~- T! R% {% D
* K# M$ c& w0 Z6 s4 g. A
另外,数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID。
1 [# ]5 }' w- t, B$ |) _& h' D! A3 {: {5 L: c# q
大部分系统使用的都是数据帧 ,我这里使用的也是数据帧。6 l7 F) m2 u! T, f7 Y9 l: ~+ K
数据帧一般由7个段构成,即:
( s9 T7 @/ ]1 }+ [(1) 帧起始。表示数据帧开始的段。
- a M" |, D+ V$ L3 q8 y& W& `+ Y(2) 仲裁段。表示该帧优先级的段。% S) I, t/ h: _3 F" m$ v- Y
(3) 控制段。表示数据的字节数及保留位的段。
& B- l9 `2 W2 J v: j* [+ X(4) 数据段。数据的内容,一帧可发送0~8个字节的数据。8 p+ v. X8 v! m$ S4 _0 J
(5) CRC段。检查帧的传输错误的段。
% a# @6 b! v1 L+ y% [2 T(6) ACK段。表示确认正常接收的段。* t( s$ Q4 Q2 [; y
(7) 帧结束。表示数据帧结束的段。$ }) k- C' Q! a" i7 z
8 ^( w+ _! C$ h. U: B8 u
明确了数据帧概念,还需要理解一下过滤器的作用。" h* W1 P2 {/ G) |- }
% M: H" d! U: o5 P: n b/ a1 L STM32的标识符屏蔽滤波目的是减少了CPU处理CAN通信的开销。STM32的过滤器组最多有28个(互联型),但是STM32F103ZET6只有14个(增强型),每个滤波器组x由2个32为寄存器,CAN_FxR1和CAN_FxR2组成。
5 J h2 v. k, ~# ], R. O
; ~5 K1 r7 M, ^+ Q2 Q$ s STM32每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:4 Y9 W, ]# j9 r+ e' H2 C! p
1个32位过滤器,包括:STDID[10:0]、EXTID[17:0]、IDE和RTR位
, u2 M9 N, J. G3 i; B5 v2个16位过滤器,包括:STDID[10:0]、IDE、RTR和EXTID[17:15]位
- d5 p& e! [( H: s1 q7 }6 J: D5 J B/ `! B; ?# l; j) c" i
此外过滤器可配置为,屏蔽位模式和标识符列表模式。1 F+ N* Y }$ ^' d3 V6 ]
; Q6 K# ^% V9 C) z9 f
在屏蔽位模式下,标识符寄存器和屏蔽寄存器一起,指定报文标识符的任何一位,应该按照“必须匹配”或“不用关心”处理。
! t; u5 e1 \9 T% p2 Z0 z3 e4 }" C! q: m) ?/ _6 T8 D& U; K) e5 N
而在标识符列表模式下,屏蔽寄存器也被当作标识符寄存器用。因此,不是采用一个标识符加一个屏蔽位的方式,而是使用2个标识符寄存器。接收报文标识符的每一位都必须跟过滤器标识符相同。相关文章:CAN总线详解。
5 A; \6 x1 E* ?# Q B9 E/ V/ N+ b x
- ^; B" x8 s+ b7 ] n" S 一般也都是使用标识符列表模式,这里使用的也是标识符列表模式。滤波过程举例如下:
0 ~: o k5 \3 L$ p j% S
- T& Q& \9 a Q9 F
4 g. a; }9 U: ~3 n+ Z
6 e5 e- `3 @+ G4 N8 F; Y 在程序中就是:
# m' D1 O: r- X* \- //要过滤的ID高位
) D) t3 R, I. s, m& C% k - CAN_FilterInitStructure.CAN_FilterIdHigh=0X00;
; j! n# I" p7 _. M$ ?& x - //要过滤的ID低位
: }& f2 A2 A" y! d - CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;
/ Z( X5 G9 k* ?8 m8 B+ p5 u0 _, u- Z - //过滤器屏蔽标识符的高16位值 y5 G' p% P, g5 j. h0 k& H. Z
- CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF; $ }) J+ g2 v( i" E
- //过滤器屏蔽标识符的低16位值
0 u# @: t, s, z" N* J# q% ? - CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
复制代码
% W: b& C/ j% V. r9 l 这里的CAN_FilterId和CAN_FilterMaskId是配合使用的,意思是CAN_FilterId指出需要屏蔽ID的什么内容,什么格式;CAN_FilterMaskId是指CAN_FilterId的每一位是否需要过滤,若CAN_FilterMaskId在某位上是1的话,ID对应位上的数值就必须和CAN_FilterId该位上的一样,保持一致,反之则是“不关心”。
/ n( O' s9 B( X1 [: @& E5 C; G$ E- E- V
上述程序的设置的含义就是:只接收来自0x1314的数据,屏蔽其他ID的数据。
: r7 ]% V8 I9 \# ^9 I$ I8 B- R; R6 p: D0 S3 l
程序思路
6 W9 @7 U. f d# t8 y 这里准备做一个主机与从机的通信,主要用扩展标识符ExtId来区分,分配的标识符是:
+ Z3 ?4 {4 ^2 o主机:0x13141 R+ T- a$ G* T
从机:0x1311. c6 m2 L$ R3 C+ v8 \# m
6 I% R& R) w7 P |4 K) X
主机负责接收所有从机的数据,不需要过滤,用扩展标识符ExtId来区分不同从机的数据;主机还可以向不同从机发送信息。而从机则只接收来自主机的数据,同样用扩展标识符ExtId来区分是否是发向自己的数据;同时,也能够向主机发送信息。3 K7 u$ c$ T& C2 e* k& {" F
3 Z' D- k1 X# j" F5 r
2 `, Q, E! [- `: N
相关代码
1 f# ^5 A3 a3 J: P* K 代码也是非常简单的,这里贴出了主机和从机的can.c和can.h两个文件。
* q' s- ]( `. s6 I) c4 J6 S0 l; L; N% F+ U2 I, m) e
从机相关代码8 R ?7 r' h, G
can.c文件:# o; U l3 ^, P8 ?/ i3 e& U
- #include "can.h"$ B: J1 i; a7 b- r, C5 D
9 K$ |' K O; D1 f6 V% Z$ F4 `. |
0 j }( j: U( D6 S6 P( T
. ]2 X4 R; F. Y% ?: ], D. H) }
( _5 h4 g4 O+ I2 F- /* 在中断处理函数中返回 */
5 X/ ^. _2 W" `- o" `3 m - //__IO uint32_t ret = 0;9 ?9 [* u3 l! o1 Y- t5 |$ `: ~
- 3 O/ \& r% f; I* S9 h5 {2 D
- 4 v9 R" g4 h. c& V4 Z5 ]+ t! i
6 K Y% c& H. s. [; O* ]2 {/ A- ! }* P- j* b4 F) u! M
- //接收数据缓冲器0 E! d( l3 D* M4 Y1 q `$ O
- u8 RxBuf[5];
% E3 v: }7 p* R/ r& [0 j/ Q - u8 Rx_flag=0;% G, J5 q: I0 a7 q J1 W" F/ N
- 7 Y3 d# T- Q$ _0 i: E' n( B
- Y$ y. h- a3 b0 V+ p, l- ' P& k: {4 _& M$ w" K- Z c) ?
0 D% Y/ f) I5 A6 f- void CAN1_Init(void)9 V/ k4 C2 r3 m" T
- {
1 l9 h Z( q$ y) l - GPIO_InitTypeDef GPIO_InitStructure;
' [6 \/ H! q) G, S - NVIC_InitTypeDef NVIC_InitStructure;
0 C3 a6 ]" z/ g5 x6 } - CAN_InitTypeDef CAN_InitStructure;& A" |. }/ j; o
- CAN_FilterInitTypeDef CAN_FilterInitStructure;
% r0 k8 B V6 P7 D% x7 J
2 S, e' J: e. l! W" `( q# ?7 K
) y, I4 U/ w+ Z! Q( y m* d
. h* l) Q5 T( e8 L7 A) v
; C' ? E+ w: A- }+ H- /* 复用功能和GPIOB端口时钟使能*/ 7 R X; V3 t5 n6 z4 @
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE); % o6 ]: a& T; B: ^' Z2 `
- 5 B- L% k7 `1 f' I1 x8 f
- + I) S$ w* o! b. U( v3 t8 b
- , Q+ l, N* C+ }
- ( p4 }: g4 n, L( S
- /* CAN1 模块时钟使能 */
* {, c! }; k6 U6 \6 w; Z3 B, w - RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
( `9 r$ C# C9 b1 g# o: U" ]8 n6 ]
3 ?/ Q9 u( ^# h. D
" N! g7 I4 \! B4 v- 5 W/ M* V" z. ?. D& K; }5 Q
- ; y/ a0 g, r! \6 u3 I( {
- /* Configure CAN pin: RX */ // PB8! j3 |/ f: p; }9 { R5 D; h; J
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
8 v, i' _8 L7 y$ Z! @ - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入5 X$ }1 O5 B5 x% i
- GPIO_Init(GPIOB, &GPIO_InitStructure);
/ ~: S# M/ k- X- `
$ n* @7 d2 n1 G
% m" C2 L g! \( A. `5 m- * g$ Q) w: H& [, o0 K0 w
- % v1 ]& Z: W+ w ]! M8 F O
- /* Configure CAN pin: TX */ // PB9$ d# ~ @2 X% L! P8 B- w% }
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;/ k9 ~0 B+ X5 D5 o
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出% B. d2 ]7 |- q! k- T3 M9 a
- GPIO_Init(GPIOB, &GPIO_InitStructure);2 m: r0 f x( F% M, T4 a
- ! G: g3 ]. P# B# h
- * W7 M' e l* b; G( k3 P
- ( E- I/ N# ]1 y& E0 Z @( _
- 3 t/ i7 T A) V7 [, a
- //#define GPIO_Remap_CAN GPIO_Remap1_CAN1 本实验没有用到重映射I/O
. ^' |6 y0 e) d' C - GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);3 ]/ t3 P# D8 x/ Z: k
- 0 |% F# D3 R# i- Y7 n
- 6 K; \1 B0 `( `7 M
: w3 F' w! L5 x7 h- 2 O7 Q1 Q2 J0 w h" a
- //CAN_NVIC_Configuration(); //CAN中断初始化 2 p1 Z3 m3 ^& M+ z+ D
- /* Configure the NVIC Preemption Priority Bits */ 9 R" S( D& T5 V
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
9 C; f" y* Y4 [$ E8 I - , L. l: P) Q( g1 G6 e; D" U! {% R
- ! w8 u& A' F! e
" a( a! |1 k4 W9 z5 F
; r+ C p. N7 F- C1 n3 p- #ifdef VECT_TAB_RAM
. [% L; ^3 k i$ R2 j: H - /* Set the Vector Table base location at 0x20000000 */; @+ U9 d6 r, d. V; U) J' M3 w
- NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);, c; E$ [; v3 E) e }' M
- #else /* VECT_TAB_FLASH */
$ @9 k. W1 p3 C' \, H) f5 V - /* Set the Vector Table base location at 0x08000000 */
! ^% E% G. M/ K- D0 ^ - NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
t5 _# W0 f9 ^2 h5 Z% ~* z$ \5 t9 S - #endif, z" L0 S) W5 Q8 B# ^
- ; ~, g3 v0 R7 n7 I/ {" S. g2 X8 D) I- J& X
- 3 b9 p. w3 f2 I2 m0 T5 N
# b8 p9 F4 q1 d6 P, e! |) @; \
" @4 `0 `4 m8 Q3 ?- /* enabling interrupt */- v% I; J2 L) |* X! |9 x1 `
- NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;
# B. z5 |% M, B$ f - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;* A4 B4 Q' |( t1 L& k
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;- |* n( D9 L; p* A' E
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
. z$ q4 N" n8 i1 ^$ n1 X; O' M - NVIC_Init(&NVIC_InitStructure);+ G( N6 v( i/ Z+ D
% m7 Z5 j' I' J8 g9 L \* ~1 V8 I" \
5 m# e& `" o3 ^# H9 Q( o/ \- / v, k Q1 x* Y/ z! c" m2 Q
- + [/ h& K" \0 D3 z: d* L/ F \
- //CAN_INIT();//CA初始化N模块' Y2 p9 l3 T% G4 I' C
- /* CAN register init */
+ R7 y$ U( y4 l- W - CAN_DeInit(CAN1); //将外设CAN的全部寄存器重设为缺省值
# ?- ~! `; K* u0 h - CAN_StructInit(&CAN_InitStructure); //把CAN_InitStruct中的每一个参数按缺省值填入( c* H1 L6 ^, I9 d! \
# t: j" q6 k7 c' n' U# T: |
$ V) J+ r" h$ ~" J ^
5 J5 g+ K* R# @' h- ! q2 K. `1 [2 T5 r4 j
- /* CAN cell init */! h3 S+ u' A' r$ Y% q% l
- CAN_InitStructure.CAN_TTCM=DISABLE; //没有使能时间触发模式7 t* W2 X0 Z, a3 W3 ]
- CAN_InitStructure.CAN_ABOM=DISABLE; //没有使能自动离线管理
& Z E/ }' Y# D/ b- x4 G; D - CAN_InitStructure.CAN_AWUM=DISABLE; //没有使能自动唤醒模式
) m8 {8 r7 g3 f; Y+ @& }) E: J - CAN_InitStructure.CAN_NART=DISABLE; //没有使能非自动重传模式9 Z- [0 }7 n. L. P7 T
- CAN_InitStructure.CAN_RFLM=DISABLE; //没有使能接收FIFO锁定模式6 g3 P' F" `6 ^$ G; Q2 Q }
- CAN_InitStructure.CAN_TXFP=DISABLE; //没有使能发送FIFO优先级
@/ m9 C$ q; Z7 d% o3 X( U - CAN_InitStructure.CAN_Mode=CAN_Mode_Normal; //CAN设置为正常模式: P0 L9 i6 s. a! m% Q9 R
- CAN_InitStructure.CAN_SJW=CAN_SJW_1tq; //重新同步跳跃宽度1个时间单位3 A5 c2 X7 y' a* i# u. n
- CAN_InitStructure.CAN_BS1=CAN_BS1_3tq; //时间段1为3个时间单位
% U4 P& N3 i4 g1 P$ R2 I$ [; A - CAN_InitStructure.CAN_BS2=CAN_BS2_2tq; //时间段2为2个时间单位% C T" E: M" K! j% ~ `) N3 j8 e, a9 _* R
- CAN_InitStructure.CAN_Prescaler=60; //时间单位长度为60# ~' Z ?* P( f3 e, G
- CAN_Init(CAN1,&CAN_InitStructure); //波特率为:72M/2/60(1+3+2)=0.1 即波特率为100KBPs2 U. t+ o$ r" R: v
- " s& v3 U- J/ f( E6 c% O
@0 u' u/ M' k: u. n" P0 x$ m5 S# B Y
4 e# n$ j+ ?+ P" ?- , B# h, W/ Q. X" G
- // CAN filter init 过滤器,注意,只接收主机发过来的数据,屏蔽其他数据
W7 F& \6 X9 A$ b - CAN_FilterInitStructure.CAN_FilterNumber=1; //指定过滤器为1
6 m' x. [0 g8 r - CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; //指定过滤器为标识符屏蔽位模式
9 M" t! W( p0 P! Y - CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //过滤器位宽为32位
. f& I# F* t0 \! b! f" \6 g. X
# K$ ^2 H' v, H g2 t+ K2 c! P- Z- ' q, E! U7 t& t: `0 ]
( [9 F" I# }9 F1 I2 f# E% S; `) A' i- 1 c9 o5 c- @4 b1 b8 M
- //CAN_FilterInitStructure.CAN_FilterIdHigh= (((u32)0x1314<<3)&0xFFFF0000)>>16; 4 ~! {6 E2 n) F) o' q* Y
- CAN_FilterInitStructure.CAN_FilterIdHigh=0X00; //要过滤的ID高位1 H, o Z1 }; X
- CAN_FilterInitStructure.CAN_FilterIdLow= (((u32)0x1314<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位
( p- h/ _4 N; x
4 j+ J1 J6 ^4 y# E) Q: G
. |/ a! S9 Y* ^' ?
# \" k9 I( T6 d- I: s9 \( u- ; E- e7 ?. |+ @
- CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF; //过滤器屏蔽标识符的高16位值
9 H* P a" v9 ~# X/ `! d* T' v- I - CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF; //过滤器屏蔽标识符的低16位值
+ I w3 w+ E, O( M - CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0; //设定了指向过滤器的FIFO为0+ `: ~4 [# _' i2 R( x" G
- CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //使能过滤器
7 |8 t ~2 O' X9 @% K - CAN_FilterInit(&CAN_FilterInitStructure); //按上面的参数初始化过滤器3 ]3 p* k( c1 K- z2 b8 }: O( a% { y
- 3 ?) K$ |8 Y6 G. u! c, @
- 0 O, C6 `8 F" L$ ]! I3 n9 G) Q, g
- 3 M2 ~& A& R, ?
& B# B j1 ^4 u( g3 ^+ A. L# I- /* CAN FIFO0 message pending interrupt enable */
& c. C. L3 |+ p9 V - CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE); //使能FIFO0消息挂号中断
& X. g. W- l, V L2 N4 K" e! k - }
2 o6 m+ L! h! j7 H' Z - . d4 i8 x* e; G% |% H& O, @" {
' |" w8 ?. I+ D2 q# A
' Q! }) N' D/ J; V v! B
" D6 f2 {# d8 G+ {7 L2 ~) e: s- /* 发送两个字节的数据*/. N9 }3 W" ~/ y$ F$ j; s2 Y
- u8 CAN_SetMsg(u8 Data1,u8 Data2)- g C. E5 A; K) G$ B# N
- {
) N3 |3 g, I5 r5 [ - u8 mbox;( n5 m/ c n3 s0 W* g
- u16 i=0;8 Q% }, `) `- y" K
- CanTxMsg TxMessage; 4 O' |- X) H) p2 L: X* Y
- 7 T9 r% r4 U( m6 ^2 u$ _' k) r
- 7 p! B* s. S0 D: }* c1 g& S& T
- 9 |) K( U. m: ]/ C, c6 q
4 \( }4 `& h$ m. h- TxMessage.StdId=0x0000; //标准标识符为0x00
. J, I6 t% |5 Q3 r+ H6 O - TxMessage.ExtId=0x1311; //扩展标识符0x1311,可以更改该标识符以示区分不同从机
" {, A0 s7 n0 Z( U# E1 N- o- { - TxMessage.IDE=CAN_ID_EXT; //使用扩展标识符
3 |, k% ?( Q. F& L) T! v - TxMessage.RTR=CAN_RTR_DATA; //为数据帧8 t; X1 e7 H/ f$ M
- TxMessage.DLC=2; //消息的数据长度为2个字节
- U8 L& e7 b; ? - TxMessage.Data[0]=Data1; //第一个字节数据
0 q) M- J# C0 X9 j0 ^# n - TxMessage.Data[1]=Data2; //第二个字节数据
- X2 K+ l2 x _1 X2 t& W
5 j* v7 u: v0 r5 p! x- 8 O5 Z- h3 {$ j- l0 @
7 m2 E D5 S- ?& E& s+ C1 V5 ^- 1 O! f) V# ^; ]4 c" w& ]
- //发送数据5 l. P- \6 D) h `3 `$ d
- mbox= CAN_Transmit(CAN1, &TxMessage); / I/ X5 F8 V! ^( j. ?
- while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF)): W& I+ ^0 }$ w8 D% Z
- i++; //等待发送结束, `7 F, x( x! `! u- c* o9 I h
- if(i>=0XFFF)
' a' ?1 G7 f3 N0 q - return 0;
' o% x; J0 E0 Z4 j - return 1;& E# d0 g, u- i& r: R, r
- }8 L( u, }. f8 I. z3 F8 E Z
- u8 CAN_GetMsg(u8 *msg1,u8 *msg2)
6 r* S& M2 B; y+ J) h& m - {' P0 i& [9 w N& @0 J; B3 D2 `
- if(Rx_flag == 1)//发现数据4 q# E/ U" S) H @) W% k7 M
- {0 @; Q* k3 _) ]' C5 D; @
- *msg1=RxBuf[0];- C, P- k0 a9 r. s- x0 r) _; _
- *msg2=RxBuf[1];
' e- V+ u. F/ b0 _5 ? - Rx_flag=0;//数据已经取走,可以更新数据* E( T) F" p" J3 |4 d. n8 b
- return 1;
* _# E; f# o. {" \& Y+ ] - }else1 \3 M+ A3 }* V8 |6 N5 a: t
- return 0;8 l# l0 k3 B7 {5 S. {
- } a Z; j( e* C; W7 ^2 U) a1 e3 }
- /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。*/4 C8 M6 L, Y4 G! y2 _8 q1 n+ D) U
- void USB_LP_CAN1_RX0_IRQHandler(void)8 u+ D* J% k( ~7 y( n) S
- {3 B2 L! I+ H, u5 L
* r6 u) z, ~# `9 {
; x% Y& U3 b6 r3 ?" B
" d. [! G1 E7 H1 Y! x* Z4 J' I
+ ?/ J6 p, o6 P2 ^7 \7 d- CanRxMsg RxMessage;
! n7 I) H& B3 ?1 u
3 I. l' A" w/ y* ~5 F
' N; W$ i! J! p) P. @- 0 F4 t8 I0 b6 A" V+ A
' Q/ `2 s4 K/ R& ^2 J. }6 T; R3 b9 x- RxMessage.StdId=0x00;( a. B' n0 I6 ~. w
- RxMessage.ExtId=0x00;
% n) H; `( {4 k3 _6 Z1 X - RxMessage.IDE=0;3 i* Y: r4 ]) P/ y! }1 U- c# D8 |
- RxMessage.DLC=0;
+ U. h4 `7 |# F2 |; C - RxMessage.FMI=0;: n3 E6 z7 S( B5 I: k+ |& M! q" R% x
- RxMessage.Data[0]=0x00;7 u& X8 W" |" t, i& D9 B
- RxMessage.Data[1]=0x00; * ~# U" ?% K- E! L" j
- o* M: j- o. ]* S5 C4 g
0 h, P8 B j: |' V5 Z/ J# E6 y
: ]8 w5 {. X' C4 Z+ W* m2 J
& q7 U; }# t2 o: F$ p- CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据 6 B" j* k% I; U3 x1 \, y6 w
) R! N8 C; [8 g9 o
" p" J! K7 U( Q8 t3 g$ W' u$ w- ; {" ?) G8 O; Y$ V+ f: a9 Q. E5 d X& ~
/ r7 e0 a. H( a: I. V- if(Rx_flag == 0)//数据已取走或者缓冲器为空9 ~# z1 F2 T! {0 ]" g
- {6 c4 G# {4 {. L; v2 U
- RxBuf[0]=RxMessage.Data[0];* i2 ~# [- i6 |/ l1 G. N
- RxBuf[1]=RxMessage.Data[1];
' J& _( z& [1 O, t6 X. W, h2 I4 g - Rx_flag=1;//数据已经备好,等待取走
$ p. r. n" P) u4 ^( R+ b - }
1 t; W. ^$ S- k; n - & Q4 x7 D4 l0 d( {& B
- ! B/ G% f5 G0 Q! F) x$ H. }$ [
- . {# b6 G* f: Q; x3 O( @+ L+ `
, T g h7 Y' }7 o- }
复制代码
4 K5 R1 j/ e/ g# w' Dcan.h文件3 e. q! k9 B# G2 B* H" R
1 A8 u+ v3 @6 R f+ \
( ~8 E4 w+ w+ v5 U! c
' `4 S" |1 [' S4 l主机相关代码
! ^0 | h' j+ y- {) k. Y6 v 这里主机代码大部分是和从机类似的,就只贴出不同的地方了。
$ `9 N3 L# p; P* x7 Acan.c文件:
: W: y" g" O( O+ ?. ~/ m% _( P- #include "can.h"4 x7 x, n$ n# I$ \
- q1 P; n& Y- b: l
/ s+ y) I$ ?9 H2 V/ W7 ~- /* 在中断处理函数中返回 */
) C+ E. {4 @' u7 W4 s i0 Q - //__IO uint32_t ret = 0;: x( D0 z$ K+ d6 V) ]0 Q
- 7 w: [ m% r- C: Y
- 7 [) d. M: t2 o# u
- void CAN1_Init(void)
0 D2 b5 e9 ?; c2 v8 P( G" Z - {- [2 k0 a' C2 f. a6 X
- ......//以上与从机部分相同
! z. p/ y, S0 _7 F0 H
) f' i. u F/ e! l9 T& U) _- + H7 ?$ m3 t+ t) ~+ t
- //CAN filter init 过滤器,已经设置为任意,可以通过ExtId标识符区分从机代号! T; m- ]3 W! m- J; B$ j
- CAN_FilterInitStructure.CAN_FilterNumber=1; //指定过滤器为1
- }8 ]. c9 b0 _% a - CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; //指定过滤器为标识符屏蔽位模式
; Z) Z7 E7 v7 O" L( g A - CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //过滤器位宽为32位* I! [, z# J8 {: Y& U5 n% Q+ h
- CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000; //过滤器标识符的高16位值
/ N9 j0 z! X9 p5 h - CAN_FilterInitStructure.CAN_FilterIdLow=CAN_ID_EXT|CAN_RTR_DATA;//过滤器标识符的低16位值7 t9 h; j' v# ?% [0 Q& z1 f
- CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000; //过滤器屏蔽标识符的高16位值& u+ V; d. E6 M. j: @
- CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000; //过滤器屏蔽标识符的低16位值
; i# ?: O: W$ g! i - CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0; //设定了指向过滤器的FIFO为0 p X9 Y/ {9 a
- CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //使能过滤器
5 P+ U. F3 W) x3 \( I - CAN_FilterInit(&CAN_FilterInitStructure); //按上面的参数初始化过滤器
/ P- a; ]7 |7 E) a- s
, f9 C9 Q& v8 j; n- 9 T* y: K" q/ O, q8 @& d7 {2 d
- /* CAN FIFO0 message pending interrupt enable */' E4 l h. ?# {) U5 p# q
- CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE); //使能FIFO0消息挂号中断$ W, d0 ?1 ~9 I8 P
- }
+ P3 g0 Y' J8 Y/ V' o
9 c0 A1 o- o6 y3 {
" u+ M1 O7 v2 T( u3 }- //接收数据缓冲器3 h6 N# }: j2 D+ H
- u8 CAN_RX_BUF[CAN_RX_LEN]={0}; //接收缓冲,最大USART_REC_LEN个字节.5 o1 q A5 Y0 ^$ G8 T9 {! C
- //接收标志位
3 C! \4 t& z: m1 G, c( D. I2 k - u8 Rx_flag=0;$ o( h" H6 d/ E) l
- /* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */
3 O; v! E+ E8 Q) H7 Y, T) e0 { - void USB_LP_CAN1_RX0_IRQHandler(void)
+ i8 ]+ G5 f _0 @5 k" O8 B - {% a2 G1 K/ }* _. M; ~6 b! H
- u8 i=0;2 k. p/ \2 s# f
- CanRxMsg RxMessage;; D, \ g# b, j. W& P) |8 C! y
% z* A( b1 @/ p' Y' R, s+ v0 F; E! Y- 0 @' x& M" r! N1 m
- RxMessage.StdId=0x00;
, K9 N) K9 _- T* |% p b - RxMessage.ExtId=0x00;6 |' ]( K) s8 M, S0 \# i& c+ d) n a
- RxMessage.IDE=0;+ l: ]4 d# D4 L" h' C
- RxMessage.DLC=0;: e( a/ ?0 K) r7 \2 K8 R; n
- RxMessage.FMI=0; r' A! b& S7 }, F% \6 s
2 E, r; k: Y' z+ \. a1 r" }1 h: A- 3 L" u1 H# B, s
- CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据 0 V& s# T0 F. J( u* ?, W1 t
- . R& n0 ^8 o; R; z. Y
- - z5 p/ X) K2 t2 x9 M. r
- if(Rx_flag == 0)//数据已取走或者缓冲器为空$ T& b9 W+ q4 U3 W$ a# V
- {
# H! |5 @4 e0 ?$ S: ` - if((RxMessage.DLC) == 2)//是否收到2位字节数据
0 E, X, G* Q( }5 @) K+ _ - {5 f3 C1 g3 J1 U$ r$ j: z
- CAN_RX_BUF[0]=RxMessage.Data[0];
) R$ o$ c6 m; C - CAN_RX_BUF[1]=RxMessage.Data[1]; / I8 d d0 G3 U/ t
- }, m2 P5 H5 ^7 C
- }/ Q' y" K* o" V* R
' U" c3 ?+ ^6 O; s+ Q" B6 S% u
+ m9 G5 d# I. w6 S/ X! B- }6 H# h, M. z: ]* Z
" l& b1 }! l6 d3 D, F- 9 G1 Q( z5 ]& b
- /* 发送两个字节的数据*/' P5 d X5 o3 l
- u8 CAN_SendMsg(u8* data1, u8* data2)
; o3 [9 A* s! d! i x4 H" N8 Y - {: W( w, p8 z5 O$ r
- u8 mbox;' a% x: ?! o e
- u16 i=0;4 {, U+ ^ l; z* a2 `
- CanTxMsg TxMessage; % T/ u! ~: i; ]% B/ s$ e5 y+ U1 G& t9 g
- ; h1 R" q: T% k( |- j9 f" G. P% d+ h" @
- 8 D3 d' d! g l- N
- TxMessage.StdId=0x0000; //标准标识符为0x00
# e9 v0 N0 \) H! E4 V - TxMessage.ExtId=0x1314; //扩展标识符0x0000
0 N: ^: s ]. a; j" N9 v# ^ - TxMessage.IDE=CAN_ID_EXT; //使用扩展标识符
0 B& R$ V' J* ?& m0 E - TxMessage.RTR=CAN_RTR_DATA; //为数据帧
8 v( C/ K& s' }* x. b% H1 C - TxMessage.DLC=2; //消息的数据长度为2个字节
, D& T1 U/ \" o3 G, `6 f" t - TxMessage.Data[0]=Data1; //第一个字节数据9 }- r4 I+ C9 T: y& Y
- TxMessage.Data[1]=Data2; //第二个字节数据: ^7 ?- }$ P. s$ l8 }6 v
) w: e9 g1 v: s, |9 j. N' e$ S
. [' ~/ w3 j/ _ m$ ^- //发送数据% M* L) Y; B! D
- mbox= CAN_Transmit(CAN1, &TxMessage); + B8 V4 w1 u# f8 F, c: S B
- while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))
0 f* v1 [; ]7 z- ~0 V, t/ f - i++; //等待发送结束
5 Z6 c" y* J& `/ x' Y* G - if(i>=0XFFF)
: M7 e6 o/ V) r* s; H4 D& y3 q - return 0;//发送失败1 l# [; {% o0 O# @3 Z3 I
- return 1;//发送成功
0 W3 q" B) M- y1 n3 I - }, [7 K& E3 p% F
- u8 CAN_GetMsg(u8 *msg1,u8 *msg2)
: G; w; W+ V0 K; |2 ^% q* w) i$ r - {
% ^7 ^1 f6 b" d/ i9 `: m. o - if(Rx_flag == 1)//发现数据
- s' F+ t: G* n) S6 C - {
m: M: j3 [" C, U& @6 y$ q - *msg1=CAN_RX_BUF[0];, w& [5 M4 b& q6 Z6 c: ]
- *msg2=CAN_RX_BUF[1];
9 F1 z/ k+ p, L7 r' z - Rx_flag=0;//数据已经取走,可以更新数据5 e/ H) a% n9 e: u% H/ h$ R
- return 1;$ U, c0 ~. S! i- J' v8 K q! F
- }else
& m. B2 b, ?$ X: a ?. J - return 0;
6 j, L& a# P2 Z; H7 Q8 u - }* |6 Y9 \! C/ m, U& r* `
- void Clear_canBuffer(void)2 ]$ @8 ^' M' X; P$ R E
- {
2 E1 i0 r8 i; M' r; k - Rx_flag=0;//清楚接收标志位6 f) [+ N: ?0 F0 Z% A" L
- memset(CAN_RX_BUF, 0, sizeof(u8)*CAN_RX_LEN);//清空缓冲区
4 F4 L& c- m2 |& H# _ - }" U) y4 B4 `9 @9 V" f% b0 m$ a5 K
- u8 Check_canRX(void)
/ k( W: W6 d/ l3 ]. X+ d) f/ G - {& ^; B6 s. a4 \+ q3 y# O# F N, N
- return (Rx_flag == 6);
2 T- R+ E& l5 d6 s/ h1 ~8 l$ O - }
复制代码 h: K, ?* h7 E% s3 x% q- r
/ F+ U, B% B* s/ T( I
can.h文件:8 d8 Q/ @& P; _
- #ifndef __CAN_H; B/ x& y9 ]* x
- #define __CAN_H7 i7 h# \- V( H5 Q0 S( A
( s8 B/ c; l/ f# x. f8 k* [6 y6 Y- 6 U* S. y6 d0 r: m1 |3 V- ^/ u0 z' Y+ m
- #include "sys.h"7 d- Y( Z9 V F! {
- #include "string.h"
1 W8 Z: {6 \. h7 L2 \+ w- A
/ J! }' F: s1 b; b- 8 `: Z* J% D) z2 J: D
- #define CAN_RX_LEN 30 //定义最大接收字节数
/ }' L2 D6 I8 n5 e2 U) M3 q - - @$ G' ?' T5 B3 K
- g7 Q3 u; z8 N; A6 n3 l- extern u8 CAN_RX_BUF[CAN_RX_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符& N% ~8 u/ j2 X& D8 `& U6 b
- ) @9 |4 ~( ] h5 O
- ' T3 `! W, ~' v0 W9 A V
- void CAN1_Init(void);: [% ~* l2 }% x, ]5 G
- u8 CAN_SendMsg(u8* data1, u8* data2);
7 ^8 ~3 f6 z8 F4 a" H8 Z- M" }' L - u8 CAN_GetMsg(u8 *msg1,u8 *msg2);6 B8 \2 ~4 m0 Y
- % o) ?( N9 {: K1 a
- 4 w8 e. R! W1 i& X: G
- #endif /* __CAN_H *// x/ J* z @" B6 `
复制代码 4 t( K9 L0 ^4 h# @
: Y& p. E# N/ i* }4 c& n' f转载自:单片机与嵌入式
7 _$ g9 t7 `6 G+ a/ h) f3 @+ ? x4 R& }4 D7 X* r: S
如有侵权请联系删除
A& I+ D6 G' p& V+ Y! d
# _( s( r1 f8 ~2 \9 Y" h- b: s, a' D0 h& H! u
+ f# X7 y: m/ n0 y/ C% Y! S
" _* f' h, @5 J, C, V |