搜档网
当前位置:搜档网 › 一天入门STM32

一天入门STM32

一天入门STM32
一天入门STM32

前言

一天入门STM32,仅一天的时间,是否有真的这么快。不同的人对入门的理解不一样,这篇一天入门STM32的教程,我们先对入门达成一个共识,如果你有异议,一天入门不了,请不要较真,不要骂街,保持一个工程师该有的修养,默默潜心学习,因为你还有很大的上升空间。

我眼中的入门:(前提是你学过51单片机和C语言)

1、知道参考官方的什么资料来学习,而不是陷入一大堆资料中无从下手。

2、知道如何参考官方的手册和官方的代码来独立写自己的程序,而不是一味的看到人家写的代码就觉得人家很牛逼。

3、消除对STM32的恐惧,消除对库开发的恐惧,学习是一个快乐而富有成就感的过程。

第1章一天入门STM32

本章参考资料:《STM32中文参考手册》《CM3权威指南CnR2》

学习本章时,配合《STM32中文参考手册》GPIO章节一起阅读,效果会更佳,特别是涉及到寄存器说明的部分。

1.151与STM32简介

51是嵌入式学习中一款入门级的精典MCU,因其结构简单,易于教学,且可以通过串口编程而不需要额外的仿真器,所以在教学时被大量采用,至今很多大学在嵌入式教学中用的还是51。51诞生于70年代,属于传统的8位单片机,如今,久经岁月的洗礼,既有其辉煌又有其不足。现在的市场产品竞争激烈,对成本极其敏感,相应地对MCU的要求也更苛刻:功能更多,功耗更低,易用界面和多任务。面对这些要求,51现有的资源就显得得抓襟见肘了。所以无论是高校教学还是市场需求,都急需一款新的MCU来为这个领域注入新的活力。

基于这市场的需求,ARM公司推出了其全新的基于ARMv7架构的32位Cortex-M3微控制器内核。紧随其后,ST(意法半导体)公司就推出了基于Cortex-M3内核的MCU—STM32。STM32凭借其产品线的多样化、极高的性价比、简单易用的库开发方式,迅速在众多Cortex-M3MCU中脱颖而出,成为最闪亮的一颗新星。STM32一上市就迅速占领了中低端MCU市场,受到了市场和工程师的无比青睐,颇有星火燎原之势。

作为一名合格的嵌入式工程师,面对新出现的技术,我们不是充耳不闻,而是要尽快吻合市场的需要,跟上技术的潮流。如今STM32的出现就是一种趋势,一种潮流,我们要做的就是搭上这趟快车,让自己的技术更有竞争力。

1.1.151与STM32架构的区别

我们先普及一个概念,单片机(即MCU)里面有什么。一个人最重要的是大脑,身体的各个部分都在大脑的指挥下工作。MCU跟人体很像,简单来说是由一个最重要的内核加其他外设组成,内核就相当于人的大脑,外设就如人体的各个功能器官。

下面我们来简单介绍下51和STM32的结构。

1.51系统结构

51系统结构框图

图151系统结构框图

我们说的51一般是指51系列的单片机,型号有很多,常见的有STC89C51、

AT89S51,其中国内用的最多的是STC89C51/2,下面我们就以STC89C51来讲解,并以51简称。

内核

51由一个IP核和片上外设组成,IP核就是上图中的CPU,片上外设就是上图中的:时钟电路、SFR和RAM、ROM、定时/计数器、并行I/O口、串行I/O口、中断系统。IP 核跟外设之间由系统总线连接,且是8bit的,速度有限。

51内核是上个世纪70年代intel公司设计的,速度只有12M,外设是IC厂商(STC)在内核的基础上添加的,不同的IC厂商会在内核上添加不同的外设,从而设计出各具特色的单片机。这里intel属于IP核厂商,STC属于IC厂商。我们后面要讲的STM32也一样,ARM属于IP核厂商,ARM给ST授权,ST公司在Cortex-M3内核的基础上设计出STM32单片机。

外设

我们在学习51的时候,关于内核部分接触的比较少,使用的最多的是片上外设,我们在编程的时候操作的也就是这些外设。

编程的时候操作的寄存器位于SFR和RAM这个部分,其中SFR(特殊功能寄存器)占有128字节(实际上只用了26个字节,只有26个寄存器,其他都属于保留区),RAM 占有128字节,我们在程序中定义的变量就是放在RAM中。其中SFR和RAM在地址上是重合的,都是在80~FF这个地址区间,但在物理区间上是分开的,所以51的RAM是有256个字节。

编写好的程序是烧写到ROM区。剩下的外设都是我们非常熟悉的IO口,串口、定时器、中断这几个外设。

2.STM32系统结构

STM32系统结构框图

图2STM32系统结构框图

内核

在系统结构上,STM32和51都属于单片机,都是由内核和片上外设组成。只是STM32使用的Cortex-M3内核比51复杂得多,优秀得多,支持的外设也比51多得多,同时总线宽度也上升到32bit,无论速度、功耗、外设都强与51。

从结构框图上看,对比51内核只有一种总线,取指和取数共用。Cortex-M3内部有若干个总线接口,以使CM3能同时取址和访内(访问内存),它们是:

指令存储区总线(两条)、系统总线、私有外设总线。有两条代码存储区总线负责对代码存储区(即FLASH外设)的访问,分别是I-Code总线和D-Code总线。

I-Code用于取指,D-Code用于查表等操作,它们按最佳执行速度进行优化。

系统总线(System)用于访问内存和外设,覆盖的区域包括SRAM,片上外设,片外RAM,片外扩展设备,以及系统级存储区的部分空间。

私有外设总线负责一部分私有外设的访问,主要就是访问调试组件。它们也在系统级存储区。

还有一个MDA总线,从字面上看,DMA是data memory access的意思,是一种连接内核和外设的桥梁,它可以访问外设、内存,传输不受CPU的控制,并且是双向通信。简而言之,这个家伙就是一个速度很快的且不受老大控制的数据搬运工,这个在51里面是没有的。

外设

从结构框图上看,STM32比51的外设多得多,51有的串口、定时器、IO口等外设STM32都有。STM32还多了很多特色外设:如FSMC、SDIO、SPI、I2C等,这些外设按照速度的不同,分别挂载到AHB、APB2、APB1这三条总线上。

3.小结

从内核和外设这两大方面来比较,STM32之于51就是一个升级版的单片机。它适应市场,引流潮流,在中低端的微控制器中流光溢彩。

1.2学习方法的区别

学习51用寄存器,学习STM32用库。

以前我们在学习51的时候,用的是寄存器编程的方法,想要实现什么效果,直接往寄存器里面赋值,优点是直观,简单粗暴,知道自己具体干了啥,心里踏实。

直接操作寄存器之所以在51上可行,究其原因,我想有两点:

1、51主频不高,资源有限,必须注重程序执行的效率,只能直接操作寄存器。关键的地方还得用汇编,不适合用固件库。

要知道当初我们学习51单片机的时候用的还是汇编,连现在的C编程都不是,就更别说什么库函数编程。

2、51功能简单,寄存器不多。以国内普及最广的STC89C52为例,寄存器全部加起来不到30个。按照功能区分来记的话,可以把每个寄存器背的滚瓜烂熟,并且寄存器每一位的功能都可以记得住,在编程的时候做到了然于胸。

现在从51过度到STM32的学习,很多人还是喜欢沿用51的学习方法。接受不了库,在学习库的时候陷入迷糊之中,来回几个月下来,都不知道到底有没学会STM32,因为在这一路的学习中都是在调用库函数,压根就没有操作过寄存器,心里面很不踏实。其实大家在调用库函数的时候心中难道就没有疑问,库的底层是怎么实现的?难道就没有勇气对库的底层一探究竟。可最后当我们开始跟踪库函数底层的时候,看到一堆的宏定义、结构体、指针、各种的文件包含,而且注释全部都是英文的,是不是又心生忌惮。鉴于此,我想用两个原因来总结下很多初学者畏惧库不愿意用库的原因。

1、C语言知识点的欠缺

库在实现寄存器映像时使用的宏定义,强制类型转换,在定义寄存器时使用的结构体,在外设初始化函数时使用的指针,在组织头文件时使用的条件编译等C语言知识,在大学课程中很少涉及,大多数老师也基本是不讲。在一些简单的51单片机编程中又很少会用到这些知识。学单片机,做嵌入式开发其实80%的工作都跟C语言编程相关,剩下的20%的工作就是阅读各种数据手册,熟悉各种硬件外设。所以掌握这些基本的C语言知识,是嵌入式学习中一道迈不过去的坎,STM32的库则给了我们一次提升C的机会。

凡是可以从书本中找到的,相信我们基本都可以学会,很多初学者并不是不够聪明或者勤奋,只是缺少方向性的指导罢了。对于这欠缺的知识点我们稍微花点时间就可以掌握,剩下的就是不断地实践调试。这里我为大家推荐一本C语言的书籍《C和指针》。

2、程序架构设计思想的欠缺

这个比较难搞,很多C语言学习得挺好好的人,也比较难掌握。还好我们遇到了STM32的库,这给了我们一个学习和提升C语言绝佳的机会。库的整个架构是如何搭建起来的,代码上是如何如何一步一步写出来的:从寄存器映像开始,到寄存器的封装,然后到函数的编写,到每个外设函数对应的驱动文件,这里面涉及到了大量的条件编译,文件包含的思想,对应刚写过几行51单片机的初学者来说简直就是噩梦。但是,如果你把这一系列的关系弄明白了,那么对库的整个架构也了解的差不多了,以后你就不用嚷嚷着说要操作寄存器了。

