Proteus仿真及应用——51单片机系列

Proteus简单操作

  • 1. 绘制最小系统
  • 2. 流水灯
  • 3. 实现流水灯的通用方法
  • 4.数码管显示
    • 4.1静态显示:每个数码管与一组I/O口相连,全部亮。
    • 4.2动态显示:段选线由==一组==I/O口相连,位码线由==一根==I/O口相连,逐个显示。
  • 5. 独立按键
  • 6. 矩阵键盘
  • 7. 定时器
    • 一、定时/计数器的方式寄存器TMOD
    • 二、定时器/计数器的控制寄存器TCON
    • 三、工作方式
      • 1.方式0 13位
      • 2.方式1 16位
      • 3.方式2 8位自动重置定时/计数器
      • 4.方式3 8位定时/计数器(只有配置T0才能使用)
  • 8.计数器
  • 9. 中断原理和外部中断的实现
  • 10.串口通信
  • 11. LCD1602的应用
  • 12.简易时钟的实现
  • 13.点阵
  • 14.DA转换及波形实现
  • 15.AD转换原理:数字电压表
  • 16.直流电机
  • 17.步进电机
  • 18.DS1302的控制

1. 绘制最小系统

Proteus仿真及应用——51单片机系列_第1张图片

2. 流水灯

电阻:RES
LED:LED-BIBY
电源:Power
Proteus仿真及应用——51单片机系列_第2张图片

/*
	时间:2021/2/14
	C语言实现流水灯
*/
# include "reg51.h"

sbit LED0 = P2^0;

void delay(unsigned int n)
{
    unsigned int i, j;
    for (i=0; i<n; i++)
    {
        for (j=0; j<120; j++);
    }
}

void led()
{
    int i = 0;
    for (i=0; i<8; i++)
    {
        P2 = ~(0x01<<i);
        delay(500);
    }
}

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

}

3. 实现流水灯的通用方法

// 数组方式显示流水灯效果

# include "reg51.h"
// 定义数组
unsigned char leds[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

void delay(unsigned int n)
{
    unsigned int i, j;
    for (i=0; i<n; i++)
    {
        for (j=0; j<120; j++);
    }
}

void led()
{
    int i;
    for (i=0; i<8; i++)
    {
        P2 = ~leds[i];
        delay(100);
    } 
}

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


4.数码管显示

4.1静态显示:每个数码管与一组I/O口相连,全部亮。

4.2动态显示:段选线由一组I/O口相连,位码线由一根I/O口相连,逐个显示。

数码管:7seg

  • 地线在下面的为共阴
    Proteus仿真及应用——51单片机系列_第3张图片
// 数码管静态共阴显示0-9 

# include "reg51.h"

unsigned char s[] = {0X3F, 0X06, 0X5B, 0X4F, 0X66, 0X6D, 0X7D, 0X07, 0X7F, 0X6F};     // 共阴0-9
/*                    {0X77, 0X7C, 0X39, 0X5E, 0X79, 0X71, 0X73, 0X3E, 0X31, 0X6E,}
                      {0X38, 0X00}
静态显示字符0-9 A-F P U T Y L “灭”  */

void delay(unsigned char n)
{
    unsigned char i, j;

    for (i=0; i<n; i++)
    {
        for (j=0; j<120; j++);
    }
}

void smg()
{
    int i = 0;

    for (i=0; i<10; i++)
    {
        P2 = s[i];
        delay(1000);
    }
}

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

Proteus仿真及应用——51单片机系列_第4张图片

// 74LS138译码器和单片机结合使用动态显示HELLO

# include "reg51.h"

unsigned char s[] = {0X76, 0X79, 0X38, 0X38, 0X3F};     // 共阴HELLO
unsigned char sbi[] = {0X00, 0X01, 0X02, 0X03, 0X04, 0X05, 0X06, 0X07};
/*                    {0X77, 0X7C, 0X39, 0X5E, 0X79, 0X71, 0X73, 0X3E, 0X31, 0X6E,}
                      {0X38, 0X00}
静态显示字符0-9 A-F P U T Y L “灭”  */

void delay(unsigned char n)
{
    unsigned char i, j;

    for (i=0; i<n; i++)
    {
        for (j=0; j<120; j++);
    }
}

void smg()
{
    int i = 0;

    for (i=0; i<5; i++)
    {
        P3 = sbi[i];
        P2 = s[i];
        delay(10);
    }
}

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

5. 独立按键

独立按键:button

Proteus仿真及应用——51单片机系列_第5张图片

// 独立按键的实现方法

# include "reg51.h"

sbit key0 = P1^0;
unsigned char s[] = {0X3F, 0X06, 0X5B, 0X4F, 0X66, 0X6D, 0X7D, 0X07, 0X7F, 0X6F};     // 共阴0-9
unsigned char num = 0;
unsigned char flag = 0;

/*
void delay(unsigned int n)          // 与方法一连用 方法二利用标志位的方法不需要延迟函数
{
    unsigned int i,j;

    for (i=0; i

void key()
{
// 软件消抖方法一:延迟函数
/*   if (key0 == 0)
   {
        delay(200);
        if (key0 == 0)
        {
            num++;
        }
   } 
*/

// 软件消抖方法二:标志位
    if (key0 == 0 && flag == 0)
    {
        flag = 1;
    }

    if (flag == 1 && key0 == 1)
    {
        num++;
        flag = 0;
    }
}

