单片机的要务——控制外设

2019-04-15 17:38发布

单片机的要务——控制外设       首先明确一个概念:当我们使用单片机的时候,我们在使用它的什么?计算能力?逻辑分析能力?NO!我们使用得最多的是它所提供得各个功能模块(外设模块)。       所谓外设,是指将特定功能做成一个模块,然后给出控制端口,让处理器来控制。只要处理器给了足够的信息,外设就能完成特定的一组任务(个人理解o.O)。        举例来说(以下只是简单举例,实际还有更多的应用);        GPIO:配置好需要的引脚之后,就可以从该引脚输入或输出信号;        Timer(定时器):配置好之后,给定一个数值,它就不断的数数,到该值之后就会触发一个信号(当然还有别的功能)。        UART(异步串行通信接口):配置好之后,给出需要传输的信息,它就会将信息传输到指定位置(如上位机)。        ADC(模数转换器):可以读取外界模拟信号的数量值(如电压),转换为数字值(如0100)。       ……       这里不再穷举了,课本里面都很详细。          确定了单片机控制外设这样一个概念之后,我们再来讲讲(简单讲讲吧,水平也不高),单片机到底是如何控制外设的。 如果看过数据手册的话,应该会发现,在每一个外设的章节,都会由寄存器映射(Register Map)和寄存器描述(Register Descriptions)。每一个外设都有……没错,MPU就是通过寄存器来控制的。我们所有的操作,都是在读取或者写入数值到相应的寄存器中。 51单片机称霸的时代(吹牛皮不犯法吧),所写的代码就是直接对寄存器赋值,或者读取寄存器的值。因为那时普遍还是8位的单片机,寄存器只有8位,开发人员熟悉这么简单的寄存器很容易。但渐渐的,单片机的位数提高了,寄存器现在普遍达到了32位之多,去记住每一位代表什么意思,让人很头疼。因此就出现了官方库,开发人员只需要了解库函数有什么作用,就可以使用单片机了。        如果想要了解对寄存器的操作,使用我们手头的EK-TM4C1294xx,也可以做到。           以最近使用的UART为例:        在头文件包含#include “inc/tm4c1294ncpdtf.h”         定义变量:char start[]={"Hello "};        使用如下语句代替UARTCharPut(UART0_BASE,arr[i]);                  while(!(UART0_FR_R & (0x0001<<7)));                  UART0_DR_R=arr[i];         //UARTCharPut(UART0_BASE,arr[i]);        这两个语句就是通过对UART0的数据寄存器写入数据的方式实现发送数据的。 其中while用来判断数据寄存器是否为空(为空就跳出,此时才能写入数据),while里面就是通过读UART0_FR_R的寄存器的第7位的状态。该位的状态就表示数据寄存器是否为空。         DataSheet中对UART的状态寄存器的描述如下图:        其中位7bit 7)叫做TXFE,就是指示当前数据寄存器是否为空。其描述如下图:
        第二句就是将我们需要发送的字符赋值送入UART0_DR_R(数据寄存器,Data Register),然后UART0外设模块就自动将数据发送至上位机了(我们这里使用的个人电脑)。这也就是UART之所以可以称为一个模块的原因,它能自动传输数据。只是数据需要我们给它而已。         DataSheet中对UART的数据寄存器的描述如下图:        可以看到只有[7:0]八位是可以给用户写入数据的,也就是说,一次只能发送一个字符,发送完之后才能重新装载。        那么UART0_DR_R=arr[i];这条语句是如何与寄存器挂钩的呢?也就是说数据是如何存储到指定的寄存器的?         在头文件中,将UART0_DR_R通过宏定义的方式定义了它指向UART0的数据寄存器。就是说,UART0_DR_R就是一个指针,指针指向的地址的值如何改变,这对于学过C语言的你们来说,应该没问题了。 可以看看头文件中对UART0_DR_R的宏定义:         可以看到UART0_DR_R指向了0x4000C000这个地址,从存储器映射那一节课我们已经了解的UART0外设就是被分配到了从这个地址开使的一段空间。         也就是说我们将数据送到了UART0的这个位置,然后它就自动帮我们发送了。 另外,对UART的配置什么的也都是通过UART 配置寄存器进行操作的,只不过我们使用库函数开发,库函数对这些东西进行了高度的封装,我们不容易注意到而已。         关于寄存器的操作,只是为了让大家熟悉底层到底在干些什么,个人认为不必去记忆对应的寄存器对应的位是干什么的,因为我们可以使用库函数。下一篇文章,如果有必要的话,我准备简单介绍一下,库函数又是对应如何实现控制外设的。         其实可能有些多余,因为这里已经讲了通过寄存器操作了。到时候看情况吧。         好了,水平不高,仅供交流,多多指教。         祝福大家。