完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
“追毛求疵” 的学习STM32,实际操作过程中知识盲区比想象中要多很多!只做了两个GPIO口项目。实战一 · I/O口 1. 文件夹结构
文件层次关系 2. 配置细节 · 从寄存器到库函数 寄存器原理 每个GPI/O口有7个寄存器:
I/O口模式介绍参照下文: I/O口配置结构图 I/O口的“输入和输出”是以片上外设为参考系的,左边是片内,右边是外部引脚 1. 输入输出模式配置 STM32将I/O口分成多个组:GPIOA,GPIOB… 每组I/O有16个I/O口,每个I/O端口位可以自由编程,必须按32位被访问。 CRL和CRH控制IO口模式以及传输速度,CRL控制低八位,CRH控制高八位。 以CRL为例,有8个2位CNF和8个二位MODE一共32位,CNF选择输出模式,MODE选择输出速度,配置表如下: 寄存器配置成CNF=01,MODE=00时,进入浮空输入模式,达到复位的效果 单片机的GPIO口在复位后默认是输入模式,而且是浮空输入模式综上: CRL控制每组IO端口中的低八位IO口模式,每个IO口占用CRL4位,高两位CNF,低两位MODE。CRH与之相同,控制高八位GPIOx_(8-15) 常用模式的配置:
回到库函数封装开发 //GPIO初始化函数 void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct); 第一个参数GPIOx指定GPIO,取值GPIOA,GPIOB… 第二个参数为初始化参数结构体指针,结构体GPIO_InitStruct,类型为GPIO_InitTypeDef,定义: typedef struct { uint16_t GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; } GPIO_InitTypeDef; 初始化实例: GPIO_InitTypeDef GPIO_InitStructure; //结构体变量定义 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //端口配置Pin_5 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度 50MHz GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数配置 GPIOB 2. IDR 端口输入数据寄存器,低16位只读寄存器,可以用于读取某个IO口电平状态。 寄存器描述: 库函数: uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) 示例 GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5);//读取GPIOA_5电平状态,返回0/1 3. ODR 端口输出数据寄存器,只用第十六位,可读写,写入数据控制输出,读取数据获取当前电平状态。 寄存器描述: 库函数: void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal); BSRR端口位设置/清除寄存器,可以设置GPIO端口输出位高低电平 寄存器描述: 库函数: void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);//置1void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)//置0 了解了GPIO配置细节,下面来进行两个基础实验:
3. 跑马灯 需要的固件库文件:
在外设硬件文件夹HARDWARE中新建led.c,依次使能时钟,查原理图配置端口,端口初始化,输出高电平,推挽输出模式,速度50MHz GPIO是APB2总线上的外设,APB2总线上的外设时钟使能函数是: RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA| RCC_APB2Periph_GPIOD, ENABLE); //使能 PA,PD 端口时钟 .c程序代码: #include "led.h" //初始化 PA8 和 PD2 为输出口.并使能这两个口的时钟 //LED IO 初始化 void LED_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA| RCC_APB2Periph_GPIOD, ENABLE); //使能 PA,PD 端口时钟 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO 口速度为 50MHz GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 //PA.8 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //LED0-->PA.8 端口配置 GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.8 GPIO_SetBits(GPIOA,GPIO_Pin_8); //PA.8 输出高 //PD.2 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //LED1-->PD.2 GPIO_Init(GPIOD, &GPIO_InitStructure); //初始化 GPIOD.2 GPIO_SetBits(GPIOD,GPIO_Pin_2); //PD.2 输出高 } .h程序代码: #ifndef __LED_H #define __LED_H #include "sys.h" //LED 端口定义 //位带操作控制某个IO口的1个位 #define LED0 PAout(8) // LED0 = PA8 #define LED1 PDout(2) // LED1 = PD2 void LED_Init(void);//初始化 #endif 位带操作: PAout (6) = 1 如是 main函数代码 #include "led.h" #include "delay.h" #include "sys.h" //跑马灯实验 int main(void) { delay_init(); //延时函数初始化 LED_Init(); //初始化与 LED 连接的硬件接口 while(1) { LED0=0; LED1=1; delay_ms(300); //延时 300ms LED0=1; LED1=0; delay_ms(300); //延时 300ms } } 4. 按键输入 IO口知识在前面已经讲解完善,直接开始硬件查接口+软件设计 硬件接口查询 按键项目需要两个组成部分,初始化和扫描 初始化函数 查接口电路发现按键的PA15与JTAG的数据输入端JTDI冲突了,于是使用函数: GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); 1 禁用JTAG,开启SWD void KEY_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; //结构体定义 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE); //使能 PORTA,PORTC 时钟 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); //关闭 jtag,使能 SWD,可以用 SWD 模式调试 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; //PA15 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入 GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA15 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //PC5 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入 GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化 GPIOC5 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PA0 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 设置成输入,默认下拉 GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.0 } 按键处理函数 //返回按键值 //mode:0,不支持连续按;1,支持连续按; //返回值: //0,没有任何按键按下 //KEY0_PRES,KEY0 按下 //KEY1_PRES,KEY1 按下 //WKUP_PRES,WK_UP 按下 //注意此函数有响应优先级,KEY0>KEY1>WK_UP!! u8 KEY_Scan(u8 mode) { static u8 key_up=1;//按键按松开标志 if(mode)key_up=1; //支持连按 if(key_up&&(KEY0==0||KEY1==0||WK_UP==1)) { delay_ms(10);//去抖动 key_up=0; if(KEY0==0)return KEY0_PRES; else if(KEY1==0)return KEY1_PRES; else if(WK_UP==1)return WKUP_PRES; } else if(KEY0==1&&KEY1==1&&WK_UP==0)key_up=1; return 0;// 无按键按下 } 扫描优先级:
按键松开标志 key_up 是 static 静态变量:
所以该函数是一个不可重入函数: “在实时系统的设计中,经常会出现多个任务调用同一个函数的情况。如果有一个函数不幸被设计成为这样:那么不同任务调用这个函数时可能修改其他任务调用这个函数的数据,从而导致不可预料的后果。这样的函数是不安全的函数,也叫不可重入函数。” |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1727 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1605 浏览 1 评论
1043 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
720 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1660 浏览 2 评论
1911浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
705浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
554浏览 3评论
581浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
538浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-14 12:42 , Processed in 0.879453 second(s), Total 78, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号