51单片机原理及应用——张毅刚版本代码全集可复制

发布时间:2024年01月19日

从左到右的流水灯的制作(重点)

在这里插入图片描述

#include <reg51.h>
#include <intrins.h> //移位函数的头文件
unsigned int j;
void Delay(unsigned int i) // 延时函数
{
	while(i--) // 注意这里是i--
    {
        for(j = 0;j < 120;j++); // 注意这里是120
    }
}

void main()
{
    P1 = 0xFE;
    while(1)
    {
        P1 = _crol_(0,1); //数据每次左移一位
        // crol函数是循环左移函数,即把挪出去的那一位补在后面空的一位
        //<<是左移函数,会在空的那一位补0
        Delay(100);
    }
}

左到右的来回流水灯的制作

在这里插入图片描述

#include <reg51.h>
#include <>
void Delay(unsigned int i)
{
    while(i--)
    {
        for(j=0;j<120;j++);
    }
}

unsigned int x;
unsigned int y;

void main()
{
    P1 = 0xFE;
    while(1)
    {
        for(x=0;x<8;x++)
        {
            P1 =  _crol_(0,1);
            Delay(100);
        }
        for(y=0;y<8;y++)
        {
            P1 = _cror_(0,1);
            Delay(100);
        }
    }
}

开关量检测指示器

在这里插入图片描述

#include <reg51.h>
void Delay(unsigned int i)
{
    while(i--)
    {
        for(int j=0;j<120;j++);
    }
}
void main()
{
    while(1)
    {
        if(P1_4 == 0)
        {
            Delay(20);
            while(P1_4==0);
            Delay(20);
            P1_0 = 0;
        }
        if(P1_5 == 0)
        {
            Delay(20);
            while(P1_5==0);
            Delay(20);
            P1_1 = 0;
        }
        if(P1_6 == 0)
        {
            Delay(20);
            while(P1_6==0);
            Delay(20);
            P1_2 = 0;
        }
        if(P1_7 == 0)
        {
            Delay(20);
            while(P1_7==0);
            Delay(20);
            P1_3 = 0;
        }
    }
}

单一外中断的应用

在这里插入图片描述

#include <reg51.h>
void Delay(unsigned int i)
{
    while(i--)
    {
        for(j=0;j<120;j++);
    }
}

void EX0_Init()
{
    EA = 1;
    EX0 = 1;
    IT0 = 1; // 负跳沿触发IT = 1   低电平触发IT = 0
}

void do_EX0() interrupt 0
{
    EX0 = 0;
    while(1)
    {
        P1 = 0xF0;
        Delay(100);
        P1 = 0x0F;
        Delay(100);
    }
    EX0 = 1;
}

void main()
{
    P1 = 0x00;
    EX0_Init();
    while(1);
}

两个外中断的应用

在这里插入图片描述

#include <reg51.h>
void Delay(unsigned int i)
{
    while(i--)
    {
        for(j=0;j<120;j++);
    }
}

void EX_Init()
{
    EA = 1;
    EX0 = 1;
    EX1 = 1;
    IT0 = 1;
    IT1 = 1;
    IP1 = 1;
    IP0 = 1; // 两个中断都设置为高优先级
}

void do_EX0() interrupt 0
{
    while(1)
    {
        P1 = 0xF0;
        Delay(100);
        P1 = 0x0F;
        Delay(100);
    }
}

void do_EX1() interrupt 2
{
    P1 = 0x00;
}

void main()
{
    EX_Init();
    while(1)
    {
        //流水灯代码
    }
}

ps:这个代码因为设置了同级中断,所以在进入任何一个中断后,另一个中断不会被响应

中断嵌套(重点)

在这里插入图片描述

#include <reg51.h>
void Delay(unsigned int i)
{
    while(i--)
    {
        for(j=0;j<120;j++);
    }
}

void EX_Init()
{
    EA = 1;
    EX0 = 1;
    EX1 = 1;
    IT0 = 1;
    IT1 = 1; // 设置触发方式
    IP0 = 0;
    IP1 = 1; //设置优先级
}

void do_EX0() interrupt 0
{
    while(1)
    {
        P1 = 0xF0;
        Delay(100);
        P1 = 0x0F;
        Delay(100);
    }
}

