51单片机第8步_absacc.h库函数

本章重点学习库函数absacc.h的使用,介绍绝对宏和绝对地址的用法。故事有点老掉牙,但学校的教授们还在继续。

#include <REG52.h>  //包含头文件REG52.h,使能51内部寄存器;

#include <absacc.h>

#include <stdio.h>  //包含头文件stdio.h

                 //_getkey();从串口读入一个字符;

                 //putchar();向串口发送一个字节;

                 /printf();向串口发送一串字节;

//函数功能:初始化串口,设置波特率为1200bps@16MHz,使能接收,使用8位UART;

void Serial_Port_Initialization()

{ SCON=0x50; //串行控制寄存器: SM0,SM1,SM2,REN,TB8,RB8,TI,RI

             //SM1:SM0=01,选择方式1,SM2=0,表示非多机通讯,8-bit UART;

             //REN=1,使能接收;

  TMOD|=0x20; //定时器方式控制寄存器:GATE1,C/T1,M11,M10,GATE0,C/T0,M01,M00

              //GATE=0,TR置1便可以启动Timer;GATE=1,TR置1,且INT脚输入高电平,

              //才可以启动Timer;

              //M11:M10=10,选择方式2,8位自动重装载; 

  TH1=221;   //TH1: reload value for 1200 baud @ 16MHz

  TR1=1;   //启动Timer1;

  TI=1;    //发送UART的第一个字节,为下次发送做准备;

}

unsigned char data    char_value _at_ 0x7f;  //用_at_定义的变量,必须为全局变量

unsigned char idata   char_value1 _at_ 0x7e;

void main(void)

{ unsigned char data   byte_in_internal_ram;

  unsigned int  data   int_in_internal_ram;

  unsigned char data   byte_in_pdata_ram;

  unsigned int  data   int_in_pdata_ram;

  unsigned char data   byte_in_xdata_ram;

  unsigned int  data   int_in_xdata_ram;

  unsigned char data   char_in_code;

  unsigned int  data   int_in_code;

  Serial_Port_Initialization();//设置波特率为1200bps@16MHz,使能接收,使用8位UART;

  for(;;)

    { DBYTE[0x7f]='1';                   //向内部RAM的地址0x7f单元写入1的ascii码;

  byte_in_internal_ram=DBYTE[0x7f];  //将内部RAM中地址为0x7f的内容保存到变量中;

  DWORD[0x3f]=0x2010;                //向内部RAM的地址0x7e和0x7f单元写入0x2010;

  int_in_internal_ram=DWORD[0x3f];  //将内部RAM中地址为0x7e和0x7f的内容保存到变量中;

  PBYTE[0x7f]=0xff;      //向外部RAM的地址0x007f写入0xff;

  byte_in_pdata_ram=PBYTE[0x7f];  //将外部RAM中地址为0x007f的内容保存到变量中;

  PWORD[0x003e]=0x2010; //向外部RAM的地址0x007e和0x007f单元写入0x2010;

  int_in_pdata_ram=PWORD[0x003e];  //将外部RAM中地址为0x007f的内容保存到变量中;

  XBYTE[0x007f]=0xff;              //向外部RAM的地址0x007f写入0xff;

  byte_in_xdata_ram=XBYTE[0x007f];  //将外部RAM中地址为0x007f的内容保存到变量中;

  XWORD[0x003f]=0x2010;      //向外部RAM的地址0x007e和0x007f单元写入0x2010;

  int_in_xdata_ram=XWORD[0x003f];  //将外部RAM中地址为0x007f的内容保存到变量中;

  char_in_code=CBYTE[0x0000];        //将位于程序存储区地址为0x0000处内容保存到变量中;

  char_in_code=CBYTE[0x0001];  //将位于程序存储区地址为0x0001处内容保存到变量中;

  int_in_code=CWORD[0x0000];  //将位于程序存储区地址为0x0000处内容保存到变量中;

  char_value1='2';  //向内部RAM的地址0x7f单元写入2的ascii码;

  char_value='3';    //向内部RAM的地址0x7f单元写入3的ascii码;

}

}

