嵌入式学习STM32—Hello world
本篇主要是实现GPIO的基本功能,以及了解GPIO,并完成嵌入式学习的第一个Hello world。本文对于传感器的工作原理没有过多讲解,需要多温故而知新。
一、嵌入式学习简介
在计算机学习过程中,每个编程语言的学习,例如C,python等编程语言都离不开第一个程序Hello world。在嵌入式学习中,类似于Hello world存在,就是嵌入式点灯的完成。嵌入式学习的第一天,我们会依次完成LED闪烁,LED流水灯,蜂鸣器,按键控制LED,光敏传感器控制蜂鸣器,并介绍相关GPIO接口的相关知识,本次LED闪烁等其他项目的完成都由STM32库函数实现,使用的语言为C语言,使用软件为Keil uVision5,(默认会进行工程模板的创建)我会进行依次讲解,接下让我们开始依次学习。
PS:如果想具体理解代码中的函数逻辑,先看四——GPIO的描述。
二、嵌入式——LED闪烁
首先,使用STM32进行LED闪烁,我们只需要进行三步走战略。
1.使能时钟,函数为RCC_APB2PeriphClockCmd(外设名字,外设的状态)
2.配置端口模式,函数为GPIO_Init(哪个GPIO,参数的结构体)。
参数的结构体为定义为GPIO_InitTypeDef GPIO_InitStructure;结构体含有三个参数分别是GPIO模式,GPIO端口,GPIO速度,结构体创建以及参数设置都是为了完成配置端口模式。
3.设置高低电平,函数为
GPIO_SetBits(GPIO口,GPIO引脚); //高电平(高电平熄灭)
GPIO_ResetBits(GPIO口,GPIO引脚); //低电平(低电平点亮)
函数作用:将指定的端口设为低高或低电平
接下来,我们举个例子,我们将使用STM32单片机的A0端口实现LED灯闪烁。
#include "stm32f10x.h" // Device header
#include "Delay.h" // 延时头文件h
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能时钟
GPIO_InitTypeDef GPIO_InitStructure; //定义结构体
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //GPIO模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIO端口
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //GPIO速度
GPIO_Init(GPIOA,&GPIO_InitStructure); // 配置端口模式
while (1)
{
GPIO_SetBits(GPIOA,GPIO_Pin_0); // 设置低电平
Delay_ms(500);
GPIO_ResetBits(GPIOA,GPIO_Pin_0); // 设置高电平
Delay_ms(500);
}
}
点击编译以及下载到单片机后,我们就可以得到LED闪烁的效果。
三、嵌入式——LED流水灯
在我们实现LED闪烁后,我们可以进一步来实现LED流水灯,具体步骤与LED闪烁大致相同。首先我们需要确定LED分别在哪些GPIO端口,例如A0~A6。接下来步骤为:
1.使能时钟,函数为RCC_APB2PeriphClockCmd(外设名字,外设的状态)
2.配置端口模式,函数为GPIO_Init(哪个GPIO,参数的结构体)。
参数的结构体为定义为GPIO_InitTypeDef GPIO_InitStructure;结构体含有三个参数分别是GPIO模式,GPIO端口,GPIO速度,结构体创建以及参数设置都是为了完成配置端口模式。
3.对7个口进行依次进行写入操作
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能时钟
GPIO_InitTypeDef GPIO_InitStructure; //定义结构体
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //GPIO模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All; //GPIO端口(这里从0~6写起来很麻烦为此选择所有端口)
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //GPIO速度
GPIO_Init(GPIOA,&GPIO_InitStructure); // 配置端口模式
while (1)
{
GPIO_Write(GPIOA, ~0x0001); // 将A0端口点亮
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0002); // 将A1端口点亮,同时A0端口熄灭
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0004);
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0008);
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0010);
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0020);
Delay_ms(500);
GPIO_Write(GPIOA, ~0x0040);
Delay_ms(500);
}
}
三、蜂鸣器
蜂鸣器实现与LED闪烁类似。(使用GPIOB的PIN12引脚)
1.使能时钟,函数为RCC_APB2PeriphClockCmd(外设名字,外设的状态)
2.配置端口模式,函数为GPIO_Init(哪个GPIO,参数的结构体)。
参数的结构体为定义为GPIO_InitTypeDef GPIO_InitStructure;结构体含有三个参数分别是GPIO模式,GPIO端口,GPIO速度,结构体创建以及参数设置都是为了完成配置端口模式。
3.设置高低电平,函数为
GPIO_SetBits(GPIO口,GPIO引脚); //高电平(默认高电平熄灭)
GPIO_ResetBits(GPIO口,GPIO引脚); //低电平(默认低电平点亮)
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
while (1)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_12);
Delay_ms(100);
GPIO_SetBits(GPIOB,GPIO_Pin_12);
Delay_ms(100);
GPIO_ResetBits(GPIOB,GPIO_Pin_12);
Delay_ms(100);
GPIO_SetBits(GPIOB,GPIO_Pin_12);
Delay_ms(700);
}
}
四、GPIO(通用输入输出口)
在STM32中,所有的GPIO都是挂载在APB2外设总线上,GPIO 的核心作用是通过软件控制硬件引脚的状态。
GPIO有八种输入输出模式。分别是四种输入模式,四种输出模式如图所示。这八种模式对应的代码中的GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;(相应的模式)