void seg()
{
    P2 = s[num];
    if (num == 10)
    {
        num = 0;
    }
}

void main()
{
    while(1)
    {
        key();
        seg();
    }
}

6. 矩阵键盘

Proteus仿真及应用——51单片机系列_第6张图片

/*
    2021-2-25
    矩阵键盘的实现
*/
# include "reg51.h"

unsigned char num = 99;
unsigned char s[] = {0X3F, 0X06, 0X5B, 0X4F, 0X66, 0X6D, 0X7D, 0X07, 0X7F, 0X6F};     // 共阴0-9

void delay(unsigned int n)
{
    unsigned int i, j;
    for (i=0; i<n; i++)
    {
        for (j=0; j<120; j++);
    }
}

void key_scan()
{
    unsigned char temp = 0,temp0 = 0,temp1 = 0;
    P1 = 0xf0;
    /*----------------检测按键是否按下----------------*/
    if (P1 != 0xf0)     // 
    {
        delay(200);
        temp0 = P1;
        P1 = 0x0f;
        if (P1 != 0x0f)
        {
            temp1 = P1;
        }
    }
    /*-----------------检测按键的值-------------------*/
   temp = temp0 + temp1;
   if  (temp == 0xee)
   {
        num = 0;
   }
   if   (temp == 0xed)
   {
        num = 1;
   }
    
}

void display()
{
    P2 = s[num];
}

void main()
{
    while(1)
    {
        key_scan();
        display();
    }

}

7. 定时器

一、定时/计数器的方式寄存器TMOD

主要的是:工作方式1

二、定时器/计数器的控制寄存器TCON

三、工作方式

1.方式0 13位

X = 8192 - N/(12/fosc) (计数值N 和 初值X)
上次计数值为0,要重复计数需要重置初值

2.方式1 16位

X = 65536 - N /(12/fosc)
上次计数值为0,要重复计数需要重置初值

3.方式2 8位自动重置定时/计数器

4.方式3 8位定时/计数器(只有配置T0才能使用)

计数值与初值的关系都为:X = 256-N/(12/fosc)
计数器自动配置初值,不需要用户重置。

Proteus仿真及应用——51单片机系列_第7张图片

// 定时器

# include "reg51.h"
unsigned char s[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f};
unsigned char count = 0, num = 0;

