simonid
12/11/2017 - 12:45 PM

51单片机

51单片机

51单片机复习

片外拓展

方法1:

采用宏定义文件absacc.h定义绝对地址变量。
格式:

#define 变量名 XBYTE[地址常数]

说明:

XBYTE宏允许用户访问8051外部数据存储器中的某一字节。

PBYTE宏允许用户按页访问8051外部数据存储器中某一字节

CBYTE宏允许用户访问8051程序存储器中某一字节

DBYTE宏允许用户访问8051内部数据存储器中某一字节

方法2:

采用指针访问呢片外RAM绝对地址
格式:

数据类型 [存储类型1]*[存储类型2] 变量名[=地址常数]; P64

demo:
unsigned char xdata *PORT = 0x1000;

方法3:

采用_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;
}

ADC数据采集系统(查询和中断)

查询

#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;  //循环右移
        }
    }
}

串行口点对点通信收发

方式1

发送

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;
}

方式2

发送

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);
}

ADC0809

将由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;  //读转换结果
    }
}

ADC0832

输出一路正弦波
查询法:

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转换
        }
    }
}