51单片机实验报告

单片微型计算机原理

                  学    院                    

                  班    级                    

                  学    号                     

                  姓    名                     

                  指导教师                     

                  成    绩                     

20##年6月

硬件实验:

实验一:定时器中断实验

实验内容:fosc=11.0592MHz,T0方式2产生定时中断实现秒表功能:数码管后两

位显示10ms;前两位显示秒数;K1/K2/K3键分别启动/停止/清零,按键操作不

分先后

实验程序流程图:

主程序流程图:                            中断程序流程图:

            

实验程序

ORG 0000H

              LJMP MAIN

              ORG 000BH

              LJMP INTT0

              ORG 0100H

MAIN:    MOV SP,#70H

              CALL INI_ALL

LOOP:    CALL DISPLAY

              MOV DPTR,#8000H

              MOVX A,@DPTR

              JB ACC.7,NEXT

              SETB TR0

NEXT:    JB ACC.6,NEXT1

              CLR TR0

NEXT1:  JB ACC.5,LOOP

              MOV R7,#0H

              MOV R6,#0H

              MOV R5,#0H

              LJMP LOOP

       /*INTT0*/

INTT0:    PUSH PSW

              PUSH ACC

              INC R5

              CJNE R5,#40,CMP1

CMP1:    JC GOON

              MOV R5,#0H

              INC R6

              CJNE R6,#100,CMP2

CMP2:    JC GOON

              MOV R6,#0H

              INC R7

              CJNE R7,#100,CMP3

CMP3:    JC GOON

              MOV R7,#0H

GOON:   POP ACC

              POP PSW

              RETI

       /*INIALL*/

INI_ALL:MOV R7,#0H

              MOV R6,#0H

              MOV R5,#0H

              MOV IE,#82H

              MOV TMOD,#02H

              MOV TH0,#25

              MOV TL0,#25

              RET

       /*DISPLAY*/

DISPLAY:MOV DPTR,#TABLE

              MOV A,R7

              MOV B,#10

              DIV AB

              MOVC A,@A+DPTR

              MOV 33H,A

              MOV A,B

              MOVC A,@A+DPTR

              MOV 32H,A

       /**/

              MOV A,R6

              MOV B,#10

              DIV AB

              MOVC A,@A+DPTR

              MOV 31H,A

              MOV A,B

              MOVC A,@A+DPTR

              MOV 30H,A

       /**/

              MOV DPTR,#8000H

              MOV A,33H

              MOVX @DPTR,A

              MOV DPTR,#8100H

              MOV A,32H

              MOVX @DPTR,A

              MOV DPTR,#8200H

              MOV A,31H

              MOVX @DPTR,A

              MOV DPTR,#8300H

              MOV A,30H

              MOVX @DPTR,A

              RET

TABLE: DB 88H,0AFH,0C4H,86H,0A3H,92H,90H,8FH,80H,82H

              END

实验结果数码管后两位显示ms计数,前两位显示s计数,按K1键启动计数,K2键停止计数,K3键清零。可实现秒表功能。

实验二:驱动蜂鸣器实验

实验内容:使P3.5端口输出周期为1S的方波信号。并通过三极管驱动一个直流小喇叭,使其发出断续的鸣响。

实验程序:

ORG 0H

         LJMP MAIN

         ORG 0100H

MAIN:  MOV SP,#70H

START: CPL P3.5

         LCALL DELAY

         LJMP START

DELAY:        MOV R7,#200

Y:       MOV R6,#100

X:       NOP

         DJNZ R6,X

         DJNZ R7,Y

         RET

         END

实验结果:蜂鸣器发出声响。

实验三:显示管增一显示

实验内容:编写程序,使数码管从0000自增一加至9999,然后再自动清零循环。

实验程序:

       ORG 0H

       LJMP MAIN

       ORG 0100H

MAIN:  MOV 30H,#0H

       MOV 31H,#0H

       MOV 32H,#0H

       MOV 33H,#0H

       MOV R0,#1

START: LCALL DELAY

       LCALL CONVERT

       LCALL DISPLAY

       INC R0

       CJNE R0,#255,XX

       LJMP START

XX:    JC START

       JNC MAIN

CONVERT:MOV A,R0

        MOV B,#10

        DIV AB

        MOV 30H,B

              MOV B,#10

              DIV AB

              MOV 31H,B

              MOV 32H,A

              RET

