嵌入式系统原理与应用实验报告-GPIO实验
文章目录
一、实验目的
1.1 基于GPIO的LED跑马灯实验
- 熟悉MDK-ARM基础开发环境
- 掌握工程模板的使用
- 掌握GPIO输出的方法,包括汇编、寄存器操作和基于固件库的GPIO输出操作方法
- 熟悉在本嵌入式实验开发平台上运行一个无操作系统环境下程序设计的方法
1.2 基于GPIO的简单人机交互接口实验
- 掌握GPIO初试化操作
- 掌握GPIO输入输出功能和基于寄存器和固件库的GPIO输入输出方法
- 练习添加代码,能够灵活应用GPIO端口进行输入/输出操作
1.3 基于GPIO的直流电机控制实验
- 掌握GPIO初试化操作
- 掌握GPIO输入输出功能和基于寄存器和固件库的GPIO输入输出方法
- 掌握直流电机控制方式
二、实验原理(硬件连接及软件流程、简单原理说明)
2.1 实验设备
- 硬件:PC一台、WEEEDK嵌入式实验开发平台一套
- 软件:操作系统Windows、MDK-ARM 集成开发环境
2.2 实验硬件连接图
![image-20220511132002860](https://i-blog.csdnimg.cn/blog_migrate/2066d4e37151b7e4735b08882c30e238.png)
2.3 实验简单原理
STM32F10x微控制器具有7个GPIO端口,分别为GPIOA、GPIOB、GPIOC、GPIOD、GPIOE、GPIOF、GPIOG,每个GPIO端口有16个I/O引脚,可配置为输入或输出,输入缓冲,输出锁存。配置寄存器GPIO_CRL和GPIO_CRH可以分别对0-7和8-15引脚进行配置,主要包括通过MODE配置为输入还是输出,通过CNF结合MODE可配置为采用输入哪种方式,输出采用哪种方式。
三、实验内容与实验步骤
3.1 基于GPIO的LED跑马灯实验
3.1.1 实验内容
- 让LED1、LED2、LED3、LED4轮流闪光(跑马灯)
- 在步骤(1)完成后,跑马灯行列加入LED5,让ED1、LED2、LED3、LED4、LED5轮流闪光
3.1.2 实验步骤
(1) 连接+5V电源到开发板,并打开电源开关,将ST-LINK 仿真器连接到WEEEDK嵌入式系统实验开发板的 JTAG插座上,USB 插头连接到PC的USB插口。如果没有驱动请安装ST-LNK 驱动,直到在设备管理器上看到STMicroelectronics STLink dongle为止。
(2) 复制"GPIO-LED跑马灯"文件夹中的所有内容到D盘,双击 GPIO-LED跑马灯实验的\Project\Project.uvprojx 实验工程文件,打开实验工程,阅读 main()函数。
(3) 按F7 功能键编译并链接工程。
(4) 按Ctrl+F5键或单击调试按钮,进入集成调试环境。
(5) 练习使用F10功能键单步执行、Crl+F10键执行到光标处以及F5功能键全速执行等断方式,在看执行代码后LED1~LED4指示灯的变化情况。
(6) 在全速运行时,除了观察跑马灯闪光外,还要观察外设窗口,查看相关寄存器的值及寄存器的变化。
(7) 通过改变GPIOD输出寄存器的ODR的值ODRi来管擦和LED亮灭情况
修改ODRi值,当ODRi=1时,灯灭;当ODRi=0时,灯亮
(8) 退出调试返回编辑模式,进行实验内容(2),用杜邦线连接JP13-LED5和P2-PB7,使PB7与LED5连接
连接后如下图所示
![image-20220527011638497](https://i-blog.csdnimg.cn/blog_migrate/36baaabecc0afe485212e68c83b82606.png)
(9) 修改GPIO初试化程序,包括是能GPIOB时钟,配置PB7为10MHz推挽输出并初始化为逻辑1(LED5灭)
添加的程序块为
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); /*使能PB口时钟*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;/*选择PD7引脚*/
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; /*频率10MHz*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /*推挽输出*/
GPIO_Init(GPIOB, &GPIO_InitStructure); /*初始化GPIOB端口*/
/*---------初始化状态四个LED全灭OFF------------*/
GPIO_SetBits(GPIOB,GPIO_Pin_7);/*PB7输出为高电平,ED5灭*/
(10)在main()循环体中添加让LED5闪烁的代码
添加的程序块为 下面为修改后的循环体
while (1)
{
GPIO_ResetBits(GPIOD, GPIO_Pin_2); /* PD2=0 LED1亮 */
Delayms(n); /* 延时 */
GPIO_SetBits(GPIOD, GPIO_Pin_2); /* PD2=1 LED1灭 */
Delayms(n); /* 延时 */
GPIO_ResetBits(GPIOD, GPIO_Pin_3); /* PD3=0 LED2亮 */
Delayms(n); /* 延时 */
GPIO_SetBits(GPIOD, GPIO_Pin_3); /* PD3=1 LED2灭 */
Delayms(n); /* 延时 */
GPIO_ResetBits(GPIOD, GPIO_Pin_4); /* PD4=0 LED3亮 */
Delayms(n); /* 延时 */
GPIO_SetBits(GPIOD, GPIO_Pin_4); /* PD4=1 LED4灭 */
Delayms(n); /* 延时 */
GPIO_ResetBits(GPIOD, GPIO_Pin_7); /* PD7=0 LED4亮 */
Delayms(n); /* 延时 */
GPIO_SetBits(GPIOD, GPIO_Pin_7); /* PD7=1 LED4灭 */
Delayms(n); /* 延时 */
GPIO_ResetBits(GPIOB, GPIO_Pin_7); /* PB7=0 LED5亮 */
Delayms(n); /* 延时 */
GPIO_SetBits(GPIOB, GPIO_Pin_7); /* PB7=1 LED5灭 */
Delayms(n); /* 延时 */
}
(11)按F7键编译并链接,然后排除所有错误,最后编译链接
(12)按CTRL+F5进入调试环境
(13)按F5功能键运行程序,查看跑马灯显示是否正确,不正确的话修改代码,继续调试到正确为止。运行时观察GPIOB窗口输出寄存器的变化
(14)试着改变闪光时间,观察显示效果
修改以下函数即可
#define n 500 /*延时时间常数*/
void Delayms(uint16_t N)
{
uint32_t i;
for (i = 0; i < (8000 * N); i++)
;
}
(15)请用寄存器操作方法实现LED1~LED5跑马灯显示
按下面所示方式进行修改即可
GPIOD->ODR &= ~(1<<2) //让LED1亮
GPIOD->ODR |= (1<<2) //让LED1灭
(16)使用汇编语言让LED1闪烁
添加下面的两个函数
__asm LED10() //LED1 亮
{
LDR R0, = 0X4001140C;
LDRH R1, [R0];
LDR R2, = 0XFFFFFFFB;
AND R1, R1, R2;
STRH R1, [R0];
BX LR;
}
__asm LED11() //LED1 灭
{
LDR R0, = 0X4001140C;
LDRH R1, [R0];
LDR R2, = 0X00000004;
ORR R1, R1, R2;
STRH R1, [R0];
BX LR;
}
在主函数里调用即可
int main(void)
{
// SystemInit(); //系统初始化,此处可以省,因为在启动文件中有该函数的调用
GPIO_LED_Init(); // GPIO初始化
while (1)
{
LED10();
Delayms(n);
LED11();
Delayms(n);
}
}
3.1.3 完整实验代码
初始代码
/************************************************************************************
** WEEEDK NUAA_CM3_107实验开发板(V4.1/V4.2)
** GPIO-LED应用跑马灯实验
** 操作及现象:下载程序运行后看到四个LED指示灯闪光(轮流亮灭,似跑马灯)
** 版 本:V4.1
** 作 者:NUAA
** 完成日期: 2017.3.18
************************************************************************************/
#include "stm32f10x_conf.h"
/*********************************************
*函数名称:void Delayms(void)
*
*入口参数:N ms
*
*出口参数:无
*
*功能说明:简单延时N ms
**********************************************/
#define n 500 /*延时时间常数*/
void Delayms(uint16_t N)
{
uint32_t i;
for (i = 0; i < (8000 * N); i++)
;
}
void GPIO_LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE); /*使能PD口时钟*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_7; /*选择PD2/PD3/PD4/PD7引脚*/
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; /*频率10MHz*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /*推挽输出*/
GPIO_Init(GPIOD, &GPIO_InitStructure); /*初始化GPIOD端口*/
/*---------初始化状态四个LED全灭OFF------------*/
GPIO_SetBits(GPIOD, GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_7); /*PD2/PD3/PD4/PD7输出为高电平,四LED全灭*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); /*使能PB口时钟*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; /*选择PD7引脚*/
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; /*频率10MHz*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /*推挽输出*/
GPIO_Init(GPIOB, &GPIO_InitStructure); /*初始化GPIOB端口*/
GPIO_SetBits(GPIOB, GPIO_Pin_7); /*PB7输出为高电平,ED5灭*/
}
__asm LED10()
{
LDR R0, = 0X4001140C;
LDRH R1, [R0];
LDR R2, = 0XFFFFFFFB;
AND R1, R1, R2;
STRH R1, [R0];
BX LR;
}
__asm LED11()
{
LDR R0, = 0X4001140C;
LDRH R1, [R0];
LDR R2, = 0X00000004;
ORR R1, R1, R2;
STRH R1, [R0];
BX LR;
}
int main(void)
{
// SystemInit(); //系统初始化,此处可以省,因为在启动文件中有该函数的调用
GPIO_LED_Init(); // GPIO初始化
while (1)
{
// GPIO_ResetBits(GPIOD, GPIO_Pin_2); /* PD2=0 LED1亮 */
// Delayms(n); /* 延时 */
// GPIO_SetBits(GPIOD, GPIO_Pin_2); /* PD2=1 LED1灭 */
// Delayms(n); /* 延时 */
// GPIO_ResetBits(GPIOD, GPIO_Pin_3); /* PD3=0 LED2亮 */
// Delayms(n); /* 延时 */
// GPIO_SetBits(GPIOD, GPIO_Pin_3); /* PD3=1 LED2灭 */
// Delayms(n); /* 延时 */
// GPIO_ResetBits(GPIOD, GPIO_Pin_4); /* PD4=0 LED3亮 */
// Delayms(n); /* 延时 */
// GPIO_SetBits(GPIOD, GPIO_Pin_4); /* PD4=1 LED4灭 */
// Delayms(n); /* 延时 */
// GPIO_ResetBits(GPIOD, GPIO_Pin_7); /* PD7=0 LED4亮 */
// Delayms(n); /* 延时 */
// GPIO_SetBits(GPIOD, GPIO_Pin_7); /* PD7=1 LED4灭 */
// Delayms(n); /* 延时 */
// GPIO_ResetBits(GPIOB, GPIO_Pin_7); /* PB7=0 LED5亮 */
// Delayms(n); /* 延时 */
// GPIO_SetBits(GPIOB, GPIO_Pin_7); /* PB7=1 LED5灭 */
// Delayms(n); /* 延时 */
LED10();
Delayms(n);
LED11();
Delayms(n);
}
}
3.2 基于GPIO的简单人机交互接口实验
3.2.1 实验内容
- 在没有按键按下时,让LED1,LED2,LED3,LED4轮流闪光,当KEY1按下时LED1闪光,当KEY2按下时LED2闪光,当KEY3按下时LED3闪光,当KEY4按下时LED4闪光。添加代码,补充功能是按下任意键,蜂鸣器均响一声。
3.2.2 实验步骤
(1) 连接+5V电源到开发板,并打开电源开关,将ST-LINK 仿真器连接到WEEEDK嵌入式系统实验开发板的 JTAG插座上,USB 插头连接到PC的USB插口。如果没有驱动请安装ST-LNK 驱动,直到在设备管理器上看到STMicroelectronics STLink dongle为止。
(2) 复制"GPIO-KEYLED跑马灯"文件夹中的所有内容到D盘,双击 GPIO-LED跑马灯实验的\Project\Project.uvprojx 实验工程文件,打开实验工程,阅读 main()函数。
(3) 按F7 功能键编译并链接工程。
(4) 按Ctrl+F5键或单击调试按钮,进入集成调试环境。
(5)按F5功能键全速执行。查看执行代码后LED1~LED4知识灯的变化情况。在没有任何操作时,与跑马灯效果已有,4个LED闪光二极管依次发光
(6)分别按KEY1、KEY2、KEY3和KEY4键 ,观察LED1、LED2、LED3、LED4显示情况
连接图如下所示
![image-20220527011717295](https://i-blog.csdnimg.cn/blog_migrate/d80e2bb3e44e19cdb6dcacb01ae023fb.png)
(7)添加代码时每按一下按键时均有一声响声
退出调试环境,返回编辑模式,添加代码,完成在按键时让蜂鸣器响一声。需要短接JP12,将PC0与蜂鸣器控制电路相连。
添加的代码为
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure); /*初始化GPIOC端口推挽输出,50MHz*/
GPIO_ResetBits(GPIOC, GPIO_Pin_0); //PC0=0,此时蜂鸣器不响
新建一个Beep()
函数,功能是响一声,代码如下
void Beep(void)
{
GPIO_SetBits(GPIOC, GPIO_Pin_0);
Delayms(n);
GPIO_ResetBits(GPIOC, GPIO_Pin_0);
}
在main()
中修改
int main(void)
{
u8 KEY = 0;
u8 i = 0;
u16 Pinx[4] = {GPIO_Pin_2, GPIO_Pin_3, GPIO_Pin_4, GPIO_Pin_7};
SystemInit(); /* 系统初始化 */
GPIO_KEYLED_Init(); /* GPIO初始化 */
while (1)
{
if (GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_11) == 0)
{
KEY = 1;
Beep();
}
else
{
if (GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_12) == 0)
{
KEY = 2;
Beep();
}
else
{
if (GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_13) == 0)
{
KEY = 3;
Beep();
}
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0)
{
KEY = 4;
Beep();
}
}
}
if (KEY == 0)
{
GPIO_ResetBits(GPIOD, Pinx[i]); /* LEDi+1亮 */
Delayms(n); /* 延时n ms */
GPIO_SetBits(GPIOD, Pinx[i]); /* LEDi+1灭 */
Delayms(n);
i++;
if (i >= 4)
i = 0;
}
else
{
GPIO_ResetBits(GPIOD, Pinx[KEY - 1]);
/* LED[KEY-1]亮 */
Delayms(n); /* 延时n ms */
GPIO_SetBits(GPIOD, Pinx[KEY - 1]);
/* LED[KEY-1]灭 */
Delayms(n);
}
}
}
(8)按F7键编译并链接,然后排除所有错误,最后编译链接
(9)按CTRL+F5进入调试环境
(10)按F5功能键运行程序,查看跑马灯显示是否正确,不正确的话修改代码,继续调试到正确为止。
(11)除了初始化程序外,将上述采用固件库函数操作代码修改为寄存器操作的代码
添加的代码为
GPIOD->ODR &= ~(1<<2) //让蜂鸣器不响
GPIOD->ODR |= (1<<2) //让蜂鸣器响
3.3 基于GPIO的直流电机控制实验
3.3.1 实验内容
在没有按键按下时,让双色灯灭;当KEY1按下时,双色灯LED7发红光,且电机正转;当KEY2按下时双色灯LED7发绿光,且电机反转;当KEY3按下时LED7灭,电机停止运转。
3.3.2 实验步骤
(1)连接 +5V电源到开发板,将ST-LINK仿真器连接到WEEEDK嵌入式系统实验开发板的JTAG插座上,USB插头连接到PC的USB插口;
(2)复制”GPIO-MOTO”文件夹的所有内容到D盘,双击…\Project\Project.uvprojx实验工程文件,打开实验工程,找到main()函数。
(3)按F7功能键编译并链接工程。
(4)按Ctrl+F5 键或单击调试按钮,进入集成调试环境。使用F10功能键单步调试、Ctrl+F10执行到光标处、F5功能键全力执行。在全速运行时,要观察LED7和电机运行情况。
(5)分别按KEY1、KEY2、KEY3,观察LED7和电机运行情况。
按KEY1:
![image-20220527011925365](https://i-blog.csdnimg.cn/blog_migrate/c8c9c3373bc858ff3221b8667614fd4b.png)
按KEY2:
![image-20220527011947406](https://i-blog.csdnimg.cn/blog_migrate/5b172bbac1292eca3ad3dc0beb2bec89.png)
按KEY3: LED7熄灭,电机不转。
(6)返回编辑模式,修改或添加代码,完成由PE14和PE15分别控制电机的正转和反转。
拔下JP5、JP6,并用杜邦线将P1中的PE14连接到JP5-3脚,让PE15连接到JP6-3脚,让PE14连接到IA,让PE15连接到IB。
修改GPIO初始化程序GPIO_MOTO_Init()
#define IA(x) ((x) ? (GPIO_SetBits(GPIOB, GPIO_Pin_14)) : (GPIO_ResetBits(GPIOB, GPIO_Pin_14)))
#define IB(x) ((x) ? (GPIO_SetBits(GPIOB, GPIO_Pin_15)) : (GPIO_ResetBits(GPIOB, GPIO_Pin_15)))
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14|GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure); /*初始化GPIOE端口PB14=IA,PB15=IB 50MHz推挽输出*/
(7)按F7编译并链接,然后排除所有错误,最后编译链接。
(8)按Ctrl+F5进入调试环境。
(9)按F5功能键运行程序,查看程序运行是否正确。如果不正确,就修改代码,继续调试,直到正确为止。
四、实验结果分析及体会
4.1 基于GPIO的LED跑马灯实验实验结果
通过添加代码成功实现让LED1、LED2、LED3、LED4、LED5轮流闪光,分别使用固件库函数方法,寄存器操作方法,以及汇编语言方法。具体的代码部分请参照上一节中的内容。
实验结果图片:
![image-20220527012722942](https://i-blog.csdnimg.cn/blog_migrate/32230ff926ea42df491cfc7166786204.png)
![image-20220527012736710](https://i-blog.csdnimg.cn/blog_migrate/aaf7f401fe1fa3576f2b1a36f06fadf2.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4fa0c0a2439d37b4884649ff9c4bd922.png)
4.2 基于GPIO的简单人机交互接口实验
通过添加代码成功实现按下任意键,蜂鸣器均响一声,分别使用了固件库函数方法,寄存器操作方法。具体的代码部分请参照上一节中的内容。
实验结果图片:
![image-20220527012811326](https://i-blog.csdnimg.cn/blog_migrate/f39cd25bd600ea6c6d74e6214729894e.png)
![image-20220527012821166](https://i-blog.csdnimg.cn/blog_migrate/1f835f0f8f5945624350e45c942cd4ed.png)
4.3 基于GPIO的直流电机控制实验
这次实验成功实现了当KEY1按下时LED7发红光、电机正转,当KEY2按下时LED7发绿光、电机反转,当KEY2按下时,LED7灭、电机停止;修改GPIO初始化程序和相关程序、改变硬件的连接后也能得到相同的结果,达到了预期的实验效果。
![image-20220527011925365](https://i-blog.csdnimg.cn/blog_migrate/c8c9c3373bc858ff3221b8667614fd4b.png)
![image-20220527011947406](https://i-blog.csdnimg.cn/blog_migrate/5b172bbac1292eca3ad3dc0beb2bec89.png)