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