如果你一开始不喜欢用库,对库开发很忌惮,那么请自问:是不是我的C语学得不够好。库是一种全新的学习方法,是一种潮流,我更把它看做是与C语言的又一次历练和提升。是否用库,只差你一个闪亮的回眸。

1.3用寄存器点亮LED

为了顺利过渡到库开发,在STM32编程的开始,我们对照51点亮一个LED的方法,给大家演示一下STM32如何用操作寄存器的方法点亮一个LED,然后再慢慢讲解到底什么是库,让大家知道库跟寄存器的关系。

1.3.1用51点亮一个LED

在用STM32点亮一个LED之前,我们先来复习下用51如何点亮一个LED。

硬件上我们假设51单片机的P0口的第0位接了一个LED,负逻辑亮。如果我们要点亮这个LED,代码上我们会这么写:

1P0=0XFE;//总线操作点亮LED

这时候我们就把LED点亮了,如果要关掉LED,则是:

1P0=0XFF;//总线操作关闭LED

这里面我们用的是总线操作的方法,即是对P0口的8个IO同时操作,但起作用的只是P0^0。

除了这种总线操作的方法,我们还学习过位操作,利用51编译器的关键字sbit,我们可以定义一个位变量:

1sbit LED=P0^0;

那么LED=0;就点亮了LED,LED=1;就关闭了LED。为了让程序看起来见名知义,我们定义两个宏:

1#define ON0

2#define OFF1

点亮和关闭LED的代码就变成了:

1LED=ON;//位操作点亮LED

2LED=OFF;//位操作关闭LED

稍微整理下代码,整体的效果就是:

1//假设51单片机的P0^0口接LED,负逻辑点亮

2

3#define ON0

4#define OFF1

5

6sbit LED=P0^0;

7

8void main(void)

9{

10P0=0XFE;//总线操作点亮LED

11P0=0XFF;//总线操作关闭LED

12

13LED=ON;//位操作点亮LED

14LED=OFF;//位操作关闭LED

15}

上面总线和位操作的的方法,学过51的朋友是非常熟悉的,也很容易理解。那么我们再说一下大家容易忽略的几个知识点。

1.什么是寄存器

在点亮LED的时候,我们都是用操作寄存器的方法来实现的,那大家是否想过,这个寄存器到底是什么?为什么我们可以直接操作P0口?

解答上面的问题之前,我们先简单介绍下51单片机的主要组成部分,这对我们学习其他单片机也有好处。

我们以国内的STC89C51为例,该单片机主要由51内核、外设IP、和总线这三大部分组成。内核是由Intel公司生产的,外设IP就是STC公司在内核的基础上添加的诸如定时器、串口、IO口等这些东西,总线就是用来连接内核和外设的接口单元。Intel在这里属于IP核设计公司,STC属于IC设计公司。世界上能设计IP核的公司屈指可数。我们非常熟悉的ARM公司就属于IP核设计公司,ARM给其他公司授权,其他IC公司就在ARM内核上设计出各具特色的MCU,我们后面要学习的STM32就是属于一中基于ARM内核的MCU。

寄存器则是内置于各个IP外设中,是一种用于配置外设功能的存储器,就是一种内存,并且有想对应的地址。学过C语言我们就知道,要操作这些内存就可以使用C语言中的指针,通过寻址的方式来操作这些具有特殊功能的内存—寄存器。比如P0口对应的地址是0X80,那么我们要修改0X80这个地址对应的内存的内容的话,按照常理可以这样操作:

1*(*0X80)=0XFE;//点亮LED

可当我们编译的时候,编译器会报错,在51里面只能通过SFR和SBIT这两个关键字来实现寄存器映像,不能直接操作寄存器对应的地址,这是51相较于STM32不同的地方。

51单片机的这些寄存器位于地址80H~FFH中,对应着128个地址,但不是每个地址都是有效的,51系列的单片机有21个,52系列的则有26个,其他的都是保留区。

图351寄存器映射

2.寄存器映射

实际上我们在编程的时候并不是通过指针来操作寄存器的,而是直接给P0、P1这些端口寄存器赋值。那么这些外设资源是如何与地址建立一一对应的关系(寄存器映射定义),这得益与51特有的两个关键字:SFR和sbit,其他单片机没有,只能用其他的方式来实现寄存器映射。这两个关键字帮我们实现了所有寄存器的定义,所以我们才可以像操作普通变量一个来操作寄存器。其实我们一开始提到的点亮LED的代码,全貌应该是这样的:

1sfr P0=0x80;//寄存器定义

2P0=0XFE;//总线操作点亮LED

为了方便起见,我们可以把寄存器映射全部写好封装在一个头文件里面,不用每用一个寄存器就定义一次。其实这方面的工作不用我们做,我们在编程的时候都会在开始的地方添加一个头文件:

1#include

这个头文件已经实现了全部寄存器的定义,该文件是keil自带,在安装目录:

Keil\C51\INC下可以找到。这个文件实现了字节寄存器和位寄存器的定义。

1/*--------------------------------------------------------------

2REG51.H

3

4Header file for generic80C51and80C31microcontroller.

5Copyright(c)1988-2002Keil Elektronik GmbH and Keil Software,Inc.

6All rights reserved.

7----------------------------------------------------------------*/ 8

9#ifndef__REG51_H__

10#define__REG51_H__

11

12/*BYTE Register*/

13sfr P0=0x80;

14sfr P1=0x90;

15sfr P2=0xA0;

16sfr P3=0xB0;

17sfr PSW=0xD0;

18sfr ACC=0xE0;

19sfr B=0xF0;

20sfr SP=0x81;

21sfr DPL=0x82;

22sfr DPH=0x83;

23sfr PCON=0x87;

24sfr TCON=0x88;

25sfr TMOD=0x89;

26sfr TL0=0x8A;

27sfr TL1=0x8B;

28sfr TH0=0x8C;

29sfr TH1=0x8D;

30sfr IE=0xA8;

31sfr IP=0xB8;

32sfr SCON=0x98;

33sfr SBUF=0x99;

34

35

36/*BIT Register*/

37/*PSW*/

38sbit CY=0xD7;

39sbit AC=0xD6;

40sbit F0=0xD5;

41sbit RS1=0xD4;

42sbit RS0=0xD3;

43sbit OV=0xD2;

44sbit P=0xD0;

45

46/*TCON*/

47sbit TF1=0x8F;

48sbit TR1=0x8E;

49sbit TF0=0x8D;

50sbit TR0=0x8C;

51sbit IE1=0x8B;

52sbit IT1=0x8A;

53sbit IE0=0x89;

54sbit IT0=0x88;

55

56/*IE*/

57sbit EA=0xAF;

58sbit ES=0xAC;

59sbit ET1=0xAB;

60sbit EX1=0xAA;

61sbit ET0=0xA9;

62sbit EX0=0xA8;

63

64/*IP*/

65sbit PS=0xBC;

66sbit PT1=0xBB;

67sbit PX1=0xBA;

68sbit PT0=0xB9;

69sbit PX0=0xB8;

70

71/*P3*/

72sbit RD=0xB7;

73sbit WR=0xB6;

74sbit T1=0xB5;

75sbit T0=0xB4;

76sbit INT1=0xB3;

77sbit INT0=0xB2;

78sbit TXD=0xB1;

79sbit RXD=0xB0;

80

81/*SCON*/

82sbit SM0=0x9F;

83sbit SM1=0x9E;

84sbit SM2=0x9D;

85sbit REN=0x9C;

86sbit TB8=0x9B;

87sbit RB8=0x9A;

88sbit TI=0x99;

89sbit RI=0x98;

90

91#endif

92

3.启动文件—STARTUP.A51

还有一个就是启动代码,这个也是很多初学者容易忽略的地方,对于这部分我们主要总结下它的功能,不详解讲解里面的代码。

单片机在上电复位后,首先执行的是启动文件—STARTUP.A51,而不是我们通常看到的main函数。我们新建51工程的时候会有一个提示:是否拷贝启动代码到当前的工程,我们一般选择是。

图4是否添加启动代码

启动代码用汇编语言编写,主要实现了以下功能:清除内部数据存储器、清除外部数据存储器、清除外部页储存器、初始化small模式下的可重入栈和指针、初始化large模式下可重入栈和指针、初始化compact模式下的可重入栈和指针、初始化8051硬件栈指针、

传递初始化全局变量的控制命令或者在没有初始化全局变量时给main函数传递命令。然后程序就跳转到main函数,来到我们熟知的C世界。

4.总结

在讲解用51点亮LED的时候,我们补充了什么是寄存器、寄存器映射、启动代码这三部分的内容,这三部分内容本来是放到STM32里面讲解的,但考虑到大家已经有51的基础,并且对51比较熟悉,那我再添加点内容,大家自然没有那么抗拒,并且可以根据上面讲的内容亲自实践,学习得也会更深入。那当我再在STM32讲解这几个内容的时候,大家就会对比着学习,对STM32也就没有那么忌惮。

1.3.2用STM32点亮一个LED