void do_EX1() interrupt 2
{
    P1 = 0x00;
    Delay(100);
    P1 = 0xFF;
    Delay(100);
}

void main()
{
    EX_Init();
    while(1)
    {
        //流水灯代码
    }
}

多外部中断源系统设计(非重点)

在这里插入图片描述
在这里插入图片描述

#include <reg51.h>
void EX_Init()
{
    EA = 1;
    EX0 = 1;
    EX1 = 1;
    IT0 = 1;
    IT1 = 1;
    IP0 = 1; // 将外部中断0设置为最高优先级
    IP1 = 0;
}

void do_EX0() interrupt 0
{
    P1 = 0xFF; // 进入外部中断0,熄灭所有灯
}

void do_EX1() interrupt 2
{
    if(P1_0 == 0){P1_4 = 0;}
    if(P1_1 == 0){P1_5 = 0;}
    if(P1_2 == 0){P1_6 = 0;}
    if(P1_3 == 0){P1_7 = 0;}
}

void main()
{
    EX_Init();
    while(1);
}

P1口外接的8只LED每0.5s闪亮一次

在这里插入图片描述

#include <reg51.h>
//计算初值
//公式:定时时间 = (2^16-初值X)*(12/fos) 其中(2^16-初值X)即为TH0和TL0的值
//定时时间为0.5s 也就是5000us 即初值X≈60927
void Timer0_Init()
{
    TMOD = 0x01;
    TH1 = 60927/256;
    TL1 = 60927%256;
    EA = 1;
    ET0 = 1;
    TR0 = 1;
}

void do_Timer0() interrupt 1
{
    P1 = ~P1;
    TH1 = 60927/256;
    TL1 = 60927%256;
}

void main()
{
    Timer0_Init();
    while(1);
}

计数器的应用(重点)

在这里插入图片描述

#include <reg51.h>
void Delay(unsigned int i)
{
    while(i--)
    {
        if(j=0;j<120;j++);
    }
}

void Timer1_Init()
{
    TMOD = 0x50; //0101 0000
    TH1 = 0xFF;
    TL1 = 0xFC;
    EA = 1;
    ET1 = 1;
    TR1 = 1;
}

void do_Timer1() interrupt 3
{
    while(1)
    {
        P1 = 0xFF;
    	Delay(100);
    	P1 = 0x00;
    	Delay(100);
    }
}

void main()
{
    Timer1_Init();
    while(1);
}

扩展一个外部中断源(非重点)

在这里插入图片描述

#include <reg51.h>
void Timer0_Init()
{
    TMOD = 0x06;
    TH0 = 0xFF;
    TL0 = 0xFF;
    ET0 = 1;
    TR0 = 1;
    TF0 = 0; //溢出标志位清零
}

void main()
{
    Timer0_Init();
    while(1);
}

在P1.0上产生周期为2ms的方波

在这里插入图片描述

#include <reg51.h>
//计算初值
//产生周期为2ms的方波,即要要让P1.0口每1ms翻转一次,所以定时器1需要定时1ms
//定时时间 = (2^16-X)*(12/fos)
//此时的定时时间为1ms,即1000us
// X = 65536-1000
void Timer1_Init()
{
    TMOD = 0x10;//0001 0000
    TH1 = (65536-1000)/256;
    TL1 = (65536-1000)%256;
    EA = 1;
    ET1 = 1;
    TR1 = 1;
}

void do_Timer1() interrupt 3
{
    P1_0 = !P1_0;
    TH1 = (65536-1000)/256;
    TL1 = (65536-1000)%256; //重置初值
}

void main()
{
    Timer1_Init();
    P1_0 = 0;
    while(1);
}

在P1.1上产生周期为1s的方波

在这里插入图片描述

多次中断法(推荐)

#include <reg51.h>
//这个题目的定时时间应该是1s/2 = 0.5s  0.5s = 500ms
//定时时间比较长,我们此时采用多次中断的方式来定时
//还是采用定时1的方式1来定时,可以让定时器1一次产生50ms的定时 一共定时10次
//50ms = 50000us
//X = 65536-50000
void Timer1_Init()
{
    TMOD = 0x10;
    TH1 = (65536-50000)/256;
    TL1 = (65536-50000)%256;
    EA = 1;
    ET1 = 1;
    TR1 = 1;
}

