本帖最后由 aimejia 于 2018-6-1 13:49 编辑
! G9 C/ O, e/ N; c$ v/ j' p7 ?& V% [) A
一. 开发平台与工具:
, z; h' G, k4 y6 u3 e4 |" p
% h1 q( ~: \; e# |& z1 H D1. 平台: STM32F103C8T6 48PIN工控板和自己设计的STM32开发板
: a, g6 ^; N# f7 J' q6 M
& Y) P% V6 g( Q6 }2. 软件: MDK5 UVision V5.14.0.0
' ~/ G r; V V; u: W- v
7 ]7 `! N9 o# q3. PACK: STM32F1xx_DFP——1.0.5(2014-03-14); f. b$ L' P1 s7 P
! l& d( Y8 g ]- E7 J0 q- N5 s" n
4. 其它:USB转串口,ST-Link下载器,
6 I7 V, f6 i$ ^) E$ ^ W/ N- R; r }( H* w& a' w
USB-CAN Adapter用于直接监视CAN口发出的数据,上位机有两个,一个是EmbededConfig for USB2CAN 配置串口、串口波特率、CAN速率等,另一个是EmbededDebug V2.0监视CAN口数据;使用顺序是先配置后查看CAN数据。2 U; W/ u! ?5 v( z* c6 f3 p7 a
4 i# H" w7 p# ?$ M3 ~* X
二. CAN总线的介绍简略:3 Q6 U5 J4 k; [5 p# ?
B) b( N( U9 x o I3 j, q; g
bxCAN 是基本扩展 CAN (Basic Extended CAN) 的缩写,它支持 CAN 协议 2.0A 和 2.0B 。它的设计目标是,以最小的 CPU 负荷来高效处理大量收到的报文。它也支持报文发送的优先级要求(优先级特性可软件配置)。3 U+ |; D& @! \, P
+ ^2 @/ L N" p4 T+ d/ U M$ g对于安全紧要的应用,bxCAN 提供所有支持时间触发通信模式所需的硬件功能。
2 B% \* c/ l" y/ s) V& B5 g: t+ N7 T4 j( X4 P' V7 i7 m* E
主要特点6 s$ S/ P( B: b0 [2 y0 m% g
· 支持 CAN 协议 2.0A 和 2.0B 主动模式; ?7 Z3 Y u; X7 [
· 波特率最高可达 1 兆位 / 秒) E# d- W# T: `. [; F
· 支持时间触发通信功能" x* H8 U) F* Y& t. g
/ F! a B) u* N# L$ h! H
发送
6 Q! A, d4 t* d4 z- U· 3 个发送邮箱# ~9 R7 \! o; }: X q
· 发送报文的优先级特性可软件配置( B) u7 D/ O- R1 Y8 U. H' J
· 记录发送 SOF 时刻的时间戳9 z. t* O: V) {: G
7 L1 m. X3 j- M( N S7 Y; b
接收3 I t$ d- G! T* l8 k0 }/ C
· 3 级深度的2个接收 FIFO
) V4 I) A5 {1 i- |: H· 14 个位宽可变的过滤器组 - 由整个 CAN 共享7 V: F' J3 X x8 V; [
· 标识符列表
. T; [5 F; U* A/ H6 @( a3 o. ~· FIFO 溢出处理方式可配置
& Y1 b( `- \/ L) S) x3 K- v· 记录接收 SOF 时刻的时间戳$ p: s3 i0 o4 M3 p% r" M) `
: c2 L8 ?) o! }, G可支持时间触发通信模式: J5 P- X& p; O
· 禁止自动重传模式6 l4 j4 v3 X: a9 Z3 t6 M9 F
· 16 位自由运行定时器* n+ W- @ H3 ?, L6 v
· 定时器分辨率可配置' m( A2 t. O, T& q
· 可在最后 2 个数据字节发送时间戳
b* \4 K/ \% f+ m* m
+ P: c7 e$ L$ ? F3 C. L管理2 @; _1 Y! m6 @9 [3 O4 D% H. H: I
· 中断可屏蔽( h* k# F. i& ]2 n7 {5 n
· 邮箱占用单独 1 块地址空间,便于提高软件效率
9 c) E9 {) X2 Q3 Q* q2 e% W7 S: v+ ]6 K: j* Y1 }
更多STM32 CAN总线介绍详见:STM32中文参考手册_V10.pdf 或 STM32F10XXX-RM0008 Reference Manual 英文版- p+ z7 p$ m3 a. V
0 j& }9 q! P; b3 I2 X三. 遇到的问题分析与解决:
. ~2 {1 w1 @$ u; N5 u5 s# T2 j( j; J4 O, p8 y# T
手上有两块STM32的板子,一个是网上买的MINI STM32工控板,另一个是自己公司设计的板子。二者有所不同,大致有两点,第一是串口,工控板用的是USART1 且用的是GPIO PA9(TX)和PA10(RX),自设板用的是USART2 且用的是GPIO PA2(TX)和PA3(RX);第二是CAN口管脚不同,工控板用的是复用功能映射到PB8(RX)和PB9(TX),而自设板用的是PA11(RX)和PA12(TX)。下图所示,两块板子部分原理图:/ n/ p1 c" @# R5 \
; C. M! P0 z$ e工控板
' i: D3 m5 x; A+ z* Z
* c; X: {. Y0 H) N. ]& Y& b* m. z: f% z% M! d* I+ x
自设板
* G- a5 G. p* c0 O+ R% D9 C3 Q* f7 @6 [4 ~5 A, J3 c
! e$ a: J& y! [现在我是在工控板测试代码基础上,用到自设板上,实现PC端串口与STM32 CAN双向通信,要做的是将USART和CAN口的GPIO配置对应到自设板上。
! |. M3 H2 Y; O" G3 U* z E
% \7 y. ]# N8 b( }首先,串口GPIO配置:
( J$ N5 J' Z/ o! N# q& C% F* _: }0 B6 ], R% N$ b
工控板# p, y l' j5 i/ G
- [objc] view plain copy' B% e! z# o7 V- B5 H0 t: K1 k
- void USART1_Config(void)
. x$ V( ^. M+ G - {
. z8 c) ^- n8 ]5 [; ? @ - GPIO_InitTypeDef GPIO_InitStructure;
5 R0 H! Z9 D3 @; F3 E - USART_InitTypeDef USART_InitStructure; , G! B* j, p) C
- ) d- q$ R2 P% p
- /* config USART1 clock */
9 ~& S4 V. a9 d; W0 g - RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
9 P0 I) H/ F6 \# Q. u5 \0 a% W - 5 [! K/ Y+ e0 S) R
- /* USART1 GPIO config */
" i5 Q: L' i, ?; q: g+ s - /* Configure USART1 Tx (PA.09) as alternate function push-pull */ ; ?# A1 j5 b* I! I
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
/ t: L8 f" V! I/ c - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 5 q' M3 ~2 I* U5 a+ ]9 I
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; ! F& a: p3 s! g9 V E; J
- GPIO_Init(GPIOA, &GPIO_InitStructure); k( m" ^0 v* H+ m# J1 P- Q
- /* Configure USART1 Rx (PA.10) as input floating */ + O# w1 `! n8 `- D+ y4 E; i
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
1 W# ]& L; |4 g9 n+ d1 h - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; 9 ^2 }! w& K/ U' U. D
- GPIO_Init(GPIOA, &GPIO_InitStructure); * {% c/ B) S. x) f, N' X1 _
-
Q: D: O3 ], V( P. m) Q - /* USART1 mode config */
! ^9 \+ p- i! d! x: l# M - USART_InitStructure.USART_BaudRate = 115200; * u1 u# l# _/ `/ V% Q k& {
- USART_InitStructure.USART_WordLength = USART_WordLength_8b; 0 H/ a9 a) H# ^9 I9 W
- USART_InitStructure.USART_StopBits = USART_StopBits_1;
$ V9 d% @7 D6 i7 m$ J; @* Y - USART_InitStructure.USART_Parity = USART_Parity_No ; : ]5 m" Y1 y$ _% ^, C4 B
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; % u4 u. |% c; V" s; x1 o5 H
- USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; 0 ?3 B2 b" i) T
- USART_Init(USART1, &USART_InitStructure);
& v- ]; g6 Z) d* X7 v - USART_Cmd(USART1, ENABLE); / Z `" F _. Q- G$ k7 Q `
- . \# h+ a$ |% f! v
- /* Enable the EVAL_COM1 Transmit interrupt: this interrupt is generated when the
# x4 n: Y$ z* Y2 s - EVAL_COM1 transmit data register is empty */ ! `, o! Y% C2 W- a- B' j# u
- //USART_ITConfig(USART1, USART_IT_TXE, ENABLE); # I4 g; w& }, f
-
% a; V2 [. |5 K5 i) D4 N - /* Enable the EVAL_COM1 Receive interrupt: this interrupt is generated when the
. ]6 _' V) u4 z' w) r) d! [" R - EVAL_COM1 receive data register is not empty */ - f; I! r& N0 T R
- USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); . ]7 E4 l7 b y3 x( V& J
- } ! z9 }; s. ]( }7 L) E
-
) Z$ C2 |. A/ i6 ]/ B& P+ R/ I* J - /***************USART1 ÅäÖÃÖжϷ½Ê½·¢ËͽÓÊÕÊý¾Ý******************************/
2 O4 A8 N2 D0 O% [, K - void USART1_NVIC_Configuration(void) ( F6 C. q& K; f1 D; S3 a' m
- {
0 L' R, q& ?2 X - NVIC_InitTypeDef NVIC_InitStructure; " e+ K, F/ }% Y
- & O3 u) n, f! k% c6 C5 j5 G/ h/ }
- /* Enable the USARTx Interrupt */
4 W) F/ [: m5 q8 t7 r$ Q! G - NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; " j# z. Y; J; O: W g% p0 Q
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; `' c$ [' Z) s& G8 L" ?# ^' R3 ?- u- E
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; : ]8 ^; ~/ U& s
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 5 f% w, Y0 _) E. j4 }. n1 s" W/ r
- NVIC_Init(&NVIC_InitStructure); 8 T0 x* n' Z3 s2 X. C7 A5 `. o
- } . o3 q0 Z! F& u: ^+ y
-
/ g* Y0 J: G0 F1 o/ y; {! z - /****************USART1 ÖжϺ¯Êý***************************/
$ ]& j( t* l( B( Z - void USART1_IRQHandler(void) o; @; r9 g3 W) {. d
- { 0 f' m3 {: O6 w3 Z
- if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
2 Y/ V1 m5 X$ Q' j- k - {
/ R F5 `7 @# W( M. N9 {) | - RxBuffer[RxCounter++] = (USART_ReceiveData(USART1));
4 \9 w$ U. c) D( f - }
( x1 ? @6 O( b6 U5 y4 o6 s - }
复制代码 USART1_Config()用于USART1的GPIO配置,配置到
+ h+ a7 [% u. Q; @; O! f: h * | PA9 - USART1(Tx) |
3 o$ l( q) ]& z" }/ D+ a* b) T: B * | PA10 - USART1(Rx) |- e! A9 J6 r7 Y: `1 M+ h5 D
* ------------------------" b" M+ }3 Q0 \$ x. f. {) j; v
USART1_NVIC_Configuration() 用于USART1设置中断方式接受发送数据
2 A3 s5 V; j7 j8 P
- @5 O8 i0 |% J$ Q7 R$ _# HUSART1_IRQHandler()用于USART1中断接受函数
% L' t* |( W% R n& L$ G' T }" \ n+ ?% @6 Y8 j' Z7 n
自设板" y% z: \# L" a [8 O
- [objc] view plain copy
, u: }, ?( g3 L9 g, ` - void USART2_Config(void)
: E M: t5 V6 {7 w& `; g } - { ; W* {/ a. s8 z2 P
- GPIO_InitTypeDef GPIO_InitStructure;
2 A7 M7 d: I% y - USART_InitTypeDef USART_InitStructure; 0 ?+ L2 F u+ x
- , l5 ~ m' K. ?, H3 {
- /* config USART2 clock */ % F$ N. Q0 O- a1 U* q
- //RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
- C: n! z. |: p! V) K) D - RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2 , ENABLE); / I6 ~+ [+ ~0 b2 a' L, D# ?
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
! S$ N, d7 X1 V# T - 3 A4 _ d3 d- Z* v+ Y5 n
- /* USART2 GPIO config */
7 W3 a1 O7 n! A' v1 Z, `1 @ - /* Configure USART2 Tx (PA.02) as alternate function push-pull */ + R2 E$ @/ |# D' ~1 r1 ~: P
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
) b5 D) w0 f2 f; S) K - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
8 l: J. t+ r7 g2 z7 U$ } - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
8 L# Z& B7 G- W: P. c4 T - GPIO_Init(GPIOA, &GPIO_InitStructure); 5 A, S0 r5 C! G' g
- /* Configure USART2 Rx (PA.03) as input floating */
. p7 R3 _! q& p8 s6 z: s0 h3 r - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; 9 h( J2 t1 s7 G/ @
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
8 u2 k; A' W( N! A" |& }, R3 }; I - GPIO_Init(GPIOA, &GPIO_InitStructure);
: J* k- f8 s& `+ c8 X) v" @7 { - , j$ g# w# `6 l6 G6 d
- /* USART2 mode config */ & t) Q$ V; L# E8 Q+ s1 u/ t, d
- USART_InitStructure.USART_BaudRate = 115200; " g2 g) j3 c1 g9 K/ F' m5 M
- USART_InitStructure.USART_WordLength = USART_WordLength_8b;
7 z) K4 F d& S9 F4 S1 F8 t - USART_InitStructure.USART_StopBits = USART_StopBits_1; 3 K7 M6 ]4 D: e6 ~' n
- USART_InitStructure.USART_Parity = USART_Parity_No ; [, \& F( x# L" c8 d
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
3 Y5 V% v2 K& r6 B2 }; f1 l: [ - USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
( Y* ~* q7 [" N/ r$ C6 `/ z& k - USART_Init(USART2, &USART_InitStructure);
% a6 R! X; P: _ - USART_Cmd(USART2, ENABLE); c, m- Y5 E3 j
- ) a( ]6 ?3 P2 F' E {5 L' r' ~
- /* Enable the EVAL_COM1 Transmit interrupt: this interrupt is generated when the ; m) u- d w8 Q* o; @( S% X3 G
- EVAL_COM1 transmit data register is empty */
% ]3 r7 |+ B6 c0 D' V0 i - //USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
/ q! }% V, n' d3 ?. C+ @ - ' M! |3 V- @" U' i, q6 H
- /* Enable the EVAL_COM1 Receive interrupt: this interrupt is generated when the + T6 O R' R* E) |/ G8 r
- EVAL_COM1 receive data register is not empty */
% l' @" _; g* y. t - //USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); ' Y J P! N# [7 Q; s/ x7 K$ M; S6 w
- USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); , y/ r4 w7 y4 |/ ?: x7 s/ H
- }
1 e: g# k- J; S' R' b" L5 k- _ - % T! @3 ~% F$ v0 L* g
-
0 {5 i: T Z/ \5 }; d0 g$ E - /***************USART2 ÅäÖÃÖжϷ½Ê½·¢ËͽÓÊÕÊý¾Ý******************************/ * W8 i/ D s8 n# P/ Y/ V
- void USART2_NVIC_Configuration(void) 9 w, {) O3 ~6 E
- { . N. y- A0 K. U' g& \! V m8 o
- NVIC_InitTypeDef NVIC_InitStructure;
% O; S& u* ^7 p! ~( ?6 Q2 h - 0 {6 `; ?% F3 `' X- [; E
- /* Enable the USARTx Interrupt */
1 {9 P/ K% ]6 N3 N* @ - NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
8 C a8 }7 c: D: E - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
, F1 G+ |, E: E1 a3 }0 q, U$ F - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
; m& }2 x. D' v0 g' ~& ~/ X - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 9 l6 U4 [' A$ M( q' `& i
- NVIC_Init(&NVIC_InitStructure);
; |$ x- \/ |( ~ - }
X' [) P/ Q, k5 C2 _( f- J7 G -
6 [, J( I+ J2 H$ `1 Z2 J" d% w - /****************USART2 ÖжϺ¯Êý***************************/
4 F! v$ I7 |' F9 s4 [ - void USART2_IRQHandler(void)
2 I( K% c* [ p7 E- m$ R ?6 P# f - {
. G d! F$ m7 t5 k' T - if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) 5 e8 z5 S+ W. v4 ~
- { 9 e( r% {9 a8 m/ g
- RxBuffer[RxCounter++] = (USART_ReceiveData(USART2)); 4 f- W6 p5 }1 I" L. X# q; m& _
- } ( p- h7 d$ `5 u4 g+ z
- }
复制代码 USART2_Config()用于USART2的GPIO配置,配置到
4 t9 ]4 G( t7 ?. Z' l7 M1 a) |4 E! v9 a * | PA2 - USART2(Tx) |
6 L* m9 R- C0 D * | PA3 - USART2(Rx) |; N" ?+ h$ V+ s o# w0 D( w
* ------------------------' H5 _0 }6 m+ \8 L6 R$ f
2 Z- F- Z0 d/ p& F" m
USART2_NVIC_Configuration() 用于USART2设置中断方式接受发送数据! T: v8 D/ W* ~: [7 _6 o6 H9 g; _
; ]0 a$ F4 x( e& ?USART2_IRQHandler()用于USART2中断接受函数7 V6 c3 b7 J) I
9 ~: f/ X# X2 T- [/ f
然后,配置CAN口GPIO
& h* {1 A: W% X
# m v8 m. R5 {8 D2 h* m* H# V工控板, L) n8 j, ?1 L( V3 _+ g3 P
- [objc] view plain copy8 s0 y( U0 P* a$ \9 \7 s
- /*CAN GPIO ºÍʱÖÓÅäÖà */ ) r- k) e9 ^1 x6 D) H7 V
- void CAN_GPIO_Config(void) & \ X$ s# _- o1 p. {
- { # J. S- X5 b& F+ A- o! G
- GPIO_InitTypeDef GPIO_InitStructure;
" X' u! Q9 a5 t. S$ b - /* ¸´Óù¦ÄܺÍGPIOB¶Ë¿ÚʱÖÓʹÄÜ*/
; x+ M* H8 }, h, e& N - RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE); 7 _/ Z. p" Q! ?- i
- & k5 |6 r" t% R! d6 { \
- /* CAN1 Ä£¿éʱÖÓʹÄÜ */
. ^& O; u+ I% `$ R4 Z; ~5 y. G - RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); 7 h# Y ?/ ]: Z) m* D5 \7 Y
-
) ]0 Y. Y. f, v5 h- p; D- J. ?9 Q - /* Configure CAN pin: RX */ // PB8 7 q. f% J. |/ J
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
5 a/ r0 J/ c# C/ t Q) \7 h* T - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 2 j1 X1 D$ ?4 ]3 |+ ?
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // ÉÏÀÊäÈë
3 }7 o4 j" ]+ Y0 r& Z; G - GPIO_Init(GPIOB, &GPIO_InitStructure); ) b/ X$ I9 A6 h. L( j3 \5 l. a7 W7 W7 g. D
- 2 r/ s# Z- e' l7 F A
- /* Configure CAN pin: TX */ // PB9
$ j0 p2 K/ }) @" `4 i - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 9 b/ ?5 I1 j8 l) x+ B
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // ¸´ÓÃÍÆÍìÊä³ö : }' V, Q. ?0 i$ w
- GPIO_Init(GPIOB, &GPIO_InitStructure); 3 A9 g% E9 k- ~! c2 K
-
~5 x# ]9 B/ T - //#define GPIO_Remap_CAN GPIO_Remap1_CAN1 ±¾ÊµÑéûÓÐÓõ½ÖØÓ³ÉäI/O ; x2 L, w J8 p1 u' G. Q0 l
- GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
$ i4 ^( g: p% |7 v: j# t. ] -
# M7 I* t; a; h# J2 z% k! M* J - * w. u, j* W. }4 P/ A
- }
复制代码 自设板) W9 s2 D1 W0 @$ f1 G$ t1 s$ h
- [objc] view plain copy" S l2 K" \2 u8 j0 u8 V+ R3 [
- void CAN_GPIOA_Config(void)
2 z. K0 q" _* [, _0 s - { & H. z7 f2 m" g0 V) n B9 W
- GPIO_InitTypeDef GPIO_InitStructure;
6 F5 x3 A/ m. [9 @) I! q4 w - /* CAN Periph clock enable */ * Z2 @8 u& y+ w$ ]
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE); 1 w. H, d& T$ U4 u' g
- // RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,ENABLE); 4 N/ `7 K7 }/ ?+ Q9 t
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); v) V% l" k# l$ q+ D6 w
-
$ x5 U3 w" d. d% u( ~. e2 k9 }6 x" W - /* Configure CAN pin: TX */
5 h1 Y. l# E/ h# {5 A - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
# A3 D* E( ?! H$ u: B a4 [ - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; + ~% H: j& `6 H+ I: p( H
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
7 C {% t# H% h% F - GPIO_Init(GPIOA, &GPIO_InitStructure);
/ c. A* }+ h7 F8 o* P" k7 } - /* Configure CAN pin: RX */ 6 {3 B& X1 a( q4 c @
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
. F/ z3 }# \9 a1 \0 } - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; - Y! G8 K0 R0 ?/ V7 s
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; / F& K) Z5 T) T8 t
- GPIO_Init(GPIOA, &GPIO_InitStructure); 3 B1 h) [+ Z i! C1 i
- //GPIO_PinRemapConfig(GPIO_Remap1_CAN1 , ENABLE);
9 h, [4 X5 \/ h1 v4 G - }
复制代码 /******************************************************************************************/
9 \1 H: a* Z5 d$ [6 q就是这里!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!) |- Q7 e! T" M- ~
出现几个小问题,但是却是致命的问题!!!!!!!!!!!!!!!!!!!! r1 S! w4 e! _" d' D2 ?6 \; g
9 I2 Z, v: y8 d! {8 b2 E4 D
/******************************************************************************************/6 K) n& P2 B2 b
4 k; N/ p4 e* e' j, T# I4 t# K第一配置GPIO_Speed:
1 T/ E7 y( a- p, P
# u0 c' E. l1 }/ y0 X O[objc] view plain copy- T; A3 ~! V% c5 e1 C) D7 Q* j
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //配置GPIO_Speed为50MHz 8 x& {; R3 {! k, O
如果配置GPIO时,省略这一步,会导致CAN口发送不出数据,工控板的配置是放在LED 的GPIO配置中,一开始忽略了这一点,之后用排除法试出来的;( ]3 _9 D* ]2 l s" A) y* h0 @0 ?
4 k; l: L ~9 g* F第二配置复用功能和映射与否:7 \. k1 z" B4 s* G) u
- [objc] view plain copy
# {5 O" ], h7 \# J& X - // RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //复用功能时钟使能
复制代码- [objc] view plain copy
' ^# g0 T. A; r - //GPIO_PinRemapConfig(GPIO_Remap1_CAN1 , ENABLE); //重映射I/O CAN使能
复制代码 上面两个被注释掉了,是由于:
8 r" |& y# g5 o. Y) ^3 M) s4 U& t2 g用PA11和PA12 用的是CAN的默认端口,而用PB8和PB9是用CAN的复用功能重映射端口。
1 P1 \2 w: G( c' B
0 `% U6 @+ c$ d6 m1 G/ x/ U- [objc] view plain copy- N: ?- c) @& G) D0 C+ ?& \
-
复制代码
/ {% }2 r o: S1 f& t) l3 j7 e4 j/ X' F2 U
具体:
B, W1 S# f w( R) d; P! Z& P-------------------------------------------------------------------------0 {3 |+ J( D- s% }8 Z0 ~8 `% c; H6 ?
4 l8 _2 C8 e# B默认模式
9 O% i9 U1 f7 [% U1 g! a3 h
7 l( _# _6 [0 P7 | /* Configure CAN pin: RX */
3 O% Z7 V& ]' x5 b
. q& o' K9 ~+ O! w+ n2 J7 }GPIO( i9 m! K) F+ ?
9 ]5 N- s* v2 c7 W
_InitStructure.GPIO_Pin = GPIO_Pin_11;
; j' ~9 ]# X$ p* q6 P9 i& y; K4 D4 Z- ^( M: s0 [+ R
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;7 o, H" X" c& Z
4 J( E+ B4 E% U8 z GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
8 F& n: X( `/ B G- c
5 G, _/ T0 i2 t( Z( x% Z8 a6 v4 D I GPIO_Init(GPIOA, &GPIO_InitStructure);
. C1 ^+ P# g# C1 s* G) c+ v$ `; R7 R9 A! m/ b' w; W$ P; w
/* Configure CAN pin: TX */
6 r$ ]0 [3 q8 K' g, g1 p0 x
0 j6 m- z$ a, | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
" s& Q! F/ S; g, S [5 C
; z- d' ^& v; g GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
) c& Q9 O" w3 f; l8 P
5 l. j6 y# B7 |' Z9 f0 j6 \" a GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;3 ^3 y6 D2 N9 l' G+ f
5 H4 a2 l, E2 |8 s" f GPIO_Init(GPIOA, &GPIO_InitStructure);% U2 |; E) m0 ~% j- r$ ]+ g Q
------------------------------------------------------------------------! I# A# N# v9 y: y0 r
/ H9 r) _. e+ R$ I4 }; ]重定义地址1模式
1 t: W" L G& Y
+ a3 l8 T/ @3 V! K0 D) ^/* Configure CAN pin: RX */: N6 p+ L2 ~9 H" ^8 K
7 ~4 H! a' g X) [4 b //GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
. c8 |2 e7 m" |3 N$ }7 m% m* L* c6 Z4 N* N( A* U, C# v' f
//GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;+ g! e2 Z. r1 a+ G
V4 z7 @( X0 G9 w //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;0 g* f' |0 U1 J" Y
+ G9 T1 Z8 ?6 q! w# ^. V* x //GPIO_Init(GPIOB, &GPIO_InitStructure);0 E8 Y) R7 K& m# f) i
8 y& k9 R2 P' j) z% S# G
/* Configure CAN pin: TX */
1 C, w% ]. H: z1 K
* K P5 ~. m6 u8 k5 f! {* l# Q //GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;, M$ H& m# f4 n' F# V
+ I5 y1 U7 I3 C; k //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;* K+ f: E! G: L5 Z/ o; f
" p( }5 ^" I/ T$ U //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;7 f' F. ^! f% [. C3 G ~
, i+ m+ l) p0 z& K% Y6 A# c: C
//GPIO_Init(GPIOB, &GPIO_InitStructure);
7 |$ E8 m* y3 E! |" m6 ~- { U* E6 c+ k" a2 s
/* Configure CAN Remap 重影射 */
: w" p3 l I& r: X/ x8 X l# M0 q6 F- S4 h
//GPIO_PinRemapConfig(GPIO_Remap1_CAN, ENABLE);- D! v( ~ _4 K' P( `9 ~
$ l' k( z1 Z4 n- S T
------------------------------------------------------------------------- 5 S' u9 e4 K$ K! n
1 Q3 y5 N, P2 }重定义地址2模式- M' y; D, i( P- }
* Z9 w/ h) L4 e /* Configure CAN pin: RX */
; j. z, }0 n' v. U7 P" `2 R% a
3 ]7 O1 P0 l' v4 I8 w* ~ //GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;$ I; w6 j1 B8 _8 u! G d
9 t& @. s5 X7 W
//GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
, F! U8 O* c5 v
v; g5 q+ d. S4 ^/ c- ?& ` //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
' t0 z3 |7 Y: a2 D; \: Z6 Q- C: k/ z
//GPIO_Init(GPIOD, &GPIO_InitStructure);: \% R# e% o2 T; S; Y, Y" O
4 ^. _8 L, _4 u7 r' i
' b {/ ~% m2 p8 ^* Y /* Configure CAN pin: TX */
2 o0 P& J a: W/ J2 M" e, c# X5 F/ j ] Z I
//GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
9 V' G7 z+ w5 {/ _
1 x; u' D3 \" w# u( R //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;' y+ M/ k0 \; K( c. z
3 N" F/ @2 c! R- W8 b //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
; x7 [3 O* T; O; k
1 w- B4 ]' S6 q- _; c //GPIO_Init(GPIOD, &GPIO_InitStructure);
0 f: K- M8 M6 d# ?0 {! e2 Y+ f+ O1 O$ a) ~5 [
9 G: T6 ?8 N7 {" ]
/* Configure CAN Remap 重影射 */& c3 `2 m* `: q
! h9 t: f8 J9 @: G, V" H0 Y# w //GPIO_PinRemapConfig(GPIO_Remap2_CAN, ENABLE);# Y0 o3 d; A- ~$ U. {4 e
4 l; g$ y& ?3 ^0 L+ c: L
-------------------------------------------------------------------------
3 f% C9 g6 h6 Q9 B1 I# U
! R6 q1 X( C% N1 a) T设置完 CAN 的引脚之后还需要打开 CAN 的时钟:2 [; T* p& K7 S6 F2 m
$ c4 x5 B2 Z/ v, G. f) |/* CAN Periph clock enable */
' i; e) q3 o6 [. W% g" M, }+ Q
7 m: {, v- g1 x: J& A$ w, h" b v: B RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN, ENABLE);4 `" P4 o' y: ` E4 B# i# p) y
$ d8 B) N+ F4 o+ u4 l第三CAN硬件部分:
8 h7 {$ c( T5 v0 p/ X
' L+ {- O. W r0 D一开始对CAN硬件部分没有过多的了解,后面经过一系列的试验,发现:
. @) p0 }( ~; H: v, t N
2 g4 P# C% }5 @1. 如果STM32 CAN TX和RX没有和CAN收发器连接的情况下,STM32的CAN TX和RX是没用数据发出的;
/ k2 i N* W% f* I& k; F9 v' _3 V/ G0 m
2. STM32 CAN TX和RX必须要与CAN收发器的TX和RX对应,即TX接TX,RX接RX,否则CAN没有数据发出,说明:之所以说这个问题,不知道你们有没有注意到,我的自设板CAN收发器TX和RX是反接的;
& Z8 O, V/ J% k9 | [1 `4 X# n' J0 t" U+ e9 O1 _
3. STM32F103C8T6-LQFP48 的CAN口和USB口复用,即用CAN口是需要将USB口断开,防止有所影响;0 K3 G" k3 e4 K' ]' o
7 G' q0 N5 v, w7 @; x5 l& g+ i4. 是我本身设备问题,我的自设板用的12V电源是我自己焊接的,不太可靠,电源12V时有时无的,所以最好烧写程序的时候点亮一个LED灯,可以显示板子的工作状态;1 o! |0 _- ?2 f$ }: o$ E% Y
A( D( }4 K" ^0 v5. 工控板上CAN收发器是用TJA1050 是5V供电的,自设板用SN65HVD234 3.3-V CAN Bus Transceivers,之前有所顾虑,怕CAN收发器不一样会导致其它后果,之后发现没有问题。" N# J4 k6 r/ r& \
# z& \, j+ D; c$ z; Y* X
- B. v/ Y1 S: O, K3 G G7 X/ G0 v7 q% \1 Q
以上为本人的一点心得,走了很多弯路。。。记录点滴,以此自励。
$ Y3 `" }& u+ S5 n9 Q% Q; y
( v" O1 m/ E7 r( ?& O
1 v) p" M2 {3 g7 G: ] Z
9 [( U" j# J9 ^; [3 [
7 R1 `6 a1 | p! P# e+ ?9 A4 s$ E: f
转载自sunnyhyh; N% }+ _! j+ S/ J6 r9 i
' q5 S1 w" R) A- l5 u! b! B
3 X3 r5 j! A0 G |