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