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

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

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

, z- N4 n8 A  }+ Z以下发表一些自己研究过程中的心得体会:若有错误,还请指正(以下代码均对应官方的STM32F4 Discovery板子,部分代码仅贴出最关键部分)' p  x4 |5 d4 L( i- o
一,IO
  \+ n( C2 p$ b4 e$ _最开始莫过于控制IO口的电平高低了,从这里开始,F4的寄存器就不同于F1,例如初始化LED的代码:: H7 L2 |7 j( E7 g
//PD12:绿灯,PD13:橙灯,PD14:红灯,PD15:蓝灯1 b+ @3 J$ ?7 @8 T9 I0 H  p
void LED_Init(void)
% o0 O2 {9 O. g6 i: L{
1 y5 ^" A/ i- N2 J' s   RCC->AHB1ENR |= 1OTYPER &= 0xFFFF0FFF;//设置PD12,13,14,15推挽输出
& N9 k0 O, b$ I! P  GPIOD->OSPEEDR &= 0x00FFFFFF;//PD12,13,14,15速度100M3 y4 x, k; [7 X2 y2 s, f, F7 o5 G
  GPIOD->OSPEEDR |= 0xFF000000;
& g, v: S9 V- b8 Q  SYSCFG->CMPCR = 0x00000001;//GPIO速度超过50M的时候,使用IO补偿单元   5 }  D* }/ n- v3 i
  GPIOD->UPDR &= 0x00FFFFFF;//PD12,13,14,15无上拉无下拉- f$ x) V* E. I1 b. c7 \" K
  GPIOD->BSRRH = 0xF000;//配置完成后使所有等保持熄灭状态1 i% s& s2 h& e
}2 J' e; Q* z6 E) U, V* v
配置过程:4 r% z$ L8 X( z( p- R' x
1,开启GPIOD时钟 2,配置IO为通用输出模式  3,配置IO为推挽输出  4,配置IO输出速度  5,配置上下拉模式  (其中,使用IO补偿单元不是必须,只是官方历程中写到,实测不加此句也可以)                                                                                                                                 2,相关寄存器为:GPIOD->MODER      GPIOD->OTYPER       GPIOD->OSPEEDR       GPIOD->UPDR
: _  Q% m) h: M1 Z! S# h/ O二,USART7 w) S. ]/ Z5 b' E
USART串口也是调试过程中,或者以后产品运行时与上位机软件通信的手段之一,十分重要,可以官方的开发板只有micro USB接到了USB OTG,虽说也可以配置通信,但是太复杂了,本人还没调通,暂时用把排针引线接到其他板子的USB转串口的芯片,再连接到电脑。: b0 r/ j' X! m4 M7 z- [7 F
注意:一开始我连接到的是USART1,也就是PA9,PA10,但是怎么也调试不通,一直在串口调试软件中显示乱码,一开始以为是波特率有问题,可是怎么也调不成功。后来我看官方开发板的原理图,才发现PA9,PA10已经连接到了板载的一个芯片上,可能是做USB设备的驱动芯片吧。所以我换成了USART3,对应发送接收引脚PD8,PD9,检查无冲突之后,仅更改引脚,使用之前的相同配置,调试通过。代码如下:# p, a: N8 S/ O* G8 R  h- \
USART初始化部分:+ o2 b) `9 N. t+ e$ r0 \/ F
//初始化串口3
, ~7 y" D/ W- n4 f//USART1,6 84MHz  USART2,3,4,5 42MHz2 V, J% f8 i( ~4 s1 }" A
//波特率不通过参数传入,直接通过计算得到,并写入USART_BRR6 D0 ^+ z% o! w5 N  O
void MYUSART_Init(void)
7 o- H+ s- j2 J6 ~{0 B3 T3 N4 K2 F- _* \
         //使能PORTDUSART3时钟
. Y5 z" J- j: |0 [         RCC->AHB1ENR |= 1OTYPER &= ~(1PUPDR |= 0x00040000;  //PD9 上拉 + l5 x* i6 V) q( s( w
         //复位USART3
" o: d1 e9 C* z  s         RCC->APB1RSTR |= 1CFGR = 0x00000000;
# |  e  y9 M  d  /* Reset HSEON, CSSON and PLLON bits */
8 J4 l( _- q2 ]& R  RCC->CR &= (uint32_t)0xFEF6FFFF;( g3 F( E6 h, c2 k$ e
  /* Reset PLLCFGR register */4 q( H) G/ W; Y; K- }% P
  RCC->LLCFGR = 0x24003010;# O4 }* q1 ~2 ]" r3 X6 M7 s
  /* Reset HSEBYP bit */3 o8 c, y' y# A- X) R
  RCC->CR &= (uint32_t)0xFFFBFFFF;! V. {  A8 i8 e
  /* Disable all interrupts */
6 W+ x" N" c) V; \  RCC->CIR = 0x00000000;# O& e' j" l* N' \
}( _+ W4 |5 s: {8 I
7 f! u. j; V) T1 A  B$ m/ l8 I
//STM32F4时钟配置; f7 F% m. f5 N
//关键是粗体部分的参数配置,此四个参数决定了配置后的MCU的主频,进而决定了整个系统的时基
# F& {7 B/ \# l3 ~//配置完成后系统主频为168MHz,注意,板载是8MHz晶振,所以要在MDK的设置里写为8  B: P# b. E  q3 ~. s' f& J; ^
//还需要在文件stm32f4xx.h中第92中把25000000改为8000000
$ v% l3 Q2 E0 O. a; U/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
; R- t: `: }  [- X3 c#define PLL_M      8
8 k4 S# Z: V+ |+ u/ z  _  S- e#define PLL_N      336
. `) z8 z- S! P9 P7 n6 y; r" M/* SYSCLK = PLL_VCO / PLL_P */
0 b# P) O2 e, h9 W0 e8 x/ M! ]. O#define PLL_P      20 H( n9 d. E9 p: [5 a
/* USB OTG FS, SDIO and RNG Clock =  PLL_VCO / PLLQ */
- e% x: M+ b& `2 g9 g' v#define PLL_Q      7
" s* [5 {. ^4 N8 d. [7 ~: hvoid F4_Clock_Init(void)
) L0 Y$ Z" T: x# N{
3 T# u4 l0 q  Z( V         /* PLL (clocked by HSE) used as System clock source */8 \' X+ U4 \, ?' I
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
5 D3 i  d' v5 @7 e. {3 n  Z         % ~5 W3 y% X% e+ F) u
         F4_Clock_DeInit();; X9 |; O; t( R( @7 |" U6 F
         ( C1 o) C) Z! G* e- q
         /* Enable HSE */
: Q  W+ d0 ~) ~( Y* F  RCC->CR |= ((uint32_t)RCC_CR_HSEON);
2 r8 Q+ v4 r, Z. ?5 {6 t         
0 |6 Z9 H1 |6 n         /* Wait till HSE is ready and if Time out is reached exit */2 r! R% S4 h# U/ J. V
  do
! a; k2 I2 l& {- F  {
, \, H" s2 W+ a8 J4 \- V% C3 a    HSEStatus = RCC->CR & RCC_CR_HSERDY;) c2 {( r( a7 |) M( {, X( f+ w
    StartUpCounter++;7 w9 s1 }; U6 J! X
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));' |7 G9 k# \* \; O
         4 S/ w# n6 i* @/ |: c
         if ((RCC->CR & RCC_CR_HSERDY) != RESET)
' L0 Y1 [8 R5 P  u; |6 [$ I  {/ u6 B; R  h9 p# J% Q& c! d
    HSEStatus = (uint32_t)0x01;9 X1 j% V" D) |" Z2 J. @3 y
  }" Q1 w' t8 @  X
  else
$ T) s: D* y5 u8 D5 Z  {4 X$ _' _7 Q. ~. _2 B
    HSEStatus = (uint32_t)0x00;
; Y. ~* L5 k' `! K& ?; C  }5 D! C: X; g8 F. U$ H

6 r+ H+ Z% S% L7 @2 G- [5 c  if (HSEStatus == (uint32_t)0x01)% f  e: C# a% E5 n1 R% j% _# n
  {
: t  N- l/ R2 i% k4 a& s8 V" e    /* Enable high performance mode, System frequency up to 168 MHz */
, I; l9 E6 w" H& i0 z4 `6 G2 V- h    RCC->APB1ENR |= RCC_APB1ENR_PWREN;
% o- g! t- J% M! J) a7 `" C    PWR->CR |= PWR_CR_PMODE;  1 s8 K" l8 t. U, e# i$ t

: C1 w! s. o# h2 X+ k" j    /* HCLK = SYSCLK / 1*/2 y. @, ^$ J& T- h3 g  \$ A$ b
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
8 B. j0 z' k, Q- T; E$ I      
+ C8 f; u+ W+ J6 t    /* PCLK2 = HCLK / 2*/1 g; c6 f2 I0 R+ A9 b7 u
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;# [# X5 P4 G& T; @
    ; T8 J& K# R* a4 O# ^$ V0 t& C
    /* PCLK1 = HCLK / 4*/# a2 S5 m2 [! |/ ~) q# [
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;/ ~3 K& T- x* e7 K8 }: R) \" d! c

  C9 {" v! o1 f4 j/ D6 C8 e6 S$ b    /* Configure the main PLL */
! c, r. V: C! s& y. |<strong>    RCC->LLCFGR = PLL_M | (PLL_N > 1) -1) CR & RCC_CR_PLLRDY) == 0)6 b! |! ?& C" T2 \- ]
    {
- {4 P2 l' y! y. e; a    }' y4 j' k3 t  b; a$ M! _# @& O. o
                  
. [* w! z3 j6 H/ {' x% G0 `                   /* Configure Flash prefetch, Instruction cache, Data cache and wait state */& g+ w4 A+ f/ c  i6 B
    FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;# @9 X. J! M3 F2 Q8 s, l

0 p6 F. ^9 v1 q8 a6 g7 ~; Q+ |2 i    /* Select the main PLL as system clock source */
! G5 \/ R- k! Z0 l4 c% |    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));% J9 `# _1 K/ g# o
    RCC->CFGR |= RCC_CFGR_SW_PLL;
/ E# {( I( |& [! ~
$ Y+ L0 B3 o  C, {9 k% V    /* Wait till the main PLL is used as system clock source */
0 ~5 G4 l0 s8 v  a1 c    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);4 [4 j+ f( I2 l" Q* m, r
    {
+ B% d$ [% J0 c" _    }1 E( W5 s1 ^- n/ |
  }$ P7 V4 [6 D# P
         else
5 W( H" M6 y8 u. p  { /* If HSE fails to start-up, the application will have wrong clock
# q2 b; U1 x8 m4 b' G         configuration. User can add here some code to deal with this error */
; `' P2 }, O' `6 V  }
* s; t! Z& x' e# A - g) q3 Q0 U5 r" o) J
! ^( f" {( F' q8 d3 _+ \
说明:以上是初始化的关键部分,SYSTICK频率默认为系统时钟的8分频,配置好了时钟,自然就可以轻松设置SYSTICK了。
$ d- Y4 \3 s5 o5 s四,定时器 PWM 输出
$ e( Y) w2 h  _  SSTM32的定时器很复杂功能也很多,此处仅说说TIM4作为PWM输出时的配置,效果是控制LED产生呼吸灯的效果。                                  此处仅配置TIM4-CH4的输出,其余几路输出同理:9 p# \/ o7 \7 l/ A% m8 y. N# J. n3 B
//PD15 BLUE   TIM4-CH4
' t. Q+ b: t9 {* vu16 TIM4_CCR4_Val = 0;( M! s& ?2 k# r
u16 PrescalerValue = 0;//预分频器值! Z9 C$ }* c1 ?9 o0 Y
u16 pwm_tempvalue=1;
2 a/ @  @* D) h: ^//TIM4-CH4 PWM输出初始化% y: |/ w. b# N$ l( R! Q  `
//必须对PD15的IO口进行重新配置
) S  K' L$ E0 x* B" S' Svoid TIM4_CH4_PWM_Init(u16 arr)4 V& P" N( [8 A2 a5 t! t. \4 Z
{) ?. S; L6 |4 N  t: y4 [
        //TIM4时钟使能
2 |" s& l8 L* Y# D( w9 x( U+ {7 n# F        RCC->APB1ENR |= 1OSPEEDR |= 0xC0000000;# [0 A7 l% j- Y
        //当速度超过50MHz时使用IO补偿单元  B3 L$ C: V; F: B1 r: s: f" B
        SYSCFG->CMPCR = 0x00000001;
/ u* D- G2 j8 w, j& a( J        //PD15上拉,PUPDR15[1:0]即31,30位  01ull-up1 Z! M% k6 \* [
        GPIOD->UPDR |= 0x40000000;
, f/ P  \# V# W        //配置第二功能寄存器(必须开启),PD15对应GPIOD->AFRH' D1 T  m7 s6 ~. s4 B
        //31,30,29,28位 AF2:0010+ {8 A- {! g8 I% k
        GPIOD->AFR[1] |= 0x20000000;
, s, i' ?+ D* w: e. }( g
% Z9 L$ d# e4 s) y' n0 x% R6 a+ F$ S
        //计算预分频器值
2 A5 ?- O$ r0 G6 h9 V5 r- o. Q        PrescalerValue = (u16)((SystemCoreClock/2)/28000000)-1;        
/ a1 b# O7 ]8 V        //设置计数器自动重装载值! a3 U- s  `' |3 d" {, V2 Q
        TIM4->ARR = arr;( A: i. }- o& F9 L* B1 X4 F
        //设置预分频器分频值
8 J' _! `% t* w2 x& J        TIM4->SC = PrescalerValue;8 G, s) h4 z- J! @6 B, D/ O2 `
        //时基配置:Bits 9:8 00:t(DTS)=t(CK_INT)! H& x# J! x1 E8 E7 Q) A, |
        //TIM4->CR1 &= 0xFCFF;
+ u' g7 f! {+ P) w  w        //计数模式配置:Bits 6:5 00
3 M" x8 K1 b+ J/ V! X        //TIM4->CR1 &= 0xFF9F;        
+ [& b- b2 L: }7 J" n1 K# W        //配置TIM4的CH4为WM1模式输出
( o+ o. I, c! A. P) u; f        //配置TIM4_CCMR2的OC4M(位14,13,12)为:110) i  i* N' }! j
        TIM4->CCMR2 |= 6CCR4的值来该表占空比,从而控制LED的亮度4 ]1 S) q5 b* t. a
        TIM4->CCR4 = TIM4_CCR4_Val;3 G9 i% E3 p+ `* l1 [# ?' _0 u
}
' b$ N, O6 F3 H6 Q % N" x) E+ c8 x3 r( Z- g, q. m3 j
主函数中:) g# X' P" E7 B0 C
TIM4_CH4_PWM_Init(800);//TIM4 CH4 PWM输出初始化
0 x! J8 Y$ K' a0 i  O# P循环里调用TIM4_CH4_PWM_OutPut();  即可6 M8 A5 y+ e! N  a, w

% n/ k6 @2 g+ K( ]4 Y说明:1,粗体部分是重点    2,IO要配置成第二功能模式     3,延时控制了呼吸灯的节奏,占空比控制了LED亮和灭的范围,这个可以自己多次设置后调试体会。* t/ y$ I; a2 a( G7 d

4 p' a4 O" d; d五,RNG 随机数生成器
  A/ u0 O' W4 V; w这个是STM32F4比较有意思的一个功能,可以硬件产生一个随机数,更加方便易用,配置也相对简单:
& z4 i7 B/ k- x% X' `/ Vvoid RNG_Init(void)//随机数寄存器初始化5 y$ ~/ t, s4 c- ]- ]( y
{  n2 _( c0 N9 x) i: |9 h! y9 }8 o/ y
  RCC->AHB2ENR |= 1CR |= 0x00000004;) f/ d7 i8 s" g/ K/ H
  RNG->SR &= 0xFFFFFFFE;) M4 u5 S8 D1 l6 g) k7 c0 v) E* q
  RNG->SR |= 0x00000001;  
