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