嵌入式学习笔记——寄存器实现控制LED小灯

news2024/10/3 0:21:32

文章目录

  • 前言
  • GPIO通用输出模式
    • 初始化LED小灯的GPIO
      • 原理图
      • 初始化代码
      • 初始化的效果
    • 功能函数封装
      • 直接分开宏定义两个
      • 使用条件运算符
      • 封装函数实现简单的功能

前言

上一篇中,介绍了GPIO相关的所有寄存器,并在最后简单实现了一个LED灯的控制,由于那个篇幅实在是太长了,编程那部分写的有些许潦草,本文再借着点亮剩下的LED小灯来做个稍微详细点的描述,会涉及一些开发环境使用中的常见BUG、以及部分位操作相关的C语言知识。文中如有不足之处欢迎大家批评指正,创作不易,需要转载或者引用的请注明出处。

GPIO通用输出模式

常见的使用通用输出模式的片外外设就是LED灯、有源蜂鸣器、继电器等等,在我们板子上最常见的就是LED灯,上一篇中,配置了GPIO的端口A的4号管脚为推挽输出模式,并输出了低电平点亮了LED灯,我们先回顾一下配置流程,

初始化LED小灯的GPIO

首先是初始化部分,这里还是借用一个伪代码,这样看起来更加直观:

//注意前面这一段注释一定要记得写上,一方面是为了方便自己能够看懂自己的代码,另一方面,当别人看你的代码的时候也能一目了然。
/*******************************
函数名:Led_Init
函数功能:LED灯IO口初始化配置
函数形参:void
函数返回值:void
备注:
LED1----->PA6 通用输出
LED2----->PA7 通用输出
********************************/
void Led_Init(void)//函数命名,一般是'模块——功能'其中模块名与功能名的首字母大写
{
	①打开PA的时钟
	②端口模式寄存器
	③输出类型寄存器
	④输出速度寄存器
	⑤上下拉寄存器
}

根据这个伪代码我们即可配置出对应端口对应管脚的模式为通用输出模式。
下面我们在昨天的基础上再来配置一次,这次将两个LED都一并初始化。

原理图

还是昨天的原理图,从这可以知道,需要配置的是PA6和PA7两个口。
在这里插入图片描述

初始化代码

/*******************************
函数名:Led_Init
函数功能:LED灯IO口初始化配置
函数形参:void
函数返回值:void
备注:
LED1----->PA6 通用输出
LED2----->PA7 通用输出
********************************/
void Led_Init(void)//函数命名,一般是'模块——功能'其中模块名与功能名的首字母大写
{
/*---------------------①打开PA的时钟------------------------------------------------------------------------*/
	RCC->AHB1ENR |= (1<<0);
	/*对应在编程手册的6.3.12节,有关于此寄存器的配置;
	GPIOA端口的时钟使能是有该寄存器的第0位进行控制的,要使能GPIOA的时钟就是对其第0位进行写1,
	根据前面提到的位操作,就是将1直接赋值给该寄存器即可。*/
/*----------------------②端口模式寄存器---------------------------------------------------------------------*/
			/*端口模式清零*/
	GPIOA->MODER &= ~(0xf<<12);
	/*这一步是保证我们操作的寄存器在我们写入数据之前一定是00.
	避免出现被覆盖,而变成其他模式的问题。清零的思路:
	1.我们需要写入的是5和6两个端口,也就是这个寄存器的15 14 13 12 这四位
	为了将这四位清零,首先使用‘|’运算肯定是不行的,只能选择‘&0’的操作才能确保对应位清零。
	2.0是不能移位操作的,所以只能借助1移位后再进行取反来实现;
	3.于是得出清零语句GPIOA->MODER &= ~(0xf<<12);也就是0xf也就是二进制的1111
	向前移了12位变成了1111 0000 0000 0000然后取反变成0000 1111 1111 1111
	然后与原来寄存器内的数据相与,和0相与的位都被清成0了,和1相与的位保持不变,
	0000 XXXX XXXX XXXX
	这样既保证了对应位写入0又保证了其他位不被干扰。*/
	/*端口通用输出模式*/
	GPIOA->MODER |= (0x5<<12);
	/*上一步已经清零了需要配置的位,接下来直接写入即可,写入过程:
	1.查询寄存器可以知道,要配置为通用输出模式,需要对这四位写入:01 01;
	2.具体操作可以通过|=来实现,GPIOA->MODER |= (0x5<<12);
	3.0101是十六进制的0x5,需要前移12位来到我们需要操作的数据位,
	由于里面的数据位都是0,所以|操作后这四位被覆盖成了0101*/
/*----------------------③输出类型寄存器-----------------------------------------------------------------------*/
		/*端口输出推挽模式*/
	GPIOA->OTYPER &= ~(3<<6);
	/*由于我们需要控制小灯的亮灭,这就要求GPIO口具有独立输出高低电平的能力,
	所以我们需要配置为推挽模式,也就是需要将第六位以及第七位进行写零操作,
	参考上面的写零思路:只需要将二进制的11也就是十进制的3左移6位即可实现。*/
/*----------------------④输出速度寄存器-----------------------------------------------------------------------*/
	/*端口输出速度25MHz就只是控制一个LED灯,对于引脚的高低电平翻转速度没有啥要求,
	配置一个中速即可,也就是需要将第15 14 13 12 四位先清零,然后写入0101,与上面操作一致*/
	GPIOA->OSPEEDR &= ~(0xf<<12);//清零OSPEEDR
	GPIOA->OSPEEDR |= (0x5<<12);//25MHZ中速
/*----------------------⑤上下拉寄存器--------------------------------------------------------------------------*/
	GPIOA->PUPDR   &= ~(0xf<<12);//默认无上下拉
	/*由于是输出模式,我们不需要上下拉操作,直接对对应的15 14 13 12 这四位写零即可*/
}

