• 51单片机自学报告--实验部分


    微机接口技术-自主学习笔记

    PPT链接:微机接口自学--51单片机自学汇报PPT_猫猫爱吃小鱼的博客-CSDN博客

    效果演示gif:

     

     

     

     

    四、Proteus仿真

    仿真环境:电路仿真软件:                       Proteus

                      HEX可执行文件编写软件:    keil uVision4

    keil uVision4新建项目简略步骤:

    1. new project,选择使用的芯片(例:AT89C51,AT89C52)。
    2. 创建main.c(或.asm),并添加进project。
    3. 选择生成 HEX 文件 ,因为单片机执行的时候,是通过执行 HEX 文件来执行的。
    4. 添加HEX文件,即可运行

    图13 步骤1

     

    图14 步骤2

    图15 步骤3

    可用芯片:AT89C51,AT89C52等,它们的区别如下所示:

    (1)、RAM 空间增大:AT89C51 有128 字节的内部 RAM,称之为 DATA 存储区。AT89C52 的内部 RAM 扩展为 256 字节,其中高 128 字节,位于从 80H 开始的地址空间中,称之为 IDATA 存储区,但IDATA 区的访问只能是间接寻址方式。
        (2)、内部 FLASH 变大:AT89C51 有 4K 字节的内部 FLASH PERAM,而。AT89C52 的内部 FLASH PERAM 增加1倍,达到8K。
        (3)、中断源增加:在AT89C52 中P1.0和P1.1还可分别作为定时器/计数器2的外部计数输入(P1.0/T2)和(P1.1/T2EX),也就是说,P1.0同时可作为定时器/计数器 T2 的外部计数输入,和输出占空比 50% 的时钟脉冲端口,P1.1同时可作为定时器/计数器 T2 捕获/重新装载触发和方向控制端口。故,AT89C52 除了具备 AT89C51 的定时器/计数器 T0 和定时器/计数器 T1,还额外增加了一个定时器/计数器 T2。而定时器/计数器 T2 的控制和状态位单独位于T2CON、T2MOD,定时器/计数器 T2 在 16 位捕获方式或自动重新装载方式下的捕获/重载寄存器组是(TCAO2H、RCAP2L)。

    4.1 简单LED灯的控制

    这是一个简单来理解51单片机定时和计数的例子。

    (1)先来介绍定时功能,当作为定时使用时,配置步骤:模式设置,配置TMOD寄存器;定时器初值设置 假设10ms中断;开定时器中断;开总中断;打开定时器。流程图如下图所示:

     

    图16 定时器中断方式计时流程图

    仿真电路图绘制如下图所示,实现每一秒点亮LED一次:

    所含电路元器件:单片机AT89C51(频率12M),LED灯,电阻,电容,电源和地等(CRYSTAL和电容组成不可编程模块,可不添加)

     图17 定时点亮LED仿真电路

    LED-RED接引脚P1.0,程序中需要这样配置:

    sbit led=P1^0;

    采用的是定时器0,16位定时器/计数器工作模式(工作与式1),参照图 TMOD格式

     图18 TMOD格式

    程序中需要这样配置:

    TMOD=0X01;

     因为:1s=50ms*20,对于12M的晶振单片机,12MHz除12为1MHz,也就是说一秒=1000000次机器周期,50ms=50000次机器周期;所以计数值为50000,每中断20次,则点亮LED灯。

    TH0=(65536-50000)/256;

    TL0=(65536-50000)%256;

    ........

    //中断服务子程序

    void time0() interrupt 1 {

    TH0=(65536-50000)/256;      //重装初值

    TL0=(65536-50000)%256;

    a++;

    }

    a每加到20,则点亮LED灯,同时置0,需要注意每次触发中断后,都需要重新装入初值。

     图19 LED点亮

    (2)定时计数器作为计数器使用,配置步骤如下:

    1.模式设置,配置TMOD寄存器。

    2.开计数器中断

    3.开总中断

    4.打开计数器

    注意: 计数器可以不开中断,这样溢出时只是不会进去中断服务程序。

    仿真电路图绘制如下图所示,实现每按五次按键(P3.4引脚)点亮LED一次:

     

    图20 计数方式点亮LED灯

    LED灯接法和定时方式下一样,但是TMOD寄存器配置不一样了,本设计中TMOD的D2位C/T为设为1,选择计数功能:

    sbit led=P1^0;

     sbit s=P3^4;

    TMOD=0x05; //模式设置,00000101,采用的是计数器0,工作模式1

    比较定时方式下的电路,在这边的P3.4/T0口接了一个简单的开关电路,对P3.4口进行下降沿的脉冲计数。因为TR0:T0充许计数控制位,为1时充许T0计数(定时),所以初始化时需要将 TR0置1。

     TR0=1;    

    本次的设计是用count存储计数值,到了5次,则人为让计数器进入中断,使得TH0和TL0溢出,进行中断处理。

       count=(TH0<<8)|TL0;

            if((count*10000)==50000)//按5下按键led状态取反  

                {

                    led=0;

                    TH0=0XFF;

                    TL0=0XFF; //人为的让计数器进入中断

                }

    中断服务程序中,使LED灯亮。

     图21  LED灯点亮

    4.2 流水灯控制(定时器中断控制的独立式键盘扫描)

    使用定时器中断控制获得按键值,实现按下S1,D8-D1循环点亮;按下S2,D1-D8循环点亮;按下S3,全部熄灭;按下S4,D1-D8同频率闪烁。仿真电路图设计如下:

     图22 按键控制流水灯方式

    D1-D8接AT89C51的P3口,按键电路接P1口。

    设计要点如下:

    1.考虑到实际电路中按键的不稳定性,需要对按键进行消抖设计。

    2.计数初值的选择,检测按键需要迅速。

    3.LED需要一定的延时,不然看不到灯亮。

    4.LED点亮方式P3由口的值进行控制。

    基于以上的设计要点,消抖设计的时间为20ms,每次检测到有按键按下时,都先进行消抖延时:

    void delay20ms(void)

    { unsigned char i,j;

    for(i=0;i<100;i++)

    for(j=0;j<60;j++);

    }

    计数初值选择1000,检测的比较迅速。P3口直接改变值,再适当延长时间来控制LED灯的流水状况。

    P3=0xfe;         //第一个灯亮

    led_delay();

    P3=0xfd;          //第二个灯亮

    led_delay();

    P3=0xfb;          //第三个灯亮

    led_delay();

    P3=0xf7;          //第四个灯亮

    led_delay();

    P3=0xef;          //第五个灯亮

    led_delay();

    P3=0xdf;          //第六个灯亮

    led_delay();

    P3=0xbf;          //第七个灯亮

    led_delay();

    P3=0x7f;          //第八个灯亮

    led_delay();  

    运行结果如下图所示(左上为S1方式,右上为S2方式,左下为S3方式,右下为S4方式):

     

    图23 流水灯结果

    4.3 液晶时钟设计

    基于51单片机实现计时(24小时制),并显示在LCD1602屏幕上。先来简单介绍下LCD1602液晶显示屏。

    LCD1602液晶显示器是广泛使用的一种字符型液晶显示模块。它是由字符型液晶显示屏(LCD)、控制驱动主电路HD44780及其扩展驱动电路HD44100,以及少量电阻、电容元件和结构件等装配在PCB板上而组成。它的引脚说明如下表所示:

    表4 LCD引脚说明

    编号

    符号

    引脚说明

    标号

    符号

    引脚说明

    1

    VSS

    电源地

    9

    D2|

    数据

    2

    VDD

    电源正极

    10

    D3

    数据

    3

    VL

    液晶显示偏压

    11

    D4

    数据

    4

    RS

    数据/命令选择

    12

    D5

    数据

    5

    R/W

    读/写选择

    13

    D6

    数据

    6

    E

    使能信号

    14

    D7

    数据

    7

    D0

    数据

    15

    BLA

    背光源正极

    8

    D1

    数据

    16

    BLK

    背光源负极

    引脚的具体功能不再进行展开,简单地介绍下我们本次设计中用到的几个指令(具体指令设计不再阐述):

    表5 LCD指令

    序号

    指令

    RS

    R/W

    D7

    D6

    D5

    D4

    D3

    D2

    D1

    D0

    1

    清屏

    0

    0

    0

    0

    0

    0

    0

    0

    0

    1

    2

    初始化

    0

    0

    0

    0

    1

    1

    1

    0

    0

    0

    3

    开显示,无光标,不闪烁

    0

    0

    0

    0

    0

    0

    1

    1

    0

    0

    4

    光标右移,字符不移

    0

    0

    0

    0

    0

    0

    0

    1

    1

    0

    仿真电路图设计如下图:

    图24 液晶时钟仿真设计图

     

    LCD1602的D0-D7连接AT89C52的P0端口,将RS位,定义为P2.0引脚,将RW位定义为P2.1引脚,将E位定义为P2.2引脚,将BF(忙碌标志位)位定义为P0.7引脚。

    BF是忙碌标志位,每次写数据前都需检查显示屏是否忙碌,端口为1,则是忙碌,等待。为0则空闲,直接写数据。读时需注意:RS为低电平,RW为高电平时,可以读状态,即RS=0,RW=1,E=1

    才允许读写。读完BF,将E恢复低电平,使E=0;    

    LCD的初始化如下:

    WriteInstruction(0x38); //确保初始化成功

    delay(5);

    WriteInstruction(0x0c);  //显示模式设置:显示开,无光标,光标不闪烁

    delay(5);

    WriteInstruction(0x06);  //显示模式设置:光标右移,字符不移

    delay(5);

    WriteInstruction(0x01);  //清屏幕指令,将以前的显示内容清除

    delay(5);

    将字符写进LCD中时,需要指定字符的位置,我们需要写两个函数,先指定位置,再写数据。

    指定字符的实际地址函数为:

     void WriteAddress(unsigned char x)

     {

         WriteInstruction(x|0x80); //显示位置的确定方法规定为"80H+地址码x"

     }

    写数据时,RS为高电平,RW为低电平时,可以写入数据, 即RS=1,RW=0,E从0到1发生正跳变,将数据送入P0口,即将数据写入液晶模块,当E由高电平跳变成低电平时,液晶模块开始执行命令。

    时间采用24小时制,控制程序就是中断服务程序,如下所示:

         count++;  //每产生1次中断,中断累计次数加1

    if(count==20)  //如果中断次数计满20次

    {count=0;  //中断累计次数清0

       s++;  }    //秒加1

    if(s==60)   //如果计满60秒

    {s=0;     //秒清0

       m++;    }    //分钟加1

    if(m==60)    //如果计满60分

     { m=0;   //分钟清0

    h++;    //小时加1

        }

    if(h==24)  //如果计满24小时

      { h=0;   //小时清0

       }

    计数器的初值:

    TH0=(65536-46083)/256;   //定时器T0高8位重新赋初值

    TL0=(65536-46083)%256;   //定时器T0低8位重新赋初值

    因为晶振为11.059Mhz,11.0592MHz除12为921600Hz,就是一秒921600次机器周期,10ms=9216次机器周期。所以1s=20*50ms,而50ms=46083,所以计数初值为46083,可以实现比较精确的秒计时。

    写时分秒分别写一个函数,时的函数如下:

    void DisplayHour()

    {

       unsigned char i,j;

    i=h/10;                //取整运算,求得十位数字

    j=h%10;                //取余运算,求得各位数字

       WriteAddress(0x44);   //写显示地址,将十位数字显示在第2行第5列

    WriteData(digit[i]);  //将十位数字的字符常量写入LCD

    WriteData(digit[j]);  //将个位数字的字符常量写入LCD

         

     }

    分和秒的类似,只是写的地址不同(在屏幕上显示的位置不同),不在具体阐述。

    结果如下图所示:

     图25 液晶时钟

    和精确时钟进行对比,还是很精准的。短时间内没有任何问题。如果想改开始时间,则可以直接在源程序中改,加日期也是一样的道理。

  • 相关阅读:
    GPT转换工具:轻松将MBR转换为GPT磁盘
    H12-831题库(华为HCIP认证题库)
    SmartDialog迁移至4.0:一份真诚的迁移说明
    vue中provide和inject的使用
    数据库、计算机网络,操作系统刷题笔记3
    Find My手机保护壳|苹果Find My与手机保护壳结合,智能防丢,全球定位
    cloudenative1-2: go语言特性
    宠物社区系统宠物领养小程序,宠物救助小程序系统多少钱?
    【Python5】光模块瓦数和温度,tlv,
    Jwt隐藏大坑,通过源码揭秘
  • 原文地址:https://blog.csdn.net/cangzhexingxing/article/details/125421279