DISPLAY:MOV A,30H

        MOV DPTR,#TABLE

        MOVC A,@A+DPTR

        MOV DPTR,#8300H

              MOVX @DPTR,A

              MOV A,31H

        MOV DPTR,#TABLE

        MOVC A,@A+DPTR

        MOV DPTR,#8200H

              MOVX @DPTR,A

              MOV A,32H

        MOV DPTR,#TABLE

        MOVC A,@A+DPTR

        MOV DPTR,#8100H

              MOVX @DPTR,A

              MOV A,33H

        MOV DPTR,#TABLE

        MOVC A,@A+DPTR

        MOV DPTR,#8000H

              MOVX @DPTR,A

              RET

DELAY: MOV R7,#100

Y:      MOV R6,#50

X:      NOP

        DJNZ R6,X

              DJNZ R7,Y

              RET

TABLE: DB 88H,0AFH,0C4H,86H,0A3H,92H,90H,8FH,80H,82H

         END

实验结果:八段数码显示管如题目要求所示自增一显示。

软件实验

实验一数据传送实验

实验内容编写程序,将内部RAM中的30H-5FH中的数据设置为55H;

(1)将其中内容传送到90H开始的内部RAM中去。

    (2)将其中内容传送到200H开始的外部RAM中去。

实验程序流程图:

实验程序:ORG 0000H

           LJMP MAIN

          ORG 0100H

MAIN:     MOV SP,#70H

           MOV R0,#30H

          MOV R7,#30H

          MOV A,#55H

LOOP1:      MOV @R0,A

               INC R0

               DJNZ R7,LOOP1  

     

               MOV R0,#30H

               MOV R7,#30H    

               MOV R1,#90H

LOOP2:         MOV A,@R0

               MOV @R1,A

               INC R0

               INC R1

               DJNZ R7,LOOP2        

WAIT:           SJMP WAIT        /*SJMP $*/

               END

实验结果

内部RAM,30H-5FH单元内都为55H。

内部RAM,90H开始的单元内都为55H。

外部RAM,200H开始的单元内都为55H

实验二:数据分类与校验实验

实验内容:编写程序,将内部RAM中30H-5FH中的数据设置为1-48;并将其中奇数传送到90H开始的内部RAM中;将30H-5FH中的数据设置按照奇校验设置最高位。

实验程序流程图:

实验程序     

        ORG 0000H

          LJMP MAIN

        ORG 0100H

MAIN:   MOV SP,#70H

        MOV R0,#30H

        MOV R7,#30H

        MOV A,#1

LOOP1:  MOV @R0,A

        INC R0

        INC A

        DJNZ R7,LOOP1

        MOV R0,#30H

        MOV R7,#30H

        MOV R1,#90H

LOOP2:  MOV A,@R0

        INC R0

        JB  0E0H,TRANS

        JMP NTRANS

TRANS:  MOV @R1,A

        INC R1

NTRANS:DJNZ R7,LOOP2 

END

实验结果

内部RAM中30H-5FH中的数据为1-48;其中奇数传送到90H单元。

30H-5FH中的数据设置按照奇校验设置最高位送到90H单元内。

程序段如下:

 //奇校验设置最高位 

          MOV R0,#30H

        MOV R7,#30H

        MOV R1,#90H

LOOP3:  MOV A,@R0

        INC R0

        JNB P,TRANS2

        JMP NTRANS2

TRANS2:SETB 0E7H

         MOV @R1,A

         INC R1

NTRANS2:DJNZ R7,LOOP3 

实验三简单算术运算

实验内容:编写程序,计算1-100的累加和。结果存放于内部RAM的30H、31H中,低字节在前。

实验程序流程图:

实验程序

ORG 0000H

       LJMP MAIN

       ORG 0100H

MAIN:  MOV SP,#70H

       MOV R0,#30H

       MOV R1,#31H

       MOV @R0,#0

       MOV @R1,#0

       MOV B,#1

              MOV R7,#100

L1:    MOV A,@R1

              ADD A,B

       MOV @R1,A

              MOV A,@R0

              ADDC A,#0

              MOV @R0,A

              INC B

              DJNZ R7,L1

END

实验结果