对比着51点亮LED的方法,我们先用操作寄存器的方法用STM32点亮一个LED,然后再一步步完善代码,构建最简单的库函数,让我们知道库是怎么建立起来的。

在写代码之前,我们先建一个工程。大家要注意的是,虽然51跟STM32用的都是keil,但是针对的MCU是不一样,软件在安装的时候要安装在不同的目录且不能安装在英文目录,不然会起冲突。我们这里用的是keil5,MDK5.15版本。

1.新建工程

用KEIL5新建一个工程,把工程放在一个事先建好的文件夹内,工程命名为REG后保存。然后在工程目录下添加启动文件:startup_stm32f10x_hd.s,该文件可以从KEIL5安装目录找到,也可以从ST库里面找到,然后把启动文件添加到工程里面。

2.启动文件—startup_stm32f10x_hd.s

启动文件由汇编语言编写,具体功能跟51里面的启动文件:STARTUP.A51差不多。

STM32的启动文件主要实现了:1、设置初始SP。2、设置初始PC=Reset_Handler 3、设置向量表入口地址,并初始化向量表。4、调用库函数SystemInit,把系统时钟配置成72M,SystemInit在库文件system_stm32f10.c定义。5、跳转到标号_mian,最终来到C的世界。这里我们先去除繁枝细节,挑重点的讲,主要理解第四和第五点,在启动文件的147~155行,是复位处理函数,代码如下:

1;Reset handler

2Reset_Handler PROC

3EXPORT Reset_Handler[WEAK]

4IMPORT__main

5IMPORT SystemInit

6LDR R0,=SystemInit

7BLX R0

8LDR R0,=__main

9BX R0

10ENDP

这里我们简单介绍下这10行代码。

第一行是程序注释,在汇编里面注释用的是“;”,跟C语言不一样。

第二行是定义了一个子程序:Reset_Handler。PROC是子程序定义伪指令。一般用法为:

1子程序名PROC NEAR(或FAR)

2……

3ret

4子程序名ENDP

其中NEAR和FAR是属性词。NEAR属性(段内近调用):调用程序和子程序在同一代码段中,只能被相同代码段的其他程序调用。FAR属性(段间远调用):调用程序和子程序不在同一代码段中,可以被相同或不同代码段的程序调用。

第三行EXPORT表示Reset_Handler这个子程序可供其他模块调用。

关键字[WEAK]表示弱定义,如果编译器发现在别处定义了同名的函数,则在链接时用别处的地址进行链接,如果其它地方没有定义,编译器也不报错,以此处地址进行链接。

第四行和第五行IMPORT说明SystemInit和__main这两个标号在其他文件,在链接的时候需要到其他文件去寻找。

SystemInit在库文件system_stm32f10x.c实现,用来初始化STM32的一系列时钟,把系统时钟设置为72MHZ。STM32的时钟比51单片机复杂,需要经过一系列的配置才能达到稳定运行的状态。

__main其实不是我们定义的,当编译器编译时,只要遇到这个标号就会定义这个函数,该函数的主要功能是:负责初始化栈、堆,配置系统环境,并在最后跳转到用户自定义的main函数,从此来到C的世界。

第六行把SystemInit的地址加载到寄存器R0。

第七行程序跳转到R0中的地址执行程序,之后系统的时钟就被设置成72MHZ。

第八行把_main的地址加载到寄存器R0。

第九行程序跳转到R0中的地址执行程序,执行完毕之后就去到我们熟知的C世界。

第十行表示子程序的结束。

总结下就是,Reset_Handler这个函数执行了两个函数调用,一个是SystemInit,把系统时钟设置成72M,令一个是__main,初始化好系统环境,最终调用C的main,从此去到C的世界。

等下我们点亮LED的时候采用最简单的方法,直接使用内部的LSI时钟(8MHZ)作为主时钟即可,不使用外部时钟LSE。

__main函数由编译器生成,负责初始化栈、堆等,并在最后跳转到用户自定义的main()函数,来到C的世界。

3.新建main.c

用记事本新建一个main.c文件放到工程目录下,然后把main.c添加到工程中。

现在我们就可以开始编写程序了,我们先编写一个main函数,里面啥都没有,暂时为空。这时跟编写51程序时是不是很像。

1int main(void)

2{

3

4}

现在我们可以编译看看,看看有啥现象。

这时候出现如下错误:

Undefined symbol SystemInit(referred from startup_stm32f10x_hd.o).

错误提示说SystemInit没有定义。从分析启动文件时我们知道,Reset_Handler调用了该函数用来初始化系统时钟,而该函数是在库文件system_stm32f10x.c中实现的。我们重新写一个这样的函数也可以,把功能完整实现一遍,但是为了简单起见,我们在main文件里面定义一个SystemInit空函数,为的是骗过编译器,把这个错误去掉。关于配置系统时钟我们在后面再写简单的代码。

1void SystemInit(void)

2{

3

4}

这时我们再编译就没有错了,完美解决。还有一个方法就是在启动文件中把有关SystemInit的代码注释掉也可以,代码如下所示:

1;Reset handler

2Reset_Handler PROC

3EXPORT Reset_Handler[WEAK]

4IMPORT__main

5;IMPORT SystemInit

6;LDR R0,=SystemInit

7BLX R0

8LDR R0,=__main

9BX R0

10ENDP

4.控制IO口

下面我们从三个方面来讲解STM32的IO在控制LED时跟51的区别。有关STM32的IO的寄存器介绍,我们可以看《STM32中文参考手册》的第八章即可,下面涉及到的IO 寄存器均来自这一章的第二小节:8.2GPIO寄存器描述

电平控制

51单片机的IO口如果要输出1和0,可以直接赋值,不用控制其他寄存器。

而STM32的IO口比较复杂,如果要输出1和0,则要通过控制:端口输出数据寄存器ODR来实现,ODR是:Output data register的简写,在STM32里面,其寄存器的命名名称都是英文的简写,很容易记住。从手册上我们知道ODR是一个32位的寄存器,低16位有效,高16位保留。低16位对应着IO0~IO16,只要往相应的位置写入0或者1就可以输出低或者高电平。

PB0输出低电平,代码如下:

1GPIOB_ODR=0<<0;

这时候编译,我们会发现有个错误,说GPIOB_ODR没有定义,不过我们确实没有定义。在51单片机中,我们可以直接往P0口赋值,那是因为在reg51.h这个头文件中实现了P0口这个寄存器的映像,用的是51特有的关键字SFR来定义的。

STM32跟51不一样,没有SFR,只能用其他的方式来实现寄存器映像。因为寄存器实际上就是具有特殊功能的内存,那么我们可以通过宏定义来实现寄存器映像,其实ST 的库函数中用的也是这种方法。

从手册中我们看到ODR寄存器的地址偏移是:0CH,这个偏移地址是基于端口的起始地址而言的。在STM32中,每个外设都有一个起始地址,叫做外设基地址,外设的寄存器就以这个基地址为标准按照顺序排列,跟结构体里面的成员差不多。

在手册中的第二章:存储器和总线构架的2.3:存储器映像小节中可以查看到所有外设的基地址,如下:

图5STM32寄存器组起始地址

其中GPIOB的起始地址是:0X40010C00,这样就可以算出GPIOB_ODR寄存器的地址是:0X40010C00+0X0C=0X40010C0C。现在我们就可以定义GPIOB_ODR这个寄存器了,代码如下:

1#define GPIOB_ODR*(volatile unsigned long*)0x40010C0C

有了这个寄存器定义,我们就可以直接操作GPIOB_ODR了。

方向控制

虽然配置了ODR寄存器,但是这个时候还不能点亮LED,因为STM32的IO口还要配置方向,这个由端口配置寄存器来控制。端口配置寄存器分为高低两个,每4bit控制一个IO口,所以端口配置低寄存器:CRL控制这IO口的低8位,端口配置高寄存器:CRH 控制这IO口的高8bit。在4位一组的控制位中,CNFy[1:0]用来控制端口的输入输出,MODEy[1:0]用来控制输出模式的速率,即输出时,IO电平翻转的速度。

输入有三种模式,输出有4中模式,我们在控制LED的时候选择通用推挽输出。

输出速率有三种模式:2M、10M、50M,这里我们选择2M。

同GPIOB_ODR一样,我们也可以算出GPIO_CRL的地址为:0x40010C00。那么设置PB0为通用推挽输出,输出速率为2M的代码则如下所示:

1#define GPIOB_CRL*(volatile unsigned long*)0x40010C00

2

3//配置PB0为通用推挽输出,输出速率为2M

4GPIOB_CRL=(2<<0)|(0<<2);

时钟控制

当我们设置了IO口的方向,并在相应的输出寄存器里面输入了值的时候,以为现在总算可以点亮LED了吧,其实还差最后一步。

STM32外设很多,为了降低功耗,每个外设都对应着一个时钟,在系统复位的时候这些时钟都是被关闭的,如果想要外设工作,必须把相应的时钟打开。

STM32的所有外设的时钟由一个专门的外设来管理,叫RCC(reset and clock control),RCC在STM32中文参考手册的第六章。

STM32的外设因为速率的不同,分别挂载到三条总系上:AHB、APB2、APB1,APB 为高速总线,APB2次之,APB1再次之。所以的IO口都挂载到APB2总线上,属于高速外设。时钟由APB2外设时钟使能寄存器(RCC_APB2ENR)来控制,其中PB端口的时钟由该寄存器的位3写1使能。