unsigned int count;
void do_Timer1() interrupt 3
{
    count++;
    if(count == 10)
    {
        count = 0;
        P1_1 = !P1_1;
	}
    TH1 = (65536-50000)/256;
    TL1 = (65536-50000)%256;
}

void main()
{
    Timer1_Init();
    P1_1 = 0;
    while(1);
}

双定时器法(不推荐)

在这里插入图片描述

T1控制发出1KHZ的音频信号(重点)

在这里插入图片描述

#include <reg51.h>
//书上写的计算初值是错误的,以下面注释为准
//产生1KHZ的音频信号,也就是产生音频信号的周期为1ms 所以需要定时的时间为0.5ms
//由0.5ms = 500us  500/1.08 = 460
// X = (65536-460)
void Timer1_Init()
{
    TMOD = 0x10;
    TH1 = (65536-460)/256;
    TL1 = (65536-460)%256;
    EA = 1;
    ET1 = 1;
    TR1 = 1;
}

void do_Timer1() interrupt 3
{
    P1_7 = !P1_7;
    TH1 = (65536-460)/256;
    TL1 = (65536-460)%256;
}

void main()
{
    P1_7 = 0;
    Timer1_Init();
    while(1);
}

测量脉冲宽度——门控位GATEx的应用(非重点)

在这里插入图片描述

#include <reg51.h>
unsigned count_high; // 读取TH0 
unsigned count_low; // 读取TL0
//最后INT1的正脉冲宽度以机器周期数的形式读入到上面俩变量中
//正脉冲是一个周期信号中高电平的信号
void read_count()
{
    do
    {
        count_high = TH1;
        count_low = TL1;
        ...//可进行显示或其他处理
    }while(count_high!=TH1)
}

void main()
{
    TMOD = 0x90; // 1001 0000
    //需要注意的是:当单片机的GATE为1的时候,如果要打开定时器,除了TR1=1以外还需要INT1=1才可以真正开启定时器
    TH1 = 0;
    TL1 = 0;
    TR1 = 1;
    while(P3_3 == 1); //等待P3_3为低电平
    TR1 = 1; //P3_3为低电平的时候,TR1=1,但是此时定时器并未被真正开启,还需要INT1=1
    while(P3_3 == 0);//等待P3_3为高电平
    while(P3_3 == 1); //P3_3为高电平后,真正打开定时器,开始计数
    TR1 = 0;
    //读取函数
    read_count();
}

串口 方式0输出输入(非重点)

例题

在这里插入图片描述

#include <reg51.h>
#include <stdio.h>
unsigned char nIndex;
unsigned char nSendByte;

void Delay()
{
    static int i = 100;
    static int j = 0;
    while(i--)
    {
        for(j=0;j<120;j++);
    }
}

void Serial_Init()
{
    SCON = 0x00; // 串口为方式0
    EA = 1;
    ES = 1; // 开启串口中断
}

void dp_Serial() interrupt 4
{
    if(TI == 1) //发送中断标志位
    {
     	P1_0 = 1;
        Delay();
        P1_0 = 0;
        nSendByte << 1;
        if(nSendByte == 0)
        {
            nSendByte = 1;
        }
        SBUF = nSendByte;
    }
    TI = 0;
    RI = 0;
}

void main()
{
    Serial_Init();
    nIndex = 1;
    SBUF = nSendByte;
    P1_0 = 0; //使能位
    while(1);
}

在这里插入图片描述

#include <reg51.h>
unsigned char nRxData;

void Serial_Init()
{
    SCON = 0x00;
    EA = 1;
    ES = 1;
}

void do_Serial() interrupt 4
{
    if(RI == 1) //接收到了数据
    {
        nRxData = SBUF;
    }
    TI = 0;
    RI = 0;
}

void main()
{
    while(1)
    {
        if(P1_0 == 0)
        {
            P1_1 = 0;
            P1_1 = 1;
        }
    }
}

方式1的应用

在这里插入图片描述

#include <reg51.h>
//甲机发送程序
unsigned char temp;

