[原创] 51单片机+LCD1602+LM75读温度(汇编语言)

godlovewinner   2014-4-11 16:41 楼主
;**************************************************************
;程序名称:LM75+LCD1602
;主控芯片:89c51,12MHZ
;**************************************************************

                RS        BIT P2.0   ;定义LCD1602的RS为P2.0
                RW        BIT P2.1   ;定义LCD1602的RW为P2.1
                E         BIT P2.2   ;定义LCD1602的E为P2.2                                                                                                                  
                SDA       BIT P3.7   ;定义24C02数据线
                SCL       BIT P3.6   ;定义24C02时钟线
                RD_DATA   DATA 30H   ;读出数据缓冲区首地
                ConfReg   EQU  01H
                DATA1      EQU  00H
         
;//////主程序开始//////////////////////////////////////////////
         ORG       0000H
         AJMP      MAIN
         ORG       0000H
MAIN:MOV      SP,#60H
;//////LCD1602初始化///////////////////////////////////////////
        MOV       P0,#01H       ;清除屏幕
        ACALL     ENABLE        ;调用ENABLE子程序 .
        MOV       P0,#38H       ;8位点阵方式 .
        ACALL     ENABLE
        MOV       P0,#06H       ;移动光标
        ACALL     ENABLE
        MOV       P0,#0CH       ;开显示,有光标,光标显示   .
        ACALL     ENABLE
;///////从LM75读数据////////////////////////////////////////////
LOOP:LCALL     WR_Byte
     LCALL     RD_Byte
         MOV       A,R5
         MOV       B,#10D
         DIV       AB
         MOV       30H,A
         MOV       A,B
         MOV       B,#10D
         MUL       AB
         MOV       B,#10D
         DIV       AB
         MOV       31H,A
         MOV       32H,B
;//////LCD1602显示部分//////////////////////////////////////////
REP2:MOV      P0,#83H         ; 第1行位置    .
        LCALL     ENABLE   
        MOV       R1,#30H     ;显示缓冲区内容
        LCALL     WRITE
        ;MOV       R6,#04H
        MOV      P0,#84H         ; 第1行位置    .
        LCALL     ENABLE   
        MOV       R1,#31H     ;显示缓冲区内容
        LCALL     WRITE

        MOV      P0,#85H         ; 第1行位置    .
        LCALL     ENABLE   
        MOV       R1,#32H     ;显示缓冲区内容
        LCALL     WRITE
        AJMP      LOOP
;//////启动LM75子程序//////////////////////////////////
START:SETB    SCL                 ;时钟高电平时数据下降沿为启动信号
        NOP
        NOP
        SETB      SDA   
        NOP
        NOP
        CLR       SDA
        NOP
        NOP
        CLR       SCL                 ;钳住IC总线准备发送或接受数据
        NOP
        NOP
        RET
;//////停止LM75子程序///////////////////////////////////
STOP:CLR      SDA           ;时钟高电平时数据上升沿为停止信号
        NOP
        NOP
        SETB      SCL
        NOP
        NOP
        SETB      SDA
        NOP
        NOP
        CLR       SCL
        RET
;//////写LM75操作子程序////////////////////////////////
;输入参数: R1---要写入的地址,B---要写入的数据
;///////////////////////////////////////////////////////
WR_Byte:LCALL      START         ;调用启动24c02子程序
REP_S1: MOV        A,#90H       ;写器件地址
            LCALL      Send_B        ;调用发送一个字节到I2C总线子程序
            LCALL      WAITACK       ;调用应答信号检测程序

        JC         REP_S1       ;没有应答则重发数据
REP_S2: MOV        A,CONFREG          ;写入地址
            LCALL      Send_B
            LCALL      WAITACK
            JC         REP_S2        
REP_S3: MOV        A,DATA1           ;写入数据      
                LCALL      Send_B
                LCALL      WAITACK
                JC         REP_S3
                LCALL      STOP          ;调用停止子程序
                LCALL      DELAY         ;130MS 延时,实际这里只需5MS延时
                RET