void inittimer()
{
    TMOD = 0x01;    // 0000 0001
    TH0 = (65536 - 50000) / 256;  // 50ms = 50000us    初值 >> 8
    TL0 = (65536 - 50000) % 256;
    ET0 = 1; // 开启定时器0的总中断
    EA = 1; // 开启总中断
    TR0 = 1; //启动定时器0
}
void display()
{
    P2 = s[num];
    if (num == 10)
    {
        num = 0;
    }
}

void timer_isr() interrupt   1                       // 0表示外部中断0; 1表示定时器中断0; 2表示外部中断1;3表示定时器中断1;4表示串口中断
{
    TH0 = (65536 - 50000) / 256;  // 50ms = 50000us    初值 >> 8
    TL0 = (65536 - 50000) % 256;    
    count++;
    if (count == 20)    // 定时1s
    {
        num++;
        count = 0;
    }

}
void main()
{
    inittimer();
    while(1)
    {
        display();
    }
}

8.计数器

C/T 端赋值为1,计数方式:X = 2^(位) - N

Proteus仿真及应用——51单片机系列_第8张图片

// 8位重置计数器

# include "reg51.h"
unsigned char s[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f};
unsigned char num = 0;

void initcounter()
{
    TMOD = 0X06;   // 0000 0110 8位自动重置
    TH0 = 256 - 3;
    TL0 = 256 - 3;
    ET0 = 1;
    EA = 1;
    TR0 = 1;
}

void display()
{
    P2 = s[num];
    if (num == 10)
    {
        num = 0;
    }
}

void counter_isr() interrupt  1
{
    num++;
}

void main()
{
    initcounter();
    while(1)
    {
       display();
    }
}

9. 中断原理和外部中断的实现

// 外部中断

# include "reg51.h"
unsigned char s[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f};
unsigned char num = 0;
sbit ex = P3^2;

void initex()
{
    IT0 = 1;
    EX0 = 1;
    EA = 1;
    ex = 1;
}

void display()
{
    P2 = s[num];
    if (num == 10)
    {
        num = 0;
    }
}

void ex_isr() interrupt 0
{
    num++;
}

void main()
{
    initex();
    while(1)
    {
        display();
    }
}

10.串口通信

Proteus仿真及应用——51单片机系列_第9张图片

// 串口通信

# include "reg51.h"
unsigned char recdat = 0, flag = 0;

void initscon()
{
    SCON = 0X50; // 0101 0000
    TMOD = 0X20; // 0010 0000
    TH1 = 256 - 3;
    TL1 = 256 - 3;
    ES = 1;
    EA = 1;
    TR1 = 1;
}

void scon_isr() interrupt 4     // 串口中断
{
    recdat = SBUF;
    RI = 0;
    flag = 1;                    
}

void senddat()
{
    SBUF = recdat;
    while(!TI);
    TI = 0;
}

void main()
{
    initscon();
    while(1)
    {
        if (flag == 1)
        {
            senddat();
            flag = 0;
        }
    }
}

11. LCD1602的应用


  • LCD1602常用的指令码:
  • 0X38:设置16 * 2 显示,5*7点阵, 8位数据接口
  • 0X0C:设置开显示,不显示光标
  • 0X06:写一个字符后地址指针加1
  • 0X01: 显示清0,数据指针清0
  • 0X80:LCD第一行的起始地址
  • 0X80+0X40:LCD第二行的起始地址

Proteus仿真及应用——51单片机系列_第10张图片

// LCD 显示

# include "reg51.h"
sbit RS = P3^0;
sbit RW = P3^1;
sbit E = P3^2;
unsigned char str[] = {"zero-money"};

void delay(unsigned char n)
{
    unsigned int i = 0, j = 0; 

    for (i=0; i<n; i++)
    {
        for (j=0; j<120; j++);
    }
}

// 写命令
void writecom(unsigned char com)
{
    RS = 0;
    RW = 0;
    E = 0;
    P2 = com;
    delay(5);      // 延时根据实际效果判断
    E = 1;
    E = 0;
}