<think>好的,用户现在问的是关于C52单片机中使用<ABSACC.H>的问题。首先,我需要回忆一下之前和用户的对话历史。之前用户询问了如何在C52中使用sin函数,我详细介绍了查表法、泰勒展开和编译器数学库三种方法,其中在查表法的代码示例中,我用了#include <ABSACC.H>这个头文件。现在用户可能在使用示例代码时遇到了这个头文件,想要了解它的具体作用和用法。 首先,我需要确认用户的需求。用户可能正在尝试在Keil C51环境下开发,遇到了这个头文件,不太清楚它的作用,或者想知道为什么需要包含它。用户可能对绝对地址访问、内存映射或硬件操作不太熟悉,所以需要详细解释。 接下来,我需要分析<ABSACC.H>的作用。这个头文件在C51编译器中提供了用于直接访问内存地址的宏,比如CBYTE、XWORD等。这些宏允许开发者通过地址直接读写存储器,这在嵌入式开发中非常重要,特别是当需要操作特定硬件寄存器或访问外部存储器时。 然后,我需要考虑用户的使用场景。用户可能在开发单片机程序时,需要与硬件外设(如ADC、DAC、GPIO等)进行交互,这些外设的寄存器通常映射到特定的内存地址。使用<ABSACC.H>中的宏可以方便地访问这些地址,而不需要手动使用指针操作,这样代码更简洁且易读。 用户可能不太明白这些宏的具体用法和区别,比如CBYTE、DBYTE、XBYTE的区别,以及何时使用它们。需要详细解释每个宏对应的存储器类型,比如CODE、DATA、XDATA等,以及它们的地址范围。此外,用户可能关心如何在实际项目中应用这些宏,例如读取外部RAM的数据或访问特定的硬件寄存器。 另外,用户可能担心使用这些宏的安全性和注意事项,比如地址越界、并发访问等问题。需要提醒用户在使用时确保地址的有效性,避免越界访问导致系统崩溃,以及注意volatile关键字的使用,防止编译器优化导致的问题。 还需要考虑用户可能的后续问题,比如如何确定硬件寄存器的地址,或者如何处理不同的存储区域。因此,在回答时应该包含实际应用的示例,让用户能够更好地理解如何将这些宏应用到自己的项目中。 最后,要确保解释清晰,结构合理,分点说明,让用户能够一理解<ABSACC.H>的作用、用法和注意事项,同时提供实际代码示例,帮助用户更好地应用所学知识。</think>在Keil C51开发环境中,`<ABSACC.H>` 是一个重要的硬件访问头文件,专门用于8051系列单片机(包括C52)的绝对地址访问操作。以下是关于该头文件的详细技术解析: --- ### **一、核心功能解析** 该头文件定义了**直接存储器访问宏**,可实现以下操作: 1. 按字节/字访问不同存储空间 2. 直接操作硬件寄存器 3. 访问扩展内存区域 4. 实现内存映射外设控制 --- ### **二、关键宏定义详解** | 宏名称 | 访问类型 | 目标存储区 | 地址范围 | 典型应用场景 | |---------------|----------|---------------|----------------|----------------------| | `CBYTE` | 字节访问 | CODE(ROM) | 0x0000-0xFFFF | 读取固化数据 | | `DBYTE` | 字节访问 | DATA(片内RAM) | 0x00-0x7F | 快速变量操作 | | `PBYTE` | 字节访问 | PDATA | 0x00-0xFF | 分页外部RAM访问 | | `XBYTE` | 字节访问 | XDATA | 0x0000-0xFFFF | 外部RAM/外设寄存器 | | `CWORD`/`XWORD` | 字访问 | CODE/XDATA | 同字节访问范围 | 16位数据操作 | --- ### **三、实际应用示例** #### 1. 读取外部ADC芯片(假设地址0x8000) ```c #define ADC_DATA XBYTE[0x8000] // 定义ADC数据寄存器 unsigned char read_adc() { return ADC_DATA; // 直接读取硬件寄存器 } ``` #### 2. 控制LED阵列(地址0xA000) ```c #define LED_CTRL XBYTE[0xA000] // LED控制寄存器 void set_leds(unsigned char pattern) { LED_CTRL = pattern; // 直接写入控制信号 } ``` #### 3. 访问固化的正弦表(CODE区) ```c #define SIN_TABLE CBYTE[0x1000] // 正弦表起始地址 float get_sin_value(unsigned char index) { return SIN_TABLE[index] / 128.0; // 读取并转换为浮点 } ``` --- ### **四、特殊用法技巧** 1. **结构体映射**(适用于外设寄存器组): ```c typedef struct { unsigned char CTRL; // 0x8000 unsigned char STATUS; // 0x8001 int DATA; // 0x8002-0x8003 } ADC_Type; #define ADC ((ADC_Type volatile xdata *)0x8000) void adc_init() { ADC->CTRL = 0x01; // 直接操作寄存器结构体 } ``` 2. **多字节访问优化**: ```c // 读取32位传感器数据(小端模式) unsigned long read_sensor() { return *(unsigned long xdata *)0x4000; // 直接转换为长整型指针 } ``` --- ### **五、硬件操作注意事项** 1. **地址有效性验证**: - 使用前必须确认目标地址在硬件设计中有效 - 避免访问未连接的地址空间(可能引发总线错误) 2. **时序控制**: ```c // 典型外设操作时序 XBYTE[0x9000] = 0x01; // 发送启动命令 _nop_(); // 插入空操作等待 _nop_(); unsigned char result = XBYTE[0x9001]; // 读取结果 ``` 3. **volatile关键字强制**: ```c #define STATUS_REG (*(volatile unsigned char xdata *)0xA100) // 防止编译器优化掉"无效"读取 ``` --- ### **六、存储空间访问速度对比** | 存储区类型 | 时钟周期/字节访问 | 特点 | |------------|-------------------|--------------------------| | DATA | 1 | 最快,但仅有128字节 | | IDATA | 2 | 间接寻址,访问0x80-0xFF | | XDATA | 3-4 | 外部总线,速度最慢 | | CODE | 4 | 只读,访问程序存储器 | --- ### **七、调试技巧** 1. **Memory窗口监控**: - 在Keil调试器中输入:`X:0x8000` 可查看XDATA区域 - 输入`C:0x1000` 查看CODE区域 2. **硬件断点设置**: ```c #pragma SETB_hwbreak(XBYTE[0xA000] == 0x55) // 当该地址值变为0x55时触发断点 ``` --- ### **八、替代方案对比** | 访问方式 | 优点 | 缺点 | |-----------------|-----------------------|-----------------------| | 绝对地址宏 | 直观,编译效率高 | 依赖具体存储类型 | | 指针操作 | 灵活 | 需要类型转换 | | 特殊功能寄存器 | 专用于SFR访问 | 仅限于预定义寄存器 | 建议在硬件寄存器操作中优先使用`<ABSACC.H>`宏,在数据结构访问时使用指针操作。实际开发中可将常用外设地址统一定义在`hardware.h`头文件中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值