(30H)=13H,(31H)=0BAH,即结果为13BAH=5050D。

实验四:定点数算术运算实验

实验内容:编写2字节乘2字节子程序。乘数位于R2R3,被乘数位于R4R5。结果存放于R4R5R6R7内。

实验说明:

实验程序

         ORG 0H

       LJMP MAIN

       ORG 0100H

MAIN:  MOV R2,#04H

       MOV R3,#03H

       MOV R4,#02H

       MOV R5,#01H

       MOV R6,#0H

       MOV R7,#0H

       MOV R0,#16D/*JISHU*/

       CLR C

LOOP:  MOV A,R5

       RLC A

       MOV R5,A

       MOV A,R4

       RLC A

       MOV R4,A

       MOV A,R7

       RLC A

       MOV R7,A

       MOV A,R6

       RLC A

       MOV R6,A

       MOV 26H,R6

       MOV 27H,R7

       MOV A,R2

       CJNE A,26H,NEXT1

NEXT1: JNC NEXT2

       MOV A,R3

       CJNE A,27H,NEXT3

NEXT3: JNC NEXT2

       CLR C

       MOV A,R7

       SUBB A,R3

       MOV R7,A

       MOV A,R6

       SUBB A,R2

       MOV R2,A

       SETB C

NEXT2: DJNZ R0,LOOP

WAIT:  SJMP WAIT

       END

实验结果当(R4R5)=21H,(R2R3)=43H时,运算结果为(R4R5R6R7)=08A3H。

  

实验五:数制转换实验一

实验内容:编写程序,将内部RAM中30H中的二进制数据转换为十进制数据并存放在31H、32H、33H中。

实验程序流程图:

实验程序:

ORG 0H

       LJMP MAIN

       ORG 0100H

MAIN:   MOV 30H,#0ABH

       MOV A,30H

       MOV B,#100D

       DIV AB

       MOV 31H,A

       MOV A,B

       MOV B,#10D

       DIV AB

       MOV 32H,A

       MOV 33H,B

WAIT:  SJMP WAIT

       END

实验结果:假设(30H)=0ABH,则(31H、32H、33H)=(01、07、01)。

实验六:数制转换实验二

实验内容:编写程序,将内部RAM中30H-3FH中的16进制数据(0-F)转换为ASCII码并存放在40H-4FH中。

实验程序

       ORG 0H

       LJMP MAIN

       ORG 0100H

MAIN:  MOV R0,#30H

       MOV A,#0H

       MOV R2,#16D

LOOP1: MOV @R0,A

       INC A

       INC R0

       DJNZ R2,LOOP1

       MOV R0,#30H

       MOV R1,#40H

       MOV R2,#16D

LOOP:  MOV A,@R0

       INC R0

       CLR C

       SUBB A,#10D

       JC SMALL

       ADD A,#7

SMALL: ADD A,#3AH

       MOV @R1,A

       INC R1

       DJNZ R2,LOOP

WAIT:  SJMP WAIT

       END

实验结果:

实验七:数据统计实验一

实验内容:编写程序,首先将内部RAM中30H-7FH中的数据设置为50H-9FH。然后编写程序统计该区域内大于80H的个数,结果存放在寄存器B内。

实验程序

       ORG 0H

       LJMP MAIN

       ORG 0100H

MAIN:  MOV R0,#30H

       MOV A,#50H

       MOV R2,#80D

LOOP1: MOV @R0,A

       INC A

       INC R0

       DJNZ R2,LOOP1

       MOV R0,#30H

       MOV R1,#0H

       MOV R2,#80D

LOOP:  CJNE @R0,#81H,NEXT

NEXT:  JC NEXT1

       INC R1

NEXT1: INC R0

       DJNZ R2,LOOP

       MOV B,R1

WAIT:  SJMP WAIT

       END

实验结果首先将30H-7FH中的数据设置为50H-9FH

统计该区域内大于80H的个数,结果存放在寄存器B内,(B)=20H。

实验八:数据统计实验二

实验内容:编写程序,首先将内部RAM中30H-7FH中的数据设置为50H-9FH;然后统计该区域内的奇数个数,存放在R6中,正数个数放在R7。

实验程序

       ORG 0H

       LJMP MAIN

       ORG 0100H

MAIN:  MOV R0,#30H

       MOV A,#50H

       MOV R2,#80D

