一、嵌入式学习简介

         在计算机学习过程中,每个编程语言的学习,例如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。本文对于传感器的工作原理没有过多讲解,需要多温故而知新。

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