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