基于ARM内核的智能手环(day2)

2024-03-31 19:44
文章标签 智能 day2 内核 arm 手环

本文主要是介绍基于ARM内核的智能手环(day2),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本次重点

  • STM32寄存器来控制led灯状态反转

  • 按键控制与非阻塞


回顾

GPIO口的八种模式:
模式描述
输入
上拉输入默认情况,输入高
下拉输入
浮空输入
模拟输入
输出
推挽输出0 1
开漏输出0 不能通过自身输出高电平信号1
复用推挽
复用开漏
添加头文件路径

image-20240331170614399

模块化编程:

image-20240331170629636

函数调用:

image-20240331170647052

image-20240331170651659

image-20240331170657477


ok,我们开始学习今天的内容

延时函数

单片机中延时的方法:

1. 空函数延时计算

空函数的执行时间取决于处理器的时钟频率。假设处理器的时钟频率为72MHz(即每秒钟执行7200万次指令),我们可以通过空函数来实现延时。

首先,我们知道执行1个空函数所需的时间是多少:

image-20240331172333722

然后,我们想要实现1微秒的延时,所以我们需要执行的空函数次数可以通过以下计算得到:

image-20240331172359072

所以,你需要大约72个空函数来实现1微秒的延时。

那么我们为了方便把你的写法,就定义函数来实现延时

void Delay_lus(void)
{__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
}

这样子就可以轻松实现1微秒的延时

那么纳秒和毫秒函数的写法也就很简单了

//毫秒
void Delay_us(uint32_t time)
{while(time--){Delay_lus();}
}
//微秒
void Delay_ms(uint32_t time)
{while(time--){Delay_us(1000);}
}

2. 定时器延时

定时器延时是一种更精确和可控的延时方法。通过配置定时器,可以生成精确的时间间隔,而不受CPU负载和其他因素的影响。这使得定时器延时比简单的空函数延时更加可靠和准确。

我们后面会讲到,这里先不展开


按键控制

人机交互的接口

我们所使用的板子上一共有四个按钮,我们来看看电路图

image-20240331173233530

我们要使用按钮,第一步一定是初始化

void KET_Config()
{//KEY1 --paPA0//KEY2 --paPC5//KEY3 --paPC6//浮空输入//step1.开时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE|RCC_APB2Periph_GPIOA,ENABLE);//step2.配置IO口模式GPIO_InitTypeDef	GPIO_InitSTRUCT;GPIO_InitSTRUCT.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_InitSTRUCT.GPIO_Pin = GPIO_Pin_0;GPIO_InitSTRUCT.GPIO_Speed = GPIO_Speed_50MHz;//step3.初始化IO口GPIO_Init(GPIOA,&GPIO_InitSTRUCT);GPIO_InitSTRUCT.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6;GPIO_Init(GPIOC,&GPIO_InitSTRUCT);
}

那接下来,我们自然要判断按钮是否被按下

我们只需要判断电平是否为高

不要忘了消抖哦

//按键检测
uint8_t KEY_Check(void)
{//按键检测if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)){Delay_ms(15);if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)){while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)){}return 1;}}return 0;
}

好的,这个时候我们就可以去通过按钮去控制led灯的亮灭了

那么就又引出了一个新的问题

我们该如何才能用同一个按钮来控制led灯的状态反转呢?

STM32寄存器来控制led灯状态反转

实际上我们要实现的操作很简单

我们只需要去改变小灯泡引脚的状态

如果是0就变成1,如果是1就变成0

那么该如何改变呢

很简单,实际上只有一行代码

GPIOE->ODR ^=0x1<<2;

我们一起来看一下这行代码

  • GPIOE: 这表示你正在操作的是GPIOE端口。
  • ODR: 这是GPIOE端口的输出数据寄存器。
  • ^=: 这是按位异或赋值操作符,用于对变量进行按位异或运算后再赋值给自身。
  • 0x1 << 2: 这是将十六进制数1向左移动2位,相当于将二进制数0001左移两位,得到0100,即十六进制数0x4。

可能有些抽象了,那我们这么来理解

首先

我们led所在的gpio状态是怎么储存的

就是使用寄存器保存,而这个寄存器名字就叫做ODR

名字可以在对应的技术参考手册里面查到

里面是怎么存储的呢(这里GPIOE有十六个引脚,所以我们用十六位寄存器来演示)

0000000000000000