同ODR和CRL,我们可以算出RCC_APB2ENR的地址为:0x40021018。那么使能PB口的时钟代码则如下所示:

1#define RCC_APB2ENR*(volatile unsigned long*)0x40021018

2

3//开启端口B时钟

4RCC_APB2ENR|=1<<3;

如果你足够细心,你会发现我们虽然开了端口时钟,那这个时钟到底是多大?时钟到底是从哪里来的?

如果我们用的是库,那么有个库函数SystemInit,会帮我们把系统时钟设置成72M。现在我们没有使用库,那现在时钟是多少?答案是8M,当外部HSE没有开启或者出现故障的时候,系统时钟由内部低速时钟LSI提供,现在我们是没有开启HSE,所以系统默认的时钟是LSI=8M。至于更深入的细节我们在后面的RCC时钟树中再详细分析。如果你想自己先尝鲜,那么看RCC外设中的:时钟控制寄存器(RCC_CR)和时钟配置寄存器(RCC_CFGR)这两个寄存器即可。

水到渠成

控制了电平,配置了方向,开启了时钟,经过这三步,我们总算可以控制一个LED 了。比起51直接输出电平,控制STM32的IO多了两步:即配置方向可开启时钟。比起AVR和PIC这两种单片机则多了开启时钟这一步。

现在我们完整组织下用STM32控制一个LED的代码:

1#define RCC_APB2ENR*(volatile unsigned long*)0x40021018

2#define GPIOB_CRL*(volatile unsigned long*)0x40010C00

3#define GPIOB_ODR*(volatile unsigned long*)0x40010C0C

4

5int main(void)

6{

7//开启端口B的时钟

8RCC_APB2ENR|=1<<3;

9

10//配置PB0为通用推挽输出模式,速率为2M

11GPIOB_CRL=(2<<0)|(0<<2);

12

13//PB0输出低电平,点亮LED

14GPIOB_ODR=0<<0;

15}

16

17void SystemInit(void)

18{

19}

很多人说学习STM32很难,一堆的寄存器,不知道怎么操作,特别是那些刚学习完51的朋友,不知道怎么过度。这里我们对比了51的编程方法,写了个简单的用STM32寄存器点亮LED的方法,希望可以起到抛砖引玉的作用。

1.4再接再厉—构建库的雏形

学习STM32存在着一个用寄存器好还是用库好的争议点,就好比编程是用汇编好还是用C好一样。其实孰优孰劣,市场自有定论,用户群说明一切。

虽然我们上面用寄存器点亮了LED,乍看一下好像代码也很简单,但是我们别侥幸以后就可以一直用寄存器开发。在用寄存器点亮LED的时候,我们是否发现STM32的寄存器都是32位的,在配置的时候非常容易出错,而且代码还很不好理解。所以学习TM32最好的方法是用库,然后在库的基础上了解底层,看遍所有寄存器。

但是很多人对库还是很忌惮,因为一开始用库的时候有很多代码,很多文件,不知道如何入手。不知道你是否认同这么一句话:一切的恐惧都来源于认知的空缺。我们对库忌惮那是因为我们不知道什么是库,不知道库是怎么实现的。

接下来,我们在寄存器点亮LED的代码上继续完善,把代码一层层封装,实现库的最初的雏形,相信经过这一步的学习后,你会对库的运用做到游刃有余。这里我们只讲关于GPIO库,其他外设的我们直接参考库学习即可,不必自己写。

1.4.1定义外设寄存器结构体

上面我们在操作寄存器的时候,操作的是寄存器的绝对地址,如果每个寄存器都这样操作,那将非常麻烦。

我们考虑到外设寄存器的地址都是基于外设基地址的偏移地址,都是在外设基地址上逐个连续递增的,每个寄存器占32个或者16个字节,这种方式跟结构体里面的成员类似。所以我们可以定义一种外设结构体,结构体的地址等于外设的基地址,结构体的成员等于寄存器,成员的排列顺序跟寄存器的顺序一样。这样我们操作寄存器的时候就不用每次都找到绝对地址,只要知道外设的基地址就可以操作外设的全部寄存器,即操作结构体的成员即可。

下面我们先定义一个GPIO寄存器结构体,结构体里面的成员是GPIO的寄存器,成员的顺序按照寄存器的偏移地址从低到高排列,成员类型跟寄存器类型一样。

1typedef struct{

2__IO uint32_t CRL;

3__IO uint32_t CRH;

4__IO uint32_t IDR;

5__IO uint32_t ODR;

6__IO uint32_t BSRR;

7__IO uint32_t BRR;

8__IO uint32_t LCKR;

9}GPIO_TypeDef;

在《STM32中文参考手册》8.2寄存器描述章节,我们可以找到结构体里面的7个寄存器描述。在点亮LED的时候我们只用了CRL和ODR这两个寄存器,至于其他寄存器的功能大家可以自行看手册了解。

在GPIO结构体里面我们用了两个数据类型,一个是uint32_t,表示无符号的32位整型,因为GPIO的寄存器都是32位的。这个类型声明在标准头文件stdint.h里面,我们在程序上只要包含这个头文件即可。

另外一个是__IO,这个是我们自己定义的,原型是volatile,作用就是告诉编译器不要因优化而省略此指令,必须每次都直接读写其值,这样就能确保每次读或者写寄存器都真正执行到位。

关于这两个数据类型,我们添加如下代码:

1#include

2#define__IO volatile

1.4.2外设声明

现在GPIO寄存器结构体已经定义好了,STM32F1系列的GPIO端口分A~G,即GPIOA、GPIOB。。。。。。GPIOG。每个端口都含有GPIO_TypeDef结构体里面的寄存器,我们可以根据各个端口的基地址把GPIO的各个端口定义成一个GPIO_TypeDef类型的指针,然后我们就可以根据端口名(实际上现在是结构体指针了)来操作各个端口的寄存器,代码实现如下:

1#define GPIOA((GPIO_TypeDef*)0X40010800)

2#define GPIOB((GPIO_TypeDef*)0X40010C00)

3#define GPIOC((GPIO_TypeDef*)0X40011000)

4#define GPIOD((GPIO_TypeDef*)0X40011400)

5#define GPIOE((GPIO_TypeDef*)0X40011800)

6#define GPIOF((GPIO_TypeDef*)0X40011C00)

7#define GPIOG((GPIO_TypeDef*)0X40012000)

对于其他外设我们也可以这样把外设的名字定义成一个外设寄存器结构体类型的指针,这里我们只讲GPIO。

对于每个GPIO的基地址我们可以从《STM32中文参考手册》2.3小节:存储器映像中找到,如下所示:

MINI-STM32 开发板入门教程.

MINI-STM32 开发板入门教程(一) 开发环境建立及其应用 我们常用的 STM32 开发编译环境为 Keil 公司的 MDK (Microcontroller Development Kit) 和 IAR 公司的 EWARM. 在这里我们提供了比较稳定的新版本编译软件下载: MDK3.50 点击此处下载 EWARM 5.40 点击此处下载 限于篇幅, 在我们的教程里面将先以 MDK 下的一个例子来介绍如何使用 MDK 进行嵌入式 应用开发. MDK 安装与配置: 基于 MDK 下的开发中基本的过程: (1) 创建工程; (2) 配置工程; (3) 用 C/C++ 或者汇编语言编写源文件; (4) 编译目标应用程序 (5) 修改源程序中的错误 (6) 测试链接应用程序 ---------------------------------------------------------------- (1) 创建一个工程: 在 uVision 3 主界面中选择 "Project" -> "New uVision Project" 菜单项, 打开一个标准对话框选择好你电脑中的保存目录后, 输入一个你的工程名字后点确认.我们的工程中建了一个名字叫 "NewProject" 的工程. 从设备库中选择目标芯片, 我们的 MINI-STM32 开发板使用的是 STM32F103V8T6, 因此选 中 STMicrocontroller 下对应的芯片: ARM 32-bit Cortex-M3 Microcontroller, 72MHz, 64kB Flash, 20kB SRAM, PLL, Embedded Internal RC 8MHz and 32kHz, Real-Time Clock, Nested Interrupt Controller, Power Saving Modes, JTAG and SWD,

STM32入门教程

前言 一天入门STM32,仅一天的时间,是否有真的这么快。不同的人对入门的理解不一样,这篇一天入门STM32的教程,我们先对入门达成一个共识,如果你有异议,一天入门不了,请不要较真,不要骂街,保持一个工程师该有的修养,默默潜心学习,因为你还有很大的上升空间。 我眼中的入门:(前提是你学过51单片机和C语言) 1、知道参考官方的什么资料来学习,而不是陷入一大堆资料中无从下手。 2、知道如何参考官方的手册和官方的代码来独立写自己的程序,而不是一味的看到人家写的代码就觉得人家很牛逼。 3、消除对STM32的恐惧,消除对库开发的恐惧,学习是一个快乐而富有成就感的过程。

