STM32微控制器及应用第一部分STM32概述第二部分STM32的开发过程第三部分实例问题1:为什么选择STM32?1、适应市场的发展近几年,STM32的出现给MCU用户前所未有的自由空间,提供了全新的32位产品选项,结合了高性能、实时、低功耗、低电压等特性,同时保持了高集成度和易于开发的优势,再加上丰富的外设和有竞争力的价格,得到了市场上高度的认可,使得它成为我们的第一选择。2、专业相关性在功能和运算中做平衡,功能是第一位,运算是第二位,其丰富的外设为我们实现功能提供了极大的方便,这使得它成为我们的第一选择。第一部分STM32概述一、STM32简介1、概述STM32是来自于ARM公司具有突破性的Cortex-M3内核的32位闪存微控制器。该内核是专门设计于满足集高性能、低功耗、实时应用、具有竞争性价格于一体的嵌入式领域的要求。STM32有两个系列增强型和基本型。STM32F103是增强型系列,工作在72MHz,带有片内RAM和丰富的外设。STM32F101是基本型系列,工作在36MHz。两个系列的产品拥有相同的片内闪存选项,在软件和引脚封装方面兼容。均可以用于显示、声音、存储和高级控制;兼有低功耗和多种省电工作模式,能够优化工业设备、物业控制设备、医疗设备和计算机外设等产品的性能。2、系统构架主系统由以下部分构成:●四个驱动单元:−Cortex™-M3内核ICode总线(I-bus),−DCode总线(D-bus),−系统总线(S-bus),−GP-DMA(通用DMA)●三个被动单元−内部SRAM−内部闪存存储器−AHB到APB的桥(AHB2APBx),它连接所有的APB设备系统架构图DMA:用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输.注意:并不是所有的外设都可以用DMA通道去传输二、STM32系统时钟控制(RCC)STM32有三种不同的时钟源可被用来驱动系统时钟,分别如下:★HSE振荡器时钟★HSI振荡器时钟★PLL时钟1、HSE振荡器时钟高速外部时钟信号(HSE)有以下两种方式产生:★HSE外部晶体/陶瓷谐振器(HSE晶振)★HSE用户外部时钟(HSE旁路)外部时钟可通过设置时钟控制寄存器中的HSEBYP和HSEON来设置这一模式,它的频率最高可达25MHZ。外部时钟信号必须连到OSC_IN管脚,同时OSC_OUT管脚悬空。HSE晶体可通过设置时钟控制寄存器RCC_CR中的HSEON位被启动和关闭。4-16MHZ的外部振荡器可为系统提供更加精准的主时钟。2、HSI振荡器时钟HSI时钟信号是由内部8MHZ的RC振荡器产生,它可以直接作为系统时钟信号或2分频后作为PLL时钟。与HSE相比,HSI时钟信号不需要任何外部器件的条件下提供系统时钟,它的启动时间比HSE晶体振荡器短,但它的时钟频率精度比较差。如果HSE晶体振荡器失效,HIS时钟会被用作备用时钟。3、PLL时钟内部PLL可以用来倍频HISRC的输出时钟或HSE晶体输出时钟。HSI2分频PLL的时钟源(配置)HSE如果需要在应用中使用USB接口,PLL必须被配置为输出48MHZ或72MHZ时钟,用于提供48MHZ的USBCLK时钟。4、LSE时钟LSE晶体时钟是一个32.768KHZ的低速外部晶体或陶瓷振荡器。它为实时时钟提供或者其它定时功能提供一个低功耗且精准的时钟源。通过程序选择可以用来驱动RTC时钟。5、LSI时钟LSIRC时钟频率大约40KHZ(30~60kHZ),担当一个低功耗时钟源的角色,它可以在停机和待机模式下保持运行,为独立看门狗和自动唤醒单元提供时钟。系统时钟的几点说明:1)用户可通过多个预分频器配置AHB、高速APB(APB1)、低速APB(APB2)域的频率。2)AHB和APB2域的最大允许频率是72MHZ,APB1域的最大允许频率是36MHZ。3)当HSI被用于作为PLL时钟的输入时,系统时钟的最大频率不得超过64MKZ。4)定时器时钟频率是其所在APB总线频率的2倍。然而,如果相应的APB预分频系数为1时,定时器的时钟频率与所在的APB时钟频率一致。三、STM32中断系统STM32目前支持的中断共为84个(16个内核+68个外部),和16个可编程的优先中断级的设置。对于外部的68个中断通道,已经固定的分配各相应的外设,每个中断通道都有自己的中断优先级8位控制字节,其中高4位有效。而对于这4位的中断优先级控制位又分成2组:从高位开始,前面是定义抢先式优先级的位,后面是定义子优先级的位。4位的分组组合可以有以下几种形式:1、NVIC的优先级概念抢占先式优先级(pre-emptionpriority):抢占先式优先级的中断事件会打断当前的主程序/中断程序运行——抢断式优先响应,俗称中断嵌套。副优先级(subpriority):在抢占先式优先级相同的情况下,高副优先级的中断优先被响应;在占先式优先级相同的情况下,如果有低副优先级中断正在执行,高副优先级的中断要等待已被响应的低副优先级中断执行结束后才能得到响应——非抢断式响应(不能嵌套)。2、具体优先级的确定和嵌套规则a、只能高抢占式优先级可以打断低抢占式优先级的中断服务,构成中断嵌套;b、当有N个相同抢占式优先级出现,他们之间不能构成中断嵌套,但STM32首先响应子优先级高的中断;c、当N个相同抢占式优先级和相同子优先级的中断出现,STM32首先响应中断通道所对应的中断向量地址低的那个中断;问题2:怎样开发STM32?第二部分STM32的开发过程一、必须阅读的相关文档1、几个重要的官方文档a)Datasheet——芯片基本数据,功能参数封装管脚定义和性能规范。b)固件函数库用户手册——函数库功能,库函数的定义、功能和用法。c)参考手册——各种功能的具体描述,使用方法,原理,相关寄存器。d)STM32F10xxx硬件开发:使用入门——相关基础硬件设计e)STM32F10XXX的使用限制:芯片内部未解决的硬件设计bug,开发需要注意绕开。2、固件函数库的应用总共24个库,不可能都学,也不可能都不学,按照自己的需要对固件库函数学习的排列顺序:a)绝大部分程序都要涉及到的库——flash,lib,nvic,rcc,gpio,只学基础的和最简单应用相关必用的部分,其他部分后期返回头再学。b)各种程序通用但不必用的库——exti,MDA,systic,只通读理解其作用。d)未来需要用到的外设的库——usart,tim,tim1,adc,i2c,spi,can,先理解等待有条件后实验。e)开发可靠性相关库——bkp,iwdg,wwdg,pwr,参考其他例程的做法。f)其他,根据兴趣来学。3、STM32的硬件使用限制(Bug)a)自身功能的受限ADC自动注入通道ADC混合同步注入+交替模式ADC通道0上的电压尖峰启动代码选项字和保护功能WFI/WFE指令后的Flash读操作b)复用功能冲突USART1_RTS和CAN_TX从模式下的SPI1和同步模式下的USART2主模式下的SPI1和同步模式下的USART2从模式下的SPI2和同步模式下的USART3主模式下的SPI2和同步模式下的USART3I2C2和SPI2以及USART3I2C1和重映射后主模式下的SPI1I2C1和重映射后的TIM3_CH2SDIO和I2S2/I2S3SDIO和TIM4以及TIM8SDIO和重映射后的TIM3SDIO和重映射后的USART3以及USART4SDIO和重映射后的I2C1FSMC和I2C1以及TIM4_CH2FSMC和重映射后的USART2二、新建工程软件配置:通过设置Flash/Configflashtools菜单下的选项,选择目标芯片的型号,flash和RAM的存储起始地址和大小,选择仿真调试工具,闪存空间等。三、模板化编程1、模板化编程步骤:1)在工程中添加启动文件(cortexm3_macro.s和stm32f10x_vector.s)2)在工程中添加对应外设的固件库函数(stm32f10x_xxx.c)3)在工程中添加中断服务程序模块(stm32f10x_it.c)4)在工程中编写外设配置(初始化)模块代码注意:必须记住所有外设的使用需要考虑以下4个问题:a)开时钟RCC(在RCC初始化中);b)自身初始化;c)相关管脚配置(在GPIO初始化中)d)是否使用中断(在NVIC初始化中)5)如果用到中断,则在“stm32f10x_it.c”填写所用中断所需的执行代码,如果用不到中断,则不用编写此文件6)编写main函数中的应用程序及其他子程序注意:一定要将”#includestm32f10x_lib.h”头文件包含在其中2、flash,lib,nvic,rcc和gpio基础程序库编写a)voidRCC_Configuration(void);//定义时钟初始化函数{ErrorStatusHSEStartUpStatus;//等待时钟的稳定RCC_DeInit();//时钟管理重置RCC_HSEConfig(RCC_HSE_ON);//打开外部晶振HSEStartUpStatus=RCC_WaitForHSEStartUp();//等待外部晶振就绪if(HSEStartUpStatus==SUCCESS){FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);//flash读取缓冲,加速FLASH_SetLatency(FLASH_Latency_2);//48-72M,Latency=2,flash操作的延时RCC_HCLKConfig(RCC_SYSCLK_Div1);//AHB使用系统时钟RCC_PCLK2Config(RCC_HCLK_Div2);//APB2(高速)为HCLK的一半RCC_PCLK1Config(RCC_HCLK_Div2);//APB1(低速)为HCLK的一半RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);//PLLCLK=8*9=72MRCC_PLLCmd(ENABLE);//启动PLLwhile(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET){}//等待PLL启动RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);//将PLL设置为系统时钟源while(RCC_GetSYSCLKSource()!=0x08);//等待系统时钟源的启动RCC_AHBPeriphClockCmd(ABP2设备1|ABP2设备2|,ENABLE);//启动AHP设备RCC_APB2PeriphClockCmd(ABP2设备1|ABP2设备2|,ENABLE);//启动ABP2设备RCC_APB1PeriphClockCmd(ABP2设备1|ABP2设备2|,ENABLE);//启动ABP1设备}}}b)voidNVIC_Configuration(void){NVIC_InitTypeDefNVIC_InitStructure;//中断管理恢复默认参数#ifdefVECT_TAB_RAM//如果C/C++Compiler\Preprocessor\Definedsymbols中的定义了VECT_TAB_RAM(见程序库更改内容的表格)NVIC_SetVectorTable(NVIC_VectTab_RAM,0x0);//则在RAM调试#else//如果没有定义VECT_TAB_RAMNVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0);//则在Flash里调试#endif//结束判断语句NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置NVIC优先级分组方式。}NVIC_InitStructure.NVIC_IRQChannel=中断通道名;//开中断,中断名称见函数库NVI