完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
1、stm32f103zet6(上篇问题3 stm32f103是什么)
上篇的跑马灯程序采用的开发板使用的mcu是stm32f103zet6,根据stm32系列产品命名规则,我们知道这款mcu为基于ARM®的32位微控制器、是增强型的、拥有144个引脚、512K字节的闪存存储器、采用LQFP封装、工作温度范围在-40℃~85℃。这款芯片包含的资源有 64KB SRAM(Static Random Access Memory静态随机存取存储器)、512KB FLASH、2个基本定时器、4个通用定时器、2个高级定时器、2个DMA(Direct Memory Access直接内存存取)控制器(公12个通道)、3个SPI(Serial Peripheral Interface串行外设接口)、2个IIC(Inter-Integrated Circuit集成电路总线)、5个串口、1个USB、1个CAN(控制器局域网络Controller Area Network)、3个12位ADC(Analog-to-Digital Converter模/数转换)、1个12位DAC(Digital-to-Analog Converter数/模转换)、1个SDIO(Secure Digital Input and Output安全数字输入输出卡)接口、1个FSMC(Flexible Static Memory Controller可变静态存储控制器)接口以及112个GPIO(General Purpose Input Output 通用输入/输出)口。 下图是其系统结构图 虽然上面已经将stm32f103zet6芯片系统构成已经介绍,但是下面的介绍是针对上图给的一个更直观的概况。 stm32主要由四个驱动单元和四个被动单元构成。
DCode总线:该总线将Cortex™-M3内核的DCode总线与闪存存储器的数据接口相连接(常量加载和调试访问) 系统总线:此总线连接Cortex™-M3内核的系统总线(外设总线)到总线矩阵,总线矩阵协调着内核和DMA间的访问 DMA总线:此总线将DMA的AHB主控接口与总线矩阵相联,总线矩阵协调着CPU的DCode和DMA到 SRAM、闪存和外设的访问。 总线矩阵:协调内核系统总线和DMA主控总线之间的访问仲裁,仲裁利用轮换算法。在互联型产品中,总线矩阵包含5个驱动部件(CPU的DCode、系统总线、以太网DMA、DMA1总线和DMA2总线)和3个从部件(闪存存储器接口(FLITF)、SRAM和AHB2APB桥)。在其它产品中总线矩阵包含4个驱动部件(CPU的DCode、系统总线、DMA1总线和DMA2总线)和4个被动部件(闪存存储器接口(FLITF)、SRAM、FSMC和AHB2APB桥)。AHB外设通过总线矩阵与系统总线相连,允许DMA访问。 AHB/APB桥(APB) :两个AHB/APB桥在AHB和2个APB总线间提供同步连接。APB1操作速度限于36MHz,APB2操作于全速(最高72MHz)。 在每一次复位以后,所有除SRAM和FLITF以外的外设都被关闭,在使用一个外设之前,必须设置寄存器RCC_AHBENR来打开该外设的时钟。 注意: 当对APB寄存器进行8位或者16位访问时,该访问会被自动转换成32位的访问:桥会自动将8位或者32位的数据扩展以配合32位的向量。 注: ROM、RAM、DRAM、SRAM和FLASH的区别 AHB (Advanced High-performance Bus高级高性能总线) 主要是针对高效率、高频宽及快速系统模块所设计的总线,它可以连接如微处理器、芯片上或芯片外的内存模块和DMA等高效率模块。2、GPIO 1)概念 GPIO英文为General Purpose Input Output,称为通用输入/输出 stm32f103zet6包含112个GPIO(stm32f103zet6有144个引脚,其中有11个VSS、11个VDD、还有10个其他用途的引脚分别是VBAT、OSC_IN、OSC_OUT、NRST、Vref+、Vref-、VDDA、VSSA、BOOT0、NC),112个GPIO分别是PA[0..15]~PG[0..15],stm32f103zet6引脚图如下: 2)如何使用 stm32单片机是操作寄存器来控制IO口的,首先我们应该知道GPIO的寄存器地址为多少,下表中记录了STM32F10ZET6中内置外设的起始地址。 从图中我们可以看到GPIO起始地址是0x40010800,在系统库函数stm32f10x.h中为我们定义了宏定义,方便我们操作寄存器控制外设,stm32f10x.h中的GPIOx定义如下 #define PERIPH_BASE ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */ #define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) #define GPIOA_BASE (APB2PERIPH_BASE + 0x0800) #define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00) #define GPIOC_BASE (APB2PERIPH_BASE + 0x1000) #define GPIOD_BASE (APB2PERIPH_BASE + 0x1400) #define GPIOE_BASE (APB2PERIPH_BASE + 0x1800) #define GPIOF_BASE (APB2PERIPH_BASE + 0x1C00) #define GPIOG_BASE (APB2PERIPH_BASE + 0x2000) #define GPIOA ((GPIO_TypeDef *) GPIOA_BASE) #define GPIOB ((GPIO_TypeDef *) GPIOB_BASE) #define GPIOC ((GPIO_TypeDef *) GPIOC_BASE) #define GPIOD ((GPIO_TypeDef *) GPIOD_BASE) #define GPIOE ((GPIO_TypeDef *) GPIOE_BASE) #define GPIOF ((GPIO_TypeDef *) GPIOF_BASE) #define GPIOG ((GPIO_TypeDef *) GPIOG_BASE) 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; 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; typedef enum { GPIO_Speed_10MHz = 1, GPIO_Speed_2MHz, GPIO_Speed_50MHz }GPIOSpeed_TypeDef; typedef struct { uint16_t GPIO_Pin; /*!< Specifies the GPIO pins to be configured. This parameter can be any value of @ref GPIO_pins_define */ GPIOSpeed_TypeDef GPIO_Speed; /*!< Specifies the speed for the selected pins. This parameter can be a value of @ref GPIOSpeed_TypeDef */ GPIOMode_TypeDef GPIO_Mode; /*!< Specifies the operating mode for the selected pins. This parameter can be a value of @ref GPIOMode_TypeDef */ }GPIO_InitTypeDef; #define GPIO_Pin_0 ((uint16_t)0x0001) /*!< Pin 0 selected */ #define GPIO_Pin_1 ((uint16_t)0x0002) /*!< Pin 1 selected */ #define GPIO_Pin_2 ((uint16_t)0x0004) /*!< Pin 2 selected */ #define GPIO_Pin_3 ((uint16_t)0x0008) /*!< Pin 3 selected */ #define GPIO_Pin_4 ((uint16_t)0x0010) /*!< Pin 4 selected */ #define GPIO_Pin_5 ((uint16_t)0x0020) /*!< Pin 5 selected */ #define GPIO_Pin_6 ((uint16_t)0x0040) /*!< Pin 6 selected */ #define GPIO_Pin_7 ((uint16_t)0x0080) /*!< Pin 7 selected */ #define GPIO_Pin_8 ((uint16_t)0x0100) /*!< Pin 8 selected */ #define GPIO_Pin_9 ((uint16_t)0x0200) /*!< Pin 9 selected */ #define GPIO_Pin_10 ((uint16_t)0x0400) /*!< Pin 10 selected */ #define GPIO_Pin_11 ((uint16_t)0x0800) /*!< Pin 11 selected */ #define GPIO_Pin_12 ((uint16_t)0x1000) /*!< Pin 12 selected */ #define GPIO_Pin_13 ((uint16_t)0x2000) /*!< Pin 13 selected */ #define GPIO_Pin_14 ((uint16_t)0x4000) /*!< Pin 14 selected */ #define GPIO_Pin_15 ((uint16_t)0x8000) /*!< Pin 15 selected */ #define GPIO_Pin_All ((uint16_t)0xFFFF) /*!< All pins selected */ 上述代码定义了8个GPIO的访问地址GPIOA~GPIOG,同时定义了每个GPIO 16个引脚的选择码,同时还可以看到定义了几个GPIO相关的结构体,分别是GPIO_TypeDef、GPIO_InitTypeDef、GPIOMode_TypeDef、GPIOSpeed_TypeDef,下面会对每个结构体做一下更细的介绍。 ① GPIO寄存器介绍(GPIO_TypeDef) 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; 从库给出的结构体结合芯片手册,我们知道GPIO端口有:
上面①中给我们详细介绍了GPIO寄存器的相应的功能,在了解之后我们即可直接操作寄存器写自己的IO控制程序了,如跑马灯的程序我们就可按如下代码编写: RCC->APB2ENR|=1<<3; //使能PORTB时钟 RCC->APB2ENR|=1<<6; //使能PORTE时钟 GPIOB->CRL&=0XFF0FFFFF; GPIOB->CRL|=0X00300000;//PB.5 推挽输出 GPIOB->ODR|=1<<5; //PB.5 输出高 GPIOE->CRL&=0XFF0FFFFF; GPIOE->CRL|=0X00300000;//PE.5推挽输出 GPIOE->ODR|=1<<5; //PE.5输出高 while(1) { GPIOB->BRR=GPIO_Pin_5;//LED0亮 GPIOE->BSRR=GPIO_Pin_5;//LED1灭 delay_ms(300); GPIOB->BSRR=GPIO_Pin_5;//LED0灭 GPIOE->BRR=GPIO_Pin_5;//LED1亮 delay_ms(300); } stm32有上百个寄存器,每次编程都需要翻手册在编程可想象这种场景应该很恐怖,故官方为我们提供了相应的库函数,这些函数将寄存器的操作封装,即可靠又方便使用。 GPIO官方为我们提供了如下几个库函数 /** @defgroup GPIO_Exported_Functions**/ void GPIO_DeInit(GPIO_TypeDef* GPIOx); void GPIO_AFIODeInit(void); void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct); void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct); uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx); uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx); void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal); void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal); void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource); void GPIO_EventOutputCmd(FunctionalState NewState); void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState); void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource); void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface); GPIO相应的库函数很多,可以查看手册或示例了解使用方法,跑马灯程序使用到的函数有: //用来设置GPIO端口的模式 void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct); //用来给GPIO端口设置1 void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); //用来给GPIO端口设置0 void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); 跑马灯库函数程序 GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE); //使能PB,PE端口时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED0-->PB.5 端口配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB.5 GPIO_SetBits(GPIOB,GPIO_Pin_5); //PB.5 输出高 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED1-->PE.5 端口配置, 推挽输出 GPIO_Init(GPIOE, &GPIO_InitStructure); //推挽输出 ,IO口速度为50MHz GPIO_SetBits(GPIOE,GPIO_Pin_5); //PE.5 输出高 while(1) { GPIO_ResetBits(GPIOB,GPIO_Pin_5); //LED0对应引脚GPIOB.5拉低,亮 等同LED0=0; GPIO_SetBits(GPIOE,GPIO_Pin_5); //LED1对应引脚GPIOE.5拉高,灭 等同LED1=1; delay_ms(300); //延时300ms GPIO_SetBits(GPIOB,GPIO_Pin_5); //LED0对应引脚GPIOB.5拉高,灭 等同LED0=1; GPIO_ResetBits(GPIOE,GPIO_Pin_5); //LED1对应引脚GPIOE.5拉低,亮 等同LED1=0; delay_ms(300); //延时300ms } 3、板子原理图确定GPIO端口 看了跑马灯的代码估计很多人会发出疑问:怎么知道操作的是GPIOB的GPIO_Pin_5去控制一个灯,操作GPIOE的GPIO_Pin_5去控制另外一个灯。 针对这个疑问,解决方法是 我们必须看所使用的板子的原理图了,我使用的板子关于LED灯的原理图如下: 控制LED灯的stm32芯片部分原理图 从上面两个图可以看出,我所使用的板子已将LED与stm32f103芯片连接好了。LED0接PB5,所以我们使用的是GPIOB、GPIO_Pin_5这两个宏定义,代表PB5。 LED1接PE5,所以我们使用的是GPIOE、GPIO_Pin_5这两个宏定义,代表PE5。 4、时钟 从跑马灯程序中我们看到以下代码: /** **使用寄存器初始化时钟** RCC->APB2ENR|=1<<3; //使能PORTB时钟 RCC->APB2ENR|=1<<6; //使能PORTE时钟**/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE); //使能PB,PE端口时钟 之所以在程序开头要开启时钟,是因为任何MCU的任何外设都需要有时钟 ,STM32为了让用户更好地掌握功耗,对每个外设的时钟都设置了开关,所以我们在使用外设(GPIO)前需要开启时钟(51单片机不用配置IO时钟,只是因为默认使用同一个时钟) 下图是RCC_APB2ENR外设时钟使能寄存器图 |
|
|
|
只有小组成员才能发言,加入小组>>
2496 浏览 0 评论
1059浏览 2评论
678浏览 1评论
440浏览 0评论
175浏览 0评论
292浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-10 13:45 , Processed in 0.971748 second(s), Total 47, Slave 39 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号