这节主要是GPIO的应用 包括点亮led灯和数码管使用。使用CubeMax进行配置使用keil5编写代码。
应用效果演示 链接
GPIO介绍
General Purpose Input Output (通用输入/输出)简称为GPIO
许多设备或电路只要求有开/关两种状态就够了,比如LED的亮与灭。对这些设备的控制,在嵌入式微处理器上通常提供了一种“通用可编程I/O端口”,也就是GPIO。
对GPIO的配置一般有
① 浮空输入_IN_FLOATING
② 带上拉输入_IPU
③ 带下拉输入_IPD
④ 模拟输入_AIN
⑤ 开漏输出_OUT_OD
⑥ 推挽输出_OUT_PP
⑦ 复用功能的推挽输出_AF_PP
⑧ 复用功能的开漏输出_AF_OD
通常有5种方式使用某个引脚功能,它们的配置方式如下:
1、作为普通GPIO输入:根据需要配置该引脚为浮空输入、带弱上拉输入或带弱下拉输入,同时不要使能该引脚对应的所有复用功能模块。
2、作为普通模拟输入:配置该引脚为模拟输入模式,同时不要使能该引脚对应的所有复用功能模块。
3、作为内置外设的输入:根据需要配置该引脚为浮空输入、带弱上拉输入或带弱下拉输入,同时使能该引脚对应的某个复用功能模块。
4、作为普通GPIO输出:根据需要配置该引脚为推挽输出或开漏输出,同时不要使能该引脚对应的所有复用功能模块。
5、作为内置外设的输出:根据需要配置该引脚为复用推挽输出或复用开漏输出,同时使能该引脚对应的所有复用功能模块。
如果有多个复用功能模块对应同一个引脚,只能使能其中之一,其它模块保持非使能状态。
GPIO使用的一些函数
重要函数:
1个初始化函数:
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);
1个读取输入电平函数:
GPIO_PinStateHAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);
1个设置输出电平函数:
void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin, GPIO_PinStatePinState);
1个电平翻转函数:
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);
1个引脚电平锁定函数:
HAL_StatusTypeDefHAL_GPIO_LockPin(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);
点亮led灯
led灯的原理很简单,通电有电流通过就有亮,没有电流就不亮。
-
首先 查看板子的原理图,看led灯所在GPIO口对应的管脚
我所使用的板子 led部分对应管脚 C1 C2 C3 A0 A1 A2 A3 A4
-
打开cubemx 选择板子对应的芯片 对相应管脚进行配置
这里写一个三个led灯点亮的项目 使用A0 A1 A2 三个管脚
选择要控制的管脚 左键点击 选择GPIO_Output 输出功能
选择之后会变那个管脚颜色会变化
可以选择配置时钟或者跳过 (下一篇文章写配置时钟过程)
- 配置工程
添加工程名字 位置 以及 使用的IDE
然后点击 GENRATE CODE 合成代码
4.使用keil5 打开代码
(打开代码第一节中写过)
打开main.c 找到主函数
一般添加的代码都在while循环中执行
可以添加
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,0);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,0);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,0);
HAL_Delay(500);
(不用写这些代码 生成hex文件 并传入板子 也会亮 ,因为默认cubemx设置的低电平而led是低电平有效)
使用writepin函数给三个引脚低电平 ,0就是低电平 1是高电平 然后HAL_Delay延时函数里面参数单位为ms。
低电平有效是共阳极,意思就是阳极电平一直不变时高电平,加上低电平的话就有了电势差就有电流通过。而加上高电平的话,没有电势差也就没有了电流。
同理高电平有效就是共阴极。阴极电平一直不变是低电平。
MX_GPIO_Init函数 里面是GPIO的初始化
(该图片不是该项目截图)
5 编译程序 烧写程序
将程序写好进行编译 编译通过就会生成一个hex文件,将该文件找到并使用烧写工具 写入板子。
(第一节有详细过程)
然后就会看到 三个led灯变亮
使用数码管
让数码管显示数字,并能够从0到9999依次递增
原理
数码管的原理跟led很类似。可以理解为很多的小的led灯
常见有一位数码管和四位数码管
先来看一位数码管接线图
a-g dp 八个引脚分别控制着相应的码段,如果是共阴极 给g高电平其余低电平 那就是只有一道横线,如果给g低电平其余高电平,那呈现的就是0 加上右下角的点。
四位数码管跟一位的类型,不过接线复杂了点,理解起来还是简单的
a-g dp控制的依旧是跟单个数码管一样
但是 A1 A2 A3 A4 控制的分别是 四个数码管
如果是共阴极 高电平有效。给A1 g高电平,其余低电平 那样显示的就是第一个数码管的一道横线亮。
如果给A1 g低电平 其余高电平,那显示的就是第一个数码管暗,其余三个数码管都显示0和点
动态显示
我们平常用到的数码管几乎都是动态显示。意思就是一次显示一个循环显示,只要相差时间不是很大,人眼就分辨不出来是循环显示的。人大脑有视觉暂留功能,所以有这种现象。同样动态显示能够节省内存,耗电等。(显示屏也是动态显示的)所以程序设计的时候要参考这个。
看原理图
打开该板子对应的原理图
可以看到控制四个数码管分别是 D2 B4 B6 B7
a-f 以及dp 为 C6 C8 —A15 (图上左边一排)
配置cubemx
把使用到的引脚 共12个 都初始化为GPIO_OUTPUT
这样就配置完成了
然后可以配置项目名称,位置,IDE,合成代码
编写代码
如果直接编译,烧写hex文件,显示的是四个数码管全亮
我们还需要根据我们的需求更改代码。
- 编写GPIO口对应的数组 ,便于调用
struct GPIO_PACK{
GPIO_TypeDef * port;
uint16_t pin;
};
struct GPIO_PACK segs[8]= {
{GPIOA,GPIO_PIN_15},
{GPIOA,GPIO_PIN_11},
{GPIOC,GPIO_PIN_9},
{GPIOC,GPIO_PIN_7},
{GPIOC,GPIO_PIN_8},
{GPIOA,GPIO_PIN_12},
{GPIOA,GPIO_PIN_8},
{GPIOC,GPIO_PIN_6},
} ;
struct GPIO_PACK bits[4]={
{GPIOD,GPIO_PIN_2},
{GPIOB,GPIO_PIN_4},
{GPIOB,GPIO_PIN_6},
{GPIOB,GPIO_PIN_7},
};
- 编写段码
段码指的是 讲单个数码管上dp a-g 高低电平用1和0代替,按照dp g f e d c b a组成的一串二进制数值,再转换为十六进制
比如 十六进制值 c0就是 1100 0000 代表的是dp 和g 高电平 灭 其他亮 形成的是数字0
同理 0-9 分别是 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e
写入数组
uint8_t shuzu[]={
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,
0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e
};
3.将段码转换为实际的对引脚控制
下面的这个函数实现的是 让特定一个数码管显示特定的值
void DisplayOnebit(uint8_t digtal,uint8_t bit){
uint8_t i;
for(i=0;i<8;i++){
HAL_GPIO_WritePin(segs[i].port,segs[i].pin,(GPIO_PinState)(shuzu[digtal]&(0x01<<i)));
}
for(i=0;i<4;i++){
HAL_GPIO_WritePin(bits[i].port,bits[i].pin,(GPIO_PinState)(i!=bit));
}
}
使用writePin函数能够给GPIO脚高低电位,使用了移位的方式来解析段码。
传入的参数 digtal 是要显示的数字 。bit 是要显示的是第几位数码管
调用 DisplayOnebit(9,1);
结果就会是 第二位数码管显示数字9 其他数码管暗 。
控制多个数码管显示多位数
void DisplayDigtal(uint16_t digtal){
int a=0;
while(a<50)
{
a++;
DisplayOnebit(digtal%10,0);
HAL_Delay(5);
if (digtal>=10){
DisplayOnebit(digtal/10%10,1);
HAL_Delay(5);
if (digtal>=100){
DisplayOnebit(digtal/100%10,2);
HAL_Delay(5);
if (digtal>=1000){
DisplayOnebit(digtal/1000%10,3);
HAL_Delay(5);
}
}
}
}
}
传入一个值 就会直接显示 输入的值 里面调用的是DisplayOnbit 函数 只不过是分配了一个每个数码管应该显示的值 并加了延时。
调用 DisplayDigtal(999);
结果会有三个数码管显示9 另一个数码管是暗的
4.控制数码管显示
前面上一步操作可以理解成前期准备条件。是放到主函数外面的,方便调用。
真正根据应用场景需求编写的代码 是在这里的。
在main函数中
while循环里 添加以下代码
DisplayDigtal(displya_data++);
if(displya_data>9999)
displya_data=0;
这里需要注意 需要前面对display_data 这个变量进行声明
uint16_t displya_data=0;
上面代码很简单就是变量从0一直增加并依次显示,当变量达到9999时需要重新赋值为0.
然后编译 运行,烧写程序就可以了。
效果
完整工程链接。GitHub
更多STM32学习教程
- STM32 cubemx keil5搭建学习环境
- 使用STM32 cubemx keil5实现led灯与数码管控制
- 基于STM32 CubeMx keil5实现键盘的应用
- 基于STM32 CubeMx keil5实现串口通信 I2C与GPIO综合应用
- 基于STM32 CubeMx keil5实现AD转换获取温度
- 基于STM32 CubeMx keil5 学习使用I2C
- 基于STM32 CubeMx keil5 学习使用串口通信
- 基于STM32 CubeMx keil5应用定时器
- 基于STM32 cubemx keil5学习使用中断
- 基于STM32 cubemx keil5综合应用实现温度控制系统