// 写数据
void writedate(unsigned char date)
{
    RS = 1;
    RW = 0;
    E = 0;
    P2 = date;
    delay(5);
    E = 1;
    E = 0;
}

// 初始化
void initlcd()
{
    writecom(0x38);
    writecom(0x0c);
    writecom(0x06);
    writecom(0x01);
}

void display()
{
    unsigned int i = 0;

    writecom(0x80 + 3);     // 第二行中间显示:0x80 + 3 + 0x40
    delay(5);
    /* 单个字符显示
    writedate('Z');
    delay(5);  
    writedate('e');
    delay(5);
    writedate('r');
    delay(5);
    writedate('o');
    delay(5);
    */
    // 字符串显示
    while (str[i] != '\0')
    {
        writedate (str[i]);
        delay(5);
        i++;
    }         
}

void main()
{
    initlcd();
    while(1)
    {
        display();
    }
}

12.简易时钟的实现

Proteus仿真及应用——51单片机系列_第11张图片

// 简易时钟

# include "reg51.h"
sbit RS = P3^0;
sbit RW = P3^1;
sbit E = P3^2;
unsigned char count = 0;
unsigned int hour = 9, min = 31, sec = 0;
unsigned char str[] = {"0123456789"};
unsigned char str1[] = {"Zero-Money's CLK"};

void delay(unsigned char n)
{
    unsigned int i = 0, j = 0; 

    for (i=0; i<n; i++)
    {
        for (j=0; j<120; j++);
    }
}

// 写命令
void writecom(unsigned char com)
{
    RS = 0;
    RW = 0;
    E = 0;
    P2 = com;
    delay(5);      // 延时根据实际效果判断
    E = 1;
    E = 0;
}

// 写数据
void writedate(unsigned char date)
{
    RS = 1;
    RW = 0;
    E = 0;
    P2 = date;
    delay(5);
    E = 1;
    E = 0;
}

// 初始化
void initlcd()
{
    writecom(0x38);
    writecom(0x0c);
    writecom(0x06);
    writecom(0x01);
}

void display()
{
    unsigned char temp0 = 0, temp1 = 0, temp2 = 0, temp3 = 0, temp4 = 0, temp5 = 0;
    unsigned char i = 0;
    temp0 = hour / 10;
    temp1 = hour % 10;
    temp2 = min / 10;
    temp3 = min % 10;
    temp4 = sec / 10;
    temp5 = sec % 10;
    writecom(0X80);
    delay(5);
    while(str1[i] != '\0')
    {
        writedate(str1[i]);
        delay(5);
        i++;
    }
    writecom(0X80 + 0X40 + 4);
    delay(5);
    writedate(str[temp0]);
    delay(5);    
    writedate(str[temp1]);
    delay(5);
    writedate(':');
    delay(5);
    writedate(str[temp2]);
    delay(5);
    writedate(str[temp3]);
    delay(5);
    writedate(':');
    delay(5);
    writedate(str[temp4]);
    delay(5);
    writedate(str[temp5]);
    delay(5);    
}

void inittimer()
{
    TMOD = 0x01;
    TH0 = (65536-50000)/256;     // 50ms
    TL0 = (65536-50000)%256;
    ET0 = 1;
    EA = 1;
    TR0 = 1;
}

void timer0_isr() interrupt 1
{
    TH0 = (65536-50000)/256;     // 50ms
    TL0 = (65536-50000)%256;
    count++;
    if (count == 20)    // 1s
    {
        sec = sec + 1;
        count = 0;
    }
    if (sec == 60)
    {
        min = min + 1;
        sec = 0;
    }
    if (min == 60)
    {
        hour = hour + 1;
        min = 0;
    }
    if (hour == 24)
    {
        hour = 0;
    }
}

void main()
{
    initlcd();
    inittimer();
    while(1)
    {
        display();
    }
}

13.点阵

