![shequ.stmicroelectronics.cn](./template/st_v1/static/img/logo2.png)
本帖最后由 harvardx 于 2015-1-24 21:52 编辑 % S8 D8 ]) W. `9 ^# [* m/ B 1 前言 ; G' I1 N# }+ Y6 p( x5 \ 友情链接: 沐紫妹妹关于最新Nucleo - F091RC开发板介绍以及相关的nucleo介绍! Q- A) J% [4 q Nucleo平台最新开发利器——ST Nucleo-F091RC开发板评测' d' M& f: A: f+ O( T5 B& m' O/ U https://www.stmcu.org.cn/module/forum/forum.php?mod=viewthread&tid=599462&fromuid=2039986+ ~8 O& s$ z0 J9 v- U 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编译就可以了. 0 x! G8 J2 x6 M 2 回顾 & k; ]1 U1 ~3 O 简单回顾一下, nucleo系列的几种开发方法,以最新的Nucleo 091开发板为例:* Q6 n! {& m a; c$ K0 L 1. nucleo 091 可以mbed开发,比较新颖, 也比较简单, 但是是cpp的, 可能很多同学太适应; 目前mbed.org已经有091系列的支持,大家可以登录mbed云端查看; 2,标准外设库,目前标准已经到了1.5.0版本, 可以到此下载:8 v( s9 H, ]# Q3 l# i 下载地址:/ ?; p2 q) A. V0 h% i. O- w0 y* r http://www.st.com/st-web-ui/stat ... 0_stdperiph_lib.zip 标准库解压后,有很多例程,其中包含了091的 ,可以到STM32F0xx_StdPeriph_Lib_V1.5.0\Projects\STM32F0xx_StdPeriph_Examples! O1 a* I: g* y9 v5 h3 B) v 目录下查看,怎么使用这些例程呢, 在里面的Libary_examples.html网页有说明,如下:2 t9 d+ [. S* U+ |7 K How to proceed?
4 `& I7 B; N5 O 3 Cubemx库,这是目前st比较推崇的. 目前pc配置软件CubeMx已经到了最新的4.6.0版本5 q1 B5 N2 d* w( F d 下载地址: ( http://www.st.com/st-web-ui/stat ... ite/stm32cubemx.zip), & [4 Z1 K3 o# [5 [ 同样支持F0的cube外设库CubeF0已经是1.2.0版本/ u k$ g9 E, L& y. I% E 下载地址: (http://www.st.com/st-web-ui/stat ... are/stm32cubef0.zip)/ Z$ `9 y: \6 [ , Z3 h9 W& D/ {$ V ? 其实Cube终究也是库,只不过代表着更加先进的方案,相信在st巡回研讨会上大家都有所了解.记得很多工程师刚开始不太适应,其实是更加方便我们开发,至少他可以通过图形化,来快速配置我们单片机.生成所需要的模块初始化或者操作代码.6 j W; T5 k3 f$ n8 H 4 M" d+ p6 ` P- `) y' R 3 CubeMx结合CubeF0_V1.2.0 库 开发 Nucleo -STM32F091 开发板实例$ g2 x* d: I; [$ A : B" X6 ~2 b( c# i9 z7 E; r 因为 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测试,感觉很好. 首先上一个最简单的例程,! l/ i& j9 Q4 |& a ![]() |
关于例程中的ticker 其实就是定时器,大家可以看下面的详细说明:
mbed 时钟系统
2 D$ Q; N) K" t. V+ m+ {; t
微处理器的大量应用都和时间相关,如我们前面代码中多次出现的wait函数就是最常用的时间等待函数,显然,精确的时间等待必须建立在精确的计时技术上,这就需要用到计数器系统。3 [ P {$ ^" t" @0 A
计数器的工作原理非常简单,就是每当它接收到一个脉冲时,它的计数值加一,一旦它的计数值达到用户设定的阈值,计数器就会产生一个中断信号让系统处理并重新从0开始计数。根据计数器可设定阈值的大小,我们可以把计数器分成8位计数器,16位计数器等,8位计数器可设定的最大阈值为2^8-1即255,16位则为65535。如果我们给定的脉冲信号频率为1M,而给定的计数器阈值为0,那么计数器就会每1us产生1个中断信号,这就为系统计时产生了依据。对于xbed LPC1768来说,它有四个通用计时器,它们可以用来计时、PWM输出等。1 A1 r( s0 {" g% Z( O
除了wait相关的等待函数以外,mbed还提供了三个对象用来完成和时间相关的功能,分别是Timeout,用来在给定的时间执行特定函数;Ticker,用来定时执行特定函数;Timer,用来给系统计时,它们可用的方法描述如下:8 r4 N7 D. j p5 R
类名
$ Y% H s: T. q! f
方法
用途
Timer
2 O. C/ Z( [: |/ P, S* K
Timer();
构造函数,实例化Timer对象
void start();
开始计时
$ Y' E0 p& Q' J" o
void stop();6 ^) V7 F& y) A. I! F8 T' E
停止计时( n6 O- q3 w- J4 J
3 p8 z5 p: r; W$ b
void reset();" K" A% k% }% D" u$ m1 ^' o
& J5 A8 B# X- h( D" W
重新计时,即把时间计数恢复从0,如果原来处于start状态,那么计时继续
* V& X+ U6 p# {2 A
float read();' _( _: w$ C1 @1 a, I, d
% S3 w) M) Z2 ?+ V' s) u& j2 N
读取计时开始后过去的时间,单位是秒
int read_ms();5 z5 a: v+ s' h+ e5 f( ?8 m$ P
3 k4 K" n; C0 g# d7 ]5 ?9 m8 X. G/ u5 N
读取计时开始后过去的时间,单位是毫秒9 b- L' o1 r, C, J3 }
int read_us();
& N ?! ?& |/ [* t- g+ J0 \
读取计时开始后过去的时间,单位是微秒8 h0 U( d1 g5 _# I
/ F; V! p: S% O# X7 Q* d, v3 X8 Y
operator float();7 U, K A+ c- N% |
操作符重载,相当于read0 T( F/ V$ H9 T$ P3 L7 B
Ticker1 y, R* w, h; q' d
; W5 S }" P/ s3 @
Ticker();
构造函数,实例化Ticker对象7 f( Q5 X7 X! D, `
void attach(void (*fptr)(void), float t)( u# X+ c% L4 w
7 Q8 t: n+ S) A L7 ]1 G$ o
设定每t秒需要执行的函数& D' v& _% Z( V9 b+ p
. p) D' [8 Q2 p1 ?% |
void attach_us(void (*fptr)(void), unsigned int t)" h+ ^+ R N5 l" v
* ?$ u8 d# j. e+ R; j3 v9 |" {1 ~
设定每t微秒需要执行的函数# \( {2 i4 c1 D5 h7 I* u5 m
void detach();
n2 f a* ^, c% f& K
取消本对象需要定时执行的函数2 x+ K4 U/ S+ C% B+ Q6 g6 X: D# t
Timeout
# r9 R# G9 ]# {6 V0 ]! G
Timeout();* R. a j q/ ^+ ]
构造函数,实例化Timeout对象- h9 _3 h0 x- y u$ D& `8 e
void attach(void (*fptr)(void), float t)
- V: C: n& G* ?% j' h
设定t秒后需要执行的函数
$ T4 Z2 p1 }1 U
void attach_us(void (*fptr)(void), unsigned int t)- _5 p* {* X( w0 z# e# p
4 w- n2 t# r' K
设定t微秒后需要执行的函数! m2 r' e$ p4 R f9 a: K
' t; c9 g8 ~% c8 V! j) z5 H; C0 _
void detach();
取消本对象需要执行的函数% Q* V4 H$ `9 a% Q& \4 b0 L& y
2 g) _5 V5 I0 w! U1 k# }
mbed Timer的应用
& j; l, T+ b+ R Y9 g- D! R
mbed的Timer对象主要用来计算用户关心的时间间隔,下面是一个简单的示例,可以计算用户按下按钮的时间,主要代码如下:
! c2 @9 z, \( J9 W" F( G* c( ~
Serial pc(USBTX,USBRX);) v3 X4 R* w8 l( q4 m$ e0 @
InterruptIn btn(P2_8);
% r: d6 ]) z* a
Timer mytimer;3 w+ V! D4 y* O* ~0 I% s' l
int falltime;
5 d( D* R+ \2 k* \. `
int risetime;
void fallfunc()
{
falltime=mytimer.read_us();, h" I4 }$ e3 c5 ]
2 g' f* u$ N3 J4 [! f' n
}
void risefunc()1 q) N- e _* _& N$ L0 R
{4 h0 x0 v! q# s% n3 m4 o8 J
risetime=mytimer.read_us();- ]" ^ M$ o# G1 l
. B4 t/ B7 y j5 ]6 S
pc.printf("You press button for %d us \n",risetime-falltime);* \/ Y* d3 A& R L3 U- H
3 d" D) N) `( P
}
$ \* p# l) J# j# C# n
int main() {
6 s$ Q2 g( r6 _( |
mytimer.start();% l, q: |/ V9 h3 M
; A" \, \9 [) t" a5 Y$ {: L1 G
btn.fall(&fallfunc);
2 ?1 T; e$ v/ z% G
btn.rise(&risefunc);
while (1);' i9 s/ c, o) U. o# k
- s0 Z3 q) y" t$ ?
+ m3 N: K2 i3 f3 m1 A% o! w+ F9 \
} v) ^8 T; v) ~% ~/ ]$ j
程序运行的结果如下,当然,我们需要理解,任何中断的处理都有一定的延迟时间,所以此结果还是会有一定的误差,但绝对在us级别。
( F8 x# w- J; h3 Y6 X- K( f; A4 G) d
You press button for 330410 us
You press button for 137603 us1 { x2 R# I6 V5 f' u
You press button for 122679 us" [$ \2 i( \, h
2 |9 }3 E; R- |+ W
You press button for 140683 us
6 |( n6 b8 x; l5 w2 Q p
有时候我们需要利用多个Timer来计算不同的时间,这只需要定义多个Timer对象即可:
Timer timer_led;
Timer timer_serial; e2 N* | D) Y: {: K5 @/ H; k
DigitalOut led1(LED1);# v9 a; q7 i3 s" e3 N7 S1 t
Serial pc(USBTX,USBRX);% A& I! O% r; d/ ^( B
% V7 s. D( E% B6 q5 N' Q6 z N
void task_led(void)9 m) Z9 z3 N2 s5 r1 o9 n! b
{
2 s2 A* F0 O6 T7 G5 N3 D+ I
led1=!led1;
}
% g! @- X. O; s/ B
void task_serial(void)
+ ]! d" t" ?" h' a( Q& d- z, F% Z' ^
{1 q2 I, V; b: j/ R- L( S
pc.printf("Timer passed %d ms \n",timer_serial.read_ms());
% S, h j7 B6 u! ?9 }
}
8 A, J: P% b9 M# ?9 E K: b
int main()
4 i. h3 O# z0 f
{6 V5 U) F2 N9 O! C6 }0 y
1 v: U3 P3 T- D3 h/ Z$ l/ ^
timer_led.start();
% X& P3 J- ]3 F: I& u2 g, q* F
timer_serial.start();) K8 A4 s- n% N% X9 I- p
while (1)% S' ~1 `8 y9 S; m3 E" {
; w1 f M2 k5 Y. o( K( D9 z' Z
{" I y" f, a+ Q$ v* T! G. ~$ h5 s
, p8 b a. E1 R1 h) ^
if (timer_led.read()>0.5)
( c% x- T6 `4 F& D; l0 M- |
{
" `$ Y" X0 t& y. V3 A& L
task_led();4 M$ T6 V6 I1 r
timer_led.reset();0 B- X$ \; D5 ^6 Y& c) f
}, p, r8 I( [' J7 x, B6 ]7 l0 k
if (timer_serial.read()>1)
& u) ^/ B& ?; i$ D# b3 _
{ //test Timer value# M& U4 n: i) b! a- E
task_serial();
7 x4 l% _0 M7 K7 j9 K# k- Y; Q9 j
timer_serial.reset();
$ U( G& j7 K) J' G
}
}% o1 k7 N; q% @* S3 w% Y- }
}
mbed Timeout的应用
mbed的Timeout对象主要用来在给定的时间后执行给定的函数,如下面的测试代码,运行后你会发现xbed LPC1768的四个led分别点亮,由于timeout只会被执行一次,所以点亮后会保持不变:
+ D7 y/ j Z5 I. I- w
DigitalOut led1(LED1);
( B1 c) X1 M5 l$ I* Q
DigitalOut led2(LED2);
1 s6 V ?8 K0 f7 B
DigitalOut led3(LED3);
# k: a: y4 E5 l& z. Y9 L: r7 h
DigitalOut led4(LED4);
Timeout timer_led1;
Timeout timer_led2;2 x$ O. M4 }) r& I
, x( O5 `& U8 s% H# A
Timeout timer_led3;
3 G1 W0 f1 L6 F Z, d3 {
Timeout timer_led4;* E2 W. Q4 F5 ~: @' O% |; Q( h& E' _
void led1flip(). Z( I; Q6 B* E; e1 Y
{
led1=!led1;2 i3 w! {" J; R3 m% e# I& w7 l
. g5 a" @2 O" {. ~# ^
}9 ^/ A$ _6 O5 ^7 n# ]; T
3 `0 A- [: W+ q7 Q( i3 A
void led2flip()9 u8 t1 F9 j+ q% C2 W5 x& d4 \
{
, z, o& e) D0 {) l! D
led2=!led2;& N6 b5 y1 i+ ?/ |- t
* r$ n' Q- ~/ W* O
}! j0 m( F$ {& V: H9 m
void led3flip()
; i1 ?& `, R" f8 N; g
{
0 z: H: T7 m$ U: c
led3=!led3;
3 M' q# K4 j" |: Z7 m
}
/ _6 S4 v$ W; g6 \# g+ e
void led4flip()
. J: Y& [9 z' T0 z% T) o& j
{
6 ~4 R+ b/ [4 U; f) a
led4=!led4;
}
int main() {1 j/ N) R0 S- O; ~1 O; P
timer_led1.attach(&led1flip,0.5);
timer_led2.attach(&led2flip,0.5*2);: R6 o3 E ]* U+ ~2 S( x
8 L! l% c, }1 V% X" E% D
timer_led3.attach(&led3flip,0.5*4);% M+ v5 F" v- \4 h% _
2 D, m" }7 |+ P! u+ m' Z9 e
timer_led4.attach(&led4flip,0.5*8);
while (1);
9 |" P" f9 v% n8 i* e4 f
* H( z7 N- ^) x2 F4 G
}
mbed Ticker的应用
: R2 W& U- i) w2 Z/ H
mbed的Ticker对象主要用来执行各类需要定期执行的函数,它和Timeout的唯一不同就是Timeout相关的函数只会被执行一次,而Ticker相关的则会被定期执行,如下面的测试代码,运行后你会发现xbed LPC1768的四个led将按照不同的频率变换:
- Q- y4 l1 E/ _2 h
DigitalOut led1(LED1); B$ {* Q2 R5 S$ M& E
DigitalOut led2(LED2);; z0 P* `0 s2 ]5 i
DigitalOut led3(LED3);
1 n4 q3 T4 a3 c
DigitalOut led4(LED4);
8 B( m. }5 L; P9 B) A- Q
Ticker timer_led1;
( J2 E" i v* @0 X& D5 {( G( O
Ticker timer_led2;, W" k- k+ V; Z. X3 e
Ticker timer_led3;
/ e$ j& W/ J. U0 ^$ v
Ticker timer_led4;6 d0 @/ U6 b" ]: A; C) k6 \
3 u1 r+ V7 Z' V5 U5 f
void led1flip()
{
led1=!led1;
}& Y% ?3 Y6 B) U0 U
: |2 G* m3 o1 _: t
void led2flip()
; I4 ?% d5 i) [( K
{
W4 c6 J& F+ @8 E( i0 ]
led2=!led2;) @. E _; x1 Z/ e1 `( ]5 ~ h; [
}7 Y( G, ^( c7 ]# G6 F# Q* v
. U4 u3 L. g3 V) ~& b* ~
void led3flip()! |# d8 w/ [4 \, t: y7 j
1 }! r2 H2 {+ [, ?- f4 T: q
{
* F) A1 _* @1 C& s+ l% L; H
led3=!led3;
: h ~* y: R. V$ w2 ]; s, d
}
void led4flip()
{
led4=!led4;
}
. I. P. P( ]; b/ |
int main() {- \1 [( c7 [9 Y: j
timer_led1.attach(&led1flip,0.5);
timer_led2.attach(&led2flip,0.5*2);
timer_led3.attach(&led3flip,0.5*4);/ \: N- R- I) L' k
timer_led4.attach(&led4flip,0.5*8);
while (1);6 U O* [/ ]3 ]: y/ p4 w
5 K+ u+ W+ n, _1 H9 {
}& O( s2 o6 c6 W+ I/ F5 @: X" O& `
. J. l" Z1 [% s7 \
我们在使用Ticker对象的过程中还可以随时对Ticker设定的间隔进行更改,更改后的时间是即时生效的,如下面的代码,我们发现,用户每按一次按钮,led1的闪烁频率就会加快一倍。* X1 H' r$ |! B- `5 f
DigitalOut led1(LED1);2 ]" F3 j% _- z. ?, W; G
InterruptIn btn(P2_8);
Ticker timer_led1;
float interval;( o, G5 }2 m( q; f+ P# @# K
3 D: Z8 q ^1 F5 i- Z; E1 ~/ D
void led1flip()8 S4 a* K2 B) x1 A C0 u: q
7 b. |* f" }) E; L. s# t
{
o! i6 I. K3 |4 A$ Z& Z
led1=!led1;& g# R8 j; } H( G' V; k, h+ J
" S1 c$ @5 d# r( t3 v/ R' P) H
}
7 K" E$ {' c* I- Q$ [
void changefred()* U9 z! h S& H
{! w* ?. i& g" V" \$ d
interval=interval /2.0;5 h1 t b$ p% X! i7 Y) o
timer_led1.attach(&led1flip,interval);
}
H9 o5 {" s8 k( Q
int main() {3 ?' N H* Q7 k7 l) q
# e$ ~) X: M2 m+ n% j0 z4 V
interval=2;+ ?% L9 m( k' D, D8 ]. ?. _1 R* y
btn.fall(&changefred);- U* {7 G4 e- C4 h1 d
timer_led1.attach(&led1flip,interval);. C. L% H G1 A$ v3 @" r
while (1);
}
0 l9 A" J* S# P: M/ M9 \7 {" P5 `
那还得再下载个其他的压缩的软件,,比较麻烦。。。4 Z/ w$ c2 M$ C- ?+ \
/ n- ~/ i# B d( N8 T" T
建议楼主以后压缩的时候压缩成常见的压缩格式,,方便下载者
0 Q; i+ ^' a1 E: Y4 v
$ ^4 h7 W4 ?9 H! ?& P% W
5 P9 l1 ^. R$ w
有的 .下载最新的F0_1.5.0的标准库. 里面有072的例程. cube_fw_1.2.0库里面也有nucleo 072的例程.哈哈
帖子的地址有,下载最新的1.5.0的标准外设库.里面就有