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