;//////向IIC总线发送一个字节数据子程序/////////////////////////////
;入口参数:A---待发送数据存放在A中
;//////////////////////////////////////////////////////////////////
Send_B: MOV R7,#08H       ;发送位数
S_B:    RLC A
                MOV       SDA,C
                NOP
                NOP
                SETB      SCL         
                NOP
                NOP
                CLR       SCL
                DJNZ      R7,S_B   ;8位发送完毕?
                NOP
                NOP
                RET
;//////检测应答信号//////////////////////////////////////////////
;出口参数:C---是否有应答信号
;////////////////////////////////////////////////////////////////
WAITACK:SETB   SDA       ;释放SDA信号线
                NOP
                NOP
                SETB   SCL
                NOP
                NOP
REP3:   MOV    C,SDA
            CLR    SCL
            NOP
            NOP
            RET
;//////读LM75操作子程序///////////////////////////////////////
;输入参数:R2---要读的字节地址,
;输出参数: A---结果
;//////////////////////////////////////////////////////////////
RD_Byte:
       LCALL     START
REP_S4:MOV       A,#90H
           LCALL     Send_B
           LCALL     WAITACK
           JC        REP_S4
REP_S5:MOV       A,DATA1
           LCALL     Send_B
           LCALL     WAITACK
           JC        REP_S5
REP_S6: LCALL    START        ;重发启动信号
                MOV       A,#91H
                LCALL     Send_B
                LCALL     WAITACK
                JC        REP_S6        
                LCALL     Receive_B    ;调用从I2C总线上接收一个字节数据子程序
                MOV       R5,A
                LCALL     Receive_B
                MOV       R4,A
                LCALL     STOP
                RET
;//////从IIC总线上接收一个字节数据子程序//////////////////////////////
;出口参数:A---接收数据存放在A中
;//////////////////////////////////////////////////////////////////////
Receive_B:
       SETB      SDA            ;释放SDA数据线
           MOV       R7,#08H        ;一个字节共接收8位数据
           CLR       A
R_B:   SETB SCL            ;启动一个时钟周期,读总线
                NOP
                NOP
                MOV       C,SDA          ;将SDA状态读入C
                RLC       A              ;结果移入A
                CLR       SCL
                NOP
                NOP
                DJNZ      R7,R_B    ;判断8位数据是否接收完全?
                SETB      SDA
                NOP
                NOP
                RET
;//////写lcd1602指令子程序/////////////////////////////
ENABLE:   
      CLR      RS
          CLR      RW
          CLR      E
          ACALL    DELAY
          SETB     E
          RET
;//////写LCD1602数据子程序/////////////////////////////
WRITE:
      MOV       A,@R1
      ADD       A,#30H     
          MOV       P0,A
          SETB      RS
          CLR       RW
          CLR       E
          LCALL     DELAY
         ; LCALL     DELAY
         ; LCALL     DELAY
      SETB      E
        ;  INC       R1
        ;  DJNZ      R6,WRITE    ; 数据写完没有.
          RET
;//////130MS延时子程序////////////////////////////
DELAY:
      MOV       R7,#0FFH
   D1:
      MOV       R6,#0FFH
          DJNZ      R6,$
          DJNZ      R7,D1
          RET
;//////写入数据存放处/////////////////////////////
TAB:        DB "0,1,2,3,4,5,6,7,8,9"
;//////程序结束/////////////////////////////////////
END


回复评论 (3)

学习了,thank you !
点赞  2014-4-11 18:05
         ORG       0000H
         AJMP      MAIN
         ORG       0000H
MAIN:MOV      SP,#60H
      ......
地址重复了,应改成如下:
         ORG       0000H
         AJMP      MAIN
         ORG       0030H
MAIN:MOV      SP,#60H
                     ......
仅就基本的51单片机的2个外部中断、3个定时器中断、1个串口中断入口,占用了0030H以下的地址(扩展功能的如stc系列用得更多),所以一般最好别再占用。也许你现在的这一点程序用不到这一块(其实第二行已经用到),以后移植或扩展功能时说不定会用到。所以习惯上都是从0100H开始写入程序。养成一个良好的习惯会有好处的。
其余的没有细看,不知道你遇到了什么问题?
点赞  2014-4-15 11:18
另外,如果使用的是89c51,栈底设置设置有点高了,61H~7FH不一定够用(60H用不到),一旦溢出出错,很难查找。
点赞  2014-4-15 11:23
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复