51单片机定时器与串口通信和普中开发板实现

目录

一、利用中断发出1Khz的方波信号,驱动蜂鸣器鸣叫。

电路原理图:

代码实现:

电路仿真实现:

普中开发板实现:

用Keil查看方波:

二、LED数码管秒表的制作

电路原理图:

代码实现:

电路仿真实现:

三、使用定时器实现一个LCD显示时钟。

电路原理图:

代码实现:

普中开发板实现:

​编辑

电路仿真实验:

四、甲乙两个单片机串口通信

串行口的4种工作方式:

1.方式0

2.方式1

3.方式2

4.方式3

实验

电路仿真实现:


一、利用中断发出1Khz的方波信号,驱动蜂鸣器鸣叫。

利用T1的中断控制P1.7引脚输出频率为1kHz方波音频信号,驱动蜂鸣器发声。系统时钟为12MHz。方波音频信号周期1ms,因此T1的定时中断时间为0.5 ms,进入中断服务程序后,对P1.7求反。

首先我们计算T1初值,系统时钟为12MHz,则机器周期为1µs。1kHz音频信号周期为1ms,要定时计数的脉冲数为a。则T1初值:

TH1=(65 536 −a) /256;

TL1=(65 536 −a) %256;

电路原理图:

代码实现:

#include<reg51.h>           //包含头文件
sbit sound=P1^7;            //将sound位定义为P1.7脚
#define f1(a) (65536-a)/256     //定义装入定时器高8位时间常数
#define f2(a) (65536-a)%256         //定义装入定时器低8位时间常数
unsigned int i=500; 
unsigned int j=0; 
void main(void)
{
        EA=1;                       //开总中断.
        ET1=1;                      //允许定时器T1中断         .
        TMOD=0x10;          //TMOD=0001 000B,使用T1的方式1定时     TH1=f1(i);                  //给T1高8位赋初值.
        TL1=f2(i);                  //给T1低8位赋初值.
        TR1=1;                      //启动T1
        while(1)  
        {                           //循环等待
        i=460; 
        while(j<2000);
        j=0;
        i=360; 
        while(j<2000);
        j=0;
    }
 }
​
void T1_(void) interrupt 3 using 0  //定时器T1中断函数
{
        TR1= 0;                     //关闭T1
    sound=~sound;           //P1.7输出求反
        TH1=f1(i);              //T1的高8位重新赋初值.
        TL1=f2(i);              //T1的低8位重新赋初值.
    j++;                
        TR1=1;                  //启动定时器T1
}

电路仿真实现:

普中开发板实现:

注:普中开发板的蜂鸣器对应管脚为1.5

需将代码中sbit sound=P1^7;修改为:sbit sound=P1^5;

用Keil查看方波:

用Keil查看方波音频信号,具体添加波形图的方法可以看我前一篇博客中有提到。

二、LED数码管秒表的制作

用2位数码管显示计时时间,最小计时单位为“百毫秒”,计时范围0.1~9.9s。当第1次按一下计时功能键时,秒表开始计时并显示;第2次按一下计时功能键时,停止计时,将计时的时间值送到数码管显示;如果计时到9.9s,将重新开始从0计时;第3次按一下计时功能键,秒表清0。再次按一下计时功能键,则重复上述计时过程。

本秒表应用定时器模式,计时范围0.1~9.9s。此外还涉及如何编写控制LED数码管显示的程序。

电路原理图:

注:这里的的显示屏为7SEG-MPX1-CC

代码实现:

#include<reg51.h>           //头文件
unsigned char code discode1[]=                                              {0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};    
                                //数码管显示0~9的段码表, 带小数点
unsigned char code discode2[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};  
                                //数码管显示0~9的段码表,不带小数点
