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