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