当前位置: 首页 > article >正文

嵌入式入门学习——5了解寄存器如何控制单片机

0 系列文章入口

嵌入式入门学习——0快速入门,Let‘s Do It!

1.内容简介

武侠的内功和招式之间的关系类似于编程中的技术和计算原理之间的关系。招式是千变万化的,而内功心法则稳定而深厚。内功心法的深度决定了可以学习的招式变术的上限高度。
单片机的控制最终是要落实到寄存器上的。使用库函数或者使用高级语言是招式,了解单片机的寄存器则是内功。

2.引言

练习武功讲究内外兼修,一味学习技巧,而忽略本质的结果就是一旦对方一旦换了招式,这边马上招架不住。学会了51单片机还要再学一遍STM32,学会了STM32后面还有DSP、ARM等等,永远有新的芯片出场,难道一直等别人嚼碎了喂招?掌握单片机的底层原理,就像打通任督二脉,以后学什么武功都快。当然这里不是让我们回归到汇编时代或者寄存器编程时代,而是在前人已经帮我们把底层的细节一层层封装后,我们依然要具备底层的认知和控制的能力。带上芯片手册一起学,有了看芯片手册寄存器的能力,再加上C语言和系统架构的知识,就能一路披荆斩棘,过关斩将了。

3.认识寄存器

3.1常见寄存器

3.1.1通用寄存器

用于存储临时数据和计算结果,如AX、BX、CX、DX等。在某些情况下,这些寄存器还可以被进一步细分为低位字节寄存器(如AL、BL、CL、DL)和高位字节寄存器(如AH、BH、CH、DH)。

3.1.2程序计数器(PC)

专门用于存储下一条指令的地址,确保CPU能够顺序或跳跃地执行程序中的指令。

3.1.3堆栈指针寄存器(SP)

用于指示当前堆栈顶部的位置,支持堆栈操作,如压栈和出栈。

3.1.4标志寄存器(FLAGS/PSR):

用于存储CPU的状态标志,如零标志(ZF)、符号标志(SF)、进位标志(CF)、溢出标志(OF)等,这些标志反映了上一条指令执行后的结果状态。

3.1.5 控制寄存器

用于控制CPU的运行模式和特殊功能,如控制定时器/计数器、串口通信等外设的行为。

3.1.6 中断寄存器

用于控制中断和异常处理,如中断描述符表寄存器(IDTR)、全局描述符表寄存器(GDTR)等。

3.1.7 定时器/计数器寄存器

用于实现计时和计数功能,如TMR0、TMR1等,这些寄存器常用于生成定时中断或实现精确的延时。

3.2 汇编时代寄存器使用

话说汇编时代,单片机编程是直接控制寄存器的,那时候的加法的编程是这样的

section .data  
    a dd 5        ; 定义一个名为a的双字(double word,即32位)变量,并初始化为5  
    b dd 10       ; 定义一个名为b的双字变量,并初始化为10  
    result dd 0   ; 定义一个名为result的双字变量,用于存储结果,初始化为0  
  
section .text  
    global _start  
  
_start:  
    ; 将a的值加载到寄存器eax中  
    mov eax, [a]  
    ; 将b的值加载到寄存器ebx中  
    mov ebx, [b]  
    ; 将eax和ebx中的值相加,结果存储在eax中  
    add eax, ebx  
    ; 将eax中的结果存储到result中  
    mov [result], eax  

要实现加法就要用CPU的通用寄存器,所以首先要数据放到寄存器里面,然后执行加法指令,最后再取出数据。程序跳转、定时器、外设控制等等也都是寄存器实现的。这个操作一直没有变,因为计算机的底层框架一直是这样,只不过我们用高级的语言屏蔽了底层的细节。汇编上面有C语言,C语言上面有C++、Rust、MciroPython。

3.3 现在为什么要学寄存器

现在寄存器操作已经被封装的很好了,一般只要强实时编程和操作系统任务切换需要频繁的用汇编直接操作寄存器,别的时候都不用。那我们现在为什么要学寄存器,举个例子:
在 51 的开发中我们常常的作法是直接操作寄存器,比如要控制某些 IO 口的状态,我们直
接操作寄存器:
P0=0x11;
而在 STM32 的开发中,我们同样可以操作寄存器:
GPIOx->BRR = 0x0011;
这种方法当然可以,但是这种方法的劣势是你需要去掌握每个寄存器的用法,你才能正确使用
STM32,而对于 STM32 这种级别的 MCU,数百个寄存器记起来又是谈何容易。于是 ST(意法
半导体)推出了官方固件库,固件库将这些寄存器底层操作都封装起来,提供一整套接口(API)
供开发者调用,大多数场合下,你不需要去知道操作的是哪个寄存器,你只需要知道调用哪些
函数即可。
比如上面的控制 BRR 寄存器实现电平控制,官方库封装了一个函数:

void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
 GPIOx->BRR = GPIO_Pin;
}

这个时候你不需要再直接去操作 BRR 寄存器了,你只需要知道怎么使用 GPIO_ResetBits()这个
函数就可以了。在你对外设的工作原理有一定的了解之后,你再去看固件库函数,基本上函数
名字能告诉你这个函数的功能是什么,该怎么使用,这样是不是开发会方便很多?
任何处理器,不管它有多么的高级,归根结底都是要对处理器的寄存器进行操作。但是固
件库不是万能的,您如果想要把 STM32 学透,光读 STM32 固件库是远远不够的。你还是要了
解一下 STM32 的原理,而这些原理了解了,你在进行固件库开发过程中才可能得心应手游刃
有余。
当然如果是Arduino或者MicroPython,是基本接触不到寄存器的,因为都已经被硬件抽象层处理掉了,要实现一组IO的输出比较麻烦,因为不能直接访问输出寄存器,只能一个个PIN的调用接口,没有了组的概念。

//0x11=0b0001 0001
digitalWrite(1, HIGH);
digitalWrite(2, LOW);
digitalWrite(3, LOW);
digitalWrite(4, LOW);
digitalWrite(5, HIGH);
digitalWrite(6, LOW);
digitalWrite(7, LOW);
digitalWrite(8, LOW);

http://www.kler.cn/news/360411.html

相关文章:

  • MySQL数据类型 与 Java实体类类型 的对应关系
  • 开始在线课程管理系统的初始化工作,搭建Vue.js和Node.js的开发环境。
  • 实现了一个基于 OpenFOAM 的强化学习环境类OpenFoam,用于模拟流体动力学问题并与智能体进行交互
  • 027_基于Node JS+Vue校园二手物品交易平台设计和实现
  • Elasticsearch文本分析器
  • 【动手学深度学习】8.1. 序列模型(个人向笔记)
  • Java基础15-Java高级(单元测试、反射、注解、动态代理)
  • Substrate 网络层深度解读:libp2p 助力去中心化点对点高效通信
  • 百元以内蓝牙耳机什么牌子好?2024年十大建议买的蓝牙耳机
  • 基于Aspose依赖添加自定义文本水印——Word、Pdf、Cell
  • 字节 HLLM 论文阅读
  • MySQL-17.DQL-案例
  • 【C#】在 WinForms 中使用 MVVM(Model-View-ViewModel) 设计模式
  • 15分钟学Go 第2天:安装Go环境
  • 解构OpenAI swarm:利用Cursor进行框架分析与示例运行
  • Apache Paimon Catalog
  • 拍立淘按图搜索API接口是什么?
  • 【大数据算法】一文掌握大数据算法之:大数据算法设计技术。
  • Android 设置控件为圆形
  • 云原生:一张图了解devops 中CI/CD