GPIO
灯如何才能亮
原理图
二极管
二极管就是由一个PN结加上相应的电极引线及管壳封装而成的
特点:正向导通,反向截止
记忆:将此符号看作一个箭头,顺着箭头的方向,电压降低才导通(压差最小为0.7v),否则相当于电阻无穷大。
有一种二极管在其导通时可以发光,这种二极管叫做发光二极管(Light Emitting Diode)
我们常说的LED,就是二极管。
换了一个灯和原理图
三极管
三极管有两种类型,PNP和NPN型。
NPN型三极管
基极高电平导通
PNP型三极管
基极低电平导通
D1灯亮,需要二极管左端为低电平
三极管导通,GND和D1左端导通,即D1左端拿到低电平,灯亮。
此三极管为NPN型三极管,当PC13为高电平时,三极管导通。
即PC13输出高电平,D1灯亮。
不难看出,此处三极管相当于一个简易的开关。
基本概念
GPIO(General-purpose input/output)通用输入输出接口
--GP 通用
--I input 输入
--O output输出
GPIO,General Purpose Input Output,指的是芯片的通用输入输出引脚。
通过配置对应引脚的输出模式,我们可以进行LED灯的点亮,继电器的开闭控制;
在输入模式下,读取按键开关的状态,模拟输入状态下,我们可以读取温湿度传感器的数据。
除了以上使用情况,也可以作为I2C,SPI,串口的引脚等。
问:VDD、VSS、VCC分别表示什么意思?
VCC:C=circuit,表示电路的意思,即接入电路的电压。
VDD:D=device,表示器件的意思,即器件内部的工作电压。
VSS:S=series,表示公共连接的意思,通常指电路公共接地端电压。
VCC :接入电路的电压 外部参考高电平3.3,
VDD : 元器件内部的工作电压,内部参考高电压,stm32中为3.3v
VSS : 公共接地端电压,内部参考地,stm32中为0v
施密特触发器:整形
输入
浮空输入
上下拉都关闭
好处:其电平完全由外部决定
不好:当引脚没有外接电路的时候,其电平信号是不确定的,不确定的信号会影响程序的正常判断
上拉输入
打开上拉,关闭下拉
好处:提供了一个默认电平,当外部电路不确定的时候,提供了一个默认的高电平。
当外部输入低电平时,输入的还是低电平
当外部输入高电平时,输入的是高电平
下拉输入
打开下拉,关闭上拉
好处:提供了一个默认电平,当外部电路不确定的时候,提供了一个默认的低电平。
当外部输入低电平时,输入的还是低电平
当外部输入高电平时,输入的是高电平
模拟输入
输出
推挽输出
P-MOS、N-MOS都能用
输出高电平
在输出数据寄存器对应引脚位置写1--->数据选择器选择上路--->输出控制器给P-MOS和N-MOS都输出高电平--->P-MOS导通,N-MOS截止--->高电平由Vdd提供
输出低电平
在输出数据寄存器对应引脚位置写0--->数据选择器选择上路--->输出控制器给P-MOS和N-MOS都输出低电平--->N-MOS导通,P-MOS截止--->低电平由Vss提供
开漏输出
P-MOS关闭
输出低电平
在输出数据寄存器对应引脚位置写0--->数据选择器选择上路--->输出控制器给P-MOS和N-MOS都输出低电平--->N-MOS导通,P-MOS截止--->低电平由Vss提供
本身无法输出高电平
在输出数据寄存器对应引脚位置写1--->数据选择器选择上路--->输出控制器给P-MOS和N-MOS都输出高电平--->P-MOS关闭,N-MOS关闭--->电路处于高阻态
由上可得:开漏本身无法输出高电平
如何让开漏输出高电平?
- 打开内部上拉电阻
2.外接上拉电阻
好处:提供的电压由用户决定,想提供高电压,把外界上拉电阻的电压源提高即可。
相关寄存器
寄存器定义与作用
为什么要学习寄存器,寄存器的作用是什么?
答:
控制某一引脚输出电压来点灯所需要控制的寄存器
- 时钟开关,总开关
- 端口模式寄存器--输出模式
- 输出类型寄存器--推挽
- 输出速度寄存器--非常慢
- 上下拉寄存器 --既不上拉也不下拉
- 输出数据寄存器 --1
配置时钟使能寄存器
思路:
我们的目的是使用PC13,所以要先打开C引脚组时钟。
通过寻找内存架构找到了RCC相关的寄存器组,RCC寄存器组里的寄存器太多了。
找到控制引脚组的RCC寄存器需要找到GPIO属于哪个总线上的(AHB1\APB1\APB2\PHB2等),通过查内存分配架构图可知,GPIO在AHB2总线上,所以,我们定位到了RCC_AHB2ENR1
RCC AHB2 peripheral clock enable register 1 (RCC_AHB2ENR1)
打开C组,就可以使用PC13
RCC_AHB2ENR1第2位写1
GPIO配置寄存器
端口模式寄存器
GPIO port mode register (GPIOx_MODER) (x = A to J)
PC13为输出模式
GPIOC_MODER第27、26位写0,1
输出类型寄存器
GPIO port output type register (GPIOx_OTYPER) (x = A to J)
PC13推挽模式
GPIOC_OTYPER 第13位写0
输出速度寄存器
GPIO port output speed register (GPIOx_OSPEEDR) (x = A to J)
PC13低速输出
GPIOC_OSPEEDR 第27、26位写 0 0
上下拉寄存器
GPIO port pull-up/pull-down register (GPIOx_PUPDR) (x = A to J)
PC13都不拉
GPIOC_PUPDR 第27、26位写 0 0
输入数据寄存器
GPIO port input data register (GPIOx_IDR) (x = A to J)
输出数据寄存器
GPIO port output data register (GPIOx_ODR) (x = A to J)
PC13输出高电平
让GPIOC_ODR第13位写1
让PC13引脚输出高电平
- 打开时钟:RCC_AHB2ENR1 给第2位写1
- 配置端口模式寄存器 配置为输出模式 GPIOC_MODER 第27、26位写 0 1
- 配置输出类型寄存器 配置为推挽输出 GPIOC_OTYPER 第13位写0
- 配置输出速度数据寄存器 配置为很低 GPIOC_OSPEEDR 第 27、26位写 0 0
- 配置上下拉寄存器 配置为既不用上拉也不下拉 GPIOC_PUPDR 第27、26位写0 0
- 配置输出数据寄存器 给PC13引脚写1 GPIOC_ODR 第13位写1
寻找寄存器地址--定位
0x56020C00是RCC寄存器组的基地址
偏移地址,相对于基地址--RCC寄存器组的起始地址
RCC_AHB2ENR1地址为:0x56020C00+0x08C=0X56020C8C
GPIOC寄存器组的基地址为0x5202 0800
GPIOC_MODER : 0x5202 0800+0X00=0x5202 0800
GPIOC_OTYPER : 0x5202 0800+0X04=0x5202 0804
GPIOC_OSPEEDR : 0x5202 0800+0X08=0x5202 0808
GPIOC_PUPDR :0x5202 0800+0X0C=0x5202 080C
GPIOc_ODR :0x5202 0800+0X14=0x5202 0814
开始点灯
C语言点灯
void SystemInit(void)
{
*(unsigned int*) 0xE000ED88|=((3UL << 20U)|(3UL << 22U));
}
int main(void)
{
}
记得使用微型C库,不勾的话可能会影响效果
如果报了两个未知错误,可尝试调整优化
烧录前一定将烧写器调成STLINK
位操作
精准置1
x|1=1;
x|0=x;
故将不希望改变的位和0相或,将希望置1的位和1相或即可。
使第26位置1,可通过让整个寄存器和1<<26相或再赋值得到,寄存器 |= (1<<26);
精准置0
x&1=x;
x&0=0;
故将不希望改变的位和1相与,将希望置0的位和0相与即可。
上图可知,使第27位置0,可通过让整个寄存器和蓝色框中的数进行与运算并赋值得到,但这个数并不好得出,我们可以曲线救国,先1<<27位,再进行取反得到该数
即寄存器 &= ~(1<<27)
void SystemInit(void)
{
*(unsigned int*) 0xE000ED88|=((3UL << 20U)|(3UL << 22U));
}
int main(void)
{
//RCC_AHB2ENR1地址为:0x56020C00+0x08C=0X56020C8C
//GPIOC_MODER : 0x5202 0800+0X00=0x5202 0800
//GPIOC_OTYPER : 0x5202 0800+0X04=0x5202 0804
//GPIOC_OSPEEDR : 0x5202 0800+0X08=0x5202 0808
//GPIOC_PUPDR :0x5202 0800+0X0C=0x5202 080C
//GPIOc_ODR :0x5202 0800+0X14=0x5202 0814
*(unsigned int *)0X56020C8C |= (1<<2);
*(unsigned int *)0x52020800 |= (1<<26);
*(unsigned int *)0x52020800 &= ~(1<<27);
*(unsigned int *)0x52020804 &= ~(1<<13);
*(unsigned int *)0x52020808 &= ~(3<<26);
*(unsigned int *)0x5202080C &= ~(3<<26);
*(unsigned int *)0x52020814 |= (1<<13);
while(1);
}
void SystemInit(void)
{
*(unsigned int*) 0xE000ED88|=((3UL << 20U)|(3UL << 22U));
}
void delay(int T);
typedef struct{
unsigned int MODER;
unsigned int OTYPER;
unsigned int SPEED;
unsigned int PUPDR;
unsigned int IDR;
unsigned int ODR;
}GPIO;
#define GPIOC (*(GPIO *)0x52020800)
#define RCC_AHB2ENR1 *(unsigned int *)0x56020C8C
int main(void)
{
RCC_AHB2ENR1 |= 1<<2;//配置RCC_AHB2ENR1的第2位置1,打开时钟
GPIOC.MODER |= 1<<26;//GPIOC_MODER 的第26位置1,配置输出
GPIOC.MODER &= ~(1<<27);//GPIOC_MODER 的第27位置0,配置输出
GPIOC.OTYPER &= ~(1<<13);//GPIOC_OTYPER 的第13位置0,配置推挽
GPIOC.SPEED &= ~(3<<26);//GPIOC_OSPPEDR 第27、26位置0
GPIOC.PUPDR &= ~(3<<26);//GPIOC_PUPDR 第27、26位置0
GPIOC.ODR |= 1<<13;//GPIOC_ODR 第13位置1
while(1)
{
GPIOC.ODR |= 1<<13;//GPIOC_ODR 第13位置1
delay(1000);
GPIOC.ODR &= ~(1<<13);//GPIOC_ODR 第13位置0
delay(1000);
}
}
void delay(int T)
{
int a,b;
for(a=0;a<T;a++)
for(b=0;b<100;b++);
}
库函数点灯
新建项目
引脚配置
打开烧录口
生成项目
代码分析
双击main.c文件,找到,我们可以查看MX_GPIO_Init();的内容以了解CubeMX帮我们生成了的初始化内容,选中MX_GPIO_Init();后按下F12或鼠标右键,选择Go To Definition of...。
库函数分析
void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
功能: 设置或清除指定的端口位
参数:GPIO_TypeDef *GPIOx 端口号
uint16_t GPIO_Pin 引脚号
GPIO_PinState PinState 电平状态
GPIO_PIN_SET 1
GPIO_PIN_RESET 0
返回值:无
void HAL_GPIO_TogglePin (GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin)
功能: 切换指定的引脚电平状态
参数:GPIO_TypeDef * GPIOx 端口号
uint16_t GPIO_Pin 引脚号
返回值:无
GPIO_PinState HAL_GPIO_ReadPin (GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin)
功能: 读取指定的引脚电平状态
参数:GPIO_TypeDef * GPIOx 端口号
uint16_t GPIO_Pin 引脚号
返回值:GPIO_PinState 电平状态
GPIO_PIN_RESET 0
GPIO_PIN_SET 1
HAL_Delay()单位毫秒
点灯
闪灯实验
底板与拓展板
底板
STM32 开发板底板,支持 5V 电源适配器与 TypeC 供电。
提供 RTC 时钟电源,提供三轴加速度与角速度传感器,用于姿态感知。
板载 ESP-12F 无线模组,用于物联网云平台项目开发。
提供 1 路五向按键,采用中断与 A/D 模式采样。
提供 1 路有源蜂鸣器,1 路 2*17P 扩展接口,用于资源扩展板的接入。
核心板接口通过 2.54mm 间距的插针引出,方便用户外接其它设备
显示屏与资源拓展板
显示屏
电容触摸显示屏在很多智能设备上得到应用,提升了设备的交互感。
在开发板套件中使用方型显示屏用来模拟圆形的一个手表项目。显示屏尺寸为 2.8寸,分辨率 320*240(RGB)。
驱动 IC采用 ILI9341,自带 172,800 字节的 GRAM 存储。电容触摸屏采用 I2C 接口,驱动 IC 采用 FT6336G。
资源拓展板
资源扩展板提供基于 I2C 总线的温湿度传感器、环境光感知、心率/脉搏测量。基于模数转换接口的电压/电流采集。
基于 EXTI 事件/中断控制类型的人体红外、光电开关、火焰感知传感器。
基于 SPI 总线的数码管驱动电路。
基于 PWM 控制的风扇、蜂鸣器、震动马达。
基于 GPIO 的按键、LED 指示灯。
基于异步串行通信的 485 总线电平转换。基于控制器局域网总线的 CAN 电平转换等外设。
资源扩展板主要用于微控制器入门外设的使用,硬件图纸原理以及项目案例的应用开发学习。
原理图
LD1这个灯连到了哪个引脚?
- 先找到想要点的灯是谁,确定丝印为LD1
2.打开拓展原理图,根据丝印LD1找到等的所在处,LED1线控制着LD1灯的亮灭
LED1为高电平灯亮,反之,灯灭
LED1肯定连到了芯片引脚上,顺线继续找LED1
3.LED1想要连到芯片引脚,必走如图所在处,其丝印为J1(空间有限,板子上并未标注)
4.打开拓展板原理图J1所在处,能够找到老熟人,LED1,其位于J1的4号口
5.拓展板通过J1连到了底板的J6口
6.打开底板原理图找J6的4号口,就找到了LED1的连接处
7.底板通过地板上的槽J1和J2连到了核心板,所以,LED1想连到芯片上肯定会走这个槽,所以去底板上找这个槽有没有叫LED1的,槽是J1和J2
8.在J2的15号口又看到了老熟人LED1,为了方便,这里直接标注上了最后连到核心板的PC14上了
底板的J2口,连到了核心板的J3口,可知15号口确实连到了芯片PC4引脚
结论:PC4最终连到了LED1,所以,控制PC4的电平高低就可以实现对灯的控制了,至此,此次原理图线路追踪结束,并得出结论
PC4高电平LD1灯亮,反之灯灭
作业:
驱动风扇、蜂鸣器、马达隔一段时间切换一次状态
将演示视频发群里
依次方法可知:风扇连到了PC6引脚,高电平驱动
马达连到了PC7引脚,高电平驱动
底板蜂鸣器连到了PA15引脚,高电平驱动
- 按键
当按键未按下,PC9为高电平
当按键被按下,PC9为低电平
所以,检测PC9是否为低电平就可以直到PC9是否按下了
按键消抖
抖动原因:
任何的机械按键都会有抖动,而且人手按下抬起并不是一瞬间的,人抬手是需要反应时间的,所以会导致按下的低电平时间过长,导致多次误进if判断语句,所以会多次切换状态,导致误判。
延时消抖
此处建议观看录课中的延时消抖讲解
抬手检测
检测到抬手动作后再进行灯的电平翻转
光电开关(任务分析)
原理
遮挡-->PE15输出高电平--->PB2输入高电平
无遮挡-->PE15输出低电平--->PB2输入低电平
光电开关控制风扇
num测试
使用调试查看变量内容
最终实现代码