第1章一天入门STM32 本章参考资料:《STM32中文参考手册》《CM3权威指南CnR2》 学习本章时,配合《STM32中文参考手册》GPIO章节一起阅读,效果会更佳,特别是涉及到寄存器说明的部分。 1.151与STM32简介 51是嵌入式学习中一款入门级的精典MCU,因其结构简单,易于教学,且可以通过串口编程而不需要额外的仿真器,所以在教学时被大量采用,至今很多大学在嵌入式教学中用的还是51。51诞生于70年代,属于传统的8位单片机,如今,久经岁月的洗礼,既有其辉煌又有其不足。现在的市场产品竞争激烈,对成本极其敏感,相应地对MCU的要求也更苛刻:功能更多,功耗更低,易用界面和多任务。面对这些要求,51现有的资源就显得得抓襟见肘了。所以无论是高校教学还是市场需求,都急需一款新的MCU来为这个领域注入新的活力。 基于这市场的需求,ARM公司推出了其全新的基于ARMv7架构的32位Cortex-M3微控制器内核。紧随其后,ST(意法半导体)公司就推出了基于Cortex-M3内核的MCU—STM32。STM32凭借其产品线的多样化、极高的性价比、简单易用的库开发方式,迅速在众多Cortex-M3MCU中脱颖而出,成为最闪亮的一颗新星。STM32一上市就迅速占领了中低端MCU市场,受到了市场和工程师的无比青睐,颇有星火燎原之势。 作为一名合格的嵌入式工程师,面对新出现的技术,我们不是充耳不闻,而是要尽快吻合市场的需要,跟上技术的潮流。如今STM32的出现就是一种趋势,一种潮流,我们要做的就是搭上这趟快车,让自己的技术更有竞争力。 1.1.151与STM32架构的区别 我们先普及一个概念,单片机(即MCU)里面有什么。一个人最重要的是大脑,身体的各个部分都在大脑的指挥下工作。MCU跟人体很像,简单来说是由一个最重要的内核加其他外设组成,内核就相当于人的大脑,外设就如人体的各个功能器官。 下面我们来简单介绍下51和STM32的结构。 1.51系统结构 51系统结构框图

用STM32一步一步点亮led灯

STM32之一步一步点亮led (2011-05-09 19:40) 标签: stm32led v3.4MDK 4.12入门分类:stm32 入手stm32以来,一直想快速上手,所以在各大论坛闲逛,各个达人的blog 上学习,正所谓欲速则不达,心急是吃不了热豆腐的!有木有? 最终决定使用st官网的库开发,据大侠们写道使用库可以快速上手,貌似的确如此,一个个教程写的那么好,直接拿过来用就是了。可是那么多个库,聪明的你请告诉到底选择哪一个啊?My God!实话实说,我被这些库折腾了个够!好吧,我最后还是承认最后用的是v3.4的库,是很方便! 切入正题,点亮LED。 硬件:红牛开发板,STM32F103ZET6(144封装). 软件:RealView MDK 4.12 stm32固件库:v3.4 附上自己整理后的库: V3.4_clean.rar 根据官网库自己整理了下,新建了工程模板如下图:(主要参考文章《在 Keil MDK+环境下使用STM32 V3.4库.pdf》)在KeilMDK+环境下使用STM32V3.4库.pdf 入图所示:新建一个目录01_ProLed,建议放在英文路径下,避免不必要的麻烦。将上面的库v3.4解压到此目录,再新建一个project目录,存放工程。 说明: CMSIS:最底层接口。StartUp:系统启动文件。StdPeriph_Lib:stm32外围设

备驱动文件。Project:工程文件。User:用户文件。新建工程步骤:此处略去300字。 简单说明: 1.core_cm3.c/core_cm3.h 该文件是内核访问层的源文件和头文件,查看其中的代码多半是使用汇编语言编写的。在线不甚了解。--摘自《在Keil MDK+环境下使用STM32 V3.4库》 2.stm32f10x.h 该文件是外设访问层的头文件,该文件是最重要的头文件之一。就像51里面的reg51.h一样。例如定义了 CPU是哪种容量的 CPU,中断向量等等。除了这些该头文件还定义了和外设寄存器相关的结构体,例如: 1.typedef struct

STM32入门基本知识

STM32学前班教程之一:选择他的理由 经过几天的学习,基本掌握了STM32的调试环境和一些基本知识。想拿出来与大家共享,笨教程本着最大限度简化删减STM32入门的过程的思想,会把我的整个入门前的工作推荐给大家。就算是给网上的众多教程、笔记的一种补充吧,所以叫学前班教程。其中涉及产品一律隐去来源和品牌,以防广告之嫌。全部汉字内容为个人笔记。所有相关参考资料也全部列出。:lol 教程会分几篇,因为太长啦。今天先来说说为什么是它——我选择STM32的原因。 我对未来的规划是以功能性为主的,在功能和面积之间做以平衡是我的首要选择,而把运算放在第二位,这根我的专业有关系。里面的运算其实并不复杂,在入门阶段想尽量减少所接触的东西。 不过说实话,对DSP的外设并和开发环境不满意,这是为什么STM32一出就转向的原因。下面是我自己做过的两块DSP28的全功能最小系统板,在做这两块板子的过程中发现要想尽力缩小DSP的面积实在不容易(目前只能达到50mm×45mm,这还是没有其他器件的情况下),尤其是双电源的供电方式和的电源让人很头疼。 后来因为一个项目,接触了LPC2148并做了一块板子,发现小型的ARM7在外设够用的情况下其实很不错,于是开始搜集相关芯片资料,也同时对小面积的AVR和51都进行了大致的比较,这个时候发现了CortexM3的STM32,比2148拥有更丰富和灵活的外设,性能几乎是2148两倍(按照MIPS值计算)。正好2148我还没上手,就直接转了这款STM32F103。 与2811相比较(核心供电情况下),135MHz×1MIPS。现在用STM32F103,72MHz×,性能是DSP的66%,STM32F103R型(64管脚)芯片面积只有2811的51%,STM32F103C型(48管脚)面积是2811的25%,最大功耗是DSP的20%,单片价格是DSP的30%。且有更多的串口,CAP和PWM,这是有用的。高端型号有SDIO,理论上比SPI速度快。 由以上比较,准备将未来的拥有操作系统的高端应用交给DSP的新型浮点型单片机28335,而将所有紧凑型小型、微型应用交给STM32。 STM32学前班教程:怎么开发 sw笨笨的STM32学前班教程之二:怎么开发目前手头的入门阶段使用的开发器概述 该产品为简易STM32调试器和DEMO板一体化的调试学习设备,价格在一百多块。 2、硬件配置

STM32F103RCT6使用说明

STM32开发板使用手册 风帆 STM32开发板是风帆电子为初学者学习STM32 Cortex M3 系列ARM 而设计的学习板。以STM32F103RCT6芯片为核心,配套2.4/2.8寸彩色TFT屏模块,板载UART、USB、ADC电压调节、按键、JTAG接口、彩屏接口、流水灯、SD卡接口、IO引出口等多种硬件资源。

JTAG 口 2个LED 灯 GPIOA 引出1O USB 串口1 DS10B20预留 HS0038红外接收头 红外温度传感器连接头 GPIOB@C 引出IO OLED@LCD 共用接口 STM32F103RCT6 2.4/2.8寸LCD 接口 485芯片 RS485接口 1:A; 3:B NRF24L01 模块接口 W25Q1 6 FLASH 芯片 SD 卡接口(在背面) JF24C 模块预留接口 GPIO C@D 引出IO 蜂鸣器跳线 PS/2鼠标键盘接口 三个按 键: WAKEUP KEY0 KEY1 RESET 按键 Rs232接口 电源开关 USB 接口 电源指示灯 自恢复保险丝 MAX232 电源芯片 24c02 3.3V 、5V 电 源输出; 线序为: GND/3.3V GND/5V BOOT 设置 线序为: GND /GND BOOT1/BOOT0 3.3V/3.3V

此板子不管硬件还是软件完全无缝接兼容正点原子的MINSTM32,并对MINSTM32进行了完美的升级,让我们用最少的钱做更多的事,具体升级的部分包括: 1、C PU的升级 利用ST意法半导体的CPU兼容性强的优点,此板采用比 STM32F103RBT6性能更强、且完全兼容的的STM32F103RCT6升级 CPU,把完美的MINNI STM板子的功能发挥到极致,具体2个CPU 的主要资源对比如下: 可以看出,FLASH增加了一倍,达到256K,RAM也增加了1倍,让 我们不用再为FLASH\RAM小而烦恼,使我们的存储空间更为强大; 增加了一个16位普通IC/OC/PWM),2个16位基本(IC/OC/PWM),1个STI,2个USART,这里比STM32F103RB还多了一个DAC通 道,这个STM32F103RB是没有的

STM32教程(1)

第一部分开发板介绍 1.1 STM32开发板简介 开发板配置: ●CPU主芯片是STM32F103VCT6,主频72MHz,256KB FLASH ,48KB RAM; ●3个按键,可实现中断或查询方式判断是否有键按下; ●4个发光二极管LED,可进行流水灯或花样显示; ●1个无源蜂鸣器,可用PWM驱动; ●1个电位器,可配合内部AD进行AD转换; ●1个RS232串行通信接口,可使开发板与PC机进行通信; ●1个基于SPI串行总线的触摸屏转换接口芯片,可进行触屏操作; ●1个基于IIC串行总线的EEPROM,可进行数据存储; ●1个基于CPU片内SDIO的TF卡接口,可进行数据读写; ●1个FSMC控制的2.83英寸TFT液晶屏,可进行图片文字显示; ●1个蓝牙模块,可使开发板与PC机进行通信; ●1个USBmin2.0接口为开发板供电; ●所有I/O口引出,可通过跳线自行配置和自制外围模块连接;

