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