LOOP1: MOV @R0,A

       INC A

       INC R0

       DJNZ R2,LOOP1

       MOV R0,#30H

       MOV R6,#0H/*JI*/

       MOV R7,#0H/*ZHENG*/

       MOV R2,#80D

LOOP:  MOV A,@R0

       JNB ACC.0,NEXT1

       INC R6

NEXT1: JB ACC.7,NEXT2

       INC R7

NEXT2: INC R0

       DJNZ R2,LOOP

WAIT:  SJMP WAIT

       END

实验结果:

首先将30H-7FH中的数据设置为50H-9FH

统计的奇数个数存放在R6中,(R6)=28H

 

第二篇:基于51单片机的水温测控系统实验报告


摘要

   本次实验是软硬件相结合的实验,通过传感器得到的阻值与其它电阻,可以搭建一个电桥,将水温转化为电压,然后通过放大器将电压放大到所需要的值,将所得的电压送入单片机的AD转换电路,将模拟信号转换成数字信号,从而在单片机的液晶屏上显示当前的温度。此烧水壶是可控制的,即设定温度,使水加热到设定温度且保温,此控制算法采用PID控制算法来控制继电器的通断,来保证水温恒定在设定温度处。

一、设计要求

1.传感器:Pt100铂热电阻

2.测量放大器:自己设计与搭建

3.被控对象:400W电热杯,约0.5公斤自来水

4.执行机构:12V驱动,5A负载能力的继电器

5.控制系统:51单片机

6.控制算法:PID

7.温度范围:环境温度~100度

8.测量误差1度,控制误差2度

二、设计原理及方案

1.    热电阻传感器

热电阻传感器是利用导体或半导体的电阻值随温度变化而变化的原进行测温的。

   热电阻的工作原理:温度升高,金属内部原子晶格的振动加剧,从而使金属内部的自由电子通过金属导体时的阻碍增大,宏观上表现出电阻率变大,电阻值增加,我们称其为正温度系数,即电阻值与温度的变化趋势相同。

2.    实验原理框图

3.    测量放大器电路图

 说明:电位器R10用来调节偏置电压,而电位器R7则用来调节增益。实验时,用R10来调节零点,用R7来调节满度。该电路将0℃-100℃转换为0-5V电压。

   上述电路图采用仪表放大器,将铂热电阻两端的电压U2与电位器R10两端的电压U1差放大,放大器输出电压U0与电压差的关系为:

由铂热电阻阻值与水温的关系可知,铂热电阻的范围是。则整理得:

而仪表放大器的输出电压为0~5V,所以放大倍数大约为:5/0.04=125。

当假设R8/R4=2时,R2/R7=30

由此,我们可以选择R8=20K,R4=10K,R2=10K,R7=2K的电位器,为了使放大器的性能更好,我们可以把R10选为200欧姆的电位器。调节R,可以调节电平,调节R7是调节放大倍数。

4.    A/D转换原理

调节测量放大电路的电位器R2和R7,使差分放大器输出0-5V电压,送入单片机。单片机的A/D转换电路将0-5V电压划分为1024个量化台阶,即0-5V对应0-1023。用10位二进制数表示。采样读出DIO口的连续10个电平值,当量化台阶为1000时,刚好1000对应的是100摄氏度,所以只需把采样读出的电平值左移一位,即可换算出对应的温度值。

5.    PID控制算法

三、程序设计

主要思想:首先AD转换器TLC1549是10位的,故转换最大值为1023,为显示及计算方便,只取到1000,对应输入电压值4.88V,对应显示温度值100摄氏度.由于温度传感器基本是线性的,故0摄氏度对应电压值0V,取放大器放大倍数约100倍,将输入的微小电流放大.程序中计时器定时为50ms,每50 次也就是2.5 秒进行一次AD 转换,显示及PID计算,也就是2.5 秒的加热周期,故占空比的比例为五十分之几,这个几是PID 计算出来的u 换算出来的.u的取值有负有正,且大小范围非常大,不好确定,故对u经行比例压缩,u越大加热的占空比就越高,u为0对应不加热,这样就将u转换为占空比.虽然可能精度不够,但基本实现了温度的控制.关于PID三个系数的确定问题,比例项应大,使温度反应快一点.积分微分项系数也稍微取大一点,使震荡次数下降,稳定值波动较小.系统也许需要比较长的时间才能准确的跟踪设定值.

