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