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