CAN协议基础知识
& w) x3 ~7 M! N6 ^) d7 _7 e9 NI2C.SPI总线多用于短距离传输,协议简单,数据量少,主要用于IC之间的通讯,而 CAN 总线则不同,CAN(Controller Area Network) 总线定义了更为优秀的物理层、数据链路层,并且拥有种类丰富、简繁不一的上层协议。与I2C、SPI有时钟信号的同步通讯方式不同,CAN通讯并不是以时钟信号来进行同步的,它是一种异步通讯,只具有CAN_High和CAN_Low两条信号线,共同构成一组差分信号线,以差分信号的形式进行通讯。" D( G( O* Y8 G* j0 p# b
$ g% G8 F% X2 h" lCAN物理层的形式主要分为闭环总线及开环总线网络两种,一个适合于高速通讯,一个适合于远距离通讯。CAN闭环通讯网络是一种遵循ISO11898标准的高速、短距离网络,它的总线最大长度为40m,通信速度最高为1Mbps,总线的两端各要求有一个
' M* X/ t! q& {* U
5 `5 a$ L: Z: n6 b“120欧”的电阻来做阻抗匹配,以减少回波反射。0 S D1 L) W4 E+ U9 c
: v: E" j; O- i6 w$ q
* ^( u7 s' T- Q6 D闭环总线网络. w" b; t1 Z3 v4 p: x
/ ~+ P$ K5 M: X a& w1 U1 a3 F1 \( \7 J
$ g( z9 t; C: w+ |
3 ]' W4 p2 D) t) t/ Q6 s* {8 ?CAN开环总线网络是遵循ISO11519-2标准的低速、远距离网络,它的最大传输距离为1km,最高通讯速率为125kbps,两根总线是独立的、不形成闭环,要求每根总线上各串联有一个“2.2千欧”的电阻。
0 n/ x2 n) u3 d$ R! d
+ F5 j$ f% Z6 R/ a: c* t! L2 n; } }: r
开环总线网络
) O2 n; j7 h; @
( N, G5 R4 ~% G0 A3 m
* u7 s- E0 ~& a
- j* }/ P; g( f! V: c: DCAN总线上可以挂载多个通讯节点,节点之间的信号经过总线传输,实现节点间通讯。由于CAN通讯协议不对节点进行地址编码,而是对数据内容进行编码,所以网络中的节点个数理论上不受限制,只要总线的负载足够即可,可以通过中继器增强负载。
* H) K9 u; P# l) x$ i, y/ T$ O
, J* M5 ]5 J7 L. |9 aCAN通讯节点由一个CAN控制器及CAN收发器组成,控制器与收发器之间通过CAN_Tx及CAN_Rx信号线相连,收发器与CAN总线之间使用CAN_High及CAN_Low信号线相连。其中CAN_Tx及CAN_Rx使用普通的类似TTL逻辑信号,而CAN_High及CAN_Low是一对差分信号线,使用比较特别的差分信号。当CAN节点需要发送数据时,控制器把要发送的二进制编码通过CAN_Tx线发送到收发器,然后由收发器把这个普通的逻辑电平信号转化成差分信号,通过差分线CAN_High和CAN_Low线输出到CAN总线网络。而通过收发器接收总线上的数据到控制器时,则是相反的过程,收发器把总线上收到的CAN_High及CAN_Low信号转化成普通的逻辑电平信号,通过CAN_Rx输出到控制器中。
0 A; x: v3 Q+ R6 I' ?9 ^6 j- t, C3 Y" i( N) }7 N" a/ h
( T+ r+ ^! p8 r5 ~差分信号
. B( L2 A. Y/ ^; w) w" u( W: A8 z! a4 ^7 w* p
差分信号又称差模信号,与传统使用单根信号线电压表示逻辑的方式有区别,使用差分信号传输时,需要两根信号线,这两个信号线的振幅相等,相位相反,通过两根信号线的电压差值来表示逻辑0和逻辑1。: r6 @) x }. r4 x
+ Z; H' N* {. k2 R( U
相对于单信号线传输的方式,使用差分信号传输具有如下优点:
2 K; m/ J$ ~' O# N
1 V$ [, h# B: N, M( N% i! _$ C* 抗干扰能力强,当外界存在噪声干扰时,几乎会同时耦合到两条信号线上,而接收端只关心两个信号的差值,所以外界的共模噪声可以被完全抵消。& }. P. m, E. y/ k& A: ?" o% t
* 能有效抑制它对外部的电磁干扰,同样的道理,由于两根信号的极性相反,他们对外辐射的电磁场可以相互抵消,耦合的越紧密,泄放到外界的电磁能量越少。
; [' @/ v; M) _; o* 时序定位精确,由于差分信号的开关变化是位于两个信号的交点,而不像普通单端信号依靠高低两个阈值电压判断,因而受工艺,温度的影响小,能降低时序上的误差,同时也更适合于低幅度信号的电路。9 ]+ A$ y* o6 }; }, r. T6 \ f6 T
* 由于差分信号线具有这些优点,所以在USB协议、485协议、以太网协议及CAN协议的物理层中,都使用了差分信号传输。
7 ?0 H- M" Y) ?& K( {
, E% E, x5 ^. E0 Y2 wCAN协议中的差分信号) V9 X9 _" H. h0 H; G
- T1 H" N1 [; Q, a0 sCAN协议中对它使用的CAN_High及CAN_Low表示的差分信号做了规定。以高速CAN协议为例,当表示逻辑1时(隐性电平),CAN_High和CAN_Low线上的电压均为2.5v,即它们的电压差V H -V L =0V;而表示逻辑0时(显性电平),CAN_High的电平为3.5V,CAN_Low线的电平为1.5V,即它们的电压差为V H -V L =2V。
& W! b' R0 ^: A8 p' A# G5 X+ q/ Q4 ?1 D- O8 e
/ z8 a% h3 @' E' O- z1 G4 n+ ^# u0 P
- H' L$ X8 d* M1 v% O# V( b6 h* x ^' O. U1 h
CAN 总线的特点3 B T$ N, Q7 `6 P
$ y& E- s* F6 A/ T( D) Z v0 s
CAN 总线网络是一种真正的多主机网络,在总线处于空闲状态时,任何一个节点单元都可以申请成为主机,向总线发送消息。其原则是:最先访问总线的节点单元可以获得总线的控制权;多个节点单元同时尝试获取总线的控制权时,将发生仲裁事件,具有高优先级的节点单元将获得总线控制权。1 O/ `. Q( p: _8 ^+ K
+ t- f5 {' K, v3 R/ }CAN 协议中,所有的消息都以固定的数据格式打包发送。两个以上的节点单元同时发送信息时,根据节点标识符(常称为 ID,亦打包在固定的数据格式中)决定各自优先级关系,所以 ID 并非表示数据发送的目的地址,而是代表着各个节点访问总线的优先级。如此看来,CAN 总线并无类似其他总线“地址”的概念,在总线上增加节点单元时,连接在总线的其他节点单元的软硬件都不需要改变。$ D Y: p5 V3 N5 ]7 ~' p
! x5 ~8 c; K( k: U, ?/ tCAN 总线的通信速率和总线长度有关,在总线长度小于 40m 的场合中,数据传输速率可以达到 1Mbps,而即便总线长度上升至 1000m,数据的传输速率仍可达到 50Kbps,无论在速率还是传输距离都明显优于常见的 RS232、RS485 和 I2C 总线。
0 @; N& C3 x8 i
& X1 O6 Y& i+ x& x+ M对于总线错误,CAN 总线有错误检测功能、错误通知功能、错误恢复功能三种应对措施,分别应对于下面三点表述:所有的单元节点都可以自动检测总线上的错误;检测出错误的节点单元会立刻将错误通知给其他节点单元;若正在发送消息的单元检测到当前总线发生错误,则立刻强制取消当前发送,并不断反复发送此消息至成功为止。 z8 n6 d+ k5 h
) {7 }: N; Y- A( M1 o: pCAN 总线上的每个节点都可以通过判断得出,当前总线上的错误是暂时的错误(如瞬间的强干扰)还是持续的错误(如总线断裂)。当总线上发生持续错误时,引起故障的节点单元会自动脱离总线。
! l( D" @) Z$ q- v, @! X
( k( a7 M( Q0 M2 e! t, |% iCAN 总线上的节点数量在理论上没有上限,但在实际上受到总线上的时间延时及电气负载的限制。降低最大通信速率,可以增加节点单元的连接数;反之,减少节点单元的连接数,则最大通信速率可以提高。% ^! b' Q4 Z* R, p8 \4 ~1 p
1 n6 ]6 j" f @
CAN总线的数据通信是以数据帧的格式进行的,而数据帧又是由位场组成的,其中每一个位又被划分为四段.即SS(SYNC SEG),PTS(PROP SEG--传播时间段),PBS1(PHASE SEG1--相位缓冲段1),PBS2(PHASE SEG1--相位缓冲段2).% M- l! j0 M3 h
3 o" j6 L/ j: T2 U6 D3 x
数据帧的结构图:
4 O& _; a5 j2 \* h/ K$ V
! w9 K( {1 h- `/ H/ L6 Y
5 z5 r* r" a% w' R3 Y
8 t: U/ t' U+ c% D9 t2 p9 |2 E图中D表示显性电平,R表示隐形电平.( J+ Y7 f) s+ Y* j' ~% M
% k0 f) p" `( a8 k& t7 ]
ID:高位在前,低位在后。
7 }, ^0 K! o# l: m7 p6 A( v- w! f* B, J
基本ID,禁止高7位都为隐性,即不能:ID=1111111XXXX。
8 z8 R: a, o$ ^/ t. `$ h$ F
( Y: n: Y; E! r/ f( uRTR,远程请求位。0,数据帧;1, 远程帧;
: r/ r4 Q3 ~% p% e- f. Y+ p7 f9 d% |+ w; H9 y7 c
SRR,替代远程请求位。设置为1(隐性电平);
+ H ?; R) L8 E J! t0 b! E
4 X% G. h0 U' c; I L' W5 Q eIDE,标识符选择位。0,标准标识符;1,扩展标识符;
/ \# D( y5 z, r5 _( G% _6 d9 _
r0,r1:保留位。必须以显现电平发送,但是接收可以是隐性电平。# `4 S% n% T( c0 b6 V% O/ n, _, x
; `# y m2 q( K, E% `% @
DLC:数据长度码。0~8,表示发送/接收的数据长度(字节)。' l9 {! E# n4 z" E0 ~0 [4 y8 P
3 `9 w" D. }& u. [' ?IDE,标识符选择位。0,标准标识符;1,扩展标识符;/ H9 C% b! R/ p! ]# w4 H k+ S% i
5 C! |9 H7 R0 I" b d. z/ y3 m
: M- d& O& O0 P
) C& ^3 {, H, ?& |; h. U, b: J
位时序分解% P8 C" J; Z2 p
! ^: [7 m4 M2 R5 i4 O* O' j# ^6 L
为了实现位同步,CAN协议把每一个数据位的时序分解成SS段、PTS段、PBS1段、PBS2段,这四段的长度加起来即为一个CAN数据位的长度。分解后最小的时间单位是Tq,而一个完整的位由8~25个Tq组成。
( d+ S' @7 b! q! h% V( `% [. y* l& G+ ^2 A; Q
5 B* z/ o+ t9 g: w7 c$ s8 F& [0 i2 H7 p% T/ y# a ]
) g9 Z; c% b0 A4 S/ \+ B1 b( x' G
! [3 V8 ?# b. U# Z: R/ V
STM32中的CAN接口
7 @* Y& ]8 n8 ~$ f. ^8 a
% {& d+ P4 T, n3 E* O S+ j1 RSTM32的芯片中具有bxCAN控制器 (Basic Extended CAN),它支持CAN协议2.0A和2.0B标准。该CAN控制器支持最高的通讯速率为1Mb/s;可以自动地接收和发送CAN报文,支持使用标准ID和扩展ID的报文;外设中具有3个发送邮箱,发送报文的优先级可以使用软件控制,还可以记录发送的时间;具有2个3级深度的接收FIFO,可使用过滤功能只接收或不接收某些ID号的报文;可配置成自动重发;不支持使用DMA进行数据收发。
+ v% E3 W: P" J d/ `4 e8 R- K& t. v- q7 G4 e3 V6 j+ {
6 m8 {% Q8 w! P& j4 o# k
: k3 O. ^3 y0 X: l ?3 U1. CAN控制内核
) e4 Z7 w6 P6 ], ]( a2. CAN发送邮箱0 m, R/ x4 c. y" N
3. CAN接收FIFO3 u: ~8 X' F Y' E* ~' l- V# A$ w
4. 验收筛选器3 g2 q# G! U- p8 G+ n# g# J
; s" b/ @5 E D. i2 G5 p( _ i4 J
STM32有两组CAN控制器,其中CAN1是主设备,框图中的“存储访问控制器”是由CAN1控制的,CAN2无法直接访问存储区域,所以使用CAN2的时候必须使能CAN1外设的时钟。
& l5 I( O, Z0 A( ?. E5 \8 U. f/ i$ s
STM32至少配备一个bxCAN(basic extend can )控制器,支持2.0A和2.0B协议,最高数据传输速率可达1M bps,支持11位标准帧格式和29位扩展帧格式的接收和发送,具备三个发送邮箱和两个接收FIFO,此wa此外还有三级可编程滤波器,STM32的bxCAN非常适应CAN总线网络y网络应用发展需求,其主要主要特征如下 :
: ^- _* ^: ?5 B9 }5 A1 c% a# k, r
* 支持CAN协议2.0A和2.0B主动模式
" B# f+ {: F# u2 l! w! H& G* 波特率最高可达1Mbps
3 }1 ^( X. _6 g" C- q* 支持时间触发通讯功能
& r# A$ P0 x0 u5 a6 Y+ E" {, O0 s. a% j0 X
数据发送特性:具备三个发送邮箱;发送报文的优先级可以通过软件配置,可记录发送时间的时间戳。
1 o( T" w6 [$ ~+ c/ }
$ Q. R! l7 u8 J' H数据接收特性:具备三级深度和两个接收FIFO;具备可变的过滤器组,具备可编程标识符列表,可配置FIFO溢出处理方式,记录接收时间的时间戳
4 b3 ^- c* l; q6 y3 Z3 V
: b0 b$ U2 U* M, \报文管理:中断可屏蔽;邮箱单独占有一块地址空间,便于提高软件效率。
4 e9 C+ `; g; F" U$ P
% X5 n4 \( G# A9 j& _本文的实验设计将利用STM32 的bxCAN控制器的环回工作模式,实现bxCAN控制器的自收发过程,并使用串口设备跟踪监视数据收发情况。
! R" m1 ?' d% I) Z- w: C) D% t3 j. c+ s G3 @9 X+ X5 y
程序流程如下图
+ \7 `3 ~8 C! z! F
& `' Q9 s6 L* R" e1 r) H3 _
1 T/ ]$ D4 L: H* N ?
5 ~' }6 W7 E9 T: K- O本程序设计主要围绕bxCAN控制器的初始化初始化配置展开,其要点罗列如下:
0 ]5 p& s) l7 v8 R/ }" s# e
: Y7 f- w0 r% P, B# i1 G1. 初始化RCC寄存器,配置PLL输出72MHZ时钟,APB1总线频率为36MHZ,分别打开CAN,GPIO和USART1的设备时钟。
* |: E& c! H* d) o7 p! B( u2. 设置CAN的Tx引脚(即PA12)为复用推挽模式,并设置Rx引脚(即PA1)为上拉输入模式,其中三个重要的参数如下配置:) t9 I, B% @$ D, {6 P: h% _
- CAN_InitStructure.CAN_SJW配置为CAN_SJW_1tq;* f& n0 a l( R, `4 M! i6 n5 ?- v
- CAN_InitStructure.CAN_BS1配置为CAN_BS1_8tq;% J+ W; T% F$ R+ r7 I" Z$ w9 x( u
- CAN_InitStructure.CAN_BS2配置为CAN_BS2_7tq;
复制代码 " U3 e1 o5 Q8 {* C# E' u9 E$ W8 L
3. 最后分频数配置为5,配置接受接受缓冲区标识符为0x00AA0000,配置过滤器为32位屏蔽位模式,过滤器屏蔽标识符为0x00FF0000.: F8 [. w* ~' f! k, E
4. 初始化USART设备9 k% }+ s% q+ U1 n" }$ f
5. 使用扩展帧shu帧数据格式,ID为0xAA,数据长度长度为8 _8 U! n ]. d! f! h9 `0 s
) Y: o: Q, e+ I; t) q9 }
6 Z( v3 C [% m1 G9 B. E
STM32的CAN控制器设计的重点集中在CAN寄存器组的初始化过程中,而CAN初始化的重点在于波特率的设置,过滤器的设置和位时序的设置,以下作详细叙述。
4 A& f+ W7 \2 P$ | d
6 z/ T# x6 W/ t. k+ p(1)CAN波特率的计算
3 |0 S0 J) u" a9 `8 a2 ~9 i+ S& k0 t6 F- _! Y0 y5 t
计算波特率是任何一种总线的zhon重要内容之一,CAN总线也不例外.从STM32微控制器的官方参考手册里可以查找到关于CAN波特率的计算公式如下.
% E0 c( }) u1 @0 h" r) n6 b' e" j$ e
8 I; r% h9 J8 [, v7 w$ j9 e4 D* J! u& [通过配置位时序寄存器CAN_BTR的TS1[3:0]及TS2[2:0]寄存器位设定BS1及BS2段的长度后,就可以确定每个CAN数据位的时间:& l. a" ~: \8 ?1 e r
( q6 P h" E' MBS1段时间:
+ K/ U* }/ L) S9 D
, K6 K7 w+ c) E) a0 `T S1 =Tq x (TS1[3:0] + 1),, M; k H& R) j
. B. F- b$ ~3 `+ l, s9 C, FBS2段时间:7 g7 i" o z+ [* ?
. S8 {3 ^8 } S: b8 PT S2 = Tq x (TS2[2:0] + 1),
0 O k* t: t1 `/ a' V& Z
6 O1 d* |- E* P: h: _- \7 u. u一个数据位的时间:7 h) Z- Q$ k' |9 X$ y: \
/ f' V1 ]' D: C# @5 R! w
T 1bit =1Tq+T S1 +T S2 =1+ (TS1[3:0] + 1)+ (TS2[2:0] + 1)= N Tq
( V8 G( \) g' L. T* _- u
" q& q% L0 G5 n6 j: r% H% g0 r其中单个时间片的长度Tq与CAN外设的所挂载的时钟总线及分频器配置有关,CAN1和CAN2外设都是挂载在APB1总线上的,而位时序寄存器CAN_BTR中的BRP[9:0]寄存器位可以设置CAN外设时钟的分频值 ,所以:
2 G2 o! @2 V( E3 _3 N5 T6 h7 h) `# {1 B' a; y) O
Tq = (BRP[9:0]+1) x T PCLK
r V1 N* c. K& ?, e* g5 k+ h: ]
其中的PCLK指APB1时钟,默认值为36MHz。0 O' d" r1 }* y# R1 h8 F8 m0 t
9 _! t) U, r+ m5 |0 u最终可以计算出CAN通讯的波特率:& i2 _9 B5 T8 e4 P6 s ]$ X
; X( I2 e8 O0 z1 c: w! y1 KBaudRate = 1/N Tq
/ h$ H' C# W7 m1 `' ~
) h7 ] w0 j+ B# z程序设计要点中强调的三个重要参数,其实是can总线物理层中所要求的位时序。共三个阶段,分别为SJW,BS1和BS2阶段,这三个阶段的时间长度都是以长度为tq的时间单元为单位的。这样可以逐步计算出CAN总线的波特率。因此要点提示中所要求的参数,实际上将CAN的波特率设置为450kdps。
, P5 i: T7 B5 E7 |3 \* f; ]/ G2 {& a; |- ^3 i) h
) y( h+ k1 o$ \6 a
过滤器的设置3 G) m% o3 J0 S$ X- E
# A; A! G" z; Y( N$ n
can总线没有所谓地址的概念。总线上的每个报文都可以被各个节点接收。这是一种典型的广播式网络。在实际应用中。某个节点往往只希望接收到特定类型的数据, 这就要借助过滤器来实现。顾名思义,过滤器的作用就是把节点不希望接收到的数据过滤掉。只将希望接收到的数据给予通行。
6 p4 p3 E! T, r/ z6 ]2 V* ?( C7 V
stm32的CAN控制器,提供14个过滤器。可以设置为屏蔽模式和列表模式对can总线上的报文进行过滤。当节点希望接收到一种报文时。可以用屏蔽位模式对can总线上的报文进行过滤。反之,当节点希望接受到单一类型报文时。则应该配置为列表模式。本机程序中使用了32位的屏蔽位模式。
4 O: t7 f; D2 [- O9 Y8 v) M9 l; o% j4 q
下面仅对这种模式进行解析。can控制器的每个过滤器都具备一个寄存器。称为屏蔽寄存器。其中标识符寄存器的每一位都有屏蔽寄存器的每一位所对应。事实上,这也对应着can数据。事实上,这也对应着看标准数据帧中的标识符段。0 N/ r# S5 @. F$ _: H; ?) s
3 |7 P3 @+ y9 O7 l0 s: @3 P2 K8 C如下图所示。
0 ?6 a2 u5 ]. i. g+ `
$ y! Y% E7 ]! O! m$ Q
/ u8 d0 w5 N9 J1 |( {* w$ C
- ^4 k4 [. ~7 h- {& J. [; G1 L此处重点在于屏蔽寄存器的作用。通过查阅stm32微控制器参考文档可以知道。当过滤器工作在屏蔽模式下时。屏蔽寄存器被置为1的每一位都要求can接收到的数据帧标识符段必须和对应的接收缓冲区标识位相同。否则予以滤除。以本程序为例。要点中要求将节点接收缓冲标识符配置为0x00AA0000。过滤器屏蔽标识符为0x00FF0000。
- u# x7 j' Q7 b0 `
1 M* y3 o* F5 g( \* m/ C. y% Q( b该节点接收到的数据帧的标识符段的位[23:16],必须和接收缓冲区标识符中的[23:16]匹配。否则予以滤除。但若满足了这一条件而即便如下的位不匹配。则该数据帧仍不会被滤除。正如本程序而言。即can接口仅仅接收标识符段的位[23:16]为0xAA的数据帧.
+ B! M! Q% T: w# V! A5 v5 F
: r% \, C9 w$ r; Y* u根据can总线物理层的要求。can总线的波特率和传输距离成反比关系。传输距离变化时,要根据位时序来调整can总线的波特率。
1 [' f% h) ]# M$ j' w' `: h, `
9 ^1 [) w( i$ C0 L3 g1 Z5 ^
. t% |7 P7 U0 ]. `
3 g2 [& J: I1 c+ L& @! R C
程序代码如下:
$ N0 _. |' S: _+ ?- X& `/ l% T- void RCC_Config(void)
6 N# _- V, Y, _3 z - {- D6 W9 R+ Y/ W+ @! z: h* t) i" Y
5 S, |5 E$ s# q5 p- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE)
5 |. y4 l9 i# w - , }( V! e% P4 l* G. p
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE)
( w/ s+ q6 V Q - 4 G% l# D ?0 V- }0 b4 q& m& u$ B
- }+ r8 t" \. \# _' B% _
- void GPIO_for_can_and_uart_Config(void)& G' F* ^. s6 K- ]" `+ `0 ]1 K
- {
4 k) g8 ?4 O2 w8 S1 n, N7 C1 ~! J! m - /*定义一个GPIO_InitTypeDef类型的结构体*/0 s* l9 W6 [( ~0 E& ]
- GPIO_InitTypeDef GPIO_InitStructure;+ y5 K0 v% Y: B4 s' F/ N
- ( c/ u- R- K* S! B y
" B! b" d. V1 Y- /*设置can的RX--pa.11引脚*/
5 p* v5 u* A$ a" o, G5 \ - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;/ y) b* O0 |, `& N. V; U
# n2 t" x1 [* g* ^3 d5 C- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;( Y6 d2 Y3 J9 D* o; {, O
6 k- f' N8 M; r+ I' w( o- k- GPIO_Init(GPIOA, &GPIO_InitStructure);( q, M3 }, a4 S6 ]( C7 y9 j) t9 ^- U
; L" ^. l$ B9 J8 W- /*设置can的TX--pa.12引脚*/( p s% T8 U, @5 G- e- F
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;4 x y; j/ J) \8 f, f, W( z x
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
; h8 ?, k2 H0 c; w3 f( p! A - GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
% O( F% W! n$ ^0 ^+ U1 \ - GPIO_Init(GPIOA, &GPIO_InitStructure);
4 _- i; O& v, |4 M - /*设置usart1 的RX 脚 -PA.10为父浮空输入脚*/+ ]* f1 w3 P- e8 r* m& v
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; p# V! L( s' G0 Z- s6 @' S& ~
) m! p6 A$ h/ Q: t9 e7 ~0 I6 ^- q- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;$ p. e4 M( v1 M! p" m' \: N
, h& W, {+ b9 N2 x- GPIO_Init(GPIOA, &GPIO_InitStructure);
~: q6 _/ s0 U* H q& q -
6 P, u9 W* t3 F - e7 e9 ]7 K4 e0 Z- S" \9 g
- u% K* o& ]0 W
7 U& M- K x0 s- K) A5 U: ^& ` K- }
# Q1 C5 [. G- j, O5 B' S8 n# u$ B -
# G3 J# d- k7 K7 D! `; H4 w7 `% o - void Can_Config(void)
$ B- j' h3 G( A; L0 p - {( g |* J4 F& j( L ^
- CAN_InitTypeDef CAN_InitStructure;: h6 x( c% b, m' x. b
- CAN_FilterInitTypeDef CAN_FilterInitStructure;( ^8 s. b A# K
- & S3 ?' Q- \7 M( R4 |
- CAN_DeInit(CAN1);
7 O% W* O1 ~: x) U* V! C, q' X" W - 1 a( j8 m1 U# d, N6 B
- CAN_StructInit(&CAN_InitStructure);) _" j$ H. d% m; K- j
- CAN_InitStructure.CAN_TTCM=DISABLE;0 n& c$ u* o; L9 r
- CAN_InitStructure.CAN_ABOM=DISABLE;
8 _) G, U' w+ A6 q - CAN_InitStructure.CAN_AWUM=DISABLE;3 J9 G1 D/ e6 e) I; L/ ?
- CAN_InitStructure.CAN_NART=DISABLE;1 P% E( E0 f# l5 n6 M9 f
- CAN_InitStructure.CAN_RFIM=DISABLE;
9 a6 U) ]# {3 @) k* i% I; a- u - CAN_InitStructure.CAN_TXFP=DISABLE;
) p2 p! s- f3 D }+ D2 G - ( g; F1 H: _" i) d) ^
- CAN_InitStructure.CAN_Mode=CAN_Mode_LoopBack;
$ n1 w* u0 q7 v# e6 ^ - CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;
6 V- p1 h7 t4 @9 I/ P - CAN_InitStructure.CAN_BS1=CAN_BS1_8tq;
9 L3 J. H& r7 Y; x1 c- W2 z+ o+ Y - CAN_InitStructure.CAN_BS2=CAN_BS2_7tq;
. M3 n4 B* K* k& q L. f' Q% }- Z - . Q0 K( @+ n% c) ~) M) A
- CAN_InitStructure.CAN_Prescaler=5;
' d- U& }' S1 ~7 ~6 N - CAN_Init(CAN1,&CAN_InitStructure);
0 t# _4 {, C: t: J; K - % s6 X% _( J0 W- _8 n' e8 |# u) V3 s
- CAN_FilterInitStructure.CAN_FilterNumber=0;2 s3 \2 s, ` v: b# b) R! F
- CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
$ o+ T+ B; Z% C4 q - CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;/ p$ k$ z) E8 k" g1 V/ ~
- CAN_FilterInitStructure.CAN_FilterIdHigh=0x00AA<<3;
0 u3 O5 R, U. z" q8 s' t. i - CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;; j3 P; M3 O- A3 U4 m+ e7 P( Y
- CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x00FF<<3;
: ]( n4 \5 i6 [ P5 j2 k. I - CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
# k8 B6 K' {$ {' @ - CAN_FilterInitStructure.CAN_FilterFIFOAssignment=0;- \7 {% w0 x* x. {% e* M
- CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
! c1 V! \0 D& D/ h: [ - CAN_FilterInit(&CAN_FilterInitStructure);
' U: g8 P y$ a7 }: ]6 m3 K -
9 V8 {# s' j, B6 A - }
* ^ p4 Z8 S, ]2 a+ l -
- B3 H. B- r% T/ c1 X# l - void main(void)( ~& R' S; c# b8 {$ z
- {8 m" K8 F& M- l
- u8 TransmitMailbox=0;
' A& u" f+ _; y, ~ - CanTxMsg TxMessage;" Q2 t% J" }4 A) ~& j) D
- CanRxMsg RxMessage;
; M" I2 J. U2 f$ o - RCC_Config();
2 m6 O$ ]& r* Z4 z, O# s) s8 ` - GPIO_for_can_and_uart_Config();
c9 X$ e! w% n1 V0 ~: e7 b% i- z - USART_Config();
& `/ X2 C" P4 P2 C$ L - Can_Config();$ F1 d2 ?% X; ]5 f- B& ` W# h
-
0 L2 {: N2 Y2 H, o! R0 E - TxMessage.ExtId=0x00aa0000;
" K2 C/ [$ F1 b9 Z, O) e X - TxMessage.RTR=CAN_RTR_Data;
5 Y1 C- [5 M6 v' a% M! V: f - TxMessage.IDE=CAN_ID_EXT;" r& \% w' n# ^
- TxMessage.DLC=8;1 W# B9 y/ M) P2 b
- TxMessage.Data[0]=0x00;
$ w1 C9 u) b6 X1 X, h - TxMessage.Data[1]=0x12;
* M! g0 W1 D" ^6 l2 g - TxMessage.Data[2]=0x34;
5 t" Y S7 p: F" T% ]' a - TxMessage.Data[3]=0x56;
( i# P, g! e% U- u5 d - TxMessage.Data[4]=0x78;
g# n8 \) v" Z% U$ S* \ - TxMessage.Data[5]=0xab;
6 q9 D8 g, C% J/ x9 P - TxMessage.Data[6]=0xcd;
- z# `5 A+ {8 D$ i( I( U8 O - TxMessage.Data[7]=0xef;6 P+ Z X" M7 K- y. p$ a1 p A
- - j0 T3 B2 S" H0 C. u
- TransmitMailbox=CAN_Transmit(CAN1,&TxMessage);
: {4 G. N3 M3 U+ E2 P - while((CAN_TransmitStatus(CAN1,TransmitMailbox))!=CANTXOK);+ ~6 G% t: a: _, a- j
- printf("rnThe CAN has send data :0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,rn",
0 Q4 h9 n0 `; V+ y4 X) a: M - TxMessage.Data[0],TxMessage.Data[1],TxMessage.Data[2],TxMessage.Data[3],
& N* Q' c# d% t" u& t2 J - TxMessage.Data[4],TxMessage.Data[5],TxMessage.Data[6],TxMessage.Data[7],);
* e" s) V; S& K' m- k7 q -
9 K% e! a- Q& t - while((CAN_MessagePending(CAN1,CAN_FIFO0)==0));
/ o; l1 M0 R9 M7 H" x8 K7 V6 W+ z - 4 b( ]. d6 j: D( `' R
- RxMessage.StdId=0x00;
O+ A/ Q# ? Y5 o - RxMessage.IDE=CAN_ID_EXT;
$ M- N9 \/ v9 o' c+ C - RxMessage.DLC=0;" S; i2 c0 O& p; U6 W9 H7 S
- RxMessage.Data[0]=0x00;+ u1 q+ R y) W; ]
- RxMessage.Data[1]=0x12;
' ^/ w$ `3 c# W" { a - RxMessage.Data[2]=0x34;
* z8 y3 Q" n4 t- N- Y" ?! O3 k - RxMessage.Data[3]=0x56;: u% M& z! s! U+ B2 Z3 I( `$ j9 x
- RxMessage.Data[4]=0x78;$ F& t) Y' t" W* z% b+ p- l* e
- RxMessage.Data[5]=0xab;
" O$ r- e: H5 Z Z+ y1 R- j& n - RxMessage.Data[6]=0xcd;: P( ~6 ?2 n, d3 e% E5 c [
- RxMessage.Data[7]=0xef;8 k# S9 C+ e' t& n9 @ D/ f
-
9 y( m, ?' m! d! @( p - CAN_Receive(CAN1,CAN_FIFO0,&RxMessage);* R" M' N. Y9 ~6 k. z
- printf("rnThe CAN has received data :0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,rn",
# V! S) T7 C0 F( i# Y - RxMessage.Data[0],RxMessage.Data[1],RxMessage.Data[2],RxMessage.Data[3],* V6 e! i9 E" w& o6 k s
- RxMessage.Data[4],RxMessage.Data[5],RxMessage.Data[6],RxMessage.Data[7],);% v6 L6 l# @) X* \3 H$ P! D
- while(1);
* B: [8 k3 {1 ? - - s) Q2 t5 u( e" W. ]7 V1 t2 j
-
1 o4 g5 i, E( C( g$ Y - }
复制代码 % k6 ]$ z' U) Z( D/ Z
" G Y, t& t, f
- d5 Q* M2 k& | x* o3 l: ^
|