完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
首先介绍一下GPIO功能,每个通用输入/输出端口有2个32位的配置寄存器(GPIOx_CRL,GPIOx_CRH),2个32位的数据寄存器(GPIOx_IDR,GPIOx_ODR),一个32位的置位/复位寄存器(GPIOx_BSRR),一个16位的复位寄存器(GPIOx_BRR),和一个32位的锁定寄存器(GPIOx_LCKR).通用输入/输出的每个端口位可以由软件单独配置成以下几种模式: - 输入浮动 - 输入上拉 - 输入下拉 - 模拟输入 - 输出开漏 - 输出推拉模式 - 备用功能推拉 - 备用功能开漏 每个I/O端口都可以自由的编程,尽管I/O端口寄存器以32位字的方式访问(不允许以半字或者字节的方式访问)。GPIOx_BSRR和GPIOx_BRR寄存器的目的就是用来允许GPIO寄存器进行原子的读/修改操作。在这种方式下,当IRQ(中断请求)发生在读和修改之间时就不会带来风险。 I/O端口位的基本结构: 端口位配置表: 为了方便使用上述GPIO的工作模式,所以定义结构体: /*GPIO模块工作模式*/ 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; /*GPIO模块时钟频率*/ typedef enum { GPIO_Speed_10MHz = 1, GPIO_Speed_2MHz, GPIO_Speed_50MHz }GPIOSpeed_TypeDef; /*GPIO模块初始化*/ typedef struct { uint16_t GPIO_Pin; /*特定引脚配置的定义/ GPIOSpeed_TypeDef GPIO_Speed; /*为GPIO_Pin设置时钟频率*/ GPIOMode_TypeDef GPIO_Mode; /*为GPIO_Pin设置工作模式 */ }GPIO_InitTypeDef; 这样在对GPIO模式设定时就不用关心数值的问题了,而且方便记忆。 下面开始解读: void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct) { uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00; uint32_t tmpreg = 0x00, pinmask = 0x00; /* 一些断言,用来判断输入参数是否符合实际,初学者可以不用管这些不太重要的东西,专注与寄存器的配置就好了*/ assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode)); assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin)); /*---------------------------- GPIO模式的配置,-----------------------*/ currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F); //配置前记录当前GPIO工作模式 if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00) { /* 还是一些断言。。。。。。。 */ assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed)); /* 通过位与输出工作模式设定,与的原因是保留先前的模式,更新现在的 */ currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed; } /*---------------------------- GPIO CRL 配置------------------------*/ /*配置底八位端口引脚*/ if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00) { tmpreg = GPIOx->CRL; for (pinpos = 0x00; pinpos < 0x08; pinpos++) { pos = ((uint32_t)0x01) << pinpos; /* 记录当前引脚*/ currentpin = (GPIO_InitStruct->GPIO_Pin) & pos; if (currentpin == pos) { pos = pinpos << 2; /*清楚底八位控制寄存器位*/ pinmask = ((uint32_t)0x0F) << pos; tmpreg &= ~pinmask; /* 把刚才的工作模式currentmode写入寄存器 */ tmpreg |= (currentmode << pos); /*复位 ODR 位*/ if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD) { GPIOx->BRR = (((uint32_t)0x01) << pinpos); } else { /* 置位 ODR 位 */ if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU) { GPIOx->BSRR = (((uint32_t)0x01) << pinpos); } } } } GPIOx->CRL = tmpreg; } /*---------------------------- GPIO CRH 配置------------------------*/ /* 配置高八位端口引脚 */ if (GPIO_InitStruct->GPIO_Pin > 0x00FF) { tmpreg = GPIOx->CRH; for (pinpos = 0x00; pinpos < 0x08; pinpos++) { pos = (((uint32_t)0x01) << (pinpos + 0x08)); /* Get the port pins position */ currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos); if (currentpin == pos) { pos = pinpos << 2; /*清除高八位控制寄存器配置*/ pinmask = ((uint32_t)0x0F) << pos; tmpreg &= ~pinmask; /* 把设定模式写入控制寄存器中*/ tmpreg |= (currentmode << pos); /* 复位 ODR 位*/ if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD) { GPIOx->BRR = (((uint32_t)0x01) << (pinpos + 0x08)); } /*置位 ODR 位 */ if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU) { GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08)); } } } GPIOx->CRH = tmpreg; } } 接着解读: void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) { /* 还是断言断言!!!!!*/ assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); assert_param(IS_GPIO_PIN(GPIO_Pin)); GPIOx->BSRR = GPIO_Pin; //这是初始化之后直接对引脚进行置位操作,非常简单的 } 解读: void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) { /*断言断言,,,,*/ assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); assert_param(IS_GPIO_PIN(GPIO_Pin)); GPIOx->BRR = GPIO_Pin; //与上个函数一样,不在叙述了 } 总结: 个人感觉编程之所以难,就是因为不会配置寄存器,所以当学会配置寄存器之后,编程的时候就会感觉好像在写51程序似得,所以要想整的学会某款芯片,一定要学会对寄存器的配置,而不是一味的用别人写好的库函数,那样学不到真东西的。送一句与大家共勉:学写代码,就用最难的方式开始,越简单的方式,经验价值就越低。 好了,就先写这么多吧,看看大家反响如何,多给我题宝贵意见,好在后面的帖子中改进。 |
|
相关推荐
|
|
【云智易试用体验】+stm32深入底层驱动之GPIO模块(上)https://bbs.elecfans.com/jishu_514265_1_1.html
|
|
|
|
|
|
@曲终人散@ 发表于 2015-9-13 09:01 下次分享串口 |
|
|
|
|
|
在编辑文本的时候,功能栏有图片那个按钮,点击就可以了,等图片上传完成了,记住,一定要点击一下图片,只有这样图片才会出现在你的编辑框里,祝你成功。 |
|
|
|
|
|
AD7686芯片不传输数据给STM32,但是手按住就会有数据。
621 浏览 1 评论
1962 浏览 0 评论
如何解决MPU-9250与STM32通讯时,出现HAL_ERROR = 0x01U
1068 浏览 1 评论
hal库中i2c卡死在HAL_I2C_Master_Transmit
1487 浏览 1 评论
LL库F030进行3个串口收发,2个串口为232,一个为485,长时间后,会出现串口1停止运行,另外两个正常,只有重启复原
1924 浏览 1 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-19 16:29 , Processed in 0.781679 second(s), Total 84, Slave 65 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号