![shequ.stmicroelectronics.cn](./template/st_v1/static/img/logo2.png)
本帖最后由 harvardx 于 2015-1-24 21:52 编辑 0 l3 N$ u- P. j2 f$ ^ y 1 前言 友情链接: 沐紫妹妹关于最新Nucleo - F091RC开发板介绍以及相关的nucleo介绍0 E$ p# A7 ~7 j7 A Nucleo平台最新开发利器——ST Nucleo-F091RC开发板评测 https://www.stmcu.org.cn/module/forum/forum.php?mod=viewthread&tid=599462&fromuid=2039986 0 u& M" ^7 \6 Y5 W# T* h" ` 4 ~/ D! P' q0 U0 {0 w ST的上新速度真够快的,如果是一个淘宝店铺,肯定是钻石带星的. 这不, STM32F091RC -nucleo 开发板又来到了我们的身边! Nucleo家族又迎来了一批新成员, 像咱们社区刚刚提供给大家的STM32f334- Nucleo 开发板. st的技术更新让我们应接不暇, 可以更加天马行空的选择自己的MCU right.拿到最新的STM32F091RC -nucleo 开发板.老规矩,先评测几个简单的例程. led_toggle, key, ADC ,DAC神马的 ,几种开发方法,大家估计都耳熟能详了. 这就是Nucleo的好处. 统一的外形,统一的包装,统一的开发方法. 真正做到了 All in one,大家所需要关心的就是自己想要实现什么应用,做些什么,底层的细节, 驱动,io分频神马的 ,都可以直接套用. 如果你要 Hello world一下,在nucleo开发板上仅仅需要, 选择不同的mcu编译就可以了. . n) }8 B, E% }* R3 J 8 q. m( m1 C5 {" F$ X6 d* p 2 回顾 1 `+ i! h- f6 P0 c2 }: o# Z# X' \ 简单回顾一下, nucleo系列的几种开发方法,以最新的Nucleo 091开发板为例: 1. nucleo 091 可以mbed开发,比较新颖, 也比较简单, 但是是cpp的, 可能很多同学太适应; 目前mbed.org已经有091系列的支持,大家可以登录mbed云端查看;& H: }* o9 a. ]4 `& \# J& r : l+ t- t, m/ t. q( m 2,标准外设库,目前标准已经到了1.5.0版本, 可以到此下载:% j% j: Y# b: B* q: I9 V: S1 i 下载地址:4 e! M% v: g$ n% U' y http://www.st.com/st-web-ui/stat ... 0_stdperiph_lib.zip 标准库解压后,有很多例程,其中包含了091的 ,可以到STM32F0xx_StdPeriph_Lib_V1.5.0\Projects\STM32F0xx_StdPeriph_Examples& L5 V8 o5 c+ h! Y2 P2 O 目录下查看,怎么使用这些例程呢, 在里面的Libary_examples.html网页有说明,如下: How to proceed?
- e4 _7 I) Z! \3 x" V2 o' ? 3 Cubemx库,这是目前st比较推崇的. 目前pc配置软件CubeMx已经到了最新的4.6.0版本 下载地址:% O! u. X/ o$ e5 p ( http://www.st.com/st-web-ui/stat ... ite/stm32cubemx.zip), ( A1 t3 _6 y* N3 |2 p6 v9 C 同样支持F0的cube外设库CubeF0已经是1.2.0版本 下载地址: (http://www.st.com/st-web-ui/stat ... are/stm32cubef0.zip) 其实Cube终究也是库,只不过代表着更加先进的方案,相信在st巡回研讨会上大家都有所了解.记得很多工程师刚开始不太适应,其实是更加方便我们开发,至少他可以通过图形化,来快速配置我们单片机.生成所需要的模块初始化或者操作代码.$ R7 r( q# E; x! ]0 h: ` 8 n4 i4 u5 H7 @9 |" G9 Q 3 CubeMx结合CubeF0_V1.2.0 库 开发 Nucleo -STM32F091 开发板实例& O' M, I! v V: S8 H) W 9 x" |" z/ r4 _1 w 因为 091比较新,在keil4下,需要添加官方的dfp支持包, 否则将看不到这些器件. keil5就好办多了. 可以通过pack installer来进行. 这是在开发st最新单片机时,需要面临的问题,具有共性. 一般情况下,如果库(标准外设库或者cube库)出来了.可以在STM32F0xx_StdPeriph_Lib_V1.5.0\Utilities\Third_Party这样类似的目录下.找到这些支持包. 标准库1.5.0下的例程很多还是uv4工程的, 最新的\STM32Cube\Repository\STM32Cube_FW_F0_V1.2.0\Projects\STM32F091RC-Nucleo\Examples\里面的例程好多已经是MKD5工程了,非常好.免除了同学们添加支持器件的麻烦,直接通过更新pack intaller就搞定.而且无需去复制模版到每个驱动模块的例程,在外设驱动模块的例程中,已经帮我们添加好了工程.直接用mdk5打开就可以.建议大家升级到最新的MDK513测试,感觉很好. 首先上一个最简单的例程, ![]() |
关于例程中的ticker 其实就是定时器,大家可以看下面的详细说明:9 Q, A# m4 i G3 X- I+ W1 \
mbed 时钟系统
$ Y) R0 j9 x' m4 |' j
微处理器的大量应用都和时间相关,如我们前面代码中多次出现的wait函数就是最常用的时间等待函数,显然,精确的时间等待必须建立在精确的计时技术上,这就需要用到计数器系统。& j: R/ T( u7 s5 ]; p" l r3 g' C
计数器的工作原理非常简单,就是每当它接收到一个脉冲时,它的计数值加一,一旦它的计数值达到用户设定的阈值,计数器就会产生一个中断信号让系统处理并重新从0开始计数。根据计数器可设定阈值的大小,我们可以把计数器分成8位计数器,16位计数器等,8位计数器可设定的最大阈值为2^8-1即255,16位则为65535。如果我们给定的脉冲信号频率为1M,而给定的计数器阈值为0,那么计数器就会每1us产生1个中断信号,这就为系统计时产生了依据。对于xbed LPC1768来说,它有四个通用计时器,它们可以用来计时、PWM输出等。+ P ]- e: j/ w5 s: S, J* g
7 {) x- j, K$ P( E' D, {3 z
除了wait相关的等待函数以外,mbed还提供了三个对象用来完成和时间相关的功能,分别是Timeout,用来在给定的时间执行特定函数;Ticker,用来定时执行特定函数;Timer,用来给系统计时,它们可用的方法描述如下:
2 H1 q4 A& ~# s& O% Q2 B
类名 R5 r' O+ G+ ^
方法
用途$ N& K4 N% u& z5 H* D" X
{5 ?4 _8 ~' Y6 K7 X" r
Timer
Timer();9 l' ]1 E1 n$ W7 m5 G2 I
构造函数,实例化Timer对象
$ P1 W5 x% U0 O5 U$ {
void start();% D; V2 t: m' M$ `) S, k! B
开始计时
3 M2 ^1 Y. K. T- o: ?" f8 B
void stop();- y% c# q: W K- t; l/ g% U$ w2 l
# Z+ n2 d4 A# G+ X8 A( k$ O5 o
停止计时
void reset();/ X7 l# g- ^: ^3 T8 ?
重新计时,即把时间计数恢复从0,如果原来处于start状态,那么计时继续
6 ]& O9 b0 U/ d0 p2 V5 Q
float read();3 ~ n( x0 I; u9 U
读取计时开始后过去的时间,单位是秒2 W' V- b" ]+ `1 n' t: r) \6 {0 o
% r- n( j- m5 a5 C$ |$ S
int read_ms();9 E- R- }( e' `+ p: I0 S
读取计时开始后过去的时间,单位是毫秒
int read_us();
0 ]& O, G, p$ c6 N# [, J
读取计时开始后过去的时间,单位是微秒0 [5 }2 [% ^) e8 }+ |) U
operator float();3 ?1 d: @+ r: U% A K2 }3 Q) [8 o
操作符重载,相当于read
5 I) \3 L. D, T- w9 k% q6 y7 s
Ticker
( Q0 X. f. @) U# K- _# K
Ticker();2 v. T3 }+ b0 y. J# B5 b* O
1 x3 f: \4 E b) i* }4 ~3 X$ \
构造函数,实例化Ticker对象
void attach(void (*fptr)(void), float t)
设定每t秒需要执行的函数% n' n' Q. v S3 t
' x* x$ J- K0 M8 J
void attach_us(void (*fptr)(void), unsigned int t)
设定每t微秒需要执行的函数
: P& l" @! o# w# R1 ~
void detach();
* U; n& Y; O% k) [& q
取消本对象需要定时执行的函数
Timeout7 A% w0 q( _- `9 z. |; K. p
7 G5 T; C0 U, d4 P
Timeout();
; C& e" Q! O3 V- S
构造函数,实例化Timeout对象4 \- u( z. `3 N! X9 d- w3 y
void attach(void (*fptr)(void), float t)
设定t秒后需要执行的函数$ J- m/ c6 j0 G
- L& U6 S+ U0 ~' ~) z/ \
void attach_us(void (*fptr)(void), unsigned int t)) H/ F; J1 j* k6 @7 K$ b
/ [' b+ r1 Y. K
设定t微秒后需要执行的函数 u- O+ I& x; o- g
void detach();4 l; M# _: z i3 M7 S0 v
* _; m; N' F m1 {) n: N
取消本对象需要执行的函数5 T" \: y+ r0 ]% ?
mbed Timer的应用
8 ?$ n9 t ] u, I# A
mbed的Timer对象主要用来计算用户关心的时间间隔,下面是一个简单的示例,可以计算用户按下按钮的时间,主要代码如下:
Serial pc(USBTX,USBRX);5 a5 }: a" ~' i, k h- P' G1 [
# h; E/ I p% |( B: ~
InterruptIn btn(P2_8);. O' v# k6 {6 @- r! h: _) t4 ?8 A
Timer mytimer;
int falltime;
int risetime;/ M4 |# Y* O% R4 Z4 s7 R/ N
6 M% d0 Q! z& q8 n
void fallfunc()2 s: ?* K% A- P: f3 u j. z, X6 a6 D
- y2 n. z' C. S9 d8 e5 F
{
falltime=mytimer.read_us();
}
void risefunc()
{
3 i- t4 ^: W; n6 \
risetime=mytimer.read_us();: S" \6 k$ q9 C7 U
pc.printf("You press button for %d us \n",risetime-falltime);4 y5 [% I: t# b
1 V ~& l3 T6 ^0 C* n) F7 N6 U! q
}% d2 C: d* g6 s8 o, }2 G3 h
U6 m7 A% J1 q2 |2 i4 `2 U
int main() {
mytimer.start();% B" L0 V$ k: ~7 C* t
( _; S) Y& `# K7 b$ D; G, t' H
btn.fall(&fallfunc);1 V8 a# ~+ @" v' @* Q! t& z( }8 ~
* q* q! c8 {# i7 K: U; ]
btn.rise(&risefunc);
while (1);! ~. K& C( z. g/ ]6 N3 o) A2 {
}
程序运行的结果如下,当然,我们需要理解,任何中断的处理都有一定的延迟时间,所以此结果还是会有一定的误差,但绝对在us级别。$ H' x2 T( e, |% M/ S
You press button for 330410 us
You press button for 137603 us
You press button for 122679 us% e- M, l' T! ]" t/ r' ?
You press button for 140683 us
有时候我们需要利用多个Timer来计算不同的时间,这只需要定义多个Timer对象即可:- Z- m% N+ c T6 G& _. z
' l4 f$ k1 z6 @1 ?# U C7 J3 n
Timer timer_led;
Timer timer_serial;
% M* O9 I4 _/ ]2 D7 ]
DigitalOut led1(LED1);; W. Q. l/ t' }2 X& j$ J0 E$ n
Serial pc(USBTX,USBRX);
void task_led(void)% d& v% ~$ P7 ~1 d; C6 z3 {
{
led1=!led1;; t3 W+ H+ ~. X u' b
}0 W; H4 J; [2 q( p# o
! B) P: S0 x+ t# ~" ^6 v
void task_serial(void)# j2 t9 S" o [
{& }6 B! m* c/ ~
pc.printf("Timer passed %d ms \n",timer_serial.read_ms());; X5 m0 W2 i0 h. R' I3 [
}0 N9 U, o+ T$ g" z3 q4 A, ~2 W
2 \ |: ^+ C/ `: e. s) A
int main()
{
timer_led.start();
timer_serial.start();# L3 A( T5 M/ f1 f, x; {
- u; b% H4 h- R. N: h6 o
while (1)
{ J/ n0 k/ s9 ?5 F" D5 B
9 C8 ?( } ]) @3 U2 z
if (timer_led.read()>0.5)/ o7 r+ _6 c0 f
{
. i- C3 H$ ]+ y1 ]% d
task_led();7 K* \+ E/ E+ E( O
# |( k0 E; X2 _3 e
timer_led.reset();
}; i. s, Z8 |& H
1 z+ a. u+ ~9 W+ r2 q- e g
if (timer_serial.read()>1)& B" N) j r: }4 ~1 o; e% ?
- A4 s# x& G- @- J5 k9 M
{ //test Timer value+ h. ]; B4 G0 b4 u
task_serial(); y9 W1 m: @# z9 o$ `
timer_serial.reset();9 G( w# n# m" T, [2 L
}8 f: q, A8 I% i, |. b+ M7 }
}+ ]: @5 p4 G. m) `& r: @, C3 B
% M5 \3 n, G) g) F. |) y2 y D
}! Y, l% s4 G$ c" z
mbed Timeout的应用, v7 i, }/ _9 o) W R' ]9 t+ ?/ Q, {
$ n3 K: o0 D Q3 `) N
mbed的Timeout对象主要用来在给定的时间后执行给定的函数,如下面的测试代码,运行后你会发现xbed LPC1768的四个led分别点亮,由于timeout只会被执行一次,所以点亮后会保持不变:$ J; b' x& F, K
8 X/ w, O2 ^7 k# g8 ]( A8 C& p( Z
DigitalOut led1(LED1);6 q* Y# W5 q$ R- A3 d; z
DigitalOut led2(LED2);7 D2 d. S9 u/ S# C: C& F
) x6 J3 m+ c, `' w
DigitalOut led3(LED3);5 G. |1 D$ {! e5 Q7 w& \" ]
+ D" ^+ z$ W. X9 E
DigitalOut led4(LED4);0 @4 Y. w! s- K! O5 W; y2 j: y9 t
Timeout timer_led1;3 ^$ i7 G, J+ y. g3 L" f
Timeout timer_led2;: [; f, ]9 Y. {0 H5 t
# J/ W' e6 W0 Y6 ~- e
Timeout timer_led3;8 x/ I. m# y8 \5 n
" \3 C% K! d$ G
Timeout timer_led4;. k% d& S* {: n2 n D
. C+ _* ]7 r5 \: |3 k' g, n1 R
void led1flip()
{8 E* R- W. t5 F3 f
led1=!led1;1 [3 a; n. [' x6 h6 s
2 ]; }- ^3 Y! }1 ]
}# ~( v. L9 I v; P" s7 |
& Y; J) k4 [( J! m5 W! \* f/ d
void led2flip()& U. y! ]( d5 e2 n% ^
9 Z) M+ v- B. A
{! h; ]* n+ `' q( `( _- t
led2=!led2;& @& U. I3 Q; `' U
% n0 T. H1 W V
}
void led3flip()
) ]' E- ^. W, U( s2 l. Y J. A
{
led3=!led3;6 D! K0 c1 x% W* p/ t# x/ _, b& K
}
void led4flip(), O$ m( Z2 G5 W3 b
, ?; J" [0 |1 e; f
{: z. d1 F( D2 W( a
led4=!led4;
1 a; w! l" o, b8 a3 N
}0 _9 }0 K8 o+ R3 G" U' i; V
2 j! M% R- q! g9 A
int main() {
timer_led1.attach(&led1flip,0.5);/ W0 D1 {3 L2 e- |' c" A! U
( x7 i7 y6 Z( r. s! D* S
timer_led2.attach(&led2flip,0.5*2);
. X& Z; V) g# y$ r7 S' {- i/ C& j
timer_led3.attach(&led3flip,0.5*4);; s: E/ n; B4 ~4 Z' a
timer_led4.attach(&led4flip,0.5*8);
: z9 L8 r b6 Y" Y! c0 K5 s6 _9 W
while (1);
# J6 t" z% V% @& i
}; J9 \6 f6 B0 Z9 w4 [; `7 q
mbed Ticker的应用 F) Q3 L+ v' ^7 o9 L2 e
mbed的Ticker对象主要用来执行各类需要定期执行的函数,它和Timeout的唯一不同就是Timeout相关的函数只会被执行一次,而Ticker相关的则会被定期执行,如下面的测试代码,运行后你会发现xbed LPC1768的四个led将按照不同的频率变换:# v8 _8 E/ V, w/ {) ~$ G6 n
DigitalOut led1(LED1);/ g4 W1 H! B( W5 s! \
8 w& i) ?( x7 |8 P, ~8 s
DigitalOut led2(LED2);: e6 ^6 Z ~3 g1 E
; x4 f8 @& [3 b8 x7 G5 s' b+ m
DigitalOut led3(LED3);4 r8 B3 O/ G, I; J
DigitalOut led4(LED4);
Ticker timer_led1;* x, [( k- I, \1 d! k
Ticker timer_led2;
Ticker timer_led3;
5 f3 |! g% m, V
Ticker timer_led4;2 s0 p; |8 k9 _ f
D0 J2 ~" c! }5 ?1 F- ?
void led1flip()
: I ]8 z6 M1 F5 k
{
led1=!led1;- u2 z! ]% b2 G' z7 S) k
}
0 p, b4 c6 A" S9 N" K5 [
void led2flip()
* ?6 m! q. G" ~% _6 B! C( k
{0 z" ]; Z5 {) X: z. v
: g3 x/ D! L0 T& I. q2 J
led2=!led2;
\0 ?2 J; @! `; [
}2 G% c: A6 t8 t3 W0 x0 d
void led3flip()
{
led3=!led3;8 j( d6 C' g/ i: F5 E. D
}4 ?3 v7 e& k4 s% {+ W# L- k7 U" T
( C @) p k( r2 w P
void led4flip()! R4 `. |2 |# B! M" i
/ a( V# Z8 b" }% j, ~! s
{
led4=!led4;
; t: i; c. z7 C4 n& ~! } v/ |' h
}) l6 O4 d6 C$ ?
( D" O. y. y, f' E4 T8 r: X
int main() {
6 `4 a& f2 f# O
timer_led1.attach(&led1flip,0.5);3 X6 y2 t' {# G3 O% C2 R* l) H F" ~
timer_led2.attach(&led2flip,0.5*2);" c3 w) B* Z4 F o% b' \4 G/ ]
) B' Y( ^0 D% {$ Q n0 t, `
timer_led3.attach(&led3flip,0.5*4);( \$ r! Y% F1 g6 m, G: `
timer_led4.attach(&led4flip,0.5*8);
: s: p" z: y% u% P) G* O
while (1);: n3 U0 l1 }* }( t7 ]" W
+ p0 [4 ?% h- s# U0 V
}
我们在使用Ticker对象的过程中还可以随时对Ticker设定的间隔进行更改,更改后的时间是即时生效的,如下面的代码,我们发现,用户每按一次按钮,led1的闪烁频率就会加快一倍。
" T+ q; k3 h4 x: y
DigitalOut led1(LED1);! N' g- E0 B' ]0 e) L& Y1 n E
InterruptIn btn(P2_8); D. @( X( m& |' \
1 `+ n! ` W3 K8 s( n. `
Ticker timer_led1;, O6 R/ a6 X' r% Z) d d
4 H5 q! A c1 }3 @+ ~
float interval; [0 }$ t! _: @, s0 ?9 P: a
! R9 c; p' T( ], Q! C! t9 E, e0 i
void led1flip()
: X! m0 U( Q1 g+ Y4 N* _
{
% E# p O- L2 ?$ P& C1 v* w" P
led1=!led1;
}
void changefred()- D" @ U7 o* |; f& s. r
{1 g: r" F" c) B6 U) a. g1 W- H
. o0 c, [+ ^5 x0 @/ y/ X( s/ U
interval=interval /2.0;. c& p- b& t$ C9 D6 E) I
timer_led1.attach(&led1flip,interval);
}
int main() {
interval=2;
btn.fall(&changefred);% Y- b( W5 |5 U# K" N# x! t: ^
; b4 U, U6 Y) z+ y3 {
timer_led1.attach(&led1flip,interval);
, S+ V, \0 c2 P" |& v
while (1);
4 Y C3 l4 {, ~, R
}
. i5 C5 J9 ]" _/ ]3 b; D
那还得再下载个其他的压缩的软件,,比较麻烦。。。
$ H4 R, R( r* u
建议楼主以后压缩的时候压缩成常见的压缩格式,,方便下载者
- v0 ?/ n3 Q9 t- F; V8 B
有的 .下载最新的F0_1.5.0的标准库. 里面有072的例程. cube_fw_1.2.0库里面也有nucleo 072的例程.哈哈
帖子的地址有,下载最新的1.5.0的标准外设库.里面就有