下面介绍一下STN32开发板的各个部分。 1、LED灯 STM32开发板有4个LED灯,它们在开发板上的标号分别为LED1、LED2、LED3、LED4。在调试代码的时候,使用LED来指示程序状态,是非常不错的辅助调试方法。 2、按键 STM32开发板有三个普通按键,它们在开发板上的标号分别为KEY1、KEY2、KEY3。可以用于人机交互的输入,三个按键通过跳线帽连接到STM32的开发板的IO口上。 3、电源指示灯 开发板上有一个蓝色电源指示灯,它在开发板上的标号为LED5(POWER)。用于指示电源状态。该开发板通过USB供电,在该电源开启的情况下,指示灯亮,否则不亮。通过这个LED灯判断开发板的上电情况。 4、蓝牙 开发板上有一个蓝牙模块,它在开发板上的标号为Bluetooth。用于开发板与电脑进行无线通讯。 5、SD卡接口 SD卡接口在开发板上的标号为TF_Card。SD卡是最常见的存储设备,是很多数码设备的存储媒介,比如数码相框、数码相机、MP5等。STM32开发板自带了SD卡接口,可用于SD卡试验,方便大家学习SD卡。 6、AT24C01 EEPROM EEPROM型号为A T24C01,用于掉电数据保存。因为STM32内部没有EEPROM,所以开发板外扩了24C01,用于存储重要的数据,也可以用来做IIC实验,及其他应用。 7、RS232接口 RS232在开发板上的标号为J2。用于与电脑进行通信,也可以用来做USART实验。 8、滑动变阻器 滑动变阻器在开发板上的标号为ADJ_RES。通过调节滑动变阻器来改变电压值,可以用来做AD转换的实验。 9、蜂鸣器 蜂鸣器在开发板上的标号为Buzzer。通过调节定时器产生的PWM波的占空比来改变蜂鸣器的声音,可以用来做PWM实验,及其他应用。 10、液晶屏 触摸屏在开发板上的标号为TFT。用来显示一些图片和汉字。可以用来学习触摸屏的一些实验。触摸屏都需要一个AD转换器,STM32开发板触摸屏控制芯片为TSC2046。 11、引出IO口 开发板有很多引出IO口,可以通过跳线帽选择是连接各部分的功能模块还是用作引出IO 口,引出的IO口方便大家使用,可以连接外部器件。 1.2 STM32开发板硬件详解 本节介绍STM32开发板的各部分硬件,让大家对开发板的各部分硬件原理有个了解。

芯达STM32入门系列教程之三《如何使用J-Flash调试》

STM32入门系列教程如何使用J-Flash调试 Revision0.01 (2010-04-12)

对初学者来说,要进行STM32的程序下载调试,一般有三种方法: (1)使用SEGGER J-Flash(J-Link)下载程序到闪存中运行; (2)使用串口ISP来下载HEX文件到CPU中运行; (3)J-Link+MDK组合,来在线调试程序(可下载、调试)。 本文档讲述如何在芯达STM32开发板上使用SEGGER J-Flash下载HEX文件。而其他两种方法,我们将在文档《如何使用MDK+J-Link调试》、以及《如何使用STM32-ISP下载调试》中详细说明。 先来解释SEGGER。实际上,大家更为熟悉的ARM仿真器J-Link,就是由SEGGER公司开发的。J-Link是SEGGER为支持仿真ARM内核芯片推出的JTAG 仿真器。 不管什么CPU的仿真器,都需要安装其相应的驱动后才能使用。J-Link也不例外,它的驱动软件可以去官方网站:https://www.sodocs.net/doc/1e15092905.html,下载最新版本。这里使用的驱动软件版本是V4.08l,该驱动的安装非常简单,请参考文档《如何安装J-Link驱动软件》。 安装完毕,会出现如下两个图标: 现在开始我们的工作吧! 步骤一先进行设备连接操作。芯达STM开发板的JTAG口(开发板面朝上,最顶端有一个JTAG20pin的插口),与J-Link V8仿真器的输出排线连接,J-Link另一头的USB插口则插在电脑的USB口上。这时,J-Link的指示灯开始闪烁,并保持“点亮”的状态。 注意:大家购买J-Link仿真器的时候,JTAG接口要求是标准的20pin的2.54间距的针座。否则需要转接卡进行JTAG接口的转换。 步骤二进入PC的桌面,点击上图左边的图标:J-Flash ARM V4.081,出现如下界面:

(完整版)STM32F103通用教程

STM32F103_使用心得 IO端口输入输出模式设置:...........; Delay延时函数:..............; IO端口使用总结:...............; IO口时钟配置:................; 初始化IO口参数:...............; 注意:时钟使能之后操作IO口才有效!......; IO端口输出高低电平函数:...........; IO的输入 IO端口输入输出模式设置: (1) Delay延时函数: (2) IO端口使用总结: (2) IO口时钟配置: (2) 初始化IO口参数: (2) 注意:时钟使能之后操作IO口才有效! (2) IO端口输出高低电平函数: (2) IO的输入和输出宏定义方式: (3) 读取某个IO的电平函数: (3) IO口方向切换成双向 (3) IO 口外部中断的一般步骤: (3) 内部ADC使用总结: (4) LCDTFT函数使用大全 (5) TFTLCD使用注意点: (5)

IO端口宏定义和使用方法: (6) Keil使用心得: (6) ucGUI移植 (6) DDS AD9850测试程序: (6) ADC 使用小结: (7) ADC测试程序: (9) DAC—tlv5638测试程序 (9) 红外测试程序: (9) DMA使用心得: (9) 通用定时器使用: (9) BUG发现: (10) 编程总结: (10) 时钟总结: (10) 汉字显示(外部SD卡字库): (11) 字符、汉字显示(内部FLASH) (12) 图片显示: (16) 触摸屏: (17) 引脚连接: (19) IO端口输入输出模式设置: Delay延时函数: delay_ms(u16 nms); delay_us(u32 nus); IO端口使用总结: 1)使能IO 口时钟。调用函数为RCC_APB2PeriphClockCmd()。 2)初始化IO 参数。调用函数GPIO_Init();

STM32F103编程入门

STM32F103单片机编程入门 一款单片机入门,至少四样:时钟、端口、定时、串口、中断。 系统时钟 RCC 系统内部有8M_RC晶振和32678Hz_RC晶振有大约2%的温飘。当外部有8M 晶振时,自动选择外部晶振,失效时自动切换成内部。程序自动倍频成72M。 如果用于通信最好加个外部晶振。判断是否使用外部晶振的方法:短接外部晶 振引脚观察工作情况。 分为两个桥,对应不同的外设,每个外设又可以单独设定时钟。 初步学习,先不用单独设定,均选用系统时钟72M。可根据情况做一步分频。 用到某外设时,配置RCC(打开外设时钟),一般只有一句指令。一般临时查找。呵呵,我也没找到好办法。 GPIO:RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC , ENABLE); USART:RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); Timer2:RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE); 端口GPIO 端口配置思路: 1,先定义一个结构体配置成员参数值, 类型是GPIO_InitTypeDef,下划线是结构体名;结构体名是GPIO_InitStructure:名称可以自定义。在后面利用参数初始化函数时要一致。 2,打开相对应的端口时钟RCC。 3,声明要配置的管脚,可以用“|”复选 4,配置模式,4种输入,4种输出 5,配置管脚频率,一般都是50Mhz 6,最后调用函数GPIO_Init(GPIOA, &GPIO_InitStructure);第2个参数是,结构体地址指针。 Eg: GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC , ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_InitStructure.GPIO_Mode =GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStructure); 一、串口 USART 串口配置思路: 1,定义结构体,类型是USART_InitTypeDef; 2,打开串口时钟,可以选择和端口GPIO一起 3,设置波特率,—————省去了复杂的烦人的计算 4,设置字长。8位?9位? 5,设置停止位。1位?2位? 6,设置校验位,奇偶?无? 7,设置硬件流(调制解调器用)————用不到设None就行 8,串口工作模式:收?发?都有? 9,调用函数USART_Init(USART1, &USART_InitStructure); 配置串口 10,开启串口中断USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);或USART_IT_TXE, ENABLE);收发中断的使能。 11,中断响应函数void USART1_IRQHandler(void) 12,取出缓存数据data=USART_ReceiveData(USART1);读操作自动清零串口接 受标志位。 13,发送数据USART_SendData(USART2,FromScreen[Ua1])和 while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);等待发送 完成(寄存器非空)。 Eg: USART_InitTypeDef USART_InitStructure;

STM32快速入门教程