接下来,我们进行依次讲解,在讲解之前我们需要了解GPIO的位结构如图所示

1.浮空输入(GPIO_Mode_IN_FLOATING)
我们观看GPIO位结构图,将图片分为上下两部分,上部分为输入,下部分为输出。
浮空输入就是将图片上部分的VDD与VSS的上拉开关与下拉开关打开。
2.上拉输入(GPIO_Mode_IPU )
上拉输入就是将图片上部分的VDD上拉开关关闭。悬空默认为高电平。
3.下拉输入(GPIO_Mode_IPD)
下拉输入就是将图片上部分的VSS下拉开关关闭。悬空默认为低电平。
4.模拟输入(GPIO_Mode_AIN)
GPIO无效
5.开漏输出(GPIO_Mode_Out_OD)
开漏输出就是将图片下部分的VSS接通。
6.推挽输出(GPIO_Mode_Out_PP)
推挽输出就是将图片下部分的VDD与VSS都接通。
7.复用开漏输出(GPIO_Mode_AF_OD)
8.复用推挽输出(GPIO_Mode_AF_PP)
9.GPIO相应的函数讲解
GPIO库函数
void GPIO_DeInit(GPIO_TypeDef* GPIOx);
参数:GPIOA,GPIOB...
作用:所指定的GPIO外设复位
void GPIO_AFIODeInit(void);
作用:所指定的GPIO_AFIO外设复位
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
作用:用结构体的参数初始化GPIO口
步骤:1.先定义结构体变量2.对结构体赋值3.调用该函数
void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct);
作用:将结构体变量赋一个默认值
GPIO的读取函数
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
第一个参数:GPIOx 第二个参数:GPIO_Pin
作用:读取输入数据寄存器某一个端口的值
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
第一个参数:GPIOx
作用:读取整个输入数据寄存器
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
第一个参数:GPIOx 第二个参数:GPIO_Pin
作用:读取输出数据寄存器的某一个位
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
第一个参数:GPIOx
作用:读取整个输出数据寄存器
作用:GPIO的读取函数
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
第一个参数:GPIOx 第二个参数:GPIO_Pin
作用:将指定的端口设为高电平
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
第一个参数:GPIOx 第二个参数:GPIO_Pin
作用:将指定的端口设为低电平
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
第一个参数:GPIOx 第二个参数:GPIO_Pin 第三个参数:Bit_RESET(低电平)Bit_SET(高电平)
作用:根据第三个参数的值来设置指定端口
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
第一个参数:GPIOx 第二个参数:0x0001
作用:同时对十六个端口进行写入操作
作用:GPIO的写入函数
五、按键控制LED
按键控制LED,这里我们需要考虑模块化编程的方法,也就是说,我们将LED初始化以及点亮与关闭封装为三个函数,将按键的初始化以及按键的键码获取封装为两个函数,然后在主函数调用相应的函数。
LED.c模块
#include "stm32f10x.h" // Device header
void LED_Init(void) //初始化LED
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_1 | GPIO_Pin_2);
}
void LED1_ON(void) //打开LED1
{
GPIO_ResetBits(GPIOA,GPIO_Pin_1);
}
void LED1_OFF(void) //关闭LED1
{
GPIO_SetBits(GPIOA,GPIO_Pin_1);
}
void LED1_Turn(void) //将LED1进行电平转换
{
if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_1) == 0)
{
GPIO_SetBits(GPIOA,GPIO_Pin_1);
}
else
{
GPIO_ResetBits(GPIOA,GPIO_Pin_1);
}
}
void LED2_ON(void) //打开LED2
{
GPIO_ResetBits(GPIOA,GPIO_Pin_2);
}
void LED2_OFF(void) //关闭LED2
{
GPIO_SetBits(GPIOA,GPIO_Pin_2);
}
void LED2_Turn(void) //将LED2进行电平转换
{
if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_2) == 0)
{
GPIO_SetBits(GPIOA,GPIO_Pin_2);
}
else
{
GPIO_ResetBits(GPIOA,GPIO_Pin_2);
}
}
Key.c模块
#include "stm32f10x.h" // Device header
#include "Delay.h"
void Key_Init(void) // 按键初始化函数
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
uint8_t Key_GetNum(void) //返回按键的键码
{
uint8_t KeyNum = 0;
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0)
{
Delay_ms(20);
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0);
Delay_ms(20);
KeyNum = 1;
}
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == 0)
{
Delay_ms(20);
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == 0);
Delay_ms(20);
KeyNum = 2;
}
return KeyNum;
}
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"
uint8_t KeyNum;
int main(void)
{
LED_Init();
Key_Init();
while (1)
{
KeyNum = Key_GetNum();
if(KeyNum==1)
{
LED1_Turn();
}
if(KeyNum==2)
{
LED2_Turn();
}
}
}
运行main.c,下载完成后按下按键1,LED1点亮再次按下,LED1熄灭,也可以修改main.c中的代码实现按下按键1,LED1点亮,按下按键2,LED2点亮,LED1熄灭。
六、光敏传感器控制蜂鸣器
光敏传感器控制蜂鸣器与按键控制LED类似,蜂鸣器模块,光敏传感器模块,main
蜂鸣器模块(Buzzer.c)
#include "stm32f10x.h" // Device header
void Buzzer_Init(void) //初始化蜂鸣器
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_12 );
}
void Buzzer_ON(void) //蜂鸣器打开
{
GPIO_ResetBits(GPIOB,GPIO_Pin_12);
}
void Buzzer_OFF(void) //蜂鸣器关闭
{
GPIO_SetBits(GPIOB,GPIO_Pin_12);
}
void Buzzer_Turn(void) //转换蜂鸣器电平
{
if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_12) == 0)
{
GPIO_SetBits(GPIOB,GPIO_Pin_12);
}
else
{
GPIO_ResetBits(GPIOB,GPIO_Pin_12);
}
}
光敏电阻模块(LightSensor.c)
#include "stm32f10x.h" // Device header
#include "Delay.h"
void LightSensor_Init(void) // 按键初始化函数
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
uint8_t LighhtSensor_Get(void) //返回按键的键码
{
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);
}
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "Buzzer.h"
#include "LightSensor.h"
int main(void)
{
Buzzer_Init();
LightSensor_Init();
while (1)
{
if (LighhtSensor_Get() == 1)
{
Buzzer_ON();
}
else
{
Buzzer_OFF();
}
}
}
编译下载后,当遮挡光敏传感器,蜂鸣器响起,取消遮挡,蜂鸣器关闭。
七、结语
本篇主要是实现GPIO的基本功能,以及了解GPIO,并完成嵌入式学习的第一个Hello world。本文对于传感器的工作原理没有过多讲解,需要多温故而知新。
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐
所有评论(0)