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