STM32快速入门教程 开发编译的软件:IAR EWARM 4.42A JTAG工具:ST-LINK2(开发板自带) 开发板:万利STM32EK(199元) 建议看的资料: 《STM32F10X-128K-EVAL MCU》ST公司STM32开发板的电路图 《STM32技术参考手册—RM0008.pdf 或STM32F103-CN.pdf 》 《Cortex-M3权威指南Cn.pdf》 《如何在IAR下使用STM库.pdf》 《STM32F10xxx_Library_Manual_ChineseV2.pdf》 《汉化STM32F的固件.rar》----网友: SUNKE9 《netjob的BLOG上的初学者笔记》 STM32 :把引脚BOOT1,BOOT0接地,3。3伏特供电,STM32就可以运行,无需外部接晶振。 芯片内部有复位电路。STM32上电后默认使用内部【精度8MHZ左右】晶振,如果外部接了8MHZ, 可以切换使用外部8MHZ,并最终PLL倍频到72MHZ. 软件开发上,我们可以从万利公司或ST公司给IAR公司写的STM32例子,首先一点,目前STM32软件开发都是使用ST公司STM32库,而我的BLOG 上例子不是使用STM32库。 我自己建立了STM32的头文件:stm32f103.h 原因是ST公司的STM32函数库太庞大复杂,效率低。而且会让开发人员不懂的如何操作STM32 的寄存器,不懂的CPU 是如何工作的。 一个STM32程序,有几个必要文件: 【 stm32f103.h 我自己定义的STM32头文件用来代替STM32函数库 cortexm3_macro.s 宏定义函数 stm32f10x_vector.c 中断初始化 stm32f10x_it.c 中断函数 main.c 主函数 】 //=================================================== // 完整例子:万利开发板上跑马灯程序 // 轮流点亮LED灯。 //===================================================

DL-STM32自学成才系列教程之十四《点亮LCD液晶屏》

STM32入门系列教程点亮LCD液晶屏 Revision0.01 (2011-09-28)

原想把本期《点亮LCD液晶屏》教程放在《GPIO编程》之后,以提高大家的兴趣,但考虑到可能网友学习STM32,是想更多地了解STM32内部工作机制,因此在之前的教程,我们先介绍了串口、外部中断、定时器等最基本的外设模块,有了这些基础,相信您再来学习LCD液晶,已经很轻松了。 我们使用的是芯达STM32配套的2.4寸TFT液晶触摸屏,它是山寨手机上的触摸液晶屏,内部驱动IC为ILI9325。我们操作LCD,实际上就是在操作ILI9325。有关该芯片的资料,请参考如下两个网址: ILI9325指令说明(中文):https://www.sodocs.net/doc/1e15092905.html,/read.php?tid=142 考虑到“触摸”涉及到太多的原理,因此把触摸屏单独列出一期教程详细讲解。这里只讲述如何去点亮LCD液晶屏,如果您看完本期教程,能理解LCD驱动过程,那么笔者心满意足。 要驱动LCD,分两个部分讲解: 1、CPU内部模块支持的LCD接口(这里使用FSMC模块) 2、LCD控制电路 一、STM32的FSMC原理 如果是单片机,相信大家再熟悉不过了,直接拿P0或者P1口用作LCD数据总线,再另外拿出几个IO口用作控制信号线——一个LCD控制电路完成了。STM32相对于单片机,有啥过人之处呢? 对于STM32系列的CPU来说,有两种方法给LCD总线赋值。第一个方法,就是给对应的GPIOx_ODR寄存器赋值——这与单片机一样,单片机也是给P0-P3寄存器赋值,使得信号能从对应的IO端口输出。而STM32的另一种方法就是使用FSMC。FSMC全称“静态存储器控制器”。使用FSMC控制器后,我们可以把FSMC提供的FSMC_A[25:0]作为地址线,而把FSMC提供的FSMC_D[15:0]作为数据总线。 1、FSMC包括哪几个部分? FSMC包含以下四个模块: (1)AHB接口(包含FSMC配置寄存器) (2)NOR闪存和PSRAM控制器 (3)NAND闪存和PC卡控制器

STM32入门系列教程之十二《实时时钟RTC编程》

STM32入门系列教程实时时钟RTC编程 Revision0.01 (2010-04-27)

对于单片机转ARM的同学来说,RTC可能比较少接触。提到实时时钟,更经常想到的是DS1302。当然,在STM32里,自己一个CPU已经足够,不需要DS1302。 实际上,RTC就只一个定时器而已,掉电之后所有信息都会丢失,因此我们需要找一个地方来存储这些信息,于是就找到了备份寄存器。因为它掉电后仍然可以通过纽扣电池供电,所以能时刻保存这些数据。我们在本期教程中将详细讲述RTC原理及例程,以引导大家顺利进入RTC的世界。 1.STM32的RTC模块 RTC模块之所以具有实时时钟功能,是因为它内部维持了一个独立的定时器,通过配置,可以让它准确地每秒钟中断一次。下面就来看以下它的组成结构。 1.1RTC的组成 RTC由两个部分组成:APB1接口部分以及RTC核心部分(感觉说了等于没说,因为任何模块都会有接口部分和它自己的核心部分。请注意,权威的STM32系列手册是这么说的?)。笔者猜想原因可能是STM32所有的外设默认时钟无效,使用某个外设时,再开启时钟,用这样的方式来降低功耗。这里的RTC,APB1接口由APB1总线时钟来驱动。为了突出时钟吧?不过据说APB1接口部分还包括一组16位寄存器。 RTC核心部分又分为预分频模块和一个32位的可编程计数器。前者可使每个TR_CLK周期中RTC产生一个秒中断,后者可被初始化为当前系统时间。此后系统时间会按照TR_CLK周期进行累加,实现时钟功能。 1.2对RTC的操作 我们对RTC的访问,是通过APB1接口来进行的。注意,APB1刚被开启的时候(比如刚上电,或刚复位后),从APB1上读出来的RTC寄存器的第一个值有可能是被破坏了的(通常读到0)。这个不幸,STM32是如何预防的呢?我们在程序中,会先等待RTC_CRL寄存器中的RSF位(寄存器同步标志)被硬件置1,然后才开始读操作,这时候读出来的值就是OK的。 那么对RTC寄存器的写操作会不会有类似的情况呢?对于写操作,我们只要注意,每一次写操作,必须确保在前一次写操作完成后进行。这个“确保”,

STM32学习笔记

sw笨笨的STM32学前班教程之一:为什么是它 SW笨笨发表于2009年01月30日21:43 阅读(70) 评论(0) 分类:个人日记 举报 经过几天的学习,基本掌握了STM32的调试环境和一些基本知识。想拿出来与大家共享,笨教程本着最大限度简化删减STM32入门的过程的思想,会把我的整个入门前的工作推荐给大家。就算是给网上的众多教程、笔记的一种补充吧,所以叫学前班教程。其中涉及产品一律隐去来源和品牌,以防广告之嫌。全部汉字内容为个人笔记。所有相关参考资料也全部列出。:lol 教程会分几篇,因为太长啦。今天先来说说为什么是它——我选择STM32的原因。 我对未来的规划是以功能性为主的,在功能和面积之间做以平衡是我的首要选择,而把运算放在第二位,这根我的专业有关系。里面的运算其实并不复杂,在入门阶段想尽量减少所接触的东西。 不过说实话,对DSP的外设并和开发环境不满意,这是为什么STM32一出就转向的原因。下面是我自己做过的两块DSP28的全功能最小系统板,在做这两块板子的过程中发现要想尽力缩小DSP的面积实在不容易(目前只能达到50mm×45mm,这还是没有其他器件的情况下),尤其是双电源的供电方式和1.9V的电源让人很头疼。 后来因为一个项目,接触了LPC2148并做了一块板子,发现小型的ARM7在外设够用的情况下其实很不错,于是开始搜集相关芯片资料,也同时对小面积的AVR和51都进行了大致的比较,这个时候发现了CortexM3的STM32,比2148拥有更丰富和灵活的外设,性能几乎是2148两倍(按照MIPS值计算)。正好2148我还没上手,就直接转了这款STM32F103。与2811相比较(核心1.8V供电情况下),135MHz×1MIPS。现在用STM32F103,72MHz×1.25MIPS,性能是DSP的66%,STM32F103R型(64管脚)芯片面积只有2811的51%,STM32F103C型(48管脚)面积是2811的25%,最大功耗是DSP的20%,单片价格是DSP 的30%。且有更多的串口,CAP和PWM,这是有用的。高端型号有SDIO,理论上比SPI速度快。 由以上比较,准备将未来的拥有操作系统的高端应用交给DSP的新型浮点型单片机28335,而将所有紧凑型小型、微型应用交给STM32。 ——SW笨笨,2009年春节假期 sw笨笨的STM32学前班教程之二:怎么开发 SW笨笨发表于2009年01月30日22:03 阅读(89) 评论(0) 分类:个人日记 举报

STM32+指导教程

豆 皮 教 程 目 录: 名 称 作 者 页 码 01. LED跑马灯littleworm 2 13 02.按键 + 蜂鸣器littleworm 03. SysTick 定时器littleworm 20 24 04.串口通讯 UART littleworm 05.豆皮会唱歌littleworm 31 06.I2C--24Cxx枫仔37 07. ADC with DMA枫仔43 08.内部温度传感器littleworm 49 55 09. SPI实战,Nokia5110 LCD littleworm 10. RTC初探枫仔61 64 11. Unique Device ID littleworm 66 12. STM32 ISP下载littleworm 72 13.SPI模式读写SD卡littleworm 80 14.基于STM32 的 FAT16文件系统littleworm 87 15.串口中间件的使用littleworm 16.EEPROM三备份带CRC校验枫仔89 17. IAP 之串口篇枫仔91

