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