+ }6 L0 [! v, \}0 S+ A% {. n# e0 |$ Z, H' ]

6 l2 I  O" W6 r1 aint RNG_Generate(int y)//生成随机数
" O- D" H# o: c+ z2 R/ @( ]{- o) H# u0 Z6 ^
  int x;: [' @- ^6 u" c; |1 \' C9 j; b8 i
  x=(RNG->DR) % y;  : v% v( c) l' [7 `
  return x;
* |: g8 T/ D& Q: B}  @. Y1 S4 l; D4 b; l" l. ]) a
说明:开启相应时钟,简单的配置几个寄存器,然后再main中初始化:RNG_Init()就OK了,若要在其他外设文件中使用随机数,包含头文件rng.h,然后定义变量接收函数RNG_Generate(int y)的值即可,简单易用。
( v7 x* Q3 i9 H# ?$ E------------END
1 w( Y4 `" d5 m# L& h* o) p6 p9 y对于STM32F429,我还是很期待的,比较自带了LCD,还有SDRAM,更多的应用可以被做出来,更流畅的跑系统和需要大内存的应用了,本想自己画个板子,接LCD,然后插在STM32F407 Discovery板子上的,可是硬件设计又是个难题,万一设计错误就无法使用了,所以STM32F429是个不错的选择,官方的开发板,外设丰富很超值。9 d" `/ |% b& [6 S$ K( u' `
以上是本人研究的一些东西,给大家分享,本人也是菜鸟,希望大家多指导,共同进步/ a. s7 z7 ~- a7 b$ j. b2 t
收藏 2 评论4 发布时间:2014-4-19 11:11

举报

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

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

最近在研究F4的ADC功能,发现跟F1的寄存器不同,比如:
5 K1 F. A+ H1 x* V+ h. ^1,选择触发方式为软件触发时,F1的寄存器有对应设置的位,但是F4中我没有找到,也不清楚到底有没有?
" m. u1 e1 m8 _& o. m. j, n1 J2,ADC校准,在F4的寄存器手册中找不到对应的寄存器的位,不校准,岂不是精度很差?
# x& J+ j' P0 X! a5 J以上两个问题,请教下大家!希望有人能发表相关意见和经验!
bjybjy 回答时间:2014-6-18 17:12:57

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

楼主你好,请教一下,STM32F407 Discovery USART CTS/RTS该怎么用,谢谢
youxiaoxiang 回答时间:2014-11-24 12:44:44
楼主你好。看了你的PWM 输出 做呼吸灯的问题。有一点疑惑。- d& h+ l; g0 x0 h8 Z% j
具体是如何调节的?
巅峰残狼 回答时间:2014-11-24 13:01:16
谢谢分享
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版