豆皮 - STM32开发板入门教程(一)LED 跑马灯 littleworm 版权所有 STMFANS 原创,转载请保留出处 一步一步创建第一个 IAR 工程 (IAR442 + ST-LINKII) 首先创建项目目录,拷贝公共文件:将 STM32 软件库中 FWlib 目录中的 library 目录拷贝到所建项目的目录中 这个是库 FWLIB 文件夹 把 FWlib 目录中的 library 目录拷贝到所建项目的目录中 将软件库的 Examples 目录里的任一例程的 stm32f10x_conf.h、stm32f10x_it.c、stm32f10x_it.h 和main.c 拷贝到项目的目录中(这里选择的是 GPIO 目录下的 \FWLib\examples\GPIO\IOToggle)TOP

最新【设计教程大集合】STM32F3XX大全

STM32F3系列是意法半导体ARM? Cortex?-M4微控制器产品组合的入门级产品。经过市场检验的M4处理器内核可支持DSP指令,内置浮点单元(FPU),运行频率高达72MHz,若再搭配意法半导体独有的且基于内核耦合存储器(CCM-SRAM) 的程序加速(Routine Booster) 功能,其电机控制等例行程序的执行速度可比原来提升43%。STM32F3系列属于共有600余款产品的STM32产品家族,性能表现比STM32F1 Cortex-M3系列更加出色。STM32系列产品的软硬件具有广泛的共性,并提供简单易用的设计工具和开发生态系统。 基本资料 【产品新闻】意法半导体(ST)推出闪存容量高达512KB的STM32F3微控制器,大幅提升系统集成度 【数据手册】STM32F358xC、STM32F378xx、STM32F318、STM32F302、STM32F303等ARM Cortex-M4 32位内核 【硬件资源】STM32F3系列固件、软件、工具资源 【视频】意法半导体STM32F3系列探索套件(discovery kit)介绍 进阶设计 目前意法半导体针对智慧型手机Sensor Hub提供采用Cortex-M0核心开发的STM32F072、采用Cortex-M4核心开发的STM32F301和STM32F401,以及采用Cortex-M4核心开发的STM32F429,其中三星(Samsung)智慧型手机Note 3的Sensor Hub中,即搭载该公司STM32F401。 【STM32F303开发】+视觉姿态识别 对一个目标进行姿态识别,以简单的三角形为例,目标放置在一个旋转平台上,初始姿态位置,通过图像识别姿态,并将姿态数据传送给nucleo,nucleo驱动舵机进行角度调整。

STM32入门C语言详解

阅读flash:芯片内部存储器flash操作函数我的理解——对芯片内部flash进行操作的函数,包括读取,状态,擦除,写入等等,可以允许程序去操作flash上的数据。 基础应用1,FLASH时序延迟几个周期,等待总线同步操作。推荐按照单片机系统运行频率,0—24MHz时,取Latency=0;24—48MHz时,取Latency=1;48~72MHz时,取Latency=2。 所有程序中必须的 用法:FLASH_SetLatency(FLASH_Latency_2); 位置:RCC初始化子函数里面,时钟起振之后。 基础应用2,开启FLASH预读缓冲功能,加速FLASH的读取。 所有程序中必须的 用法:FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); 位置:RCC初始化子函数里面,时钟起振之后。 3、阅读lib:调试所有外设初始化的函数。 我的理解——不理解,也不需要理解。只要知道所有外设在调试的时候,EWRAM需要从这个函数里面获得调试所需信息的地址或者指针之类的信息。 基础应用1,只有一个函数debug。所有程序中必须的。 用法:#ifdef DEBUG debug(); #endif 位置:main函数开头,声明变量之后。 4、阅读nvic:系统中断管理。 我的理解——管理系统内部的中断,负责打开和关闭中断。 基础应用1,中断的初始化函数,包括设置中断向量表位置,和开启所需的中断两部分。 所有程序中必须的。 用法:void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; //中断管理恢复默认参数 #ifdef VECT_TAB_RAM //如果C/C++ Compiler\Preprocessor\Defined symbols中的定义了 VECT_TAB_RAM(见程序库更改内容的表格) NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); //则在RAM调试 #else //如果没有定义VECT_TAB_RAM NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);//则在Flash里调试 #endif //结束判断语句 //以下为中断的开启过程,不是所有程序必须的。 //NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC优先级分组,方式。 //注:一共16个优先级,分为抢占式和响应式。两种优先级所占的数量由此代码确定, NVIC_PriorityGroup_x可以是0、1、2、3、4,分别代表抢占优先级有1、2、4、8、16个和响应优先级有16、8、4、2、1个。规定两种优先级的数量后,所有的中断级别必须在其中选择,抢占级别高的会打断其他中断优先执行,而响应级别高的会在其他中断执行完优先执行。 //NVIC_InitStructure.NVIC_IRQChannel = 中断通道名; //开中断,中断名称见函数库 //NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级 //NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应优先级

STM32-开发入门教程

STM32 开发入门教程 (一) 开发环境建立及其应用 入门准备: 我们常用的STM32 开发编译环境为Keil 公司的MDK (Microcontroller Development Kit) 和IAR 公司的EWARM. 在这里我们提供了比较稳定的新版本编译软件下载: MDK4.10 限于篇幅, 在我们的教程里面将先以MDK 下的一个例子来介绍如何使用MDK 进行嵌入式应用开发. MDK 安装与配置: 基于MDK 下的开发中基本的过程: (1) 创建工程; (2) 配置工程; (3) 用C/C++ 或者汇编语言编写源文件; (4) 编译目标应用程序 (5) 修改源程序中的错误 (6) 测试链接应用程序 ---------------------------------------------------------------- (1) 创建一个工程: 在uVision 3 主界面中选择"Project" -> "New uVision Project" 菜单项, 打开一个标准对话框选择好你电脑中的保存目录后, 输入一个你的工程名字后点确认.我们的工程中建了一个名字叫"NewProject" 的工程. 从设备库中选择目标芯片, 我们的MINI-STM32 开发板使用的是STM32F103V8T6, 因此选中STMicrocontroller 下对应的芯片: ARM 32-bit Cortex-M3 Microcontroller, 72MHz, 64kB Flash, 20kB SRAM, PLL, Embedded Internal RC 8MHz and 32kHz, Real-Time Clock, Nested Interrupt Controller, Power Saving Modes, JTAG and SWD, 3 Synch. 16-bit Timers with Input Capture, Output Compare and PWM, 16-bit 6-ch Advanced Timer, 2 16-bit Watchdog Timers, SysTick Timer, 2 SPI, 2 I2C, 3 USART, USB 2.0 Full Speed Interface, CAN 2.0B Active, 2 12-bit 16-ch A/D Converter, Fast I/O Ports

stm32f107_的学习(新手入门)

1,说明:为什么选择STM32: 经过几天的学习,基本掌握了STM32的调试环境和一些基本知识。想拿出来与大家共享,笨教程本着最大限度简化删减STM32入门的过程的思想,会把我的整个入门前的工作推荐给大家。就算是给网上的众多教程、笔记的一种补充吧,所以叫学前班教程。其中涉及产品一律隐去来源和品牌,以防广告之嫌。全部汉字内容为个人笔记。先来说说为什么是它——我选择STM32的原因。 我对未来的规划是以功能性为主的,在功能和面积之间做以平衡是我的首要选择,而把运算放在第二位,这根我的专业有关系。里面的运算其实并不复杂,在入门阶段想尽量减少所接触的东西。 不过说实话,对DSP的外设并和开发环境不满意,这是为什么STM32一出就转向的原因。下面是我自己做过的两块DSP28的全功能最小系统板,在做这两块板子的过程中发现要想尽力缩小DSP的面积实在不容易(目前只能达到50mm×45mm,这还是没有其他器件的情况下),尤其是双电源的供电方式和1.9V的电源让人很头疼。 后来因为一个项目,接触了LPC2148并做了一块板子,发现小型的ARM7在外设够用的情况下其实很不错,于是开始搜集相关芯片资料,也同时对小面积的A VR和51都进行了大致的比较,这个时候发现了CortexM3的STM32,比2148拥有更丰富和灵活的外设,性能几乎是2148两倍(按照MIPS值计算)。正好2148我还没上手,就直接转了这款 STM32F103。 与2811相比较(核心1.8V供电情况下),135MHz×1MIPS。现在用STM32F103, 72MHz×1.25MIPS,性能是DSP的66%,STM32F103R型(64管脚)芯片面积只有2811的51%,STM32F103C型(48管脚)面积是2811的25%,最大功耗是DSP的20%,单片价格是DSP的30%。且有更多的串口,CAP和PWM,这是有用的。高端型号有SDIO,理论上比SPI速度快。 由以上比较,准备将未来的拥有操作系统的高端应用交给DSP的新型浮点型单片机28335,而将所有紧凑型小型、微型应用交给STM32。 2,首先:stm32f107vc和stm32f103vb的个区别 stm32f107vc和stm32f103vb有几个区别,都是芯片内部设备的区别,就像好电脑和差电脑的配置不同,但都用xp,win7系统,而且软件也是通用的。 首先看头几个字母“stm32”,这两个都是stm32芯片,是意法半导体为ARM M3内核出的用于自动控制领域的微处理器。F107是互联型接口和内部资源较多,F103是曾强型(比F101强),相比103,F107加入ieee以太网接口,2个i2s音频接口(做音频解码用),全部64kb 的SRAM缓存。 但是这两个芯片的开发方法和调用的库函数都是一样的,你看官方称他们为 STM32f10X就知道了,引脚也是兼容的。 你学习的话都是学习库函数,f107多出来的增强功能等你学完基本的stm32开发的时候很快上手的。送你一副图哦,看看吧。

相关主题