|
CAN现场总线的应用最重要的就是其接口端口映射、初始化及数据的发送、接收。 1.接口映射 STM32中的CAN物理引脚可以设置成三种:默认模式、重定义地址1模式、重定义地址2模式。 CAN信号可以被映射到端口A、端口B或端口D上,如下表所示,对于端口D,在36、48和64脚的封装上没有重映射功能。 8 Q S( \# K; d, n* A7 P9 @
表1:CAN复用功能重映射 重映射不适用于36脚的封装 当PD0和PD1没有被重映射到OSC_IN和OSC_OUT时,重映射功能只适用于100脚和144脚的封装上 ---------------------------------------------------------------------------------------------------------------------- 默认模式 - /* Configure CAN pin: RX */2 U: ?4 a5 d3 `. B* u! d# y
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
1 z8 I% f- s0 I" L' C' O - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;: }+ K- l$ h0 V! [
- GPIO_Init(GPIO_CAN_Key, &GPIO_InitStructure);4 @8 E7 t( Z h9 M6 k: T2 z3 I
-
d6 V( ]; A% `4 r - /* Configure CAN pin: TX */
/ o. V1 l x" n3 K( m1 @8 J - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;' o0 d% a: \+ x
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;4 L- t& I c# f* j
- GPIO_Init(GPIOA, &GPIO_InitStructure);
( U- E$ d3 P) x
复制代码---------------------------------------------------------------------------------------------------------------------- i- V k, |: K$ W9 c8 |$ t
重定义地址1模式 - /* Configure CAN pin: RX */9 {# A2 |( ?( X# @" c+ f6 n4 P' m6 }
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
6 j' R, a# H, O& o0 b0 I - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
9 e& q0 R* i% K - GPIO_Init(GPIO_CAN_Key, &GPIO_InitStructure);4 d: g1 E# d' X3 L, T' v; p
-
: S7 W1 C# @& z& x( W - /* Configure CAN pin: TX */" G( S5 D' ~8 w, |) M* L; d
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
" j% Y- N! N! K& F - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
8 K! c$ C" ]" b! G - GPIO_Init(GPIO_CAN_Key, &GPIO_InitStructure);
! I# e; ^3 D9 U -
2 r7 P0 l3 u+ k8 H( [4 S - /*Configure CAN Remap 重映射 */- D' i8 N% D" F" W v7 l @( C* n; @# L
- GPIO_PinRemapConfig(GPIO_Remap1_CAN,ENABLE);
- h/ e% r a# G. I - ----------------------------------------------------------------------------------------------------------------------
$ A0 ]& k9 [* R3 n - /* Configure CAN pin: RX */
5 _) v; V8 F/ k% }% p - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
$ i7 P, \# U( w; e/ \ E m - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
8 W5 z; L! l3 W9 ?, _, t - GPIO_Init(GPIO_CAN_Key, &GPIO_InitStructure);
9 y& F) T% i( w- f, C+ Y -
' x+ V1 J: L' Y. H# X! q+ | M - /* Configure CAN pin: TX */! Y, h+ h. P6 d
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;/ Y# k/ W' B5 z% M
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;3 e6 [; m- K5 W# n* h) @# a2 l
- GPIO_Init(GPIO_CAN_Key, &GPIO_InitStructure);
# f% J7 o& P- _) k2 u" {; I& W' \' ` - 9 a' x* ~9 m/ n* ]8 |
- /*Configure CAN Remap 重映射 */$ u/ F- ~! `3 q3 E6 S1 Z! F
- GPIO_PinRemapConfig(GPIO_Remap2_CAN,ENABLE);' e9 L9 }# k0 V X6 z
复制代码----------------------------------------------------------------------------------------------------------------------
c6 |3 y8 b! d设置完CAN的引脚之后还需要打开CAN的时钟: - /* CAN Periph clock enable */
" s x/ E6 A1 Q7 b - RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN,ENABLE);
. t3 r6 V ~: X4 U" M* s; P5 u: x1 V
复制代码2. 初始化2.1.2 CAN报文过滤器初始化 STM32共有14组过滤器,每组过滤器包括了2个可配置的32位寄存器:CAN_FxR0和CAN_FxR1。 可以将过滤器组配置成屏蔽位模式,这样CAN_FxR0中保存的就是标识符匹配值,CAN_FxR1中保存的是屏蔽码,即CAN_FxR1中如果某一位为1,则CAN_FxR0中相应的位必须与收到的帧的标志符中的相应位吻合才能通过过滤器;CAN_FxR1中为0的位表示CAN_FxR0中的相应位可不必与收到的帧进行匹配。 还可以将过滤器组配置成标识符列表模式,此时CAN_FxR0和CAN_FxR1中的都是要匹配的标识符,收到的帧的标识符必须与其中的一个吻合才能通过过滤。 对CAN报文过滤器的初始化实际上就是对接收FIFO邮箱标识符寄存器(CAN_RixR)(x=0,1)的设置。这些寄存器如下图所示: | 31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | | STID[10:0] | | | r | r | r | r | r | r | r | r | r | r | r | r | r | r | r | r | * [, b4 c+ f/ B( H2 o$ ], B
|
/ }2 f6 @8 O) d& T6 S p" D |
9 E% _$ j! F- p5 `) B9 g0 ^! b5 V | . C: A( i9 e5 f4 L! U
|
8 Y: T \* b. X/ o, C9 k! N j: j |
, p1 q' Y. B/ B3 h | : L3 P8 }- I7 m: }2 I( r+ n
| ' g) i M' P+ y1 R. Q
|
# L9 N; W$ j6 E3 g6 z8 L0 _% u% j |
& c: N; [! J/ I! s, Q | + e0 Y4 U( m! v( H
| 4 K; a; R+ k* H& Y |/ p6 t3 t
|
. C: r5 T' f. z8 b/ l7 d7 } | " _. N* e& G/ ]' d- S- J) |& @! o) z
| , N" z d/ A8 y7 {
|
+ A; [# H9 |( E | | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | | EXID[12:0] | | | | | r | r | r | r | r | r | r | r | r | r | r | r | r | r | r | r | 6 K3 d. I0 q5 m0 V; C
CAN_RIxR寄存器各位域定义: | 位 | | | STID[10:0]:标准标识符 标识符的标准部分 | | EXID[17:0]: 扩展标识符 标识符的扩展部分(如果使用了扩展标识符) | | IDE:标识符选择 0:标准标识符;1:扩展标识符 | | | | | " e/ T) t& c1 u& M* L/ H% i+ c0 I
注意:CAN_FilterIdHigh是指高16位,CAN_FilterIdLow是低16位,应该将需要得到的帧和过滤器的设置值坐对齐起。 采用stm32f10x标准外设库时过滤器的完整设置如下: - CAN_FilterInitTypeDef CAN_FilterInitStructure; //定义一个过滤器5 X% O, Y6 c$ y& Z
- CAN_FilterInitStructure.CAN_FilterNumber=0; //选定第一组过滤器
/ w: Z* h' [5 G& K- J - CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;//屏蔽位模式: `/ L7 u, h- }/ p2 s0 ~
- CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位
, O' k8 d) B" E. a - CAN_FilterInitStructure.CAN_FilterIdHigh=(0x0010 << 5); //接收ID为10的消息,11位标准帧因此左移5位
/ w2 K4 n) {- |; ~+ n+ `4 { - CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;; J! o5 y1 U y: g
- CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFFF;
( n) @$ O' F5 T# K* m2 D - CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFFF;
# [* O2 h1 G) F2 u+ A' ~ - CAN_FilterInitStructure.CAN_FilterFIFOAssignment=0; //第一组过滤器指向FIFO0
( R) G& i- U% G- I" D P- C* g4 v - CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
6 R) z1 ]: ?1 r) }. K; o! w9 P - CAN_FilterInit(&CAN_FilterInitStructure);
. A1 f/ i4 O7 M+ g) ~- C, a6 T
复制代码3.数据发送 CAN_Transmit()函数的操作包括: 1. [选择一个空的发送邮箱] 2. [设置Id]* 3. [设置DLC待传输消息的帧长度] 4. [请求发送] 请求发送语句: CAN->sTxMailBox[TransmitMailbox].TIR|= TMIDxR_TXRQ;//对CAN_TIxR寄存器的TXRQ位置1,来请求发送 采用stm32f10x标准外设库时CAN发送的完整方法如下: - CanTxMsg TxMessage; //定义发送信息
1 [2 E- Q, F ` k - TxMessage.StdId = 0x0110; //设定标识符(采用标准标识符时,硬件会自动把数据左移5位)
0 k0 `( [6 n' }+ e - TxMessage.ExtId=0x0000; //设定扩展标识符(非必须,采用标准标识符时可不设定)6 K$ G7 I$ o, m
- TxMessage.RTR = CAN_RTR_DATA; //设定待传输消息的帧类型
; J1 O9 C1 i8 ?8 ? - TxMessage.IDE = CAN_ID_STD; //设定消息标识符的类型3 p3 s- D% ]; G
- TxMessage.DLC = X; //设定待传输消息的帧的长度" D, x* u4 W, D2 W
- TxMessage.Data[0] = 0xXX; //写入要传送的数据,最多可写8个字节
1 r) j" I2 A0 k7 u) Y! K/ m - .4 V- \# ^4 a: f3 }$ ]! v2 k% k9 N9 V
- .
% z& q, Z& U9 T( f2 G. u - TxMessage.Data[7] = 0xXX;; Z3 K3 v6 K1 t1 k0 L) i2 S2 c9 s' u
- 2 m- {( q8 g" x" `' Z4 ^& }3 v
- CAN_Transmit(CAN1, &TxMessage); //开始一个消息的传输
9 {0 T3 E* r7 i* m
复制代码4.数据接收 0 k0 ]+ T( t2 D% w: w% B/ A
CAN数据的接收可以放在一个中断中,以下为一完整中断接收程序: - void USB_LP_CAN1_RX0_IRQHandler(void)
" s5 a3 v+ I; @% D8 A, E5 r - {
& f' a* [. ^ U! o( K - CanRxMsg RxMessage;& M4 p+ W* g1 @) T$ A7 f3 L2 C
% v5 Z) R3 |7 g! ?# ]% u& A1 e- RxMessage.StdId=0x0004;' i2 Q9 a' {. u$ L2 V
- RxMessage.IDE=0;
7 J! T. L9 P0 ^ - RxMessage.DLC=2;
# H; n* k6 G. ~/ I - RxMessage.FMI=0;
) z# l* v% \% Z - RxMessage.Data[0]=0x00;
5 x* B. O+ P: h: i8 X, } - RxMessage.Data[1]=0x00;* Y4 P8 J4 E6 f5 \8 C2 j; G1 @
7 m v6 K. z0 X) T# n$ |( P* f- CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);. I5 ^( i% u5 f
- % y6 ~* N6 b; W7 N
- CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0); # u) y* D9 b; o
- }
W) G Z% U0 Q
复制代码
- z7 u: A$ }& w 4 Y5 T/ i% r3 |" P
. \$ @1 u# E# N0 H, J
& M {' W# w% h$ h* t |
Y* s. a- n, A8 q4 ~; L9 {
冗余双CAN现场总线STM32F105开发板KeilC++源程序,欢迎 大家 交流交流
https://www.stmcu.org.cn/module/foru ... 916&fromuid=33990245 [. Q1 S0 }2 g% ^" D' R, f6 p" n5 b
(出处: 意法半导体STM32/STM8技术社区) ~; r% n, x; p ~- J# S6 t
+ i3 r6 {& ?: s- }. E