
本人一直以来都在接触STM32方面的软硬件开发工作,最初的是做基于STM32F1的汽车电子相关的软件研发工作,有用到F1的一些基本功能,例如USART串口通信,IIC存储EEPROM芯片,SPI读写FLASH等等,内核的SYSTICK,NVIC,中断,强大的定时器功能也总是用到,尤其是CAN总线,其稳定的工作机制和强大的纠错,适应能力,最适合汽车电子等工作环境不稳定的场合。最开始的这些研发工作使我对STM32情有独钟,其强大的外设资源,能满足绝大部分的应用需求,丰富的系列产品,能满足预算和功能的协调统一。 有了一些基础之后,我在网上看到了STM32F4 Discovery的出现,高达168MHz的主频,1M的片内FLASH和192K的SRAM,内置RNG和FPU等等,并且包含了F1系列的几乎所有功能,尤其支持USB OTG,强化了音视频解码,能做出更多的功能和有意思的探索。接下来就STM32F4 Discovery官方开发板,本人自己研究的一些过程经验和体会,分享给大家,限于本人能力有限,仅代表个人观点,还请大家多多指教。 首先,对于开发方式,本人采用“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的手册,主要看管脚对应功能,外设配置简介等 Cortex-M4 Devices Generic User Guide -- Cortex-M4内核手册,包含NVIC,SYSTICK等等内核的详细说明; T1 l+ Z+ J9 Z1 w0 U# T 还可以去ST官网下载3.5的库函数,以及STM32F4 Discovery板的例程,经常看一看,借鉴学习下,非常有好处。 F4系列和F1系列的寄存器有少许差别,大家使用时可参考F1的相关例程,对照修改即可。, U$ ?$ O* y. k 以下发表一些自己研究过程中的心得体会:若有错误,还请指正(以下代码均对应官方的STM32F4 Discovery板子,部分代码仅贴出最关键部分)' p x4 |5 d4 L( i- o 一,IO 最开始莫过于控制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) { RCC->AHB1ENR |= 1OTYPER &= 0xFFFF0FFF;//设置PD12,13,14,15推挽输出 GPIOD->OSPEEDR &= 0x00FFFFFF;//PD12,13,14,15速度100M3 y4 x, k; [7 X2 y2 s, f, F7 o5 G GPIOD->OSPEEDR |= 0xFF000000; SYSCFG->CMPCR = 0x00000001;//当GPIO速度超过50M的时候,使用IO补偿单元 5 } D* }/ n- v3 i GPIOD-> ![]() 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-> ![]() 二,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 //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) {0 B3 T3 N4 K2 F- _* \ //使能PORTD和USART3时钟 RCC->AHB1ENR |= 1OTYPER &= ~(1PUPDR |= 0x00040000; //PD9 上拉 + l5 x* i6 V) q( s( w //复位USART3 RCC->APB1RSTR |= 1CFGR = 0x00000000; /* Reset HSEON, CSSON and PLLON bits */ RCC->CR &= (uint32_t)0xFEF6FFFF;( g3 F( E6 h, c2 k$ e /* Reset PLLCFGR register */4 q( H) G/ W; Y; K- }% P RCC-> ![]() /* Reset HSEBYP bit */3 o8 c, y' y# A- X) R RCC->CR &= (uint32_t)0xFFFBFFFF;! V. { A8 i8 e /* Disable all interrupts */ 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的主频,进而决定了整个系统的时基 //配置完成后系统主频为168MHz,注意,板载是8MHz晶振,所以要在MDK的设置里写为8 B: P# b. E q3 ~. s' f& J; ^ //还需要在文件stm32f4xx.h中第92行中把25000000改为8000000 /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */ #define PLL_M 8 #define PLL_N 336 /* SYSCLK = PLL_VCO / PLL_P */ #define PLL_P 20 H( n9 d. E9 p: [5 a /* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */ #define PLL_Q 7 void F4_Clock_Init(void) { /* PLL (clocked by HSE) used as System clock source */8 \' X+ U4 \, ?' I __IO uint32_t StartUpCounter = 0, HSEStatus = 0; % ~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 */ RCC->CR |= ((uint32_t)RCC_CR_HSEON); /* Wait till HSE is ready and if Time out is reached exit */2 r! R% S4 h# U/ J. V do { 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) {/ 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 {4 X$ _' _7 Q. ~. _2 B HSEStatus = (uint32_t)0x00; }5 D! C: X; g8 F. U$ H if (HSEStatus == (uint32_t)0x01)% f e: C# a% E5 n1 R% j% _# n { /* Enable high performance mode, System frequency up to 168 MHz */ RCC->APB1ENR |= RCC_APB1ENR_PWREN; PWR->CR |= PWR_CR_PMODE; 1 s8 K" l8 t. U, e# i$ t /* HCLK = SYSCLK / 1*/2 y. @, ^$ J& T- h3 g \$ A$ b RCC->CFGR |= RCC_CFGR_HPRE_DIV1; /* 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 /* Configure the main PLL */ <strong> RCC-> ![]() { }' y4 j' k3 t b; a$ M! _# @& O. o /* 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 /* Select the main PLL as system clock source */ RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));% J9 `# _1 K/ g# o RCC->CFGR |= RCC_CFGR_SW_PLL; /* Wait till the main PLL is used as system clock source */ while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);4 [4 j+ f( I2 l" Q* m, r { }1 E( W5 s1 ^- n/ | }$ P7 V4 [6 D# P else { /* If HSE fails to start-up, the application will have wrong clock configuration. User can add here some code to deal with this error */ } - g) q3 Q0 U5 r" o) J ! ^( f" {( F' q8 d3 _+ \ 说明:以上是初始化的关键部分,SYSTICK频率默认为系统时钟的8分频,配置好了时钟,自然就可以轻松设置SYSTICK了。 四,定时器 PWM 输出 STM32的定时器很复杂功能也很多,此处仅说说TIM4作为PWM输出时的配置,效果是控制LED产生呼吸灯的效果。 此处仅配置TIM4-CH4的输出,其余几路输出同理:9 p# \/ o7 \7 l/ A% m8 y. N# J. n3 B //PD15 BLUE TIM4-CH4 u16 TIM4_CCR4_Val = 0;( M! s& ?2 k# r u16 PrescalerValue = 0;//预分频器值! Z9 C$ }* c1 ?9 o0 Y u16 pwm_tempvalue=1; //TIM4-CH4 PWM输出初始化% y: |/ w. b# N$ l( R! Q ` //必须对PD15的IO口进行重新配置 void TIM4_CH4_PWM_Init(u16 arr)4 V& P" N( [8 A2 a5 t! t. \4 Z {) ?. S; L6 |4 N t: y4 [ //TIM4时钟使能 RCC->APB1ENR |= 1OSPEEDR |= 0xC0000000;# [0 A7 l% j- Y //当速度超过50MHz时使用IO补偿单元 B3 L$ C: V; F: B1 r: s: f" B SYSCFG->CMPCR = 0x00000001; //PD15上拉,PUPDR15[1:0]即31,30位 01 ![]() GPIOD-> ![]() //配置第二功能寄存器(必须开启),PD15对应GPIOD->AFRH' D1 T m7 s6 ~. s4 B //31,30,29,28位 AF2:0010+ {8 A- {! g8 I% k GPIOD->AFR[1] |= 0x20000000; % Z9 L$ d# e4 s) y' n0 x% R6 a+ F$ S //计算预分频器值 PrescalerValue = (u16)((SystemCoreClock/2)/28000000)-1; //设置计数器自动重装载值! a3 U- s `' |3 d" {, V2 Q TIM4->ARR = arr;( A: i. }- o& F9 L* B1 X4 F //设置预分频器分频值 TIM4-> ![]() //时基配置:Bits 9:8 00:t(DTS)=t(CK_INT)! H& x# J! x1 E8 E7 Q) A, | //TIM4->CR1 &= 0xFCFF; //计数模式配置:Bits 6:5 00 //TIM4->CR1 &= 0xFF9F; //配置TIM4的CH4为 ![]() //配置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 } % 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输出初始化 循环里调用TIM4_CH4_PWM_OutPut(); 即可6 M8 A5 y+ e! N a, w 说明:1,粗体部分是重点 2,IO要配置成第二功能模式 3,延时控制了呼吸灯的节奏,占空比控制了LED亮和灭的范围,这个可以自己多次设置后调试体会。* t/ y$ I; a2 a( G7 d 五,RNG 随机数生成器 这个是STM32F4比较有意思的一个功能,可以硬件产生一个随机数,更加方便易用,配置也相对简单: void 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; }0 S+ A% {. n# e0 |$ Z, H' ] int RNG_Generate(int y)//生成随机数 {- 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; } @. Y1 S4 l; D4 b; l" l. ]) a 说明:开启相应时钟,简单的配置几个寄存器,然后再main中初始化:RNG_Init()就OK了,若要在其他外设文件中使用随机数,包含头文件rng.h,然后定义变量接收函数RNG_Generate(int y)的值即可,简单易用。 ------------END 对于STM32F429,我还是很期待的,比较自带了LCD,还有SDRAM,更多的应用可以被做出来,更流畅的跑系统和需要大内存的应用了,本想自己画个板子,接LCD,然后插在STM32F407 Discovery板子上的,可是硬件设计又是个难题,万一设计错误就无法使用了,所以STM32F429是个不错的选择,官方的开发板,外设丰富很超值。9 d" `/ |% b& [6 S$ K( u' ` 以上是本人研究的一些东西,给大家分享,本人也是菜鸟,希望大家多指导,共同进步 ![]() |
RE:【MCU实战经验】STM32F407 Discovery开发实例心得分享
1,选择触发方式为软件触发时,F1的寄存器有对应设置的位,但是F4中我没有找到,也不清楚到底有没有?
2,ADC校准,在F4的寄存器手册中找不到对应的寄存器的位,不校准,岂不是精度很差?
以上两个问题,请教下大家!希望有人能发表相关意见和经验!
RE:【MCU实战经验】STM32F407 Discovery开发实例心得分享
具体是如何调节的?