寄存器讲解(exynos4412开发板)
文章目录
前言
详细介绍:单片机怎么控制程序,变量数据,硬件模块,寄存器的理解,地址映射,指针写法,封装等等
一、单片机两大作用
单片机(处理器)作用:
第一:逻辑算数数据运算(程序控制)
第二:控制硬件模块
二、外设举例,ROM,RAM
1.地址空间:
一个单片机,它能够读写一段存储范围(储存器),将一个处理器能够读或者写的范围称为地址空间(寻址空间),地址空间的大小一般由地址总线的宽度决定,简单来说就说硬件设计有关。存储器有很多,比如ROM,RAM,IO,RSV等等。
2.ROM,RAM对于单片机运行而言具体区别
存储器有很多,比如ROM,RAM,IO,RSV等等。而我们一般写的程序就存在ROM(存在这里面的东西只能读)当中,然后处理器(单片机)去进行读操作(执行程序),对于一个处理器来说,它除了执行程序而外,它在运行的时候还要经常处理一些变量(数据),这些变量存在哪里?
对于RAM来说:有点像内存,里面的东西可读可写,但是当给单片机断电之后,里面的数据会消失。当程序运行时,其程序本身不用改,但是里面的变量会经常改动,读写操作,所以一般变量数据(value)存放于RAM中
3.硬件外设控制原理
而不管是ROM,还是RAM,这些都是单片机的第一个功能,对于单片机来说除了有CPU(准确是MCU)之外,还有很多硬件,硬件如何控制?在一个处理器可寻址空间范围内,还开出了一段空间给了寄存器,硬件控制器…(比如:网卡,UART(串口控制器)(用于通讯,对外进行数据发送,接收外部数据),ADC转换器(外部的模拟信号转化为数字信号),GPIO(对外输出一些高低电平信号,当然也可以检测外部输入内部的电平信号)…) 而每一个硬件控制器它都有对应的寄存器,寄存器的本质是什么呢?就是储存器,只要往寄存器里面(读)写特定的值,就可以控制对应硬件模块的工作。这也是硬件控制的原理
4.cpu间接控制
而单片机里面有cpu,还有硬件控制器。而cpu本身是不能直接控制硬件的,硬件一般是由其对应的控制器来控制,处理器中将各个硬件控制器的寄存器映射到cpu地址空间中的一段范围,这样cpu可以通过读写寄存器的地址来间接控制硬件。
三.地址映射表
在一个处理器中,一般会将RAM,ROM,寄存器等储存设备分别映射到寻址空间中的不同地址段,我们将这个映射关系称为这个处理器的地址映射表。如果要读程序,就在特定的地址空间访问,如果要读写变量,就在RAM对应的地址空间访问;同理硬件控制(而外设的控制一般位于芯片内部)
1.基于ARM exynos4412开发板举例
Exynos4412芯片(它是32位的处理器)(地址映射表)
所以它的地址空间2^32即4G,即一次能够读写4G的空间大小数据
32位:二进制转十六进制是4个位对应一个位,而这里0x0000_0000转二进制即8*4=32位对应起来了
这里的第一行0x0000_0000到0x0001_0000:一共64KB空间大小,分配给ROM
再比如第三行0x0202_0000到0x0206_0000:一共256KB空间大小,分配给了RAM
再比如倒数第三行0x1000_0000到0x1400_0000:这段空间地址大小分配给了特殊功能寄存器(SFR region)
最后两行,一共3G空间地址大小,分配给了内存条,其实也是RAM
当然这里空间范围没有细说,比如串口1,串口2对应的地址范围在芯片数据手册上有细分。一个寄存器能存储的字节数,不同的芯片不一样。而这里举例的寄存器占4字节。
基于ARM exynos4412开发板LED点亮
GPX2CON[7]寄存器
比如LED点亮实验,是由GPIO来控制输出高低电平,同样的GPIO也有寄存器,通过对寄存器(register)写值来控制(至于怎么写值,如何写值,要根据芯片手册写)
此芯片GPX2CON寄存器来控制功能(GPX2这一组引脚)
寄存器的地址=首地址+offset(偏移量)
offset芯片手册上对偏移量的描述,比如这里就是0x0c40,这里的description描述了具体怎么写值。
这里的Bit位即表示第28位到31位的寄存器GPX2CON[7]的值用于控制GPX2_7引脚
它的功能由表可知:输入input,输出output,中断EXT_INT42,键盘功能,调式功能…等
当要求是输出功能的时候,看description的第二行,对应的寄存器值为0x1
1.ARM exynos4412开发板LED电路
由电路图知:GPX2_7管脚控制第一个LED亮灭
那比如led点亮实验,就要求GPIO的输出功能,那我们只需要在地址0x1100_0000+0x0C40对应的28位到31位(共4位)设置成0x1(0001)即可,此时就指定了GPIO现在是输出功能。
GPX2DAT寄存器
那当要求点亮led,则除了要求输出功能,还得要求对外输出的具体电平,则就需要另外的寄存器来控制了(GPX2DAT),它有32位,但我们只用了低8位(0-7)
在功能描述中:When configuring as output port then pin state should be same as corresponding bit :意思为引脚的状态和对应的位一样,什么意思呢?如下:
那代码如下:
Int main(void)
{
*0x11000c40=0x10000000;//c语言认不到GPX2CON,所以直接*地址就是访问里面内容
return 0;
}
0x11000c40地址怎么来的:芯片手册上Address=Base Address+0x0c40
但是上述写法错误,编译器会理解0x11000c40就是一个普通的数,它没看芯片手册并不知道这是一个地址,就不会用指针方式操作访问里面的内容,解决方法就是c语言中的强制类型转换。
int main(void)
{
*(unsigned int*)0x11000c40=0x10000000;
return 0;
}
告诉编译器0x11000c40是unsigned int类型指针,在指针前面+取地址符 则访问里面的内容,再赋值(输出功能的值)
unsigned int它指向的int(4字节)32位空间,才能对应起来,所以不可以转换成unsigned char型指针
接下来是GPX2DAT寄存器设置,让其输出高电平,对应的值应该是1000_0000即0x80
int main(void)
{
*(unsigned int*)0x11000c40=0x10000000;
While(1)
{
*(unsigned int *)0x11000c44=0x80;//让第7个管脚led亮,就是10000000
Delay_10us(100);
}
return 0;
}
但是这样写可读性太差,不好维护,一般在main前加宏,给GPX2COND等寄存器封装,就很好看了。
再细看可知:一个寄存器占4个字节,
GPX2CON[7]地址为0x11000c40
而 GPX2DAT地址为0x11000c44
说明他们两个在内存里面地址是连续的,在c语言,只有数组类型地址是连续的,连续存储的。在STM32编程中,结构体成员在内存地址也是连续的,自然而然可以想到把这两个东西封装成一个结构体。
typedef struct{
unsigned int CON;
unsigned int DAT;
}GPX2;
#define GPX2 (*(GPX2*)0x11000c40)
对GPX2宏定义, 告诉编译器,这个数0x11000c40是GPX2*指针,一个结构体指针,再在前面+*号即是结构体内容(两个寄存器)
那么芯片手册上面的Base Address:0x1100_0000就是整个结构体的首地址但是这个地址是GPX2CON,我们现在在讲GPX2CON[7],所以结构体首地址以0x11000c40为准。
封装后代码如下:
void delay_10us(unsigned int ten_us)
{
While(ten_us--);
}
typedef struct{
unsigned int CON;
unsigned int DAT;
}GPX2;
#define GPX2 (*(GPX2*)0x11000c40)
Int main(void)
{
GPX2.CON=0x10000000;
While(1)
{
GPX2.DAT=0x80;//让第7个引脚对应的led亮
delay_10us(10000);
GPX2.DAT=0x00;//全灭
delay_10us(10000);
}
}
再升级一点,即是把结构体等相关声明放入头文件中,再main.c中包含include头文件就行。
总结
实际上对于led亮,就是对两个寄存器写值,对于怎么写值,学会看芯片数据手册即可,c语言代码规范。