void Serial_Init()
{
    PCON = 0x00; // 波特率不倍增
    SCON = 0x40; // 0100 0000 SM2位只能在方式二和方式三多机通信
    //串口的方式一专门是为了双机通信设置的
    TMOD = 0x20;// 0010 0000
    TH1 = 0xFD;
    TL1 = 0xFD; // 波特率9600
    TR1 = 1;
    P1 = 0xFF; //P1口输入的时候,需要拉高电平
}

void main()
{
    while(1)
    {
        temp = P1;
        SUBF = temp;
        //查询方式,无需申请中断
        while(TI == 0); //TI = 1 说明一帧数据发送完毕
        TI = 0;
    }
}

//乙机接收程序
unsigned char temp;
void Serial_Init()
{
    PCON = 0x00;
    SCON = 0x50;//0101 0000
    TMOD = 0x20;//0010 0000
    TH1 = 0xFD;
    TL1 = 0xFD;
    TR1 = 1;
}

void main()
{
    while(1)
    {
        //查询方式
        while(RI == 0);
        RI = 0;
        temp = SBUF;
        P1 = temp;
    }
}

方式2和方式3的应用

在这里插入图片描述

#include <reg51.h>
sbit p = PSW_0;
//甲机发送程序
unsigned char Tab[] = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F}; //流水灯显示数据

void Delay()
{
    unsigned int i = 100;
    unsigned int j;
    while(i--)
    {
        for(j=0;j<120;j++);
    }
}

void Serial_Init()
{
    SCON = 0xC0;//1100 0000 注意这里的SM2位不需要为1
    PCON = 0x00;
    TMOD = 0x20;//0010 0000
    TH1 = 0xFD;
    TL1 = 0xFD; //波特率9600
    EA = 1;
    ES = 1;
    TR1 = 1;
}

void Send(unsigned char data)
{
    ACC = data; //把data数据暂存到ACC寄存器中
    TB8 = p; //奇偶校验位
    SBUF = data; //准备发送数据
    while(TI == 0); //等待数据发送
    TI = 0;
}

unsigned int count;
void main()
{
    Serial_Init();
    while(1)
    {
        for(count=0;count<8;count++)
        {
            Send(Tab[count]);
            Delay(); //等待一段时间再发送
        }
    }
}

//乙机接收程序
sbit p = PSW_0;

unsigned char Receive()
{
    unsigned char data;
    while(RI == 0); // 等待接收 查询方式
    RI = 0;
    ACC = SBUF;
    if(RB8 == p) //奇偶校验
    {
        data = ACC;
        return data;
    }
}

void Serial_Init()
{
    SCON = 0xD0; // 1101 0000 注意这里需要把REN位也置为1
    PCON = 0x00;
    TMOD = 0x20;
    TL0 = 0xFD;
    TH0 = 0xFD; //波特率9600
    EA = 1;
    ES = 1;
    TR1 = 1;
}

void main()
{
    while(1)
    {
        P1 = Receive();
    }
}

单片机向计算机发送数据(重点)

在这里插入图片描述

#include <reg51.h>
unsigned char Tab[] = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F}; //流水灯显示数据

void Send(unsigned char data)
{
    SBUF = data;
    while(TI == 0); // 等待单片机发送数据结束
    TI = 0;
}

void Delay()
{
    unsigned int i = 100;
    unsigned int j;
    while(i--)
    {
        for(j=0;j<120;j++);
    }
}

void Serial_Init()
{
    SCON = 0x40;//0100 0000
    PCON = 0x00;
    TMOD = 0x20;
    TH1 = 0xFD;
    TL1 = 0xFD; //波特率9600
    EA = 1;
    ES = 1;//EA和ES可以不写,因为这里用的是查询方式
    TR1 = 1;
}

unsigned int count;
void main()
{
    Serial_Init();
    while(1)
    {
        for(count=0;count<8;count++)
        {
            Send(Tab[count]);
            Delay();
        }
    }
}

单片机接收计算机发送的数据(重点)

在这里插入图片描述

#include <reg51.h>
void Serial_Init()
{
    SCON = 0x50;//0101 0000
    PCON = 0x00;
    TMOD = 0x20;
    TL1 = 0xFD;
    TH0 = 0xFD; //波特率9600
    EA = 1;
    ES = 1; //EA和ES可以不写,因为这里用的是查询方式
    TR1 = 1;
}

