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