本帖最后由 harvardx 于 2015-1-24 21:52 编辑 9 d# t# Q8 f: f# i$ d 1 前言 ) l, l6 N( s4 z! L 友情链接: 沐紫妹妹关于最新Nucleo - F091RC开发板介绍以及相关的nucleo介绍/ H A/ N6 Y: m! R [ Nucleo平台最新开发利器——ST Nucleo-F091RC开发板评测/ }4 n! J$ \4 J# W: _ https://www.stmcu.org.cn/module/forum/forum.php?mod=viewthread&tid=599462&fromuid=2039986 8 L& v9 ~& `4 n% f2 { g1 D # w: Z3 F$ L6 ~$ w8 g. C 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编译就可以了. 2 回顾 ; S; A4 ~/ {* l 简单回顾一下, nucleo系列的几种开发方法,以最新的Nucleo 091开发板为例:/ y3 P: w6 r8 a4 b v 1. nucleo 091 可以mbed开发,比较新颖, 也比较简单, 但是是cpp的, 可能很多同学太适应; 目前mbed.org已经有091系列的支持,大家可以登录mbed云端查看; 2,标准外设库,目前标准已经到了1.5.0版本, 可以到此下载:' ^" {7 y( z. m+ H1 D# w* q2 @# _ 下载地址: http://www.st.com/st-web-ui/stat ... 0_stdperiph_lib.zip , \- C8 B: h9 ]1 P- l6 K( r 标准库解压后,有很多例程,其中包含了091的 ,可以到STM32F0xx_StdPeriph_Lib_V1.5.0\Projects\STM32F0xx_StdPeriph_Examples 目录下查看,怎么使用这些例程呢, 在里面的Libary_examples.html网页有说明,如下:' H9 n0 w/ M' H" `5 o9 d How to proceed?
3 e5 j' U* w) F$ @; g( V4 G 8 |& W6 j# S9 P$ L 3 Cubemx库,这是目前st比较推崇的. 目前pc配置软件CubeMx已经到了最新的4.6.0版本 下载地址: ( http://www.st.com/st-web-ui/stat ... ite/stm32cubemx.zip), - _8 c4 w) X5 q, G* G5 D 同样支持F0的cube外设库CubeF0已经是1.2.0版本 下载地址: (http://www.st.com/st-web-ui/stat ... are/stm32cubef0.zip) p$ Y9 q z( ?6 i; N c* N$ [ 其实Cube终究也是库,只不过代表着更加先进的方案,相信在st巡回研讨会上大家都有所了解.记得很多工程师刚开始不太适应,其实是更加方便我们开发,至少他可以通过图形化,来快速配置我们单片机.生成所需要的模块初始化或者操作代码. 3 CubeMx结合CubeF0_V1.2.0 库 开发 Nucleo -STM32F091 开发板实例 因为 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测试,感觉很好. 首先上一个最简单的例程, |
9 A1 P0 s7 y& y8 w( `$ _
关于例程中的ticker 其实就是定时器,大家可以看下面的详细说明: n* k, e6 \8 I3 d+ U$ T) T3 K
mbed 时钟系统
. c+ j8 ?) J' Q6 Z" h
微处理器的大量应用都和时间相关,如我们前面代码中多次出现的wait函数就是最常用的时间等待函数,显然,精确的时间等待必须建立在精确的计时技术上,这就需要用到计数器系统。2 H4 w. ]9 P4 c- z
+ T% C/ ?( A4 |" T$ M+ W
计数器的工作原理非常简单,就是每当它接收到一个脉冲时,它的计数值加一,一旦它的计数值达到用户设定的阈值,计数器就会产生一个中断信号让系统处理并重新从0开始计数。根据计数器可设定阈值的大小,我们可以把计数器分成8位计数器,16位计数器等,8位计数器可设定的最大阈值为2^8-1即255,16位则为65535。如果我们给定的脉冲信号频率为1M,而给定的计数器阈值为0,那么计数器就会每1us产生1个中断信号,这就为系统计时产生了依据。对于xbed LPC1768来说,它有四个通用计时器,它们可以用来计时、PWM输出等。
4 J- l) r0 ^. W$ j9 z
6 I' Z% v( _) |6 r5 D; c
除了wait相关的等待函数以外,mbed还提供了三个对象用来完成和时间相关的功能,分别是Timeout,用来在给定的时间执行特定函数;Ticker,用来定时执行特定函数;Timer,用来给系统计时,它们可用的方法描述如下:+ ]3 z) l! H4 R" o0 R
类名( O& U1 j5 k' ^/ _, t, ]# i
方法6 H7 s" m/ n# b
7 h$ p. y. D6 _. ^, o1 |) W! _7 k, Z
用途5 @5 b: R2 s" o- v) P% Y
Timer# [9 j7 o4 o* ?* t4 {
4 I2 Z+ {9 t4 t7 P* \+ P8 S1 T
Timer();
构造函数,实例化Timer对象
! c8 _0 B; ]% A( V. h: _: m8 S$ @
void start();
" M' h+ A% I$ T1 ?6 s% h5 V6 r0 }
开始计时- n6 d% W' H9 Z8 p
void stop();
5 l* A5 D1 F0 W( f3 A
停止计时
9 C' H2 q9 m) B% L. y1 E- a1 [' h B
void reset();
重新计时,即把时间计数恢复从0,如果原来处于start状态,那么计时继续) c" B/ [" T' Z: g
float read();
读取计时开始后过去的时间,单位是秒 W3 {8 J8 J1 g; L
int read_ms();1 n' z6 s8 u9 m: L
读取计时开始后过去的时间,单位是毫秒
int read_us();
) ?4 \" K1 l! n$ } Z
读取计时开始后过去的时间,单位是微秒: R/ |* X; l8 G3 N& [( C
operator float();+ h9 a% F. Z+ c" W& L
操作符重载,相当于read
Ticker s2 b+ y3 u4 N+ U" W' H# e3 s
0 o# _0 D9 Y+ H; A R) s
Ticker();
构造函数,实例化Ticker对象
void attach(void (*fptr)(void), float t)
$ }- A, v+ `% M |" F0 V
设定每t秒需要执行的函数' U1 h, H: F9 `% ` y
void attach_us(void (*fptr)(void), unsigned int t)% w/ x* v, K2 N2 j$ P
设定每t微秒需要执行的函数# g3 w/ b# ]& W1 P) D0 d1 s
void detach();2 r+ ~' o D1 n& U) u5 C
取消本对象需要定时执行的函数# C5 J, w& p' w' d% C
Timeout2 {, H G9 h2 ~1 S* D9 T: k% m! Q
Timeout();
' T/ V' _" u7 S' @( a4 ]* l
构造函数,实例化Timeout对象
+ G0 J/ F1 p, ]" G
void attach(void (*fptr)(void), float t)) s2 L/ x @9 r# L" D8 Q7 r
]% \% O( ~/ R2 ]: R! [
设定t秒后需要执行的函数
void attach_us(void (*fptr)(void), unsigned int t)
设定t微秒后需要执行的函数
6 j% m7 \9 G2 u& v* S2 W) s, X
void detach();
9 C' q2 `: Y& |# B/ I7 b7 l! m
取消本对象需要执行的函数
mbed Timer的应用
: _+ @# ~' J6 r) i& c9 S
mbed的Timer对象主要用来计算用户关心的时间间隔,下面是一个简单的示例,可以计算用户按下按钮的时间,主要代码如下:
Serial pc(USBTX,USBRX);
InterruptIn btn(P2_8);8 Z) m o# ?! {1 j: _
Timer mytimer;: p/ l% ]+ j# J' `8 ?$ Z" T3 o
int falltime;' h: b0 G( p* h
; |/ M- O. a% J$ x3 |- L$ O& q3 x, l
int risetime;
void fallfunc()
{
3 z, k9 O$ d' i5 O! l& @$ G8 z, s
falltime=mytimer.read_us();: Y) ` l# i3 P u7 {. D
}
8 N; ], _3 w% O8 g/ R$ \
void risefunc()/ E! U1 z: \4 Q j
y" `0 q( }; m# ^
{
0 l5 k" j' c! K& U) q0 T
risetime=mytimer.read_us();6 G+ D, K8 }8 |
0 A- f: n( q+ V, G g- u
pc.printf("You press button for %d us \n",risetime-falltime);
}$ H6 C# g" L$ p3 h
int main() {
mytimer.start();2 @4 r1 X, ?- y! c* k: i
, a M% m5 m8 n) Z6 M! L
btn.fall(&fallfunc);
btn.rise(&risefunc);8 h1 j. z6 c! Q; k6 l
while (1);
6 H9 a! Y+ U9 d) C8 ?# F
F9 c/ N/ ]/ e
}
程序运行的结果如下,当然,我们需要理解,任何中断的处理都有一定的延迟时间,所以此结果还是会有一定的误差,但绝对在us级别。
) a1 I" J. [% u
You press button for 330410 us
You press button for 137603 us
You press button for 122679 us6 q/ V5 [% k6 i1 {
2 k3 u$ f/ V8 _9 G* q N* N
You press button for 140683 us
有时候我们需要利用多个Timer来计算不同的时间,这只需要定义多个Timer对象即可:6 Y1 u2 \/ H, [4 ]8 M
Timer timer_led;2 S$ {4 @8 ^. S
* n$ _; k* A* o8 l8 ]5 w# t
Timer timer_serial;# m! l2 \. o) D4 S3 f
DigitalOut led1(LED1);
# ^$ r1 B) r! U' I
Serial pc(USBTX,USBRX);
" p2 T: I, T9 w/ h W' g
void task_led(void)% ] D c+ ?# a
{
$ [& _6 ^/ y( X1 _
led1=!led1;2 e) y: v0 L- M. v2 ]+ X
( z% u- Q& I7 [# O6 O
}- v8 _0 g9 u6 Y+ J/ J( U: W
7 A' P5 N7 X0 d3 C7 J$ r7 t
void task_serial(void)4 Z" {; |: s# s+ e5 U0 u% y* f: e
# \3 V4 |& c6 W: H! J3 R ]8 ?
{
pc.printf("Timer passed %d ms \n",timer_serial.read_ms());8 W3 p) F" v0 M( l1 q, Z$ A1 c
5 z" `& d: X+ D
}
int main()
{4 p3 e0 R+ ]7 @6 d
" q1 N- I8 D, ]4 y, m$ E
timer_led.start();
timer_serial.start(); L0 w6 ~) |; o' C- M! [3 Z! R, d/ \3 ]/ L
5 h/ a6 t) H( }- U _" N" E
while (1)1 ~$ E0 x: R8 i8 V" Y
; Z9 D. M# R6 e2 T) e
{$ U$ C' @ I6 R: P
: d* J: A% b- e; g
if (timer_led.read()>0.5)$ M4 I7 d9 u- _8 Y
# T" t5 v, D% l
{3 N+ \3 w0 `" M. ^6 b
task_led();
timer_led.reset();
}
2 M" L1 V5 }0 w, m
if (timer_serial.read()>1). }9 B& g n; `1 Z8 B
{ //test Timer value: _6 A* s1 }3 O) {( W; B
) a C+ \: m+ [
task_serial();
# _8 S2 j$ c$ {1 T
timer_serial.reset();- O, s5 w1 Q1 |. |! V0 v
}6 D4 k' m$ y; n0 Z
+ N( s% h, Q( B Q
}
- Y; \& w7 ~1 p
}
mbed Timeout的应用# [" V% n* F* `2 S
, ]1 L8 M+ q1 a- `2 ] ]+ i* r
mbed的Timeout对象主要用来在给定的时间后执行给定的函数,如下面的测试代码,运行后你会发现xbed LPC1768的四个led分别点亮,由于timeout只会被执行一次,所以点亮后会保持不变:
9 n3 j5 ?' R6 v% Q
DigitalOut led1(LED1);
DigitalOut led2(LED2);. u# i# l: R& e2 Q8 P
( n4 W5 t! L& _2 _/ Y0 W" z2 ~
DigitalOut led3(LED3);( K& c* V( f4 q2 i0 a7 _
DigitalOut led4(LED4);
3 M- H9 |) [7 G$ ]" j/ |, D5 k1 o
Timeout timer_led1;
! j7 |5 \/ A' [: T& L+ l. L5 f# ?8 ^1 @ {
Timeout timer_led2;' q- B J. _) h2 R2 k R
Timeout timer_led3;' j$ l7 K2 l! H. Y; y# M
Timeout timer_led4;
, G! @1 ?1 X$ E$ u
void led1flip()
2 Z( J' ~0 E! h+ j
{
6 M- C' B1 \: K8 B: s
led1=!led1;8 e& p& @ C) k: A1 s/ ~6 M+ ~6 y
}
void led2flip()
; ]. u" ~( R; O) i1 a( _8 L' F# w
{
led2=!led2;
4 C4 q3 V( Z$ P
}/ Z/ i4 g& K7 S' \% U% m1 `
void led3flip()
{% K7 G0 Z7 ?4 O0 Y! O2 M# V
+ L) o8 W+ d5 ~3 C2 I
led3=!led3;. T$ T* [" I0 d {
8 j& f) X6 N$ Y7 a8 S% t; o, ~
}
void led4flip()) ~: s% q' v# p5 {- a
4 ~" F4 y0 ?* o4 \
{
led4=!led4;/ C5 @' T: K/ g' O4 I
}
int main() {) M1 O% o7 Q; C
, u8 Y; b% Q! w% K% v" c2 O
timer_led1.attach(&led1flip,0.5);5 ]1 J5 W8 `) d6 p- b
timer_led2.attach(&led2flip,0.5*2);
0 p) N, S ^0 @: W8 x* E+ D& J
timer_led3.attach(&led3flip,0.5*4);
timer_led4.attach(&led4flip,0.5*8);- G' D. \+ B8 r
) U7 r- r: D9 T. z' c5 `+ X+ B
while (1);
4 Y1 H& a* t" N3 W; Y. L( E' d; A
7 g5 y3 E) t7 @. R1 E
}5 b3 K( X1 v7 S5 q. E
/ o. U9 L0 w# R$ G3 a9 }' t" a0 V. Z
mbed Ticker的应用
mbed的Ticker对象主要用来执行各类需要定期执行的函数,它和Timeout的唯一不同就是Timeout相关的函数只会被执行一次,而Ticker相关的则会被定期执行,如下面的测试代码,运行后你会发现xbed LPC1768的四个led将按照不同的频率变换:
1 ~7 t6 X4 _8 N) r* Z0 _9 Q
DigitalOut led1(LED1);/ m* ?2 l: h8 T; N7 P
DigitalOut led2(LED2);
8 R9 n5 J3 q4 c2 W, T8 U
DigitalOut led3(LED3);; R' t/ _3 ~) q
2 u* }) U/ @6 U" A
DigitalOut led4(LED4);# S- Y( X: j, t1 T! v
. O5 A' ~- }# B
Ticker timer_led1;/ Z2 w* `5 {4 F" {( R5 F
Ticker timer_led2;5 ? D" ~: D% l, I
4 |% _1 J! f5 h- t) K1 ?5 V
Ticker timer_led3;5 \* I2 G3 d; b: d, r
Ticker timer_led4;
( X9 [' S! F8 S) J3 N) F
void led1flip()
! A8 n1 E0 W. g- Z0 Y
{
led1=!led1;
}+ ~4 `2 o% s$ K
4 ]8 e& J% | c3 s1 O
void led2flip()
/ k- ^ R8 B4 U3 m, W; d
{
led2=!led2;3 [' w; H) X) h7 d0 Q7 _8 s1 z
}9 j2 m8 e9 @% ]( d
void led3flip()
{5 w3 U# K( }2 d, ?* Q, B
* r" T3 b. A7 Z% G
led3=!led3;
}& i7 e$ }, A0 s' k0 x; w* C
& a' C$ k. b* `" g# [/ y4 O
void led4flip()& K! s7 S. S7 O3 I- s4 Z* z* v
( N8 f0 q, u9 o6 H2 f& _7 I
{
( e& S; G0 ], Q- G; W# \+ `; Z& K
led4=!led4;
}$ _) _5 Y% i9 [" u6 m
! V+ E' A0 v: M/ j
int main() {
% \5 z; w9 F( _- S }1 P4 H
timer_led1.attach(&led1flip,0.5);
6 L4 E& |. c+ r: k6 M5 K8 a" r! ]
timer_led2.attach(&led2flip,0.5*2);4 P6 G7 M% {7 c
timer_led3.attach(&led3flip,0.5*4);0 R* n9 s" W$ n
$ y" s6 I( }9 O; N
timer_led4.attach(&led4flip,0.5*8);
1 L9 r6 o+ | S+ B+ s! C, J' ?
while (1);0 d8 H7 I7 i2 [6 W
$ \/ C, ~( U9 F7 Z
}
我们在使用Ticker对象的过程中还可以随时对Ticker设定的间隔进行更改,更改后的时间是即时生效的,如下面的代码,我们发现,用户每按一次按钮,led1的闪烁频率就会加快一倍。
DigitalOut led1(LED1);& ^; i: q* }9 ]
. o. u& H! R8 b$ `6 y1 L
InterruptIn btn(P2_8);( R6 G- t! c& z
Ticker timer_led1;
# t; u$ L. T1 p) i# K2 w: z
float interval; u) B& ?9 P1 Z5 J2 U% m, J
void led1flip()! [8 y2 S9 f" c* @7 `* E& l
- D% w+ Z0 Y# F& l
{
led1=!led1;
1 n# Y4 \! ~: `
}
void changefred()) }* a6 h) x; H) \
{+ c( F8 G- j4 y- z
interval=interval /2.0;1 t( B k: R( I; q3 t5 h" s
/ Q& x0 m# B' Q! p) z4 W+ u
timer_led1.attach(&led1flip,interval);0 `! J$ w' S4 m. c' I4 _+ p5 A3 u
! J9 C3 i/ ~- S9 {4 T
}
int main() {: A" t$ o9 d+ `+ d) X& s
' m& x" @. y+ ?4 q: m
interval=2;
btn.fall(&changefred);. L+ L: Y! p" K2 @2 M5 O- u
/ b7 J, B1 s* s% p
timer_led1.attach(&led1flip,interval);
2 R3 N) _1 u t
while (1);! r5 {8 r+ X; M3 o- h
# Y) i9 P, r4 W' N$ x
}
那还得再下载个其他的压缩的软件,,比较麻烦。。。: P& u5 C. w3 r2 w: y
0 U9 j, E0 Q; O. E' i* [( F
) |( [7 B5 m" H# ?9 U
5 j! X" L9 ~0 {7 b
建议楼主以后压缩的时候压缩成常见的压缩格式,,方便下载者2 g. q0 ]) y: e' ]2 r
* G1 {! f$ Y0 I9 F, y" j
+ [/ J; F' x$ I" Z+ G" T) ]
' w* K) h( J3 V- u0 H
4 {; T# m9 p1 O. r9 ~
有的 .下载最新的F0_1.5.0的标准库. 里面有072的例程. cube_fw_1.2.0库里面也有nucleo 072的例程.哈哈
帖子的地址有,下载最新的1.5.0的标准外设库.里面就有