unsigned char timer=0;      //timer记录中断次数
unsigned char second;           //second储存秒
unsigned char key=0;        //key记录按键次数
​
main()              //主函数
{
     TMOD=0x01;         //定时器T0方式1定时
     ET0=1;                     //允许定时器T0中断
EA=1;                           //总中断允许
second=0;                       //设初始值
P0=discode1[second/10];         //显示秒位0
P2=discode2[second%10];         //显示0.1s位0
while(1)                 //循环
{   
    if((P3&0x80)==0x00)     //当按键被按下时
    {    
        key++;          //按键次数加1
        switch(key)     //根据按键次数分三种情况
        {
            case 1:     //第一次按下为启动秒表计时
            TH0=0xee;   //向TH0写入初值的高8位
TL0=0x00;       //向TL0写入初值的低8位,定时5ms
    TR0=1;              //启动定时器T0
    break;
    case 2:             //按下两次暂定秒表
    TR0=0;              //关闭定时器T0
    break;
    case 3:                 //按下3次秒表清0
    key=0;                  //按键次数清
    second=0;               //秒表清0
    P0=discode1[second/10];     //显示秒位0                 P2=discode2[second%10];     //显示0.1s位0
    break;
}
while((P3&0x80)==0x00);             //如果按键时间过长在此循环
}
}
}
void int_T0() interrupt 1  using 0      //定时器T0中断函数
{                       
    TR0=0;          //停止计时,执行以下操作(会带来计时误差)
    TH0=0xee;       //向TH0写入初值的高8位
    TL0=0x00;       //向TL0写入初值的低8位,定时5ms
    timer++;        //记录中断次数
    if (timer==20)      //中断20次,共计时20*5ms=100ms=0.1s
    {
        timer=0;                //中断次数清0
        second++;               //加0.1s
        P0=discode1[second/10];     //根据计时,即时显示秒位       P2=discode2[second%10];     //根据计时,即时显示0.1s位     }
if(second==99)       //当计时到9.9s时
{
    TR0=0;          //停止计时
    second=0;       //秒数清0      
    key=2;          //按键数置2,当再次按下按键时,                   //key++,即key=3,秒表清0复原   
}                           
else                //计时不到9.9s时
{
    TR0=1;          //启动定时器继续计时
}
}

电路仿真实现:

三、使用定时器实现一个LCD显示时钟。

使用定时器实现一个LCD显示时钟。采用LCD 1602,最小计时单位是秒,如何获得1s的定时?可将T0定时时间定为50ms,采用中断方式进行溢出次数累计,满20次,则秒计数变量second加1;若秒计满60,则分计数变量minute加1,同时将秒计数变量second清0;若分钟计满60,则小时计数变量hour加1;若小时计数变量满24,则将小时计数变量hour清0。

电路原理图:

代码实现:

#include"reg51.h"
sbit RS=P3^0;
sbit RW=P3^1;
sbit E=P3^2;
unsigned char s[]={"0123456789"};
unsigned char s1[]={"clock:"};
unsigned char num=0,sec=0,min=25,hour=12;
unsigned char temp0=0,temp1=0,temp2=0,temp3=0,temp4=0,temp5=0;
 
void delay(unsigned int m)
{
    unsigned int i=0,j=0;
    for(i=0;i<m;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 writedat(unsigned char dat)
{
    RS=1;
    RW=0;
    E=0 ;
    P2=dat; 
    delay(5);
    E=1;
    E=0;
}
 
void initlcd()
{
    writecom(0x38);
    writecom(0x0c);
    writecom(0x06);
    writecom(0x01);
}
 
void inittime()
{
    TMOD=0x01;//定时器0
    TH0=(65536-50000)/256;
    TL0=(65536-50000)%256;
    EA=1;
    ET0=1;
    TR0=1;
}
 
void display()
{       
    unsigned int i=0;
    temp0=sec%10;
    temp1=sec/10;
    temp2=min%10;
    temp3=min/10;
    temp4=hour%10;
    temp5=hour/10;
 
    writecom(0x80+0x46); 
    delay(5);
    writedat(s[temp5]);
    delay(5);
    writedat(s[temp4]);
    delay(5);
    writedat(':');
    delay(5);
    writedat(s[temp3]);
    delay(5);
    writedat(s[temp2]);
    delay(5);
    writedat(':');
    delay(5);
    writedat(s[temp1]);
    delay(5);
    writedat(s[temp0]);
    delay(5);
 
 
    writecom(0x80);
    delay(5);
    while(s1[i]!='\0')
    {
        writedat(s1[i]);
        i++;
    }
    
}
 
void main()
{
    initlcd();
    inittime();
    while(1)
    {
        display();
    }
}
 
void inittime_isr() interrupt 1
{
    TH0=(65536-50000)/256;
    TL0=(65536-50000)%256;
    num++;
    if(num==20)
    {
        sec++;
        num=0;
    }
    if(sec==60)
    {
        min++;
        sec=0;
    }
    if(min==60)
    {
        hour++;
        min=0;
    }
    if(hour==24)
    {
        hour=0;
    }
}

普中开发板实现:

需将代码:

sbit RS=P3^0;
sbit RW=P3^1;
sbit E=P3^2;

修改为:

sbit RS=P2^6;
sbit RW=P2^5;
sbit E=P2^7;

电路仿真实验:

四、甲乙两个单片机串口通信

单片机的数据通信有并行通信与串行通信两种方式,串行通信又有两种方式:异步通信与同步通信。

  同步串行通信是采用一个同步时钟,通过一条同步时钟线,加到收发双方,使收、发双方达到完全同步,此时,传输数据的位之间的距离均为“位间隔”的整数倍,同时传送的字符间不留间隙,既保持位同步关系。

  异步串行通信是指收、发双方使用各自的时钟控制数据的发送和接收,这样可省去连接收、发双方的一条同步时钟信号线,使得异步串行通信连接更加简单且容易实现。为使收发双方协调,要求收、发双方的时钟尽可能一致。

  异步串行通信不要求收、发双方时钟严格一致,实现容易,成本低,但是每个数据帧要附加起始位、停止位有时还要再加上校验位。

  同步串行通信相比异步串行通信,同步串行通信数据传输的效率较高,但是额外增加了一条同步时钟线。

串行口的4种工作方式:

1.方式0

 方式0以8位数据为1帧,没有起始位和停止位,先发送或接收最低位。波特率是固定的,为fosc/12。

输出:当单片机执行将数据写入发送缓冲器SBUF指令时,产生一个正脉冲,串口把8位数据以fosc/12固定波特率从RXD脚串行输出,低位在先,TXD脚输出同步移位脉冲,当8位数据发送完,中断标志位TI置“1”。

输入:方式0输入时,REN为串行口允许接收控制位,REN=0,禁止接收;REN=1,允许接收。 当CPU向串行口SCON寄存器写入控制字(设置为方式0,并使REN位置“1”,同时RI=0)时,产生一正脉冲,串口开始接收数据。当接收器接收完8位数据时,中断标志RI置“1”,表示一帧接收完毕,可进行下一帧接收

2.方式1

  方式1为双机串行通信方式。当SM0、SM1=01时,串行口设为方式1双机串行通信。TXD脚和RXD脚分别用于发送和接收数据。

  方式1收发一帧数据为10位,1个起始位(0),8个数据位,1个停止位(1),先发送或接收最低位。  方式1为波特率可变的8位异步通信接口。波特率由下式确定:

式中,SMOD为PCON寄存器的最高位的值(0或1)。

输出:串口以方式1输出,数据位由TXD端输出,发送一帧信息为10位,1位起始位0,8位数据位(先低位)和1位停止位1,当CPU执行写数据到发送缓冲器SBUF的命令后,就启动发送。

接收:数据从RXD(P3.0)脚输入。当检测到起始位负跳变时,则开始接收。

3.方式2

每帧数据均为11位,1位起始位0,8位数据位(先低位),1位可程控为1或0的第9位数据及1位停止位。

发送:先由通信协议由软件设置TB8),然后将要发送的数据写入SBUF,即可启动发送过程。串行口能自动把TB8取出,并装入到第9位数据位的位置,再逐一发送出去。发送完毕,则使TI位置“1”。

接收:当SCON寄存器SM0、SM1=10,且REN=1时,允许串行口以方式2接收数据。接收时,数据由RXD端输入,接收11位信息。当位检测逻辑采样到RXD引脚从1到0的负跳变,并判断起始位有效后,便开始接收一帧信息。在接收完第9位数据后,需满足以下两个条件,才将接收到的数据送入接收缓冲器SBUF。

4.方式3

当SM0、SM1两位为11时,串行口被定义工作在方式3。方式3为波特率可变的9位异步通信方式,除了波特率外,方式3和方式2相同。方式3发送和接收时序见方式2.

实验

在实物实验时,用笔记本电脑的串口助手程序代替其中一个单片机,实现课件上描述的主要功能。

方式2:接收/发送11位信息,第0位为起始位,第1~8位为数据位,第9位是程控位,由用户设置的TB8位决定,第10位是停止位1,这是方式2与方式1的一个不同点。 

波特率=振荡器频率/n

甲、乙两单片机进行 方式3(或方式2)串行通信。甲机把控制8个流水灯点亮的数据发送给乙机并点亮其P1口的8个LED。方式3比方式1多了1个可编程位TB8,该位一般作奇偶校验位。乙机接收到的8位二进制数据有可能出错,需进行奇偶校验,其方法是将乙机的RB8和PSW的奇偶校验位P进行比较,如果相同,接收数据;否则拒绝接收。

本例使用了一个虚拟终端来观察甲机串口发出的数据。  

电路原理图:

注:最右侧被遮挡处为VCC电源

代码实现:

甲机:

#include <reg51.h>
  sbit T_P=PSW^0;       
  unsigned char Tab[8]= {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f}; 
​
void Send(unsigned char dat)    
  {     
  TB8=T_P;          
  SBUF=dat;
  while(TI==0);         
  TI=0;         
  }
 void delay (void)  
  { 
    unsigned char m,n;
    for(m=0;m<250;m++)
    for(n=0;n<250;n++);
  } 
​
     void main(void)                
 {  
    unsigned char i;
    TMOD=0x20;              
    SCON=0xc0;          
    PCON=0x00;                    
    TH1=0xfd;               
  TL1=0xfd;
  TR1=1;                
  while(1)
  { 
    for(i=0;i<8;i++)
        {
        Send(Tab[i]);
        delay( );   
      }
  }
  }

乙机:

#include <reg51.h>
  sbit R_P=PSW^0;       
  
    unsigned char Receive(void) 
  { 
  unsigned char dat;
  while(RI==0);         
  RI=0;         
  ACC=SBUF;         
  if(RB8==R_P)      
  { 
    dat=ACC;    
    return dat;     
  }
  }
    
      void main(void)       
  { 
    TMOD=0x20;  
    SCON=0xd0;  
    PCON=0x00;      
    TH1=0xfd;       
    TL1=0xfd;
    TR1=1;  
    REN=1;      
  while(1)
  { 
  P1= Receive( );       
  }
  }

电路仿真实现:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值