这就代表着我们的引脚全部都是低电平

那么实际情况可能是这样子的

0010111000110110

然后

我们的led灯在2号引脚,也就是倒数第3位(寄存器从0开始)

也许有人问为什么是倒数的位呢,其实也很简单,你写一个1当然是从最右边开始写起,进位再向前

那我们该如果只改变第三位的状态,让它反转,而且还能让别的位保持不变呢

我们学过的知识

单目操作符			^
移位操作符			<<

我们就要用到单目操作符 按位异或 相异为真

那这里就涉及到一个小技巧,二进制数和1或都是取反,和0或都是它本身

移位操作符我们也很熟悉了,如果大家又不是很清楚的可以去看我的前几篇博客

最后

那么我们直接看例子

GPIOE->ODR ^=0x1<<2;

我们假设寄存器目前里面状态是这样子的

0010111000110110

我们需要让第三位反转电平

那么我们只需要让它和这样一串数字相或就行

0000000000000100

那我们怎么得到上面那串数字呢

我们只需要定义一串

0000000000000001

然后这串数字左移两位就ok啦

再用或来计算即可得到

0010111000110010

大家可以写一下试一下


明天将会更新

阻塞与非阻塞 串口通信

相关内容

这篇关于基于ARM内核的智能手环(day2)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/865171

相关文章

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

内核启动时减少log的方式

内核引导选项 内核引导选项大体上可以分为两类:一类与设备无关、另一类与设备有关。与设备有关的引导选项多如牛毛,需要你自己阅读内核中的相应驱动程序源码以获取其能够接受的引导选项。比如,如果你想知道可以向 AHA1542 SCSI 驱动程序传递哪些引导选项,那么就查看 drivers/scsi/aha1542.c 文件,一般在前面 100 行注释里就可以找到所接受的引导选项说明。大多数选项是通过"_

智能交通(二)——Spinger特刊推荐

特刊征稿 01  期刊名称: Autonomous Intelligent Systems  特刊名称: Understanding the Policy Shift  with the Digital Twins in Smart  Transportation and Mobility 截止时间: 开放提交:2024年1月20日 提交截止日

基于 YOLOv5 的积水检测系统:打造高效智能的智慧城市应用

在城市发展中,积水问题日益严重,特别是在大雨过后,积水往往会影响交通甚至威胁人们的安全。通过现代计算机视觉技术,我们能够智能化地检测和识别积水区域,减少潜在危险。本文将介绍如何使用 YOLOv5 和 PyQt5 搭建一个积水检测系统,结合深度学习和直观的图形界面,为用户提供高效的解决方案。 源码地址: PyQt5+YoloV5 实现积水检测系统 预览: 项目背景

【C++学习笔记 20】C++中的智能指针

智能指针的功能 在上一篇笔记提到了在栈和堆上创建变量的区别,使用new关键字创建变量时,需要搭配delete关键字销毁变量。而智能指针的作用就是调用new分配内存时,不必自己去调用delete,甚至不用调用new。 智能指针实际上就是对原始指针的包装。 unique_ptr 最简单的智能指针,是一种作用域指针,意思是当指针超出该作用域时,会自动调用delete。它名为unique的原因是这个

单片机毕业设计基于单片机的智能门禁系统的设计与实现

文章目录 前言资料获取设计介绍功能介绍程序代码部分参考 设计清单具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订

笔记整理—内核!启动!—kernel部分(2)从汇编阶段到start_kernel

kernel起始与ENTRY(stext),和uboot一样,都是从汇编阶段开始的,因为对于kernel而言,还没进行栈的维护,所以无法使用c语言。_HEAD定义了后面代码属于段名为.head .text的段。         内核起始部分代码被解压代码调用,前面关于uboot的文章中有提到过(eg:zImage)。uboot启动是无条件的,只要代码的位置对,上电就工作,kern

【C++】作用域指针、智能指针、共享指针、弱指针

十、智能指针、共享指针 从上篇文章 【C++】如何用C++创建对象,理解作用域、堆栈、内存分配-CSDN博客 中我们知道,你的对象是创建在栈上还是在堆上,最大的区别就是对象的作用域不一样。所以在C++中,一旦程序进入另外一个作用域,那其他作用域的对象就自动销毁了。这种机制有好有坏。我们可以利用这个机制,比如可以自动化我们的代码,像智能指针、作用域锁(scoped_lock)等都是利用了这种机制。