你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【MCU实战经验】STM32F407 Discovery开发实例心得分享

[复制链接]
仙人掌 发布时间:2014-4-19 11:11
      本人一直以来都在接触STM32方面的软硬件开发工作,最初的是做基于STM32F1的汽车电子相关的软件研发工作,有用到F1的一些基本功能,例如USART串口通信,IIC存储EEPROM芯片,SPI读写FLASH等等,内核的SYSTICK,NVIC,中断,强大的定时器功能也总是用到,尤其是CAN总线,其稳定的工作机制和强大的纠错,适应能力,最适合汽车电子等工作环境不稳定的场合。最开始的这些研发工作使我对STM32情有独钟,其强大的外设资源,能满足绝大部分的应用需求,丰富的系列产品,能满足预算和功能的协调统一。
1 @. E% w) w$ _/ [* ~      有了一些基础之后,我在网上看到了STM32F4 Discovery的出现,高达168MHz的主频,1M的片内FLASH和192K的SRAM,内置RNG和FPU等等,并且包含了F1系列的几乎所有功能,尤其支持USB OTG,强化了音视频解码,能做出更多的功能和有意思的探索。接下来就STM32F4 Discovery官方开发板,本人自己研究的一些过程经验和体会,分享给大家,限于本人能力有限,仅代表个人观点,还请大家多多指教。# p9 D  ~, U! n) q' E
   首先,对于开发方式,本人采用“MDK4.72 + 寄存器”进行开发,首先,此版本的MDK(keil)有在线纠错功能,让你能时刻看到自己写的语句是否有问题,虽然有时候的软件提示有少许BUG,但是瑕不掩瑜,还是很不错的功能,其次,新版本的MDK支持的芯片更多,可以方便你移植代码到其他平台上去。再就是用寄存器方式开发,这个纯属个人兴趣,我的方法是:比如我要写某个功能,我会先看官方或者网上一些高手写的库函数的代码,慢慢去分析他们的思路,和一些初始化或者配置的过程,最后总结出一个规律或者套路,再去看芯片的手册,找到相关寄存器,分析用到的每个位的作用,写出寄存器配置的代码,这个过程虽然枯燥无味,却能真正然你理解其中含义,非常清晰的看到一步步配置的过程,不会在云里雾里,所以我采用寄存器方式开发。这个适合时间充裕,想真正了解和学习内核的人。当然,萝卜白菜各有所爱。相关寄存器配置资料:
# v, ?/ W; R0 q) v- JSTM32F4_DISCOVERY    --   官方开发板的说明手册,外设介绍等等
6 Z  X' e# P. q2 n4 x! C2 MRM0090 Reference Manual  --  寄存器手册,也是寄存器方式开发重点要看的- B4 B1 Z$ O9 P
STM32F407数据手册        --   主芯片STM32F407VGT6的手册,主要看管脚对应功能,外设配置简介等
! b  W1 ^2 f2 K3 n/ y6 f* YCortex-M4 Devices Generic User Guide  --  Cortex-M4内核手册,包含NVIC,SYSTICK等等内核的详细说明
8 ~' O# z( I9 t5 K还可以去ST官网下载3.5的库函数,以及STM32F4 Discovery板的例程,经常看一看,借鉴学习下,非常有好处。, T  ]9 U8 u) l) z9 z1 X1 J
F4系列和F1系列的寄存器有少许差别,大家使用时可参考F1的相关例程,对照修改即可。/ o$ G. C, Z6 e- v+ ?

6 J1 V9 ]$ ~* F3 M( P2 U+ b% d4 q以下发表一些自己研究过程中的心得体会:若有错误,还请指正(以下代码均对应官方的STM32F4 Discovery板子,部分代码仅贴出最关键部分)6 U, G+ e8 w7 S: {% `
一,IO- A* t) R8 y4 X% J  Z' [
最开始莫过于控制IO口的电平高低了,从这里开始,F4的寄存器就不同于F1,例如初始化LED的代码:
. Z2 C# A, Q9 H+ A5 J//PD12:绿灯,PD13:橙灯,PD14:红灯,PD15:蓝灯
  m3 z+ e) o! `# K/ ]2 hvoid LED_Init(void)) a. L  f- k9 C9 U+ s2 D
{0 M! X. _' m6 @9 Y: i2 @$ O- H( [
   RCC->AHB1ENR |= 1OTYPER &= 0xFFFF0FFF;//设置PD12,13,14,15推挽输出
7 m  E4 s$ c. I9 b0 D: v  [; H3 y  GPIOD->OSPEEDR &= 0x00FFFFFF;//PD12,13,14,15速度100M% D+ k# x5 e+ _4 n- n5 H
  GPIOD->OSPEEDR |= 0xFF000000;3 E0 c. Q2 }  _1 P; \/ I* s
  SYSCFG->CMPCR = 0x00000001;//当GPIO速度超过50M的时候,使用IO补偿单元   
+ R' K# N, p& N% i6 Z: b$ m0 A  GPIOD->UPDR &= 0x00FFFFFF;//PD12,13,14,15无上拉无下拉; T9 F$ E9 |$ n8 L+ ~; }& c' P, T7 ^$ E
  GPIOD->BSRRH = 0xF000;//配置完成后使所有等保持熄灭状态4 M( _0 j& g: W
}
4 J/ L* ~: s- S( V2 [配置过程:
, q" q# y* p) k: d! W  y1,开启GPIOD时钟 2,配置IO为通用输出模式  3,配置IO为推挽输出  4,配置IO输出速度  5,配置上下拉模式  (其中,使用IO补偿单元不是必须,只是官方历程中写到,实测不加此句也可以)                                                                                                                                 2,相关寄存器为:GPIOD->MODER      GPIOD->OTYPER       GPIOD->OSPEEDR       GPIOD->UPDR9 d6 _/ E, F' g- e* \/ P: e/ _
二,USART
7 i7 {* v6 L- t' iUSART串口也是调试过程中,或者以后产品运行时与上位机软件通信的手段之一,十分重要,可以官方的开发板只有micro USB接到了USB OTG,虽说也可以配置通信,但是太复杂了,本人还没调通,暂时用把排针引线接到其他板子的USB转串口的芯片,再连接到电脑。
/ ^5 Z" L# ?3 w1 ?3 y& |% u- \) e注意:一开始我连接到的是USART1,也就是PA9,PA10,但是怎么也调试不通,一直在串口调试软件中显示乱码,一开始以为是波特率有问题,可是怎么也调不成功。后来我看官方开发板的原理图,才发现PA9,PA10已经连接到了板载的一个芯片上,可能是做USB设备的驱动芯片吧。所以我换成了USART3,对应发送接收引脚PD8,PD9,检查无冲突之后,仅更改引脚,使用之前的相同配置,调试通过。代码如下:
# }- A6 i8 R- GUSART初始化部分:) }4 z4 {3 j1 w1 ]) _: U
//初始化串口34 n0 b- B8 S, f9 o9 g
//USART1,6 84MHz  USART2,3,4,5 42MHz: p. @" Q/ v) E9 g9 V1 @
//波特率不通过参数传入,直接通过计算得到,并写入USART_BRR
; [7 _3 |2 ^. @$ ~& H4 Qvoid MYUSART_Init(void)
4 n; ]5 q9 |8 H7 Z) {+ R: u{
1 U/ }: n8 U' Y' D         //使能PORTD和USART3时钟
6 z3 a( X# Z; a+ L% _         RCC->AHB1ENR |= 1OTYPER &= ~(1PUPDR |= 0x00040000;  //PD9 上拉
5 Y4 `: ^8 v) s+ i' Q! b# Z& R/ _0 |         //复位USART3; M% Z, @; {1 V' r
         RCC->APB1RSTR |= 1CFGR = 0x00000000;! N5 D8 Y5 E! t) }- Q) B
  /* Reset HSEON, CSSON and PLLON bits */. P& W) a2 \; l# E8 F
  RCC->CR &= (uint32_t)0xFEF6FFFF;
' a, o: z2 U: O$ l6 s8 z  /* Reset PLLCFGR register */
3 ?1 E/ G. B4 L0 S: N  RCC->LLCFGR = 0x24003010;0 Q7 C0 n& w. `9 q7 h* e+ C
  /* Reset HSEBYP bit */& j" ?8 C' k" _. Y
  RCC->CR &= (uint32_t)0xFFFBFFFF;
+ d! w: S7 L( R, i% A  /* Disable all interrupts */
9 R3 a/ L) x7 m; S( d& E$ o: A  RCC->CIR = 0x00000000;# F9 _$ w( v, l! a' \
}
: P( I( m/ h. W) c0 D2 b4 \ 0 R0 i1 P8 ^" F; t: `, p
//STM32F4时钟配置
3 V3 c3 a4 }" S4 w% l$ i& k//关键是粗体部分的参数配置,此四个参数决定了配置后的MCU的主频,进而决定了整个系统的时基
$ R7 i0 b5 ^" D/ Q: _# M, E4 l3 d//配置完成后系统主频为168MHz,注意,板载是8MHz晶振,所以要在MDK的设置里写为8
' V9 \2 v% [; @0 B  V" U//还需要在文件stm32f4xx.h中第92行中把25000000改为80000009 x( S( J( s* d
/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */. r1 n1 C0 J5 f- x/ u1 `4 P
#define PLL_M      88 {0 n! ^: Y  J5 h$ d3 O* q
#define PLL_N      336
" ~  Z8 Z3 O9 T5 k, q/* SYSCLK = PLL_VCO / PLL_P */
+ H3 J. k( {& [) w) Z8 G#define PLL_P      2
& O+ l+ L$ m& r6 {2 v1 f/* USB OTG FS, SDIO and RNG Clock =  PLL_VCO / PLLQ */
( }9 P  t( w4 z! g6 @# _3 Q' G! i#define PLL_Q      7
, Q% w; p7 W& I0 l/ qvoid F4_Clock_Init(void)
  z' s6 @2 e- k4 H2 V0 u4 D{) K0 Y: V0 i' @0 D8 l
         /* PLL (clocked by HSE) used as System clock source */
% y3 S' L  h  Q% a' L __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
" x7 p9 [9 G3 H7 m+ S+ a+ I, N4 W         0 W6 g" `" V; g9 ^
         F4_Clock_DeInit();
2 V  w- w1 ^  h6 F: M9 u         
. ^1 _- s. C# V2 ], y( W$ w         /* Enable HSE */
, O8 k# B# a& V% c& T, Z% H  RCC->CR |= ((uint32_t)RCC_CR_HSEON);9 Q- p8 d: X1 I
         
1 a4 t6 q0 M  n! F8 \         /* Wait till HSE is ready and if Time out is reached exit */
5 x2 W2 @! d+ Y: M& u  do" C" T- \5 i* |; A2 R( R" |; J
  {
: l0 |9 t2 V& N& g8 b    HSEStatus = RCC->CR & RCC_CR_HSERDY;
, q" h& F/ X. E$ U- c3 P1 d, y    StartUpCounter++;
+ O5 [- G: b3 k! B( |  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
  y3 i* M/ l8 G2 `         
8 z7 y3 Y3 ^, c: C8 e6 ^) Q         if ((RCC->CR & RCC_CR_HSERDY) != RESET)
7 W" G9 x3 F; L- U/ N' }! i  {
& C8 P6 f3 H% l' p4 E    HSEStatus = (uint32_t)0x01;5 h- J8 b, j2 g
  }6 y% ?: L. D" i5 n& Z& D! {$ D3 N
  else6 p: z0 O, b5 b5 r) p
  {! B2 j% n/ ], X# E) S4 j
    HSEStatus = (uint32_t)0x00;" V6 ~" d) o& s- K# T* s
  }
- e5 T* X# n* H5 `0 ?6 ] 2 H9 d! R3 }. Q3 N
  if (HSEStatus == (uint32_t)0x01)
& v8 Y: f* u; c  {
2 X0 h* T; n$ U2 }' Z' _    /* Enable high performance mode, System frequency up to 168 MHz */: x# K$ q* {: I7 Z# s3 n: r
    RCC->APB1ENR |= RCC_APB1ENR_PWREN;7 d5 K. }! q( k/ a7 Y
    PWR->CR |= PWR_CR_PMODE;  ( e+ }' s6 o2 [, K9 y0 L

  x! Q  r0 O; x    /* HCLK = SYSCLK / 1*/$ e1 I0 t* Y6 u" {( c; s( Z
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;- {( u/ S) t5 ~2 Z" O8 |
      
% P" M; d. y9 l    /* PCLK2 = HCLK / 2*/
5 L' a; d' ~( e& K    RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
: \, o, w+ C- J: X2 m& t   
1 M$ D# r# X7 ^1 N0 h1 u  b9 L- g    /* PCLK1 = HCLK / 4*/2 x7 g9 G/ U$ r+ c; r, h! f& j
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;/ V) u2 e" f. B4 R& l/ q# Y5 r
: U( G7 @3 l( Z! g+ ^3 }( @
    /* Configure the main PLL *// h, v$ ~* p$ Q& W' L
<strong>    RCC->LLCFGR = PLL_M | (PLL_N > 1) -1) CR & RCC_CR_PLLRDY) == 0)& ^4 g+ }+ p4 [$ P' R
    {
  A. t6 E0 H( R% U3 g# y5 T    }) _! a- k1 H* i- r+ ?
                   9 t$ `: B) z% m7 }# I/ G/ z
                   /* Configure Flash prefetch, Instruction cache, Data cache and wait state */" V: Y7 a- R" m6 E
    FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
% c; c) F% l+ W' J1 \$ Y
/ A& N9 c1 b- k# b    /* Select the main PLL as system clock source */
% e! A# F: C- _% W" M+ H    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));2 Z: D7 W2 n- ~! q
    RCC->CFGR |= RCC_CFGR_SW_PLL;
9 A& {' ?9 \2 X  w5 }# H 5 ]0 k( I3 y+ t7 a% K% \( K
    /* Wait till the main PLL is used as system clock source */2 V* g) t/ n# b0 Q0 q
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
: ]6 m" H4 ], o& f' o9 \    {8 x& x# o1 e8 Z: ^
    }) H7 ]- B5 h; c4 c5 s, j  U6 [
  }) K( s0 d! c* D+ O/ N4 f+ R
         else' E$ F/ b* T+ }) E1 b3 ^
  { /* If HSE fails to start-up, the application will have wrong clock/ f2 Z5 r  h6 e7 k4 Z% \! c7 F8 l( y) V
         configuration. User can add here some code to deal with this error */" w7 ?  \) X9 W; x$ h
  }5 {2 ]0 E0 R8 F1 t
4 A3 [: o$ A) A2 x: [

+ ~! n" |; `# \. E  L说明:以上是初始化的关键部分,SYSTICK频率默认为系统时钟的8分频,配置好了时钟,自然就可以轻松设置SYSTICK了。: |% P' R4 K7 |8 \1 ^0 Y( Y" X" Q1 Q8 O* W
四,定时器 PWM 输出  ?  Z/ k! Y8 i7 h
STM32的定时器很复杂功能也很多,此处仅说说TIM4作为PWM输出时的配置,效果是控制LED产生呼吸灯的效果。                                  此处仅配置TIM4-CH4的输出,其余几路输出同理:
' s, _/ K, P! D9 b+ _$ t% u$ K# L//PD15 BLUE   TIM4-CH41 x* F0 @- ?: U7 V9 \. T5 ~6 [
u16 TIM4_CCR4_Val = 0;- \/ j2 Q, o; J% h: ?* B1 H. d
u16 PrescalerValue = 0;//预分频器值1 ]1 ]2 N8 l, A1 H3 K2 v
u16 pwm_tempvalue=1;
* q; A) q# P5 S* ~. S4 q6 y0 u0 q//TIM4-CH4 PWM输出初始化
. \: s$ Y/ e+ w8 ~" h  K//必须对PD15的IO口进行重新配置. j/ e4 _& \. X1 d
void TIM4_CH4_PWM_Init(u16 arr)# T7 x. p& B$ E3 i
{
# A- C; f( N: E        //TIM4时钟使能7 m$ \2 r; y! e
        RCC->APB1ENR |= 1OSPEEDR |= 0xC0000000;
3 r) `- Q1 m# Z8 L5 P5 W        //当速度超过50MHz时使用IO补偿单元. W/ S8 E+ W3 Z" G  _* f/ f- k
        SYSCFG->CMPCR = 0x00000001;" v( d4 k- e5 N, J
        //PD15上拉,PUPDR15[1:0]即31,30位  01ull-up9 j. L' W, v5 n* ^$ i/ p
        GPIOD->UPDR |= 0x40000000;3 k) @$ j8 r, l) U% \$ q
        //配置第二功能寄存器(必须开启),PD15对应GPIOD->AFRH  \# Q4 Q% G* d4 X
        //31,30,29,28位 AF2:0010# K1 b) m6 e) b. Z2 ^: }& v& l. r
        GPIOD->AFR[1] |= 0x20000000;4 a% F5 H$ H9 l! Y

/ r, Z6 F1 q+ @! v' n( _& f) B: \. w        //计算预分频器值1 Y8 w4 g7 _( r0 i
        PrescalerValue = (u16)((SystemCoreClock/2)/28000000)-1;        . J- [$ z! a0 t- S- Y3 Z
        //设置计数器自动重装载值
+ z9 {( W$ O/ y8 ?) T& J6 g$ D        TIM4->ARR = arr;9 j% u, g+ E6 v2 H: q" ~
        //设置预分频器分频值1 m& Z, z, |/ M5 x& Y
        TIM4->SC = PrescalerValue;
; Y, `& L! r$ X1 n0 |$ A8 ]        //时基配置:Bits 9:8 00:t(DTS)=t(CK_INT)9 K9 j+ t+ @3 d2 L; R6 B. ^2 F
        //TIM4->CR1 &= 0xFCFF;0 F- [  b$ C0 \
        //计数模式配置:Bits 6:5 00# b& n% W* k& l" p6 z
        //TIM4->CR1 &= 0xFF9F;        
. ~1 k. j! y+ P) q        //配置TIM4的CH4为WM1模式输出
& K5 B2 |5 _' B0 Y* _* N# [2 Z        //配置TIM4_CCMR2的OC4M(位14,13,12)为:110
+ l# C! A- V7 j3 I        TIM4->CCMR2 |= 6CCR4的值来该表占空比,从而控制LED的亮度
- M1 k; a& |8 a: p& s9 D) }- f        TIM4->CCR4 = TIM4_CCR4_Val;! t/ M8 I: ^" H0 f. u1 K
}# q! b" Q# E, d  ]- v
  k; j+ A8 F6 R0 c4 F
主函数中:
3 e; t: b( `: {& P$ l8 aTIM4_CH4_PWM_Init(800);//TIM4 CH4 PWM输出初始化7 R0 J" D; w/ _/ r6 l1 d+ ~
循环里调用TIM4_CH4_PWM_OutPut();  即可
  y% J( |' I) {7 q% e! H" i 7 T; g- k+ Y2 a& |( F) ]
说明:1,粗体部分是重点    2,IO要配置成第二功能模式     3,延时控制了呼吸灯的节奏,占空比控制了LED亮和灭的范围,这个可以自己多次设置后调试体会。& ~  A2 \5 w  s5 j6 O) W
6 j& S4 C2 y* x! Z; z; l
五,RNG 随机数生成器
3 f) g; |& o4 R4 o+ `, y这个是STM32F4比较有意思的一个功能,可以硬件产生一个随机数,更加方便易用,配置也相对简单:( j& C( t% b0 s7 _2 Z, y9 s
void RNG_Init(void)//随机数寄存器初始化
# U% w# G1 g' |" {1 o0 l+ ~{
' {. s/ N5 Z! J) y  RCC->AHB2ENR |= 1CR |= 0x00000004;
$ U$ s4 ]; h. _* ^! ~. a0 |' A  RNG->SR &= 0xFFFFFFFE;0 N( z2 q/ k( A8 [2 h, f- m% t0 j
  RNG->SR |= 0x00000001;  
8 G1 h! ]# W. N; K& x}
3 }' d3 q; d: a, U
7 ^% f+ D9 u1 x- C6 dint RNG_Generate(int y)//生成随机数$ _& w9 W4 m. v
{
( M% ^( I9 ~" c5 I  int x;
, T# \5 d. n' [  x=(RNG->DR) % y;  4 ~# _$ N- B/ \
  return x;; n& J' ~2 f- @
}
! d6 }/ Q7 O, @2 @- n2 V说明:开启相应时钟,简单的配置几个寄存器,然后再main中初始化:RNG_Init()就OK了,若要在其他外设文件中使用随机数,包含头文件rng.h,然后定义变量接收函数RNG_Generate(int y)的值即可,简单易用。
1 S+ x- m5 Z! w7 E" f- d------------END, B7 \! S( y) M& ?7 S( G- U; ^! M
对于STM32F429,我还是很期待的,比较自带了LCD,还有SDRAM,更多的应用可以被做出来,更流畅的跑系统和需要大内存的应用了,本想自己画个板子,接LCD,然后插在STM32F407 Discovery板子上的,可是硬件设计又是个难题,万一设计错误就无法使用了,所以STM32F429是个不错的选择,官方的开发板,外设丰富很超值。
8 c. S8 X; p3 x) D# Y以上是本人研究的一些东西,给大家分享,本人也是菜鸟,希望大家多指导,共同进步!+ o+ m/ v) M: H4 J1 l$ P' M, k
赞 收藏 2 评论4 发布时间:2014-4-19 11:11

举报

4个回答
仙人掌 回答时间:2014-4-24 21:25:40

RE:【MCU实战经验】STM32F407 Discovery开发实例心得分享

最近在研究F4的ADC功能,发现跟F1的寄存器不同,比如:
# v* K7 n8 ~+ ?4 U1,选择触发方式为软件触发时,F1的寄存器有对应设置的位,但是F4中我没有找到,也不清楚到底有没有?4 |! A. I/ ^0 h  J$ j1 V7 W0 Z
2,ADC校准,在F4的寄存器手册中找不到对应的寄存器的位,不校准,岂不是精度很差?9 c( S/ j6 E, ]* l2 j0 s
以上两个问题,请教下大家!希望有人能发表相关意见和经验!
bjybjy 回答时间:2014-6-18 17:12:57

RE:【MCU实战经验】STM32F407 Discovery开发实例心得分享

楼主你好,请教一下,STM32F407 Discovery USART CTS/RTS该怎么用,谢谢
youxiaoxiang 回答时间:2014-11-24 12:44:44
楼主你好。看了你的PWM 输出 做呼吸灯的问题。有一点疑惑。$ |7 i* N2 d5 E4 t! o
具体是如何调节的?
巅峰残狼 回答时间:2014-11-24 13:01:16
谢谢分享

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版