Proteus仿真及应用——51单片机系列_第12张图片

// 点阵的显示

# include "reg51.h"
unsigned char code tab[] = { 0x00, 0x7e, 0xff, 0xc3, 0xc3, 0xff, 0x7e, 0x00,   // 0
                             0x00, 0x00, 0x43, 0xff, 0xff, 0x03, 0x00, 0x00,   // 1
                             0x00, 0x63, 0xc7, 0xcf, 0xdb, 0xf3, 0x63, 0x00,   // 2
                             0x00, 0x42, 0xdb, 0xdb, 0xdb, 0xff, 0x66, 0x00,   // 3
                             0x00, 0x3e, 0x46, 0xff, 0xff, 0x06, 0x06, 0x00,   // 4
                           };     
unsigned char row[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
unsigned char num = 0, flag = 0;
sbit key0 = P1^0;

void key()
{
    if (flag == 0 && key0 == 0)
    {
        flag = 1;
    }
    if (flag == 1 && key0 == 1)
    {
        num++;
        flag = 0;
    }
    if (num == 5)
    {
        num = 0;
    }
}

void matrix()
{
    unsigned int i = 0;

    for (i=8*num; i<8*(num+1); i++)      // 
    { 
        P3 = ~row[i-8*num];
        P2 = tab[i];
    }
}

void main()
{
    while(1)
    {
        matrix();
        key();  
    }
}

14.DA转换及波形实现

Proteus仿真及应用——51单片机系列_第13张图片

// DA转换及相关波形

# include "reg51.h"
unsigned int value = 100, flag = 0;
sbit key0 = P1^0;
sbit key1 = P1^1;

void key()
{
    if (key0 == 0 && flag == 0)
    {
        flag = 1;
    }
    if (flag == 1 && key0 == 1)
    {
        value += 10;
        flag = 0;
    }

    if (key1 == 0 && flag == 0)
    {
        flag = 1;
    }
    if (flag == 1 && key1 == 1)
    {
        value -= 10;
        flag = 0;
    }
}
void delay(unsigned int n)
{
    int i=0, j=0;
    for (i=0; i<n; i++)
    {
        for (j=0; j<120; j++);
    }
}
/*  pwm波形
void PWM()
{
    P2 = 0;
    delay(100);         // 占空比变化的方法一: 改变延迟时间
    P2 = 255;
    delay(value);

}
*/
void stair()
{
    int i = 0;
    for (i=0; i<255; i++)
    {
        P2 = i;
    }
    for (i=255; i<0; i--)
    {
        P2 = i;
    }
}

void main()
{
    while(1)
    {
        // PWM();
        stair(); // 锯齿波
        key();
    }
}

15.AD转换原理:数字电压表

Proteus仿真及应用——51单片机系列_第14张图片

// 数字电压表

# include "reg51.h"
sbit st = P3^0;
sbit eoc = P3^1;
sbit oe = P3^2;
sbit RS = P3^3;
sbit RW = P3^4;
sbit E = P3^5;
unsigned int vol = 0;
unsigned char t[] = {"012346789"};
unsigned char str[] = {"VOLTAGE: "};

void delay(unsigned char n)
{
    unsigned int i = 0, j = 0;
    for (i=0; i<n; i++)
    {
        for (j=0; j<120; j++);
    }
}

// 写数据
void writedate(unsigned int date)
{
    RS = 1;
    RW = 0;
    E = 0;
    P1 = date;
    delay(5);
    E = 1;
    E = 0;
}

// 写命令
void writecom(unsigned char com)
{
    RS = 0;
    RW = 0;
    E = 0;
    P1 = com;
    delay(5);      // 延时根据实际效果判断
    E = 1;
    E = 0;
}

// 初始化
void initlcd()
{
    writecom(0x38);
    writecom(0x0c);
    writecom(0x06);
    writecom(0x01);
}

void adc()
{
    // 开启START
    st = 0;
    st = 1;
    delay(5);
    st = 0;
    while (eoc != 1);
    oe = 1;
    vol = P2;
    oe = 0; 
}                  

void display()
{
    unsigned char temp0 = 0, temp1 = 0, temp2 = 0;
    int i = 0;

    vol = vol * 100 / 51;
    temp0 = vol/100;
    temp1 = (vol%100)/10;
    temp2 = vol%10;

    writecom(0x80);
    delay(5);
    for(i=0; i<8; i++)
    {
        writedate(str[i]);
        delay(5);
    }
    writecom(0x80 + 0x40 + 4);
    delay(5);
    writedate(t[temp0]);
    delay(5);
    writedate('.');
    delay(5);
    writedate(t[temp1]);
    delay(5);
    writedate(t[temp2]);
    delay(5); 
    writedate('V');
    delay(5);   
}

void main()
{
    initlcd();
    while(1)
    {
        adc();
        display();
    }
}

16.直流电机

  • 一、直流电机的控制:

  • 1.方向控制:直流电机只有正负极,只需交换正负极就可以调节正反转。

  • 2.转速控制:负载变化不大的时候,加在直流电动机两端的电压大小与其速度近似成正比。

  • 二、PWM技术:

  • 1.电动机的电枢绕组两端的电压平均值U为:U = (t1/T) Us = D * Us*

  • 2.D为PWM的占空比:D = t1 / T

  • 占空比:一个周期之内高电平的时间与整个周期时长之比。范围:0~1

  • 三、L293D 芯片:

  • 顺时针转动:最大转速192
    Proteus仿真及应用——51单片机系列_第15张图片

  • 占空比%50:逆时针转速-96
    Proteus仿真及应用——51单片机系列_第16张图片

// 51单片机对直流电机的控制

# include "reg51.h"
typedef unsigned int uint;
sbit IN0 = P2^0;
sbit IN1 = P2^1;
sbit E = P2^2;

//void delay(uint n)
//{
//    uint i = 0, j = 0;
//    for (i=0; i
//    {
//        for (j=0; j<120; j++);
//    }
//}

void motor()
{
    IN0 = 0;
//    IN1 = 1;
//    delay(25);
//    IN1 = 1;
//    delay(75);
    E = 1;
}

void inittimer()
{
    TMOD = 0X01;
    TH0 = (65536 - 10000)/256;
    TL0 = (65536 - 10000)%256;
    ET0 = 1;
    EA = 1;
    TR0 = 1;
    IN1 = 0;
}

void timer_isr() interrupt 1
{
    TH0 = (65536 - 10000)/256;
    TL0 = (65536 - 10000)%256;          // 占空比:%50
    IN1 = ~IN1;
}

void main()
{
    inittimer();
    while(1)
    {
        motor();
    }
}

17.步进电机

  • 驱动芯片:L298
  • 四相步进电机四步法和八步法:四步法:给ABCD引脚给控制信号:1001、1100、0110、0011步进电机顺时针转动。八步法:四步法的一半,1001、1000、1100、0100、0110、0010、0011、0001

Proteus仿真及应用——51单片机系列_第17张图片

// 步进电机

# include "reg51.h"
typedef unsigned  char uchar;
typedef unsigned  int uint;
uchar st[] = {0x09,0x08,0x0c,0x04,0x06,0x02,0x03,0x01};

void delay(uint n)
{
    uint i = 0, j = 0;
    for (i=0; i<n; i++)
    {
        for (j=0; j<120; j++);
    }
}

void stepper()
{
    int i = 0;
    for (i=7; i>0; i--)     // 反转 每次转动45°
    {
        P2 = st[i];
        delay(100);

    }    
}

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

18.DS1302的控制

  • 时钟芯片:同步串行通信方式,通信只需要:RES(复位线)、I/O(数据线)、SCLK(串行时钟)
  • 读写:低位在前,高位在后

你可能感兴趣的:(单片机)