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