嵌入式课程实验指导书实验一、开发环境构建和GPIO控制实验一、硬件环境1.1 STM32芯片介绍STM32系列基于专为要求高性能、低成本、低功耗的嵌入式应用专门设计的ARM Cortex-M核增强型系列时钟频率达到72MHz,是同类产品中性能最高的产品;基本型时钟频率为36MHz,以16位产品的价格得到比16位产品大幅提升的性能,是32位产品用户的最佳选择两个系列都置32K到128K的闪存,不同的是SRAM的最大容量和外设接口的组合时钟频率72MHz时,从闪存执行代码,STM32功耗36mA,是32位市场上功耗最低的产品,相当于0.5mA/MHzSTM32的特点:核:ARM32位Cortex-M3 CPU,最高工作频率72MHz,1.25DMIPS/MHz单周期乘法和硬件除法存储器:片上集成32-512KB的Flash存储器6-64KB的SRAM存储器时钟、复位和电源管理:2.0-3.6V的电源供电和I/O接口的驱动电压POR、PDR和可编程的电压探测器(PVD)4-16MHz的晶振嵌出厂前调校的8MHz RC振荡电路部40 kHz的RC振荡电路用于CPU时钟的PLL带校准用于RTC的32kHz的晶振。
低功耗:3种低功耗模式:休眠,停止,待机模式为RTC和备份寄存器供电的VBAT调试模式:串行调试(SWD)和JTAG接口DMA:12通道DMA控制器支持的外设:定时器,ADC,DAC,SPI,IIC和UART2个12位的us级的A/D转换器(16通道):A/D测量围:0-3.6 V双采样和保持能力片上集成一个温度传感器2通道12位D/A转换器:STM32F103xC,STM32F103xD,STM32F103xE独有最多高达112个的快速I/O端口:根据型号的不同,有26,37,51,80,和112的I/O端口,所有的端口都可以映射到16个外部中断向量除了模拟输入,所有的都可以接受5V以的输入最多多达11个定时器:4个16位定时器,每个定时器有4个IC/OC/PWM或者脉冲计数器2个16位的6通道高级控制定时器:最多6个通道可用于PWM输出2个看门狗定时器(独立看门狗和窗口看门狗)Systick定时器:24位倒计数器2个16位基本定时器用于驱动DAC最多多达13个通信接口:2个IIC接口(SMBus/PMBus)5个USART接口(ISO7816接口,LIN,IrDA兼容,调试控制)3个SPI接口(18 Mbit/s),两个和IIS复用。
CAN接口(2.0B)USB 2.0全速接口SDIO接口ECOPACK封装:STM32F103xx系列微控制器采用ECOPACK封装形式二、软件开发环境介绍与安装2.1 STM32固件库STM32标准外设库之前的版本也称固件函数库或简称固件库,是一个固件函数包,它由程序、数据结构和宏组成,包括了微控制器所有外设的性能特征该函数库还包括每一个外设的驱动描述和应用实例,为开发者访问底层硬件提供了一个中间API,通过使用固件函数库,无需深入掌握底层硬件细节,开发者就可以轻松应用每一个外设因此,使用固态函数库可以大大减少用户的程序编写时间,进而降低开发成本每个外设驱动都由一组函数组成,这组函数覆盖了该外设所有功能每个器件的开发都由一个通用API (application programming interface 应用编程界面)驱动,API对该驱动程序的结构,函数和参数名称都进行了标准化ST公司2007年10月发布了V1.0版本的固件库,MDK ARM3.22之前的版本均支持该库2008年6月发布了V2.0版的固件库,从2008年9月推出的MDK ARM3.23版本至今均使用V2.0版本的固件库。
V3.0以后的版本相对之前的版本改动较大,本书使用目前较新的V3.4版本2.2 KeilA. 打开Keil MDK4.21的安装包,双击安装程序后,起始页面如下图所示,依次单击“Next”按钮完成安装;B. 安装完成后,以管理员身份打开uVision4,点击File à License Management 打开License Management窗口,复制右上角的CID;C. 打开Keillic.exe注册机,在CID窗口里填上复制的CID,点击Generate生成许可号,复制许可号;D. 将许可号复制到License Management窗口下部的New License ID Code,点击右侧的Add LIC,若上方的Product显示RealView MDK-ARM即表示注册成功到此为止,表示MDK安装并注册完成2.3J-LinkJ-link用于开发过程中的调试与仿真,是开发过程中必不可少的器件,使用J-link需要安装其驱动程序,具体安装步骤如下所示,首先打开光盘下的Keil MDK4.21的安装包,双击安装程序,逐步往下,直至完成在完成驱动的安装以后,将J-link的一端接至开发板的JTAG口,另一端接至PC,此时打开PC的设备管理器,如能找到J-link表示正常安装,此时J-link已经安装完成。
在后面的容中,将详细介绍J-link的使用方法2.4 FlashLoaderFlashLoader用于STM32可执行文件的下载,支持ISP的方式,把文件下载到指定的地址在安装Keil MDK4.21时已经按照了FlashLoader三、工程模板构建UE-STM32F103的所有开发调试都在MDK4.21中完成的,为了后面更好的使用此环境,请熟悉以下MDK的窗口的示意图 3.1创建工程打开”KEIL 4.21”,准备进行工程的创建1) 在创建一个工程之前,首先新建一个文件夹用于存放工程文件,此处文件夹名为uetest,放置路径可自行选择,在其下分别建立如下几个目录:a. startup:启动代码解压../实验一/软件安装包/stm32f10x_stdperiph_lib_v3.5源代码.zip文件,该文件为stm32固件库解压后,拷贝"STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm"目录下的"startup_stm32f10x_hd.s"到该目录下b. cmsis:与Cortex-M3核设备访问相关的代码拷贝"../STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\CoreSupport"目录下的"core_cm3.c"、"core_cm3.h"以与"STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x"目录下的"stm32f10x.h"、"system_stm32f10x.c"、"system_stm32f10x.h"放到该目录下c. libraray:外设库文件拷贝"STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\STM32F10x_StdPeriph_Driver"目录下的"inc"和"src"文件夹放到该目录下d. source:用户应用开发文件包含:main.c、stm32f10x_conf.h文件(stm32f10x_conf.h可以在任意已有工程中复制,如:..\stm32f10x_stdperiph_lib_v3.5源文件\STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Examples\ADC\3ADCs_DMA\stm32f10x_conf.h)e. run:用来放置工程编译后最终执行的HEX文件2) 单击ProjectàNew uVision Project…菜单项目;3) 此时打开一个标准对话框,输入新建工程的名字uetest,新工程保存在文件夹uetest,uVision4将会创建以uetest.uvproj为名字的新工程文件;4) 上图点击“保存”后,弹出处理器选择对话框,此处选择STM32F103VE;5) 出现一个提示框,是否复制STM32启动代码到工程文件夹,选择“是”,就可以看到工程区有一个名为startup_stm32f10x_hd.s的启动代码自动添加进来了;6) 右键单击“Target 1”àManage Components 在Project Target中可以把Target1改成你想要的名字,然后在groups单击新建按钮,这些组对应工作目录的文件夹,方便源文件的分类和管理,我们这里新建了cmsis、libraray、run、source和startup目录,并在Files栏加入工程目录中对应文件夹下的文件。
这几个目录在后面的历程中都会出现最后如下图所示:3.2配置和编译工程以上步骤,项目已经建立了,但是仍然需要进行配置工作,相关如下,首先打开工程;首先用鼠标右击左边工程窗口的项目名“uetest”,会出现一个菜单,选择“Options for Target 'Project'”,即出现工程配置的对话框,如下图所示:这个option相对繁琐,而且根所选择的芯片有关,这里共有10个选项卡,绝大多数选择默认配置即可,下面将对一些需要注意的配置简单介绍一下1) Device设置在此选项卡中选择相关的芯片型号,此处为STM32F103VE;2) Target设置在此选项卡中需要输入开发板上所用的晶振的大小,此处为8.0MHz,如上图所示;3) Output设置Select Folder for Objects:选择编译之后的目标文件存储在哪个目录里,默认位置为工程文件的目录里此处选在目标文件存放在uetest/run中Name of Executable:生成的目标文件的名字,缺省是工程的名字Create Executable:生成OMF以与HEX文件OMF文件名同工程文件名但没有带扩展名Debug Information:用于Debug版本,生成调试信息,否则的话无法进行单步调试。
Create Batch File:生成用于实现整个编译过程的批处理文件,使用这个文件可以脱离IDE对省程序进行编译Create Hex File:这个选项默认情况下未被选中,如果要写片做硬件实验就必须选中该项这一点是初学者易疏忽的,在此特别提醒注意一定要要选中,否则编译之不生成Hex文件Big Endian:编码格式,与CPU相关,如果CPU采用的是Big Endian编码则勾选上 Browse Information:产生用于在源文件快速定位的信息Create Library:生成lib库文件,默认不选4) C/C++设置在Define宏中添加宏定义:STM32F10X_HD,USE_STDPERIPH_DRIVERInclude Paths:指定头文件的查找路径,可以添加多个,这里我们将工程文件中的路径全部加入如下所示:5) Debug设置左边是对应uVision4的模拟环境,右边是针对仿真器,这里选择右边的Cortex-M/R J-LINK/J-Trace,同时勾选Run to main,这样在调试的时候,会从main函数开始 如果已经将J-LINK仿真器连接到你的电脑,点击“Settings”你将进入ARM Target Driver Setup 界面;J-Link/J-Trace Adapter: --Serial No:列出了当前连接到主机的所有J-LINK适配器的串号,你可以通过列表选择要使用的J-LINK适配器。
--J-LINK Version,Device Family以与Firmware Version分别列出了当前选择的J-LINK适配器的版本,设备家族和固件版本 -- Port:根据和开发板接口的类型选择端口,有JTAG和SW两种,勾选SWJ表示支持两种方式 --Max Clock:指定和开发板的最高通信时钟 --JTAG Device Chain:显示当前通过适配器连接上的开发板 --Automatic Detection:自动监测,选择系统将自动检测连接上的开发板,建议使用 --Manual Configuration:手动配置,通过手动设置ID CODE,Device Name和IR len等属性来查找设备Debug:--Cache Code:通知调试器已经下载的程序代码不会改变,选中的话uVision将不会从目标系统读取程序代码Cache Memory:决定调试程序期间程序停止运行的时候,是否更新存储器显示Verify Code Download:比较目标存储器和调试器上的应用程序的容Download to Flash:将代码下载到所有的存储器区域,如果不选中,调试器不会把代码下载到Flash Download Setup中制定的存储器地址围。
6) Utilities标签页的设置Configure Flash Menu Command Use Target Driver for Flash Programming:列表选择和调试接口一致的驱动点击Settings按钮出现如下界面:Download Function:定义了Flash烧写的时候进行的操作Erase Full Chip:前面三项要选一,烧写程序之前擦除整个Flash存储器Erase Sectors:烧写程序之前擦除程序要使用的扇区Do not Erase:不进行擦除操作Program:使用当前uVision工程的程序烧写ROMVerify:验证Flash ROM的容和当前工程中的程序一致Reset and Run:在烧写和验证完成之后复位开发板并且运行程序RAM for Algorithm:指定用于烧写程序的RAM区域,通常是微控制器上的一段片上空间Start:起始地址Size:大小此处可以通过点击Add添加,点击Add你将看到如下的选择列表,可以根据你选用的芯片选择合适的,也可以自己手动添加到此为止工程设置就结束了,接下来需要对工程进行编译单击编译所有文件的按钮,完成对软件工程的编译。
3.3调试程序编译通过只是说明我们的代码没有语法错误,至于源程序中存在的其他错误,必须通过调试才能发现并解决,事实上,除了极简单的程序以外,绝大部分的程序都要通过反复调试才能得到正确的结果,因此,调试是软件开发接下来我们需要运行我们的程序来验证是否达到了预期的目的也就是程序调试,程序调试往往是程序开发过程中最难的阶段,尤其是对一些比较大型的程序下面我们就来看看uVision4对调试的支持在对工程成功进行汇编、连接之后,按Ctrl+F5或者使用菜Debug->Start/Stop Debug Session即可进入调试状态进入调试状态后,界面与编辑状态相比有明显的变化,Debug才单项中原来不能用的命令现在已经可以使用了,工具栏会多出一个用于运行和调试的工具栏,如下图所示,Debug菜单上的大部分命令可以在此找到对应的快捷按钮常用的Debug菜单命令如下所示:Start/Stop Debug Session:开始或者停止调试Run:一直执行下一个活动的断点Step:单步执行Step Over:过程单步执行,即将一个函数作为一个语句来执行Step out of current Function:跳出当前的函数。
Run to Cursor line:执行到光标所在的行 Stop Running:停止运行Breakpoints:打开断点对话框Insert/Remove Breakpoint:在当前行插入/删除一个断点Enable/Disable Breakpoint:激活当前行的断点或者使断点无效Disable All Breakpoints:使程序中所有的断点都无效Kill all Breakpoints:删除程序中所有的断点学习程序调试,必须明确两个重要的概念,即单步执行与全速执行全速执行是指一行程序执行完了以后紧接着执行下一行程序,中间不停止,这样程序执行的速度就很快,并可以看到该段程序执行的总体效果,即最终结果正确还是错误,但如果程序有错,则难以确认错误出现在哪些程序行单步执行是每次执行一行程序,执行完该行程序执行完以后即停止,等待命令执行下一行程序,此时我们可以观察该行程序执行完以后得到的结果,是否与我们写程序行所想要得的结果相同,借此可以找到程序中问题所在程序调试中,这两种运行方式都要用到,要灵活应用,可以大大提高调试效率在调试窗口中,我们可以看到一个黄色的调试箭头,指向了当前执行到的程序行。
1)断点设置程序调试时,有些程序行往往很难确认什么时候能够执行到,这类问题就不适合单步调试,这时需要使用程序调试中的断点设置断点设置的方法有多种,常用的是在某一程序行设置断点,设置好断点之后可以全速运行程序,一旦执行到该程序行即停止,可在此观察有关的变量值,以确定问题所在设置断点的命令请参考上一节常用调试命令介绍一旦某一行被设置了断点,我们可以在程序行的左端看到一个红色方框(如图5.24调试窗口图所示),如果该断点被禁用,方框将会变为白色除了在某程序行设置断点这一基本方法以外,uVision4还提供了多种设置断点的方法,按Debug->Breakpoints,即出现一个对话框,该对话框用于对断点进行详细的设置,如下图所示2)调试窗口前面讲了调试的一些方法,里面多次提到检查程序的执行状态调试窗口就是用于查看程序执行状态的uVision4提供了多种调试窗口,如寄存器窗口,存储器窗口,反汇编窗口,外设窗口等,下面将会一一作介绍a. 寄存器窗口上图是工程窗口寄存器页的容,寄存器页包含了当前所有的工作寄存器和系统寄存器,每当程序中执行到对某个寄存器的操作时,该寄存器会反色显示,用鼠标单击然后按F2(鼠标连续单击两次),即可修改该值。
b. 存储器窗口存储器窗口可以显示系统中各种存中的值,通过在Address后的编辑框中输入“字母:数字”即可显示相应存值,其中字母C、D、I、X,分别代表代码存储空间、直接寻址的片存储空间、间接寻址的片存储空间、扩展的外部RAM单元值、键入C:0即可显示从0开始的ROM单元中的值,即查看程序的二进制代码该窗口的显示值可以以各种形式显示,如十进制、十六进制、字符型等改变显示方式的方法是点鼠标右键,在弹出的快捷菜单中选择除了显示,还可以修改存中的值c. 查看和调用栈窗口这个窗口可以帮助我们查看当前调用树的情况,我们还可以通过这个窗口查看和修改一些变量的值鼠标停留在某个变量的时候点右键,在弹出的浮动菜单中选择Add ***to Watch window,Local 窗口显示当前一些局部变量的值,变量值的现实方式可以在十六进制和十进制之间切换,方式是在查看窗口点右键,在某个变量的Value栏用鼠标单击然后按F2(鼠标连续单击两次),即可修改该值如下图所示d. 反汇编窗口点击View->Dissambly Window可以打开反汇编窗口,该窗口可以显示反汇编后的代码、源代码和相 应反汇编代码的混合代码,可以在该窗口进行汇编、利用该窗口跟踪已找行的代码、在该窗口按汇编代码的方式单步执行。
点击鼠标右键,出现快捷菜单,如图5.29所示,其中Mixed Mode是以混合方式显示,Assembly Mode是以返回编码方式显示e. 外设窗口为了能够比较直观地了解单片机中各种外设的使用情况,uVison4提供了一个外围接口对话框通过Peripherals菜单,下拉菜单中的容和你选择的芯片有关,会列出你所选择的芯片上所有的外设选择一项你可以进入查看或修改该外设的一些状态3.4下载说明3.4.1 FlashLoader下载说明正确安装Flash Loader软件,然后正确连接UE-STM32F103开发板上的的UART1串口1和PC机的的DB9串口,用短接帽短接UE-STM32F103开发板上的BOOT0(BOOT0=1,BOOT1=0),上电运行Flash Loader 点击NEXT后按照如下选择设置点击NEXT,选择器件点击NEXT,再点击Download,然后选择需要下载的文件路径点击NEXT,开始ISP下载程序下载结束后点击Finish完成下载断电并拔下BOOT0的短接帽重新上电即可运行下载的程序3.4.2 J-link下载说明安装JLink ARM_V400a程序将JLINK的连接线的凸起对准盘古UE-STM32F103开发板上的JTAG插座(1XS11)的凹进部分插好,运行安装好的“J-Flash ARM V4.00a”点击“OPTIONS”下的“Project settings”点击CPU,如图选择芯片型号,然后点击确定返回到主菜单环境:点击File下的Open菜单键,选择需要烧写的合适的文件路径后,如图点击Target下的Connect,如果JLINK与开发板连接正确,在底部的窗口将会显示Connected successfully;点击Target下的Erase Chip,删除芯片的程序空间,成功后将提示相关信息;点击Target下的Auto,自动将需要烧写的程序写入到芯片,成功后将提示相关信息。
中间如有提示信心,直接选择是断电并拔下JLINK连接线重新上电即可运行下载的程序四、 GPIO控制实验一、实验目的实现开发板上的LED等按照一定规律“亮、灭”,掌握STM32基本GPIO口的使用二、硬件原理实现跑马灯仅需要对STM32的GPIO进行配置与读写GPIO是STM32最常用的设备之一,STM32可以提供多达80个双向GPIO口,它们分别分布在A~E等5个端口中每个端口有16个引脚,每个引脚可以承受最大为5V的压降STM32的每个I/O端口都由7个寄存器控制,分别是: 2个32位端口配置寄存器GPIOx_CRL和GPIOx_CRH;2个32位的数据寄存器GPIOx_IDR和GPIOx_ODR;1个32位的置位/复位寄存器GPIOx_BSRR;1个16位的复位寄存器GPIOx_BRR;1个32位的锁存寄存器GPIOx_LCKR1) 端口配置寄存器STM32端口由端口配置寄存器进行配置,由于每个端口有16个I/O口(即引脚),而每个I/O口需要4位配置,因此每个端口需要64位配置,这也是每个端口有2个32位端口配置寄存器的原因如A端口配置寄存器GPIOA_CRL与GPIOA_CRH,其中GPIOA_CRL配置低8位I/O口,GPIOA_CRH配置高8位I/O口,图中是GPIO_CRL寄存器。
每个I/O口可以由软件配置成8种模式:输入浮空、输入上拉、输入下拉、模拟输入、开漏输出、推挽输出、推挽式复用功能、开漏复用功能,以后根据不同的功能配置不同的模式表3.1 STM32的I/O口位配置表配置模式CNF1CNF0MODE[1:0]PxODR寄存器通用输出推挽式(Push-Pull)00011011参见表0或1开漏(Open-Drain)10或1复用功能输出推挽式(Push-Pull)10任意开漏(Open-Drain)1任意输入模拟输入0000任意输入浮空1任意输入下拉100输入上拉1表3.2 STM32输出模式配置表MODE[1:0]含义00保留01最大输出速率10MHz10最大输出速率2MHz11最大输出速率50MHz在固件库开发中,操作寄存器CRH和CRL来配置I/O口的模式和速度是通过GPIO初始化函数完成: void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct); 这个函数有两个参数,第一个参数用来指定GPIO,取值围GPIOA~GPIOG第二个参数为初始化参数结构体指针,结构体类型为GPIO_InitTypeDef,在此可以详细了解该结构体定义,该定义在stm32f10x_gpio.h中。
typedef struct { uint16_t GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; } GPIO_InitTypeDef; 配置GPIO的代码如下: GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; // 配置端口中引脚5 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 速度50MHzGPIO_Init(GPIOB, &GPIO_InitStrucure);上述代码设置GPIOB的第5个端口为推挽输出模式,同时速度为50Mbit/s 首先GPIOB是端口GPIOB的配置寄存器编址,该编址可以在 中查到结构体GPIO_InitStructure的第一个成员变量GPIO_Pin实际指出了需要配置的引脚在GPIOB配置寄存器中的偏移量。
成员变量GPIO_Mode用来设置引脚的输入输出模式,这是通过一个枚举类型定义: typedef enum { GPIO_Mode_AIN = 0x0; GPIO_Mode_FLOATING = 0 }2) 数据输入/输出寄存器图3.2 GPIO_IDR寄存器图3.3 GPIO_ODR寄存器GPIOx_IDR是端口的输入数据寄存器,GPIOx_ODR是端口的输出寄存器当配置引脚的输入输出模式是通过GPIOx_CRL和GPIOx_CRH两个寄存器来配置的,但是每个端口的16个引脚它们有的可能是输出模式,有的是输入模式,甚至一会输出一会输入,而GPIOx_IDR和GPIOx_ODR两个寄存器是以word模式访问而不能以bit模式访问,GPIOx_IDR只能读,而GPIOx_ODR可以读写因此,如果输入输出公用一个寄存器,将不知道读出的数据到底应该是输入还是输出如果是模拟输入或者浮空输入模式,那么与GPIOx_ODR无关,如果配置成下拉输入模式,则应将GPIOx_ODR各位都设置0,如果是上拉输入模式,则GPIOx_ODR各位设置成1在开漏输出模式下,通过读GPIOx_IDR来获取IO状态。
3)置位/复位寄存器图3.4 GPIO_ODR寄存器GPIOx_BSRR和GPIOx_BRR寄存器,通过这两个寄存器可以直接对对应的GPIOx端口置'1'或置'0'GPIOx_BSRR的高16位中每一位对应端口x的每个位,对高16位中的某位置'1'则端口x的对应位被清'0';寄存器中的位置'0',则对它对应的位不起作用GPIOx_BSRR的低16位中每一位也对应端口x的每个位,对低16位中的某位置'1'则它对应的端口位被置'1';寄存器中的位置'0',则对它对应的端口不起作用简单地说GPIOx_BSRR的高16位称作清除寄存器,而GPIOx_BSRR的低16位称作设置寄存器另一个寄存器GPIOx_BRR只有低16位有效,与GPIOx_BSRR的高16位具有相同功能使用BRR和BSRR寄存器可以方便地快速地实现对端口某些特定位的操作,而不影响其它位的状态比如希望快速地对GPIOE的位7进行翻转,则可以:GPIOE->BSRR = 0x80; // 置'1'GPIOE->BRR = 0x80; // 置'0'如果使用常规'读-改-写'的方法:GPIOE->ODR = GPIOE->ODR | 0x80; // 置'1'GPIOE->ODR = GPIOE->ODR & 0xFF7F; // 置'0'BSRR的高16位并不是多余,假如在一个操作中对GPIOE的位7置'1',位6置'0',则使用BSRR非常方便: GPIOE->BSRR = 0x400080; 如果没有BSRR的高16位,则要分2次操作,结果造成位7和位6的变化不同步! GPIOE->BSRR = 0x80; GPIOE->BRR = 0x40;三、固件库函数1)初始化函数在固件库开发中,操作寄存器CRH和CRL来配置I/O口的模式和速度是通过GPIO初始化函数完成:void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);这个函数有两个参数,第一个参数用来指定GPIO,取值围GPIOA~GPIOG。
第二个参数为初始化参数结构体指针,结构体类型为GPIO_InitTypeDef,在此可以详细了解该结构体定义,该定义在stm32f10x_gpio.h中 typedef struct { uint16_t GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; } GPIO_InitTypeDef; 配置GPIO的代码如下: GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; // 配置端口中引脚5 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 速度50MHzGPIO_Init(GPIOB, &GPIO_InitStrucure); 上述代码设置GPIOB的第5个端口为推挽输出模式,同时速度为50Mbit/s 首先GPIOB是端口GPIOB的配置寄存器编址,该编址可以在 中查到。
结构体GPIO_InitStructure的第一个成员变量GPIO_Pin实际指出了需要配置的引脚在GPIOB配置寄存器中的偏移量成员变量GPIO_Mode用来设置引脚的输入输出模式,这是通过一个枚举类型定义:typedef enum{GPIO_Mode_AIN = 0x0,GPIO_Mode_IN_FLOATING = 0x04,GPIO_Mode_IPD = 0x28,GPIO_Mode_IPU = 0x48,GPIO_Mode_Out_OD = 0x14,GPIO_Mode_Out_PP = 0x10,GPIO_Mode_AF_OD = 0x1C,GPIO_Mode_AF_PP = 0x18} GPIOMode_TypeDef;2)数据输入/输出函数A.. uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);返回输入端口某个引脚的状态.GPIOx: x (A~G).GPIO_Pin: 端口的哪个bit位需要读取 (0~15).如GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0); 读A0的状态,返回值可能0 或 1B. uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);如GPIO_ReadInputData(GPIOA); 返回A0~A15的状态其中typedef struct{ __IO uint32_t CRL; __IO uint32_t CRH; __IO uint32_t IDR; __IO uint32_t ODR; __IO uint32_t BSRR; __IO uint32_t BRR; __IO uint32_t LCKR;} GPIO_TypeDef;C. uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);读GPIO某一位的输出D. uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);//读GPIO的输出3)位设置函数将GPIO的某个位置位A. void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);将GPIO的某个位复位B. void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);四、实验设计本实验是STM32开发最基础的实验,如图3.4所示,3个LED灯分别接GPIOD的引脚PD5、PD6、PD7,实现LED灯的闪烁功能。
图3.4 LED灯硬件连接图完成上述功能的步骤为:(1)使能I/O口时钟,调用函数为RCC_APB2PeriphClockCmd( );(2)初始化I/O参数,调用函数GPIO_Init( );(3)操作I/O,调用函数GPIO_SetBits( )和GPIO_ResetBits五、例程/************************************************************************ 文件:main.c* 编辑:理工大学计算机学院* 日期:2013/12/04* 修改:* 版本:V1.0* 描述:UE-STM32F103开发板板载了3个LED,分别为LED1、LED和LED3 本实验将通过教你如何控制STM32的IO口配置实现这三个灯的交替闪烁***********************************************************************/#include "stm32f10x.h"/*宏定义*/#define LED_PORT GPIOD#define LED1 GPIO_Pin_5#define LED2 GPIO_Pin_6#define LED3 GPIO_Pin_7/*函数声明*/void LED_Init(void);void delayms(int loop_times);/******************************************************************** 函 数:main* 入口参数:无* 出口参数:无* 描 述:程序入口*******************************************************************/int main(void){ LED_Init(); while(1) { GPIO_SetBits(LED_PORT,LED1); GPIO_ResetBits(LED_PORT , LED2 | LED3); delayms(500); GPIO_SetBits(LED_PORT,LED2); GPIO_ResetBits(LED_PORT , LED1 | LED3); delayms(500); GPIO_SetBits(LED_PORT,LED3); GPIO_ResetBits(LED_PORT , LED1 | LED2); delayms(500); }}/******************************************************************************** Function Name : void LED_Init(void)* Description : 初始化LED的控制引脚 PD5-7* Input : None* Output : None* Return : None* Attention : None*******************************************************************************/void LED_Init(void){ GPIO_InitTypeDef GPIO_InitStructure;//打开GPIOD的外设时钟 RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOD ,ENABLE); GPIO_InitStructure.GPIO_Pin = LED1 | LED2 | LED3; // 选择操作的IO口 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO口最大输出速率 GPIO_Init(LED_PORT, &GPIO_InitStructure); // 完成初始化//将三个引脚全部复位,LED灯全灭。
GPIO_ResetBits(LED_PORT , LED1 | LED2 | LED3); }/******************************************************************************** Function Name : void delayms(int loop_times)* Description : 软件延时,延时1ms.* Input : None* Output : None* Return : None*******************************************************************************/void delayms(int loop_times){ vu32 loop_i,loop_j; for(loop_i=0; loop_i
2)按下STM32开发板上的Key1,点亮LED1与LED2本实验不仅需要例程的知识,还需要学习将GPIO模式配置为上拉输入,以与使用GPIO_ReadInputDataBit( )读取按键输入实验二、串行数据通信实验一、实验目的学习STM32的串口发送和接收数据,掌握STM32的串口通信二、硬件原理USART英文全称为“Universal Synchronous/Asynchronous Receiver/Transmitter”,即通用同步/异步串行接收/发送器,常被称作串口在STM32的参考手册中,串口被描述成通用同步异步收发器(USART),它提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换USART利用分数波特率发生器提供宽围的波特率选择它支持同步单向通信和半双工单线通信,也支持LIN(局部互联网),智能卡协议和IrDA(红外数据组织)SIR ENDEC规,以与调制解调器(CTS/RTS)操作它还允许多处理器通信还可以使用DMA方式,实现高速数据通信USART通过3个引脚与其他设备连接在一起,任何USART双向通信至少需要2个引脚:接受数据输入(RX)和发送数据输出(TX)。
RX: 接受数据串行输入通过过采样技术来区别数据和噪音,从而恢复数据TX: 发送数据输出当发送器被禁止时,输出引脚恢复到它的I/O端口配置当发送器被激活,并且不发送数据时,TX引脚处于高电平在单线和智能卡模式里,此I/O口被同时用于数据的发送和接收串口的工作方式有两种:查询与终端1)查询:串口程序不断地循环查询,看看当前有没有数据要它传送如果有,就帮助传送(可以从PC到STM32板子,也可以从STM32板子到PC)2)中断:平时串口只要打开中断即可如果发现有一个中断来,则意味着要它帮助传输数据——它就马上进行数据的传送同样,可以从 PC到STM3板子,也可以从STM32板子到PC图3.6给出异步串行通信中一个字符的传送格式开始前,线路处于空闲状态,送出连续“1”传送开始时首先发一个“0”作为起始位,然后出现在通信线上的是字符的二进制编码数据每个字符的数据位长可以约定为5位、6位、7位或8位,一般采用ASCII编码后面是奇偶校验位,根据约定,用奇偶校验位将所传字符中为“1”的位数凑成奇数个或偶数个也可以约定不要奇偶校验,这样就取消奇偶校验位最后是表示停止位的“1”信号,这个停止位可以约定持续1位、1.5位或2位的时间宽度。
至此一个字符传送完毕,线路又进入空闲,持续为“1”经过一段随机的时间后,下一个字符开始传送才又发出起始位每一个数据位的宽度等于传送波特率的倒数图3.6 串口通信格式UE-STM32F103开发板板载了2个RS-232串口,分别为串口1和串口3,了解串口通信主要有以下几部分容:1)波特比率寄存器(USART_BRR)STM32有数个串口,每个串口都有一个自己独立的波特率寄存器USART_BRR,通过设置该寄存器就可以达到配置不同波特率的目的,由于STM32采用了分数波特率,所以STM32的串口波特率设置围很宽,而且误差很小图3.7 USART_BRR寄存器由图3.6可知:USART_BRR的最低4位(位[3:0])用来存放小数部分DIV_Fraction,紧接着的12位(位[15:4])用来存放整数部分DIV_Mantissa,最高16位保留STM32的串口波特率计算公式如下: 式3.1上式中,fPCLK是给串口的时钟(PCLK1用于USART2、3、4、5,PCLK2用于USART1, PCLK1是由系统时钟分频得来,最大36MHZ,PCLK2是直接由系统时钟得来,最大72MHZ。
USARTDIV是一个无符号定点数,如果已知要设置的波特率与系统时钟,就可以算出USARTDIV的值,并把它的整数和小数分离开来,分别写入USART_BRR寄存器里的对应位假设串口1要设置为115200的波特率,而PCLK2的时钟为72M根据公式3.1有:USARTDIV=72000000/(115200*16)=39.0625那么得到:DIV_Fraction=16×0.0625=1=0x01;DIV_Mantissa= 39=0x27;这样,就得到了USART1->BRR的值为0x271只要设置串口1的BRR寄存器值为0x271就可以得到115200的波特率2)保护时间和预分频寄存器(USART_GTPR)图3.7 USART_GTPR寄存器位31:16保留位,硬件强制为0位15:8GT[7:0]:保护时间值(Guard time value) 该位域规定了以波特时钟为单位的保护时间在智能卡模式下,需要这个功能当保护时间过去后,才会设置发送完成标志注:UART4和UART5上不存在这一位位7:0PSC[7:0]:预分频器值(Prescaler value) - 在红外(IrDA)低功耗模式下:PSC[7:0]=红外低功耗波特率对系统时钟分频以获得低功耗模式下的频率:源时钟被寄存器中的值(仅有8位有效)分频00000000:保留– 不要写入该值;00000001:对源时钟1分频;00000010:对源时钟2分频;…… - 在红外(IrDA)的正常模式下:PSC只能设置为00000001 - 在智能卡模式下:PSC[4:0]:预分频值对系统时钟进行分频,给智能卡提供时钟。
寄存器中给出的值(低5位有效)乘以2后,作为对源时钟的分频因子00000:保留– 不要写入该值;00001:对源时钟进行2分频;00010:对源时钟进行4分频;00011:对源时钟进行6分频;…… 注意:1.位[7:5]在智能卡模式下没有意义2.UART4和UART5上不存在这一位一般在系统刚开始配置外设的时候,都会先执行复位该外设的操作串口1的复位是通过配置APB2RSTR寄存器的第14位来实现的,通过向该位写1复位串口1,写0结束复位其他串口的复位位在APB1RSTR里面设置3)控制寄存器(USART_CR)串口控制寄存器有三个:USATR_CR1-3,串口的很多配置都是通过这3个寄存器来设置的,该寄存器的各位描述如下图所示:UE:USART使能 (USART enable)M:字长 (Word length) 该位定义了数据字的长度, 0:一个起始位,8个数据位,n个停止位;1:一个起始位,9个数据位,n个停止位 n由USART_CR2中设置WAKE:唤醒的方法 (Wakeup method) 0:被空。