TMOD设置

  1.采用T1定时/计数器,工作在方式1下,见下表:

     所以 TMOD=10H

   2.开中断:EA=1;

         定时器T1开:ET1=1

   3.TH1、TL1设置

  定时时间设为50ms,所以

  50×10-3=(216-初始值)×(12/11.0592)×10-6

         解得: 初始值=19456=01001100 00000000B

      因此:TH1=01001100B=4CH  TL1=00000000B=00H

程序中需用到的系统地址

    A1A0组合分别是00:写指令;01:写数据;10:读指令;11:读数据

    系统地址:0A000H 0A001H 0A002H  0A003H

源程序附在附录里面。

四、实验结果

       在电热水杯加热的初始阶段,继电器始终保持接通状态,电热水杯全速加热。当水温到达50℃以上,继电器在PID算法的控制下开始通断交替,且随着水温的升高,继电器接通的时间逐渐减少,断开的频率逐渐增大。当水温到达设定温度左右(±2℃)时,继电器通断时间比例不再变化,电热水杯处在保温状态,水温恒定在设定温度上下。经过调试和温度的校后显示的温度值是比较准确的,误差大约在零点几摄氏度内.在做温度控制的时候,由于我显示出了占空比值和时间t,故调整系数很方便和直观.控制误差大约一摄氏度左右,也是符合要求的,但系统的超调量还是比较大的,故做了适当软件上的调整,如温度超过设定值时直接将继电器断开,而不是等待PID 做出反应,毕竟温度控制是一个大滞后性和大惯性的系统.

五、实验总结

       3年大学时光中,觉得最有用的课程就是这些实验了,它让我们学有所用,而不仅仅是各种理论,而是通过实践来巩固深入理解理论。这门实验课让我们不仅在软件上花了大量的功夫,代码力求精益求精;而且.在实际的调试中,还是发现软件只是一方面的内容,外硬件的优劣也是影响系统性能和精度的致命因素.尤其是做控制的时候和调整温度的时候,一个可靠的硬件可以省下不少功夫.温度控制系统的设计让我们学会的不仅仅是对单片机的内部结构的进一步理解与运用,还在上一次实验的基础上进一步提高运放集成电路设计与运用的能力。

源程序

#include <REG52.H>

#include <absacc.h>

#include <intrins.h>

#include <math.h>

#define uchar unsigned char

#define uint unsigned int

#define KP 0.55       //比例系数

#define KI 0.02       //积分系数

#define KD 0.1        //微分系数

sbit pout=P1^7;

sbit SCLK=P1^2;

sbit DIO=P1^3;

sbit AD_CS=P1^4;

 uchar num1[13]={0x53,0x45,0x54,0x54,0x3A,0,0,0,0x2E,0,0xDF,0x43};

 uchar num2[13]={0x4E,0x4F,0x57,0x54,0x3A,0,0,0,0x2E,0,0xDF,0x43};

unsigned int settemp=500,nowtemp;

unsigned char timecount=0;

bit adflag,showflag;                  //ad标志位

unsigned char duty=0,duty_tem=0;      //输出控制量

float el,en=0,es=0;

float p_out,i_out,d_out;

void write();

void BUSY();

void LCD_inti();

void delay(uchar n)

{

       int ii,jj;

       for(ii=0;ii<n;ii++)

              for (jj=0;jj<120;jj++);

       return;

}

void keyscan()

{   uchar key=0,tempKey=0;  

       XBYTE[0x8fff]=0x0f;                 

    delay(100);   

       tempKey=XBYTE[0x8fff];//读取按键    

       tempKey&=0x0f;    

    delay(100);   

       key=XBYTE[0x8fff];//再次读取按键    

       key&=0x0f;    

       if(key==tempKey)    

       {

              while(key==tempKey)//等待按键弹起    

              {

                     key=XBYTE[0x8fff];  

                     key&=0x0f;    

              }

              switch(tempKey)

              {

                     case 1:if(settemp<=900)settemp+=100;break;

                     case 2:if(settemp>100)settemp-=100;break;

                     case 4:if(settemp<=990)settemp+=10; break;

                     case 8:if(settemp>10)settemp-=10; break;

                     default: break;

              }

      }        

}

      

