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