初始化的效果

到这里,我们已经初始化完成了两个LED的GPIO口,此时不管我们先抛开ODR寄存器不管,直接编译烧录,就会发现,两个LED灯已经点亮了,这是因为ODR寄存器默认状态就是低电平输出,所以他会亮。
在这里插入图片描述

功能函数封装

实际做产品的过程中,很少有说初始化后就直接点亮或者开启的,都是需要有后续逻辑控制了后再开启的,所以我们需要对上面的代码进行加工,
按照之前的思路,应该是直接操作对应的·ODR寄存器,来实现开灯与关灯,但是这样不利于后期维护代码,可能过个一两周,你回来看自己的代码都看不明白了,所以我们采用宏定义来对这个开灯关灯操作做一个封装,我这里有两种方式,两个灯用了不同的方式,大家根据自己的喜好来就行。

直接分开宏定义两个

第一种方式就是直接分别宏定义一个LEDn_ON,与一个LEDn_OFF,具体写法如下:

// An highlighted block
#define LED_1_ON GPIOA->ODR &= ~(1<<6)//置零拉低对应端口,LED1灯亮
#define LED_1_OFF GPIOA->ODR |= (1<<6)//置1拉高对应端口,LED1灯灭
//这个比较好理解,直接对对应端口的控制位写零写一。

使用条件运算符

