1. ARM单片机的头文件如何用结构体定义地
下面我们以ARM Cortex-M0内核单片机LPC1114的头文件lpc11xx.h文件进行说明。
1.先说两句
lpc11xx.h文件是lpc11xx系列单片机包含的头文件。这个文件的作用和51单片机中的reg51.h头文件是一个性质,都是用来定义寄存器在单片机中的地址的。
你现在就可以打开reg51.h文件和lpc11xx.h文件看看,对比后你会发现两个主要的区别,首先是lpc11xx.h文件的寄存器定义是用结构体的形式,而reg51.h文件中,寄存器的定义都是一条一条的很直接的地址定义。然后是reg51.h文件中有sfr这样的“伪c语言”,而lpc11xx.h中用的是标准的c语言。C语言的最大用武之地就是单片机,要想学c,就在单片机上学,要想学单片机,就先入门c语言。两者相辅相成的学,效果最好。学以致用,才是学习的最终目标。
2.lpc11xx.h文件中如何定义寄存器地址?
在文件中,定义寄存器地址用到了一下几方面的c语言基础知识:
结构体;
结构体指针;
宏定义#define
关键字typedef
关键字volatile
关键字const
lpc11xx.h文件中,把每个模块都定义了一个结构体,这些模块有SYSCON、IOCON、UART、GPIO、SSP、I2C、WDT、ADC等。
例如,下面是ADC模块的结构体定义:
typedef struct
{
__IO uint32_t CR;
__IO uint32_t GDR;
uint32_t RESERVED0;
__IO uint32_t INTEN;
__IO uint32_t DR[8];
__I uint32_t STAT;
} LPC_ADC_TypeDef;
结构体的定义有三种形式,我们这里使用的是“直接说明变量”的形式。
lpc11xx.h文件的第566~584行,给每个模块的结构体变量定义了结构体指针,并加了宏定义#define,为的是以后写程序时书写方便。
把鼠标放到uint32_t上面,单击鼠标右键,在弹出的菜单中选择“Go To Definition Of ‘uint32_t’”,如下图所示:
选择后,就会跳到它的定义之处,如下图所示:
typedef是类型重定义关键字,所以实际上,CR寄存器的定义是这样的:
__IO unsigned int CR;
按照同样的方法,可以找到__IO的定义为:
所以,CR寄存器定义实际上是:
volatile unsigned int CR;
volatile关键字的作用是为了让编译器不要优化这个变量。
unsigned int关键字,用来定义无符号的整形变量。
这时候,有人会问,为什么不直接写成这样呢?答:为了阅读方便。
__IO uint32_t CR;
看到这条语句,我们就会知道,CR寄存器是一个“32位的可读可写寄存器”。
volatile unsigned int CR;
同样的这句话,我们对它的了解就不是那么一目了然了。
3.如何查看每个寄存器的地址?
上面讲到,寄存器的地址是由结构体和结构体指针定义的。现在我们来验证一下它的正确性。
我们随便找个寄存器,比如ADC模块的INTEN寄存器(ADC中断允许寄存器),打开LPC1114的用户手册,找到第25章ADC模块部分,如下图所示:
从上面图中,可以看到INTEN的寄存器的地址是0x4001C00C,接下来,我们打开lpc11xx.c文件来验证一下吧。
打开lpc11xx.c文件,找到ADC模块的结构体,如下图所示:
然后再找到LPC_ADC_TypeDef的结构体指针,如下所示:
结构体指针就是用来指向一个地址的,我们来看看上面语句中的LPC_ADC_BASE是什么:
再看看上条语句中的LPC_APB0_BASE是什么:
现在终于挖到底了,原来LPC_ADC_TypeDef指针指向的地址为:
0x40000000+0x1C000=0x4001C000
c语言基础知识:结构体的第一个变量的地址=结构体指针的地址。
所以结构体的第一个变量地址就是0x4001C000,INTEN前面有3个4字节的变量,所以INTEN的地址就是0x4001C00C。
验证完毕。
4.程序中,如何操作寄存器?
C语言基础知识:用结构体变量指针访问结构体中的变量,形式有两种:
*结构体指针变量.变量名
结构体指针变量->变量名
还是拿INTEN寄存器为例,假设我们要给这个寄存器写0x837,可以这样写:
*LPC_ADC.INTEN=0x837;
LPC_ADC->INTEN=0X837;
以上两种形式,在写程序的时候,都可以用。人们习惯用第二种形式。
2. C51单片机语言枚举和结构体在单片机里面究竟用来处理什么功能
枚举和结构体的应用都差不多.
通常都是定义一个结构体或枚举,然后再用其定义成一个数组,
举例,有人做字库时有结构体,
里面包括一个unsigned int用于存汉字代码,
一个unsigned char[32]用于存点阵.
然后用该结构定义一个数组,
然后查询数组里unsigned int是否对应汉字,如果对应,则unsigned char[32]为该汉字的点阵,
这通常应用于LCD汉字显示.
总的一句话,就是方便数据归类,
如果学过C++,其实就有点类似C++的类,
当然,这比类要弱很多很多.
3. 在keil C51中使用结构体的问题
楼主没有搞清楚 51的 结构.
楼上说的虽然大多是废话,,对你的项目可以没多少帮助
但是至少有一点是对的..设置成xdata可以解决你的问题.
虽然不是什么好办法.
51的 ram 分外三种.
内部直接寻址你的128byte 内部间接的128byte
还有就是外部 ram
你的51单片机有512byte
那么肯定是 内部 直接 间接各128
外加外部256字节
你把那些大一点的数据全部改成 xdata 声明就可以了.
当然如果你会控制ram大小的话..用idata 声明效率更好一点
例如 unsigned char yy;
写个成 unsigned char xdata yy;
(你看你自己的编译结果显示 data=137, xdata=0, code=4856
就应该猜测一下 xdata 干吗用的了
最后 建议楼主. 最好不用在keil c51里面使用printf函数(浪费啊)
回去.仔细看一遍51的结构..然后看看keil c51的区别于ansi c的东西
会对你有帮助
如果对您有帮助,请记得采纳为满意答案,谢谢!祝您生活愉快!
4. 单片机的位域是什么意思如何使用
标准C提供了一种基于结构体的数据结构--位域(BitField),位域就是把一个存储单元中的二进制划分为几个不同的区域。并说明每个区域的
位数。每一个域有一个域名,允许在程序中按域名进行操作,位域的定义格式如下:
struct
位域结构名{
位域列表
};
位域列表格式为:类型说明符
位域名:位域长度如:
struct
k{
unsigned
int
a:1
unsigned
int
:2
unsigned
int
b:3
unsigned
int
:0
//空域
}k1;
说明:
1)各位依次从低位到高位排列,排满一个存储单元,按地址接着排下一单元;
2)位域可以无域名,但不能被引用,如第二域,这时其只用来填充或调整位置;
3)第四行称空域,目的是将目前存储单元的剩余部分分为一个域,且填充0。
位域的引用很简单,如:
k1.a=1;
//置k1的b0位为1
k1.b=7;
//将k1的b3-5位置111
通过位域定义位变量,是实现单个位位操作的重要途径和方法,采用位域定义位变量,产生的代码紧凑、高效。这种位域应用于单片机开发比较普遍。
5. 51单片机在Keil环境下,用C语言编程,关于片外存储区xdata中存放结构体类型的数据的问题,替朋友问的。
Keil本身对STC单片机缺乏支持,对外部xram没有数据库描述。在器件库中选个带xram的单片机就可以了,比如sst89x516rd.