51单片机
采用宏定义文件absacc.h定义绝对地址变量。
格式:
#define 变量名 XBYTE[地址常数]
说明:
XBYTE宏允许用户访问8051外部数据存储器中的某一字节。
PBYTE宏允许用户按页访问8051外部数据存储器中某一字节
CBYTE宏允许用户访问8051程序存储器中某一字节
DBYTE宏允许用户访问8051内部数据存储器中某一字节
采用指针访问呢片外RAM绝对地址
格式:
数据类型 [存储类型1]*[存储类型2] 变量名[=地址常数]; P64
demo:
unsigned char xdata *PORT = 0x1000;
采用_at_关键字访问片外ram绝对地址
使用_at_可对指定存储器空间的绝对地址定位,但使用_at_定义的变量只能是全局变量。
格式:
变量类型 [存储类型] 变量名 _at_ 常量;
demo:
unsigned char xdata xram[0x80] _at_ 0x1000;
两类:
可编程IO扩展芯片  - 功能可由控制字设置
锁存/缓冲器接口芯片 - 功能固定不变
选用芯片的原则:输入三态、输出锁存
## ADC0809
#### 转换步骤
1.ALE信号上升沿,锁存地址并选中相应通道。 2.START信号下降沿开始启动AD转换,AD转换期间START为低电平 3.EOC信号由低变高时,表示AD转换结束 4.OE信号由低变高时,允许D0-D7输出转换结果
注意:实际使用时,将ALE、START合二为一<br>
模拟通道地址:
## ADC0832
### DAC性能指标
1.分辨率<br>
V0=-B*(Vref/256)<br>
0832分辨率8位<br>
2.转换时间<br>
将一个数字量转换位稳定模拟信号所需时间<br>
0832转换时间位1us<br>
3种控制方式:
直通方式 --两个寄存器都处在直通状态 单缓冲方式 - 一个寄存器处于直通,另一个受控 双缓冲 - 两个寄存器都在受控状态
## 编程题
### 1.利用定时器产生一方波信号,要求采用查询或终端方式编写
#### 查询法
```c
#include <reg51.h>
sbit P1_0=P1^0;
 void main(){
    TMOD = 0x01;
    TR0=1;
    while(1){
        TH0=0xff;
        TL0=-125;
        while(!TF0);
        TF0=0;
        P1_0=!P1_0;
    }
 }
void main(){
    TMOD=0x01;
    TH0=0xff;
    TL0=-125;
    EA=1;
    ET0=1;
    TR0=1;
    while(1);
}
void int() interrupt 1{
    TH0=0xff;
    TL0=-125;
    P1_0=!P1_0;
}
#include<intrins.h>
sbit START=P2^5;
sbit EOC=P2^6;
sbit OE=P2^7;
void main(){
    ulong temp,val;
    while(1){
        START=1; //启动转换
        _nop_();
        START=0;
        while(EOC==0);  //等待转换完成
        OE=1;
        P1=0xff;
        temp=P1; //读数据
        OE=0;
        val=(1000*5*temp/255+5)/10; //四舍五入
        display(val);
    }
}
void delayms(uint n){
    uint i,j;
    for(i=n;i>0;i--)
        for(j=123;j>0;i--)
}
void main(){
    uchar i,led=0x7f;
    while(1){
        for(i=0;i<8;i++){
            P0=led;
            delayms(200);
            led=(led>>1)|0x80;  //循环右移
        }
    }
}
发送
void main(){
    uchar c=0,temp;
    SCON=0x50; //SM0=0,SM1=1 方式1;REN=1,允许接收;SM2=TI=RI=0;
    TMOD=0x20;  //TI定时方式2
    TH1=TL1=0xf4 //波特率2400bps
    TR1=1;
    
    while(1){
        SBUF=c;  //发送
        while(!TI);  //等待发送完毕
        TI=0;
        while(!RI);  //等待从机返回
        RI=0;   //收到清零
        temp=SBUF; 
        if(temp==c){
            P2=x;
            if(++c>=16) c=0;
            delay();
        }
    }
}
接收
uchar r=0;
void main(){
    SCON=0x50;
    TMOD=0x20;
    TH1=TL1=0xf4;
    TR1=1;
    EA=1;
    ES=1;
    while(1);
}
void int() interrupt 4{
    RI=0;
    ES=0;
    r=SBUF;
    P2=r;
    SBUF=r;
    while(TI==0);
    TI=0;
    ES=1;
}
发送
void main(){
    uchar count=0;
    P2=0x00;
    TMOD=0x20;  //定时器1方式2
    TH1=TL1=0xfd; //自动重装,波特率9600
    SCON=0xd0;  //串口方式3,允许接收
    TR1=1;
    while(1){
        ACC=count;
        TB8=P;
        SBUF=count;
        while(TI==0);
        TI=0;
        while(RI==0);
        RI=0;
        if(RB8==1){
            P2=count;
            if(++count>15) count=0;
            delay();
        }
    }
}
    
接收
void main(){
    uchar rec;
    P2=0x00;
    TMOD=0x20;  //定时器1方式2
    TH1=TL1=0xfd;
    SCON=0xd0;
    TR1=1;
    while(1){
        while(RI==1)   //是否收到数据
        {
            RI=0;
            rec=SBUF;
            ACC=rec;  //讲数据放入累加器,以便于奇偶校验
            if(P==RB8) TB8=1;  //奇偶校验位和接收到的一致,则讲发送的奇偶校验位赋值1,否则0,一遍发送放处理接收到的数据
            else TB8=0;
            SBUF=rec;
            while(TI==0);
            TI=0;
            P2=rec;
        }
    }
}
char mod[] = {0x38,0x5b}; //LED字模L2
void main(){
    char point=0;
    while(1){
        P3=2-point; //输出LED位码
        P2=mod[point];
        point=1-point;
        delay();
    }
}
char mod[]={...}; //字模
char key[]={...}; //键模
char getkey(){
    char scan[]={0xef,0xdf,0xbf,0x7f};
    char i=0,j=0;
    for(i=0;i<4;i++){
        P2=scan[i];
        if((P2&0x0f)!=0x0f){
            for(j=0;j<16;j++){
                if(buf[j]==P2) return j;
            }
        }
    }
    return -1;
}
void main(){
    char key=0;
    P0=0x00;
    while(1){
        key=getkey();
        if(key!=-1) P0=mod[key];
    }
}
如果是用中断法:
void getkey() interrupt 0{
    char scan[]={0xef,0xdf,0xbf,0x7f};
    char i=0,j=0;
    for(i=0;i<4;i++){
        P2=scan[i];
        for(j=0;i<16;j++){
            if(buf[j]==P2){
                P0=mod[j];
                break;
            }
        }
    }
    P2=0x0f;
}
void main(){
    P0=0x00;
    IT0=1;  //脉冲触发
    EX0=1;  //INT0允许
    EA=1;
    P2=0x0f;
    while(1);
}
将由IN7通道输入的模拟量信号进行AD转换,结果以16进制显示,设工作时钟频率为5kHz
查询法1
#include<absacc.h>
#define AD_IN7 XBYTE[0xfeff] //IN7通道访问地址
sbit busy=p3^3;     //AD转换结束标志
void main(){
    while(1){
        AD_IN7=0;
        while(busy==1);
        P1=AD_IN7;  //转换数据显示
    }
}
查询法2
sbit START=P3^6;
sbit P20=P2^0;
sbit EOC=P3^7;
void main(){
    while(1){
        P20=0; START=1;START=0;START=1;  //启动AD转换
        while(EOC==1);
        OE=0; P1=P0; OE=1;  //读转换结果
    }
}
输出一路正弦波
查询法:
include<math.h>
int num;
void main(){
    while(1){
        for(num=0;num<360;num++)
            P2=127 + 127*sin((float)num / 180 *PI);
    }
}
中断法:
#include<adsacc.h>
void int() interrupt 2{
    P1=AD_IN7;
    AD_IN7=0;
}
void main(){
    IT1=1; //边沿触发
    EA=1;
    EX1=1;
    AD_IN7=0;
    while(1);
}   
输出一路三角波
#include<absacc.h>
#define DAC XBYTE[0xfeff]  //设置0832访问地址
char num;
void main(){
    while(1){
        for(num=0;num<255;num++) //上升段波形
            DAC=num;  //转换输出
        for(num=255;num>0;num--) //下降段波形
            DAC=num;  //转换输出
    }
}
实现两路锯齿波同步发生
#define DAC1 XBYTE[0xfeff]  //DAC1输入锁存器地址
#define DAC2 XBYTE[0xfdff]  //DAC1输入锁存器地址
#define DACOUT XBYTE[0xefff]  //DAC寄存器共同地址
void main(){
    uchar num;
    while(1){
        for(num=0;num<=255;num++){
            DAC1=num;   //上锯齿送入1
            DAC2=255-num;  //下锯齿送入2
            DACOUT=num;     //两路同时进行DA转换
        }
    }
}