STM入门教程.pdf
- 文档编号:3438004
- 上传时间:2023-05-05
- 格式:PDF
- 页数:53
- 大小:3.09MB
STM入门教程.pdf
《STM入门教程.pdf》由会员分享,可在线阅读,更多相关《STM入门教程.pdf(53页珍藏版)》请在冰点文库上搜索。
零死角玩转零死角玩转STM32F1系列系列第第1页共页共53页页前言前言一天入门STM32,仅一天的时间,是否有真的这么快。
不同的人对入门的理解不一样,这篇一天入门STM32的教程,我们先对入门达成一个共识,如果你有异议,一天入门不了,请不要较真,不要骂街,保持一个工程师该有的修养,默默潜心学习,因为你还有很大的上升空间。
我眼中的入门:
(前提是你学过51单片机和C语言)1、知道参考官方的什么资料来学习,而不是陷入一大堆资料中无从下手。
2、知道如何参考官方的手册和官方的代码来独立写自己的程序,而不是一味的看到人家写的代码就觉得人家很牛逼。
3、消除对STM32的恐惧,消除对库开发的恐惧,学习是一个快乐而富有成就感的过程。
零死角玩转零死角玩转STM32F1系列系列第第2页共页共53页页第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内核的MCUSTM32。
STM32凭借其产品线的多样化、极高的性价比、简单易用的库开发方式,迅速在众多Cortex-M3MCU中脱颖而出,成为最闪亮的一颗新星。
STM32一上市就迅速占领了中低端MCU市场,受到了市场和工程师的无比青睐,颇有星火燎原之势。
作为一名合格的嵌入式工程师,面对新出现的技术,我们不是充耳不闻,而是要尽快吻合市场的需要,跟上技术的潮流。
如今STM32的出现就是一种趋势,一种潮流,我们要做的就是搭上这趟快车,让自己的技术更有竞争力。
1.1.151与STM32架构的区别我们先普及一个概念,单片机(即MCU)里面有什么。
一个人最重要的是大脑,身体的各个部分都在大脑的指挥下工作。
MCU跟人体很像,简单来说是由一个最重要的内核加其他外设组成,内核就相当于人的大脑,外设就如人体的各个功能器官。
下面我们来简单介绍下51和STM32的结构。
1.51系统结构51系统结构框图零死角玩转零死角玩转STM32F1系列系列第第3页共页共53页页图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的时候,关于内核部分接触的比较少,使用的最多的是片上外设,我们在编程的时候操作的也就是这些外设。
零死角玩转零死角玩转STM32F1系列系列第第4页共页共53页页编程的时候操作的寄存器位于SFR和RAM这个部分,其中SFR(特殊功能寄存器)占有128字节(实际上只用了26个字节,只有26个寄存器,其他都属于保留区),RAM占有128字节,我们在程序中定义的变量就是放在RAM中。
其中SFR和RAM在地址上是重合的,都是在80FF这个地址区间,但在物理区间上是分开的,所以51的RAM是有256个字节。
编写好的程序是烧写到ROM区。
剩下的外设都是我们非常熟悉的IO口,串口、定时器、中断这几个外设。
2.STM32系统结构STM32系统结构框图图2STM32系统结构框图内核内核在系统结构上,STM32和51都属于单片机,都是由内核和片上外设组成。
只是STM32使用的Cortex-M3内核比51复杂得多,优秀得多,支持的外设也比51多得多,同时总线宽度也上升到32bit,无论速度、功耗、外设都强与51。
零死角玩转零死角玩转STM32F1系列系列第第5页共页共53页页从结构框图上看,对比51内核只有一种总线,取指和取数共用。
Cortex-M3内部有若干个总线接口,以使CM3能同时取址和访内(访问内存),它们是:
指令存储区总线(两条)、系统总线、私有外设总线。
有两条代码存储区总线负责对代码存储区(即FLASH外设)的访问,分别是I-Code总线和D-Code总线。
I-Code用于取指,D-Code用于查表等操作,它们按最佳执行速度进行优化。
系统总线(System)用于访问内存和外设,覆盖的区域包括SRAM,片上外设,片外RAM,片外扩展设备,以及系统级存储区的部分空间。
私有外设总线负责一部分私有外设的访问,主要就是访问调试组件。
它们也在系统级存储区。
还有一个MDA总线,从字面上看,DMA是datamemoryaccess的意思,是一种连接内核和外设的桥梁,它可以访问外设、内存,传输不受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主频不高,资源有限,必须注重程序执行的效率,只能直接操作寄存器。
关键的地方还得用汇编,不适合用固件库。
零死角玩转零死角玩转STM32F1系列系列第第6页共页共53页页要知道当初我们学习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语言的又一次历练和提升。
是否用库,只差你一个闪亮的回眸。
零死角玩转零死角玩转STM32F1系列系列第第7页共页共53页页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同时操作,但起作用的只是P00。
除了这种总线操作的方法,我们还学习过位操作,利用51编译器的关键字sbit,我们可以定义一个位变量:
1sbitLED=P00;那么LED=0;就点亮了LED,LED=1;就关闭了LED。
为了让程序看起来见名知义,我们定义两个宏:
1#defineON02#defineOFF1点亮和关闭LED的代码就变成了:
1LED=ON;/位操作点亮LED2LED=OFF;/位操作关闭LED稍微整理下代码,整体的效果就是:
1/假设51单片机的P00口接LED,负逻辑点亮23#defineON04#defineOFF156sbitLED=P00;78voidmain(void)零死角玩转零死角玩转STM32F1系列系列第第8页共页共53页页910P0=0XFE;/总线操作点亮LED11P0=0XFF;/总线操作关闭LED1213LED=ON;/位操作点亮LED14LED=OFF;/位操作关闭LED15上面总线和位操作的的方法,学过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单片机的这些寄存器位于地址80HFFH中,对应着128个地址,但不是每个地址都是有效的,51系列的单片机有21个,52系列的则有26个,其他的都是保留区。
零死角玩转零死角玩转STM32F1系列系列第第9页共页共53页页图351寄存器映射2.寄存器映射实际上我们在编程的时候并不是通过指针来操作寄存器的,而是直接给P0、P1这些端口寄存器赋值。
那么这些外设资源是如何与地址建立一一对应的关系(寄存器映射定义),这得益与51特有的两个关键字:
SFR和sbit,其他单片机没有,只能用其他的方式来实现寄存器映射。
这两个关键字帮我们实现了所有寄存器的定义,所以我们才可以像操作普通变量一个来操作寄存器。
其实我们一开始提到的点亮LED的代码,全貌应该是这样的:
1sfrP0=0x80;/寄存器定义2P0=0XFE;/总线操作点亮LED为了方便起见,我们可以把寄存器映射全部写好封装在一个头文件里面,不用每用一个寄存器就定义一次。
其实这方面的工作不用我们做,我们在编程的时候都会在开始的地方添加一个头文件:
1#include零死角玩转零死角玩转STM32F1系列系列第第10页共页共53页页这个头文件已经实现了全部寄存器的定义,该文件是keil自带,在安装目录:
KeilC51INC下可以找到。
这个文件实现了字节寄存器和位寄存器的定义。
1/*-2REG51.H34Headerfileforgeneric80C51and80C31microcontroller.5Copyright(c)1988-2002KeilElektronikGmbHandKeilSoftware,Inc.6Allrightsreserved.7-*/89#ifndef_REG51_H_10#define_REG51_H_1112/*BYTERegister*/13sfrP0=0x80;14sfrP1=0x90;15sfrP2=0xA0;16sfrP3=0xB0;17sfrPSW=0xD0;18sfrACC=0xE0;19sfrB=0xF0;20sfrSP=0x81;21sfrDPL=0x82;22sfrDPH=0x83;23sfrPCON=0x87;24sfrTCON=0x88;25sfrTMOD=0x89;26sfrTL0=0x8A;27sfrTL1=0x8B;28sfrTH0=0x8C;29sfrTH1=0x8D;30sfrIE=0xA8;31sfrIP=0xB8;32sfrSCON=0x98;33sfrSBUF=0x99;343536/*BITRegister*/37/*PSW*/38sbitCY=0xD7;39sbitAC=0xD6;40sbitF0=0xD5;41sbitRS1=0xD4;42sbitRS0=0xD3;43sbitOV=0xD2;44sbitP=0xD0;4546/*TCON*/47sbitTF1=0x8F;48sbitTR1=0x8E;49sbitTF0=0x8D;50sbitTR0=0x8C;51sbitIE1=0x8B;52sbitIT1=0x8A;53sbitIE0=0x89;54sbitIT0=0x88;5556/*IE*/57sbitEA=0xAF;58sbitES=0xAC;59sbitET1=0xAB;60sbitEX1=0xAA;61sbitET0=0xA9;62sbitEX0=0xA8;63零死角玩转零死角玩转STM32F1系列系列第第11页共页共53页页64/*IP*/65sbitPS=0xBC;66sbitPT1=0xBB;67sbitPX1=0xBA;68sbitPT0=0xB9;69sbitPX0=0xB8;7071/*P3*/72sbitRD=0xB7;73sbitWR=0xB6;74sbitT1=0xB5;75sbitT0=0xB4;76sbitINT1=0xB3;77sbitINT0=0xB2;78sbitTXD=0xB1;79sbitRXD=0xB0;8081/*SCON*/82sbitSM0=0x9F;83sbitSM1=0x9E;84sbitSM2=0x9D;85sbitREN=0x9C;86sbitTB8=0x9B;87sbitRB8=0x9A;88sbitTI=0x99;89sbitRI=0x98;9091#endif923.启动文件STARTUP.A51还有一个就是启动代码,这个也是很多初学者容易忽略的地方,对于这部分我们主要总结下它的功能,不详解讲解里面的代码。
单片机在上电复位后,首先执行的是启动文件STARTUP.A51,而不是我们通常看到的main函数。
我们新建51工程的时候会有一个提示:
是否拷贝启动代码到当前的工程,我们一般选择是。
图4是否添加启动代码启动代码用汇编语言编写,主要实现了以下功能:
清除内部数据存储器、清除外部数据存储器、清除外部页储存器、初始化small模式下的可重入栈和指针、初始化large模式下可重入栈和指针、初始化compact模式下的可重入栈和指针、初始化8051硬件栈指针、零死角玩转零死角玩转STM32F1系列系列第第12页共页共53页页传递初始化全局变量的控制命令或者在没有初始化全局变量时给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_Handler3、设置向量表入口地址,并初始化向量表。
4、调用库函数SystemInit,把系统时钟配置成72M,SystemInit在库文件system_stm32f10.c定义。
5、跳转到标号_mian,最终来到C的世界。
这里我们先去除繁枝细节,挑重点的讲,主要理解第四和第五点,在启动文件的147155行,是复位处理函数,代码如下:
1;Resethandler2Reset_HandlerPROC3EXPORTReset_HandlerWEAK4IMPORT_main5IMPORTSystemInit6LDRR0,=SystemInit7BLXR0零死角玩转零死角玩转STM32F1系列系列第第13页共页共53页页8LDRR0,=_main9BXR010ENDP这里我们简单介绍下这10行代码。
第一行是程序注释,在汇编里面注释用的是“;”,跟C语言不一样。
第二行是定义了一个子程序:
Reset_Handler。
PROC是子程序定义伪指令。
一般用法为:
1子程序名PROCNEAR(或FAR)23ret4子程序名ENDP其中NEAR和FAR是属性词。
NEAR属性(段内近调用):
调用程序和子程序在同一代码段中,只能被相同代码段的其他程序调用。
FAR属性(段间远调用):
调用程序和子程序不在同一代码段中,可以被相同或不同代码段的程序调用。
第三行EXPORT表示Reset_Handler这个子程序可供其他模块调用。
关键字WEAK表示弱定义,如果编译器发现在别处定义了同名的函数,则在链接时用别处的地址进行链接,如果其它地方没有定义,编译器也不报错,以此处地址进行链接。
第四行和第五行IMPORT说明SystemInit和_main这两个标号在其他文件,在链接的时候需要到其他文件去寻找。
SystemInit在库文件system_stm32f10x.c实现,用来初始化STM32的一系列时钟,把系统时钟设置为72MHZ。
STM32
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- STM 入门教程
![提示](https://static.bingdoc.com/images/bang_tan.gif)