ARM体系结构及编程 实验一 GPIO接口实验控制led灯

一、实验目的

     1. 深入理解STM32处理器的GPIO接口原理和使用方法;

     2. 掌握GPIO接口寄存器、固件函数及应用编程方法;

     3. 掌握GPIO寄存器编程方法和固件函数应用编程方法。

二、实验内容

      1. 使用寄存器开发模版编写GPIO应用程序,当按键key_up按下时可以实现LED灯D1和D2的交替闪烁,当key_up未按下时灯不闪烁;

      2. 使用库函数开发模版编写GPIO应用程序,当按键key_up按下时可以实现LED灯D1和D2的交替闪烁,当key_up未按下时灯不闪烁。

三、实验设备仪器及材料

      硬件:STM32开发板, PC 机;

      软件:MDK5集成开发环境,Windows 操作系统;

四、实验原理

GPIO工作模式:

1. 输入模式(上拉、下拉、浮空)

    (1)GPIO_Mode_IN_FLOATING:浮空输入模式

      浮空输入模式下,I/O端口的电平信号直接进入输入数据寄存器,I/O的电平状态是不确定的,完全由外部输入决定,如果在该引脚悬空(在无信号输入)的情况下,读取该端口的电平是不确定的。浮空输入一般多用于外部按键输入。

    (2)GPIO_Mode_IPU:上拉输入

      上下拉的电阻阻值都在30-50k之间,上拉就是使I/O接口接上拉电阻到VCC,下拉就是使I/O口接下拉电阻到GND。

      上拉输入模式下,I/O端口的电平信号直接进入输入数据寄存器。但是在I/O端口悬空(在无信号输入)的情况下,输入端的电平可以保持在高电平;并且在I/O端口输入为低电平的时候,输入端的电平也还是低电平。

    (3)GPIO_Mode_IPD:下拉输入

      下拉输入模式下,I/O端口的电平信号直接进入输入数据寄存器。但是在I/O端口悬空(在无信号输入)的情况下,输入端的电平可以保持在低电平;并且在I/O端口输入为高电平的时候,输入端的电平也还是高电平。

2. 输出模式(推挽/开漏、上拉/下拉)

    (1)GPIO_Mode_Out_PP:推挽输出

      推挽结构一般是指两个三极管分别受两个互补信号的控制,总是在一个三极管导通的时候另一个截止。

      这种结构既可以输出高电平,也可以输出低电平,可以用于连接数字器件。

推挽电路是两个参数相同的三极管或MOSFET,以推挽方式存在于电路中,各负责正负半周的波形放大任务,电路工作时,两只对称的功率开关管每次只有一个导通,

      所以推挽电路导通损耗小,效率高。输出既可以向负载灌电流,也可以从负载抽取电流。推拉式输出级既提高电路的负载能力,又提高开关速度。

    (2)GPIO_Mode_Out_OD:开漏输出

      一般来说,开漏是用来连接不同电平的器件,匹配电平用的,因为如果外部不接上拉电阻时,只能输出低电平,所以想要输出高电平必须要外接上拉电阻。很好的一个优点是通过改变上拉电源的电压,便可以改变传输电平,用于不同电压的系统之间的通信。比如加上上拉电阻就可以提供TTL/CMOS电平输出等。(上拉电阻的阻值决定了逻辑电平转换的速度。阻值越大,速度越低功耗越小,所以负载电阻的选择要兼顾功耗和速度。)

      利用外部电路的驱动能力,减小内部电流,当IC内部MOSFET导通时,驱动电流是从外部的VCC流经上拉电阻、MOSFET到GND。内部是需要是很小的栅极驱动电流。

      开漏输出提供了灵活的输出方式,但是也有其弱点,就是带来上升沿的延时,通信的速度也受到上拉电阻阻值的影响。因为上升沿是通过外接上拉无源电阻对负载充电,所以当电阻选择小时延时就小,通信速度可以很快,但功耗大;反之延时大通信速度变慢功耗小。所以如果对延时有要求,则建议用下降沿输出。

      可以将多个开漏输出连接到一条线上。通过一只上拉电阻,在不增加任何器件的情况下,形成“与逻辑”关系,即“线与”。

3. 复用功能(推挽/开漏、上拉/下拉)

   (1)GPIO_Mode_AF_PP:复用推挽输出

   (2)GPIO_Mode_AF_OD:复用开漏输出

      复用模式相当于把GPIO配置为第二功能能使用的时候的配置,并非作为通用I/O口使用。

4. 模拟输入输出(上下拉无影响)

    (1)GPIO_Mode_AIN:模拟输入

      I/O端口的模拟信号(电压信号,而非电平信号)直接模拟输入到片上外设模块,比如ADC模拟输入等。

      GPIO端口置位/复位寄存器(GPIOx_BSRR):

       端口低16位(0-15)为置位位,即端口的某一位(例如BS2)写1,则该一小位(BS2)输出高电平;若该一小位(例如BS2)写0,则该一小位(BS2)输出状态仍为原状态(并不是输出低电平)。

       端口高16位(16-31)为复位位(与低16位置位位状态相反),即端口的某一位(例如BR2)写1,则该一小位(BR2)输出状态仍为原状态(并不是输出高电平);若该一小位(BR2)写0,则该一小位(BS2)输出低电平。

五、实验操作步骤

(一)使用寄存器开发模板编写GPIO应用程序

1. 编写led.c文件

      Led.c文件用于进行LED初始化