void writeData(uchar data1)

{

       while(XBYTE[0xa001]&0x80);//等待可写

       XBYTE[0xa002]=(data1);//向数据端口写入数据

}

void writeString(uchar data1[],int len)

{

       int k=0;

       for(k=0;k<len;k++)//写入字符串

              writeData(data1[k]);

}

//LCD初始化

void LCD_inti()

{

       BUSY();

       XBYTE[0xa000]=0x01;

       BUSY();

       XBYTE[0xa000]=0x06;

       BUSY();

       XBYTE[0xa000]=0x1c;

       BUSY();       

       XBYTE[0xa000]=0x38;

       BUSY();

       XBYTE[0xa000]=0x0c;

      

}

void BUSY()

{

       uchar BUSYBF=0;

       while(1)

       {

              BUSYBF=XBYTE[0xa001];

              if(BUSYBF <0x80) break;

       }

       return;

}

//AD初始化

void AD_init()      

{

       AD_CS=1;    //必须为高

       SCLK=1;     //上升沿有效

       DIO=1;     //置高

}

unsigned int AD()  //本次AD读取上一次的值

{

    uint temp=0;

    uchar i;

    AD_CS = 0;

    SCLK = 0;

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

    {

           temp <<=1;

        temp |= DIO;

        SCLK = 1;

        SCLK = 0;

    }

    AD_CS = 1;

    delay(256);  //延迟>17us

    return temp;

}

//定时器初始化

void timer_init()

{

       TMOD=0x10; //T1:计时器

       EA=1;        //全局中断允许

       TH1=0x4C;

       TL1=0x00;  //初值19456

       ET1=1;      //允许定时器中断

       timecount=0;

       TR1=1;     // 开始计时

}

void OnTimer1() interrupt 3 

{

       TR1=0;  // 停止计时

    EA=0;

       TH1=0x4C;

       TL1=0x00;// 初值19456

       timecount++;

       if (timecount>50)     //2.5秒进行一次PID控制

       {

              timecount=1;

              adflag=1;//ad采样 开始控制

       }

/*    if (timecount<=duty)

       {

              pout=1;

       }

       else

       {

              pout=0;

       }*/

       if (timecount%10==0) 

          {showflag=1;   //0.5秒对屏幕进行一次刷新

          //nowtemp+=1;   

         }

       TR1=1;  // 开始计时

       EA=1;

}

//pid控制算法

 pid()

{

    el=en;

    en=(signed)settemp-(signed)nowtemp;

    es+=en;

    p_out=KP*en;       //比例项输出

    i_out=KI*es;       //积分项输出

    d_out=KD*(en-el);   //微分项输出

    if(i_out>100)          //积分分离

       i_out=100;

    if(i_out<-100)

       i_out=-100;

    duty_tem=p_out+i_out+d_out; //总输出量

    if(duty_tem<0)

       duty_tem=0;

    if(duty_tem>=100)

       duty_tem=100;

       duty=floor(duty_tem)/2; //u最大值为50

       if(duty_tem<0)  pout=1;

       else pout=0;

       return (pout);

}

///////////////////////

main()

{  

    pout=1;

      

      LCD_inti();

       AD_init();

       timer_init();

    if (adflag)

              {

                     nowtemp=AD();

                     nowtemp=AD();

                     adflag=0;

                     pid();

              }

      

       while (1)

       {

           keyscan();

              if (showflag)

              {

                  LCD_inti();

                     nowtemp=AD();       

                     nowtemp=AD();

                      num1[5]=settemp/1000+48;

                num1[6]=(settemp/100)%10+48;

                num1[7]=(settemp/10)%10+48;

                num1[9]=settemp%10+48;

             XBYTE[0xa000]=0x80;

                   writeString(num1,13);

   

                     num2[5]=nowtemp/1000+48;

               num2[6]=(nowtemp/100)%10+48;

               num2[7]=(nowtemp/10)%10+48;

               num2[9]=nowtemp%10+48;

                  XBYTE[0xa000]=0xc0;

            writeString(num2,13);

                     showflag=0;

              }

              if (adflag)

              {

                     nowtemp=AD();

                     nowtemp=AD();

                     pid();

                     adflag=0;

              }

       }

       }

相关推荐