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