unsigned char Recevive()
{
    unsigned char data;
    while(RI == 0); //接收数据
    RI = 0;
    data = SBUF;
    return data;
}

void main()
{
    Serial_Init();
    while(1)
    {
        P1 = Receive();
    }
}

数码管的实现(重点)

#include <reg51.h>
unsigned char Nixie_Table[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};

void Delay(unsigned int i)
{
    unsigned int j;
    while(i--)
    {
        for(j=0;j<120;j++);
    }
}

void Nixie(unsigned location,unsigned number)
{
    switch(location)
    {
        case 1:P2_4=1;P2_3=1;P2_2=1;break;
        case 2:P2_4=1;P2_3=1;P2_2=0;break;
        case 3:P2_4=1;P2_3=0;P2_2=1;break;
        case 4:P2_4=1;P2_3=0;P2_2=0;break;
        case 5:P2_4=0;P2_3=1;P2_2=1;break;
        case 6:P2_4=0;P2_3=1;P2_2=0;break;
        case 7:P2_4=0;P2_3=0;P2_2=1;break;
        case 9:P2_4=0;P2_3=0;P2_2=0;break;
    }
    P0 = Nixie_Table[number];
    Delay(1);
    P0 = 0x00; // 消影子
}

矩阵键盘的实现(重点)

#include <reg51.h>

void Delay(unsigned int i)
{
    unsigned int j;
    while(i--)
    {
        for(j=0;j<120;j++);
    }
}

unsigned char MartrixKey()
{
    unsigned char KeyNumber;
    
    P1 = 0xFF;
    P1_3 = 0;
    if(P1_7 == 0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=1;}
    if(P1_6 == 0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=5;}
    if(P1_5 == 0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=9;}
    if(P1_4 == 0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=13;}
    
    P1 = 0xFF;
    P1_2 = 0;
    if(P1_7 == 0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=2;}
    if(P1_6 == 0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=6;}
    if(P1_5 == 0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=10;}
    if(P1_4 == 0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=14;}
    
    P1 = 0xFF;
    P1_1 = 0;
    if(P1_7 == 0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=3;}
    if(P1_6 == 0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=7;}
    if(P1_5 == 0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=11;}
    if(P1_4 == 0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=15;}
    
	P1 = 0xFF;
    P1_0 = 0;
    if(P1_7 == 0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=4;}
    if(P1_6 == 0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=8;}
    if(P1_5 == 0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=12;}
    if(P1_4 == 0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=16;}
    
    return KeyNumber;
}

DAC0832输出锯齿波

在这里插入图片描述

#include <reg51.h>
#include <absacc.h>
#define DAC0832 XBYTE[0x7FFF]

void stair()
{
    unsigned char i;
    for(i=0;i<255;i++)
    {
        DAC0832 = i;
    }
}

DAC0832输出三角波

在这里插入图片描述

#include <reg51.h>
#include <absacc.h>
#define DAC0832 XBYTE[0x7FFF]

void triangle()
{
    unsigned char i;
    for(i=0;i<255;i++)
    {
        DAC0832 = i; //上升沿
    }
    for(i=255;i>0;i--)
    {
        DAC0832 = i; // 下降沿
    }
}

DAC0832输出矩形波

在这里插入图片描述

#include <reg51.h>
#include <absacc.h>
#define DAC0832 XBYTE[0x7FFF]

void rectangular()
{
    DAC0832 = 0xAF; //上限电平
    Delay();
    DAC0832 = 0x10; //下限电平
    Delay()
}

ADC转换

在这里插入图片描述

#include <reg51.h>
#include <absacc.h>
#define ADCstart 0x7FFF
#define ADCdata 0x2000

unsigned char i;
void main()
{
    i = 8; //8路模拟信号
    EA = 1;
    EX1 = 1;
    IT1 = 1;
    XBYTE[ADCstart] = i;
    while(i);
}

void int1() interrupt 2
{
    unsigned char temp;
    temp = XBYTE[ADCstart];
    i--;
    XBYTE[ADCdata+i] = temp;
    XBYTE[ADCstart] = i;
}
文章来源:https://blog.csdn.net/EchoToMe/article/details/135704099
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。