void LED_Init()
{
	GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量,该语句的作用是将GPIO_InitTypeDef结构体命名为GPIO_InitStructure
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE); //使能端口F时钟,
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;//设置输出模式
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9|GPIO_Pin_10;//管脚设置为F9和F10
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//IO口速度为100M
	GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上拉
	GPIO_Init(GPIOF,&GPIO_InitStructure); //初始化结构体,初始化PF口
	GPIO_SetBits(GPIOF,GPIO_Pin_9|GPIO_Pin_10);//输出高电平
}
2. 编写key.c文件
void KEY_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE|RCC_AHB1Periph_GPIOA,ENABLE); //使能端口PORTE、PORTA时钟
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN; //设置GPIO工作模式为输入
	GPIO_InitStructure.GPIO_Pin=KEY_LEFT_Pin|KEY_DOWN_Pin|KEY_RIGHT_Pin;//设置管脚
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上拉
	GPIO_Init(KEY_Port,&GPIO_InitStructure); //初始化结构体
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN; //设置GPIO工作模式为输入
	GPIO_InitStructure.GPIO_Pin=KEY_UP_Pin;//设置管脚
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_DOWN;//下拉
	GPIO_Init(KEY_UP_Port,&GPIO_InitStructure); //初始化结构体
}

      KEY_Scan函数用于按键的扫描检测,mode为0时表示不支持连续按键,mode为1时可支持连续按键,按键K_UP是高电频有效,而K_DOWN、K_LEFT、K_RIGHT都是低电频有效,所以当K_UP为1时表示按下K_UP,而其它按键为0表示按下,由此可以完成按键的扫描检测,具体代码如下:

u8 KEY_Scan(u8 mode)
{
	static u8 key=1;
	if(key==1&&(K_UP==1||K_DOWN==0||K_LEFT==0||K_RIGHT==0)) //任意一个按键按下
	{
		delay_ms(10);  //减少抖动
		key=0;
		if(K_UP==1)
		{
			return KEY_UP; 
		}
		else if(K_DOWN==0)
		{
			return KEY_DOWN; 
		}
		else if(K_LEFT==0)
		{
			return KEY_LEFT; 
		}
		else
		{
			return KEY_RIGHT;
		}
	}
	else if(K_UP==0&&K_DOWN==1&&K_LEFT==1&&K_RIGHT==1)    //无按键按下
	{
		key=1;
	}
	if(mode==1) //连续按键按下
	{
		key=1;
	}
	return 0;
}
3. 编写main.c文件

      寄存器开发即直接操作寄存器。

      操作步骤和思路:

    (1)RCC_AHB1ENR |= 1<<5

      开启GPIOF时钟。RCC_AHB1ENR该寄存器的第5位是控制GPIOF外设的时钟使能位,只有该位为1时才使能,如果为0即关闭GPIOF时钟,所以要让1左移5位。

    (2)GPIOF_MODER = (101<<(2*9))

      配置GPIOF为输出模式。让PF9管脚输出一个低电平,所以采用输出模式。该寄存器每2位控制一个管脚,00表示输入(复位);01表示通用输出模式;10表示复用功能模式;11表示模拟模式,所以选择01通用输出模式,让1左移2*9位即可。

    (3)GPIOF_BSRR=(1<<(16+9))

      使PF9输出为低电平,GPIOF_BSRR为置位复位寄存器,其高16位用于复位,如果当高16位某位为1,表示那一位管脚输出为低电平,为0不影响其输出。如果当低16位的某位为1,表示那一位管脚输出为高电平,为0不影响其输出,所以让1左移16+9位。

      具体代码:

#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "key.h"
#include "stm32f4xx2.h"
typedef unsigned int u32; 
void delay(u32 i)
{
	while(i--);
}//延迟函数
int main()
{
	u8 key,i=0;
	SysTick_Init(168);
	//LED_Init();
	BEEP_Init();
	KEY_Init();
	while(1)
	{
		key=KEY_Scan(0);   //扫描按键
		switch(key)
		{
			case KEY_UP: 
			//led1闪烁
			RCC_AHB1ENR |= 1<<5;
	     //初始化pf9和pf10工作模式通用输出模式01
	    GPIOF_MODER = (101<<(2*9));
			while(1){
		    GPIOF_BSRR=(1<<(16+9));//高16位中的第9位置1,高电平
		    delay_ms(500);
	
		    GPIOF_BSRR=(1<<(9));//低16位汇总的第9位置1,高电平
		    delay_ms(500);
		    //led2闪烁
		    GPIOF_BSRR=(1<<(16+10));//高16位中的第10位置1,高电平
		    delay_ms(500);
	
		    GPIOF_BSRR=(1<<(10));//低16位中的第10位置1,高电平,具体参考GPIO端口置位/复位寄存器相关知识
		    delay_ms(500);
			}
}
}
}

(二)使用库函数开发模板编写GPIO应用程序

1. 编写led.c文件
2. 编写key.c文件

      库函数开发模板的led.c文件、key.c文件与寄存器开发模板一致

3. 编写main.c文件
#include "system.h"
#include "SysTick.h"
#include "stm32f4xx.h"
#include "led.h"
#include "key.h"
int main()
{
	u8 key,i=0;
	SysTick_Init(168);
	LED_Init();//调用初始化led函数
	KEY_Init();//调用初始化key函数
	while(1)
	{
		key=KEY_Scan(0);   //扫描按键程序
		switch(key)
		{
			
			case KEY_UP: //当识别到KEY_UP键被按下时,进行led1与led2闪烁
				while(1){
				led1=!led1;//不断改变led1与led2的状态即可实现闪烁
			  delay_ms(500);//设置延迟为0.5秒,否则不容易观察到闪烁现象
			  led2=!led2;
			  delay_ms(500);}
}
	}
}

六、实验结果

      未按下KEY_UP健:

      按下KEY_UP键:

      led1与led2交替闪烁画面:

  • 18
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

布零酱

阿里嘎多!谢谢打赏嗷喵~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值