【实验目的】
- 计数增功能:按一次按键S1,指示灯按二进制增加。
- 计数减功能:按一次按键S2,指示灯按二进制减少。
- 完成计数增功能,同时按S1,S2两个按键复位。
- 同时按S1、S3两个按键,实现翻转计数。
【实验环境】
nrf52840、keil、电脑
【实验资源】
IK-52840DK 开发板上设计了 4 个轻触按键 S1、S2、S3、S4,分别连接到 nRF52840 的 GPIO P0.11 P0.12 P0.24 和 P0.25。我们可以通过读取轻触按键对应的 GPIO 的状态来判断该按键是否按下。
在轻触按键的电路中,轻触按键一端接 GND,当轻触按键按下时,轻触按键触点导通, 轻触按键对应的引脚电平为低电平,这样,nRF52840 检测到按键对应的引脚为低电平时即 可判断按键按下。当轻触按键释放时,轻触按键触点断开,由于对应的引脚开启了内部上拉 电阻,所以轻触按键对应的引脚为高电平,这样,nRF52840 检测到按键对应的引脚为高电 平时即可判断按键释放。
【实验要求】
- 计数增功能:按一次按键S1,指示灯按二进制增加。
- 计数减功能:按一次按键S2,指示灯按二进制减少。
- 完成计数增功能,同时按S1,S2两个按键复位。
- 同时按S1、S3两个按键,实现翻转计数。
【实验步骤】
实验一:编写驱动led驱动,在此基础上,更进一步,编写按键的程序。想要设置led的点亮和熄灭,需要以下几个步骤:
1、初始化:配置用于驱动LED指示灯D1的管脚,即配置P0.13为输出
nrf_gpio_cfg_output(LED_1);
2、LED指示灯D1初始状态设置为熄灭,即引脚P0.13为输出高电平
nrf_gpio_pin_set(LED_1);
然后使用以下函数对led进行操控。
注意:首先判断是否有按键按下:if(nrf_gpio_pin_read(BUTTON_1) == 0 || nrf_gpio_pin_read(BUTTON_2) == 0||nrf_gpio_pin_read(BUTTON_3) == 0)
1、 if(nrf_gpio_pin_read(BUTTON_1) == 0 && nrf_gpio_pin_read(BUTTON_2) == 0)//判断按键1、2是否被按下
2、 else if(nrf_gpio_pin_read(BUTTON_1) == 0 && nrf_gpio_pin_read(BUTTON_3) == 0) 判断按键1、3是否被按下
3、 if(nrf_gpio_pin_read(BUTTON_1) == 0) 判断按键1是否被按下
4、 if(nrf_gpio_pin_read(BUTTON_2) == 0) 判断按键2是否被按下
以此完成1、计数增功能。2、计数减功能。3、完成计数增功能,同时按S1,S2两个按键复位。4、同时按S1、S3两个按键,实现翻转计数。
5、指示灯按二进制显示原理:把得到的数字,按位取反后进行比较,如果是0,则灯亮,否则灯灭。
void printled(int count){
nrf_gpio_pin_write(LED_1,~count&0x01);//1111 1110
nrf_gpio_pin_write(LED_2,~count&0x02);//1111 1101 8+4+1
nrf_gpio_pin_write(LED_3,~count&0x04);//1111 1011 8+2+1
nrf_gpio_pin_write(LED_4,~count&0x08);//1111 0111 4+2+1}
软件流程图如下:
展示实验运行结果和结论,需要有文字描述和截图。
在本次任务中,我成功在IK-52840DK开发板上实现以下功能:①计数增功能:按一次按键S1,指示灯按二进制增加。②计数减功能:按一次按键S2,指示灯按二进制减少。③复位功能:同时按S1和S2两个按键,计数器复位。④翻转计数功能:同时按S1和S3两个按键,实现计数方向的翻转。
为了实现这些功能,我们编写相应的程序代码,并通过读取按键的状态来控制LED的显示。
通过本次实验,我不仅掌握了基本的GPIO控制和按键检测,还学会了如何实现计数器的增减、复位和翻转功能。这些技能为未来的嵌入式系统开发打下了坚实的基础。未来,我将继续深入学习嵌入式系统的相关知识,探索更多复杂的应用场景。
[实验代码]
实验代码如下:
#include <stdbool.h>
#include <stdint.h>
#include "nrf_delay.h"
#include "boards.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "stdio.h"
#include "string.h"
#include "ctype.h"
// 定义LED引脚
#define LED1 NRF_GPIO_PIN_MAP(0, 13)
#define LED2 NRF_GPIO_PIN_MAP(0, 14)
#define LED3 NRF_GPIO_PIN_MAP(0, 15)
#define LED4 NRF_GPIO_PIN_MAP(0, 16)
// 初始化日志模块
static void log_init(void)
{
ret_code_t err_code = NRF_LOG_INIT(NULL);
APP_ERROR_CHECK(err_code);
NRF_LOG_DEFAULT_BACKENDS_INIT();
}
// 设置GPIO高电平时的输出电压为3.3V
static void gpio_output_voltage_setup_3v3(void)
{
if ((NRF_UICR->REGOUT0 & UICR_REGOUT0_VOUT_Msk) !=
(UICR_REGOUT0_VOUT_3V3 << UICR_REGOUT0_VOUT_Pos))
{
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
{
}
NRF_UICR->REGOUT0 = (NRF_UICR->REGOUT0 & ~((uint32_t)UICR_REGOUT0_VOUT_Msk)) |
(UICR_REGOUT0_VOUT_3V3 << UICR_REGOUT0_VOUT_Pos);
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
{
}
NVIC_SystemReset();
}
}
// 计数器变量
volatile uint8_t count = 0;
// 计数方向翻转标志
volatile bool flip_count = false;
// 检查按钮状态并更新计数器
void check_buttons()
{
static bool s1_pressed = false;
static bool s2_pressed = false;
static bool s3_pressed = false;
bool s1_state = nrf_gpio_pin_read(BUTTON_1) == 0;
bool s2_state = nrf_gpio_pin_read(BUTTON_2) == 0;
bool s3_state = nrf_gpio_pin_read(BUTTON_3) == 0;
if (s1_state && !s1_pressed)
{
if (s2_state)
{
count = 0; // 按钮1和2同时按下,复位计数器
}
else if (s3_state)
{
flip_count = !flip_count; // 按钮1和3同时按下,翻转计数方向
}
else
{
if (!flip_count)
{
count = (count + 1) % 16; // 正向计数
}
else
{
count = (count - 1) & 0x0F; // 反向计数
}
}
s1_pressed = true;
}
else if (!s1_state)
{
s1_pressed = false;
}
if (s2_state && !s2_pressed)
{
if (s1_state)
{
count = 0; // 按钮1和2同时按下,复位计数器
}
else
{
if (!flip_count)
{
count = (count - 1) & 0x0F; // 反向计数
}
else
{
count = (count + 1) % 16; // 正向计数
}
}
s2_pressed = true;
}
else if (!s2_state)
{
s2_pressed = false;
}
if (s3_state && !s3_pressed)
{
if (s1_state)
{
flip_count = !flip_count; // 按钮1和3同时按下,翻转计数方向
}
s3_pressed = true;
}
else if (!s3_state)
{
s3_pressed = false;
}
}
// 更新LED状态
void update_leds()
{
nrf_gpio_pin_write(LED1, !(count & 0x01)); // 显示最低位
nrf_gpio_pin_write(LED2, !((count >> 1) & 0x01)); // 显示第1位
nrf_gpio_pin_write(LED3, !((count >> 2) & 0x01)); // 显示第2位
nrf_gpio_pin_write(LED4, !((count >> 3) & 0x01)); // 显示最高位
}
// 主函数
int main(void)
{
gpio_output_voltage_setup_3v3(); // 设置GPIO输出电压为3.3V
log_init(); // 初始化日志模块
bsp_board_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS); // 初始化LED和按钮
NRF_LOG_INFO("led blinky example started"); // 打印启动信息
NRF_LOG_FLUSH();
while (true)
{
check_buttons(); // 检查按钮状态
update_leds(); // 更新LED状态
}
}