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