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