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