第二种方式,使用条件运算符来实现,宏定义的时候定义为LED_n(x) ;当x非0的时候执行(GPIOA->ODR &=~(1<<7);将GPIO对应的控制位置0,拉低IO口,小灯点亮;当x=0时,执行(GPIOA->ODR |=1<<7)将对应位拉高,小灯熄灭。

#define  LED_2(x) (x)?(GPIOA->ODR &=~(1<<7):(GPIOA->ODR |=1<<7)) 

宏定义应该放在那个位置呢,这个我们上一篇中提到过哈,在我们写头文件的时候还专门区分了一个区域用来存放宏定义的。此时的宏定义就放到这。
在这里插入图片描述

然后将上面的两个封装好的宏进行调用进初始化,使LED默认熄灭。
在这里插入图片描述
编译烧录后,可以发现LED上电后默认是熄灭的。
在这里插入图片描述

封装函数实现简单的功能

经过上面的操作,已经将LED的开启与关闭做了封装,接下来,就是做对应功能的封装,类似跑马灯、流水灯,闪烁之类的操作。这类操作,一般都是采用一个功能函数进行封装而不是直接码在while(1)里面的。
这里实现一个流水灯吧。查一个小技巧,如果我们有一个函数代码写的很长了,往后翻比较麻烦,可以在代码任意位置右键------>选择1的位置,---------->点击一下2的位置。
在这里插入图片描述
就会出现左侧的折叠符号,点击就可以将整个函数进行折叠。
在这里插入图片描述

//第一步,写注释
/***********************************************
*函数名    :Led_Flow
*函数功能  :实现一个简单的流水灯(非阻塞)
*函数参数  :u8 delay
*函数返回值:void
*函数描述  :灯1亮 灯1灭 灯2亮  灯2灭灯1亮(非阻塞)
delay 用来控制流水灯的速度。
*********************************************/
//第二步写函数,由于是非阻塞的流水灯,所以是不能使用while(i--)的那种死等的延时的。
void Led_Flow(u8 delay)
{
	static u8  n=1;
	static u32 cnt=0;
	if(n==1){LED_1_ON;}
	if(n==2){LED_2(1);}

	cnt++; 
	//延时切换灯
	if(cnt>50000*delay)  //不精准延时
	{
		if(n==1)
		{LED_1_OFF; }
		if(n==2)
		{
			LED_2(0);
		}
		n++;    //往后切灯
		if(n>2)
		{
		  n=1;	
		}
		cnt=0;
	}
}

然后函数声明,在主函数调用;
在这里插入图片描述
主函数调用,由于设置了一个可以调速的delay形参,因此在主函数中需要摄者一个Led_Speed来传递参数。
在这里插入图片描述
然后编译下载,可以实现如下图效果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/397462.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

以获取笔记本电池信息为例介绍WMI的使用

注&#xff1a;本人也还没有完全弄懂WMI的原理&#xff0c;以下内容仅供参考。。。 简单来说&#xff0c;比起Win32提供的接口&#xff0c;WMI可以提供更多的系统信息&#xff0c;它本身是一个数据库架构&#xff0c;通过它可以访问、配置、管理和监视几乎所有的Windows资源&…

AM5728(AM5708)开发实战之移植OpenCV-3.4.11

一 概述 OpenCV是一个开源的跨平台计算机视觉库&#xff0c;可以运行在Linux、Windows、Mac OS等操作系统上&#xff0c;它为图像处理、模式识别、三维重建、物体跟踪、机器学习提供了丰富的算法。 由于OpenCV依赖包特别多&#xff0c;尽量不要使用交叉编译&#xff0c;即在什…

VMware虚拟机搭建环境通用方法

目录一、前期准备1.下载并安装一个虚拟机软件二、开始创建虚拟机1.配置虚拟机硬件相关操作2.虚拟机网络相关操作三、开机配置相关内容0.开机遇到报错处理&#xff08;选看--开机没有报错请忽略&#xff09;1.开始配置2.开机之后配置3.使用xshell远程登录4.使用xshell配置虚拟机…

下一个7年,保持期待、持续思考,酷雷曼继续向前!

过去7年&#xff0c;我们一直在思考&#xff0c; VR技术究竟能为我们的生活带来什么&#xff1f; 是足不出户就能云游千里的秀美风光&#xff1f; 是在家就能沉浸式体验线上消费的便利&#xff1f; 还是为商企和用户搭建更快速的沟通桥梁&#xff1f; NO.1、技术变革 在信…

磁盘阵列Raid探讨

最近公司买服务器&#xff0c;顺便了解一下服务器配置方面的问题 以下讨论的都是入门级服务器配置&#xff0c;全部是主观意见&#xff0c;没有任何科学依据&#xff0c;欢迎大家讨论 Raid0&#xff0c;Raid1&#xff0c;Raid10&#xff0c;Raid5&#xff0c;Raid6(Raid5热备)…

计算机科学导论笔记(四)

目录 六、计算机网络和因特网 6.1 引言 6.1.1 网络 6.1.2 因特网 6.1.3 硬件和软件 6.1.4 协议分层 6.1.5 TCP/IP协议族 6.2 应用层 6.2.1 应用层模式 6.2.2 标准客户机-服务器应用 6.2.3 文件传输协议&#xff08;FTP&#xff09; 6.2.4 电子邮件 6.2.5 TELNET 6…

vue 模拟 chatgpt 聊天效果:js 实现逐字显示、延时函数模拟对话

vue 模拟 chatgpt 聊天效果&#xff1a;js 实现逐字显示、延时函数模拟对话模拟 chatgpt 聊天功能&#xff0c;展示对话效果。其中比较有意义的技术点是&#xff1a;js 实现逐字显示、延时函数&#xff0c;同步遍历。 <template><div class"chat-gpt">…

SpringBoot中的bean注入方式和原理介绍

Spring Boot是一个非常流行的Java框架&#xff0c;它可以帮助开发者快速地构建高效、健壮的应用程序。其中一个重要的功能就是依赖注入&#xff0c;也就是将一个对象注入到另一个对象中&#xff0c;以便它们可以相互协作。在Spring Boot中&#xff0c;依赖注入是通过bean实现的…

易优cms 标签常用函数

【基础用法】 标签&#xff1a;无 描述&#xff1a;作用于标签变量 用法&#xff1a; {$field.typename|html_msubstr###,0,10,true} 注意&#xff1a;函数与字段名之间用竖线&#xff08;|&#xff09;隔开&#xff0c;###表示当前变量 属性&#xff1a; 无 涉及表字段…

Kafka 消费进度

Kafka 消费进度Kafka 自带命令Java Consumer APIJMX 监控指标监控消费进度 : 看滞后程度&#xff1a;消费者 Lag , Consumer Lag 滞后程度 : 消费者落后于生产者的程度 如 : Kafka 生产者向某主题成功生产 100 万条消息&#xff0c;消费者消费 80 万条消息那消费者就滞后 20 …

ccc-pytorch-卷积神经网络实战(6)

文章目录一、CIFAR10 与 lenet5二、CIFAR10 与 ResNet一、CIFAR10 与 lenet5 第一步&#xff1a;准备数据集 lenet5.py import torch from torch.utils.data import DataLoader from torchvision import datasets from torchvision import transformsdef main():batchsz 128C…

基于嵌入式libxml2的ARM64平台的移植(aarch64)

由于libxml在移植过程中依赖于zlib的库文件&#xff0c;因此本节内容包含zlib&#xff08;V1.2.13&#xff09;的移植libxml2(V2.10.3)的移植两部分组成。 &#xff08;一&#xff09;zlib的移植&#xff08;基于arm64&#xff09; 1、在github上下载zlib的最新源码压缩包&am…

【C++的OpenCV】第十课-OpenCV图像常用操作(七):直方图和直方图同等化(直方图均衡化)

&#x1f389;&#x1f389;&#x1f389;欢迎各位来到小白piao的学习空间&#xff01;\color{red}{欢迎各位来到小白piao的学习空间&#xff01;}欢迎各位来到小白piao的学习空间&#xff01;&#x1f389;&#x1f389;&#x1f389; &#x1f496;&#x1f496;&#x1f496…

看完书上的链表还不会实现?不进来看看?

1.1链表的概念定义&#xff1a;链表是一种物理存储上非连续&#xff0c;数据元素的逻辑顺序通过链表中的指针链接次序&#xff0c;实现的一种线性存储结构。特点&#xff1a;链表由一系列节点组成&#xff0c;节点在运行时动态生成 &#xff08;malloc&#xff09;&#xff0c;…

【react】类组件

React类创建组件&#xff0c;通过继承React内置的Component来实现的 class MyComponent extends React.Component{render() {console.log(this)// render是放在哪里的 —— 类(即&#xff1a;MyComponent)的原型对象上&#xff0c;供实例使用return <h2>我是用函数定义的…

python实现波士顿房价预测

波士顿房价预测 目标 这是一个经典的机器学习回归场景&#xff0c;我们利用Python和numpy来实现神经网络。该数据集统计了房价受到13个特征因素的影响&#xff0c;如图1所示。 对于预测问题&#xff0c;可以根据预测输出的类型是连续的实数值&#xff0c;还是离散值&#xff…

QGraphicsItem的简单自定义图形项

QGraphicsItem的继承重写序言重点函数QRectF boundingRect() constQPainterPath shape() constvoid paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget 0)序言 学习途中记录一下&#xff0c;可谓是精华点 重点函数 QRectF boundingRect()…

农产品销售系统/商城,可运行

文章目录项目介绍一、项目功能介绍1、用户模块主要功能包括&#xff1a;2、商家模块主要功能包括&#xff1a;3、管理员模块主要功能包括&#xff1a;二、部分页面展示1、用户模块部分功能页面展示2、商家模块部分功能页面展示3、管理员模块部分功能页面展示三、部分源码四、底…

蓝牙 - 设备类型设置: Class of Device

在电脑或手机上&#xff0c;搜寻和连接蓝牙设备时&#xff0c;不同的蓝牙设备显示的图标是不同的&#xff0c;比如搜到或连接上的设备是一个蓝牙键盘&#xff0c;显示的就会是键盘图标&#xff0c;如果搜索到的设备是一个手柄&#xff0c;显示的就是一个手柄图标。 显示的图标是…

进程(操作系统408)

进程的概念和特征 概念&#xff1a; 进程的多个定义&#xff1a; 进程是程序的一次执行过程 进程是一个程序及其数据在处理机上顺序执行时所发生的活动 进程时具有独立功能的程序在一个数据集合上运行的过程&#xff0c;它是系统进行资源分配和调度的一个独立单位 上面所说…