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