单片机入门

当前位置:首页>文章中心>单片机入门
全部 352 技术分享 332 单片机入门 20

单片机与PC串口通信1

作者:电子开发网   来源:本站   时间:2008-10-17   访问量:1058

实验任务:

1)将采集的温度值显示在数码管上(0-99.9度,保留1位小数),
2)通过串口将测量温度值传递给PC。
   传送数据格式:发送2位16进制数,比如发送十六进制数19代表十进制数25℃。
3)当温度大于50度时,继电器1动作;当温度小于20度时,继电器2动作。

所需硬件:   1.单片机实验开发板B
            2.杜邦头插线
            3.DS18B20
            4.STC89C51RC单片机
所需软件:   1. Keil C51 V8.08Keil_uv3 绿色版本
            2.STC单片机ISP下载编程软件

             18B20中文资料

1664848702169604.jpg

            DS18B20连接图

1664848719113014.jpg
            串口接收到的数据

    DS18B20数字温度计是DALLAS公司生产的1-Wire,即单总线器件,具有线路简单,体积小的特点。因此用它来组成一个测温系统,具有线路简单,在一根通信线,可以挂很多这样的数字温度计,十分方便。
1.DS18B20产品的特点
   (1)、只要求一个端口即可实现通信。
   (2)、在DS18B20中的每个器件上都有独一无二的序列号。
   (3)、实际应用中不需要外部任何元器件即可实现测温。
   (4)、测量温度范围在-55。C到+125。C之间。
   (5)、数字温度计的分辨率用户可以从9位到12位选择。
   (6)、内部有温度上、下限告警设置。

2.DS18B20的引脚介绍
     TO-92封装的DS18B20的引脚排列见图1,其引脚功能描述见表1。
1664848748792475.jpg
(底视图)图1
表1 DS18B20详细引脚功能描述

序号名称引脚功能描述
1GND地信号
2DQ数据输入/输出引脚。开漏单总线接口引脚。当被用着在寄生电源下,也可以向器件提供电源。
3VDD可选择的VDD引脚。当工作于寄生电源时,此引脚必须接地。



3.DS18B20的使用方法
  由于DS18B20采用的是1-Wire总线协议方式,即在一根数据线实现数据的双向传输,而对AT89S51单片机来说,硬件上并不支持单总线协议,因此,我们必须采用软件的方法来模拟单总线的协议时序来完成对DS18B20芯片的访问。
  由于DS18B20是在一根I/O线上读写数据,因此,对读写的数据位有着严格的时序要求。DS18B20有严格的通信协议来保证各位数据传输的正确性和完整性。该协议定义了几种信号的时序:初始化时序、读时序、写时序。所有时序都是将主机作为主设备,单总线器件作为从设备。而每一次命令和数据的传输都是从主机主动启动写时序开始,如果要求单总线器件回送数据,在进行写命令后,主机需启动读时序完成数据接收。数据和命令的传输都是低位在先。
DS18B20的复位时序
1664848760183322.gif

DS18B20的读时序
  对于DS18B20的读时序分为读0时序和读1时序两个过程。
  对于DS18B20的读时隙是从主机把单总线拉低之后,在15微秒之内就得释放单总线,以让DS18B20把数据传输到单总线上。DS18B20在完成一个读时序过程,至少需要60us才能完成。
1664848771128150.gif

DS18B20的写时序
  对于DS18B20的写时序仍然分为写0时序和写1时序两个过程。
  对于DS18B20写0时序和写1时序的要求不同,当要写0时序时,单总线要被拉低至少60us,保证DS18B20能够在15us到45us之间能够正确地采样IO总线上的“0”电平,当要写1时序时,单总线被拉低之后,在15us之内就得释放单总线。
1664848781175050.gif

4.电路原理图
    请参考开发板原理图.

5.系统板上硬件连线
(1).把开发板串口线连接到电脑上。
(2).DS18B20的GND DQ VDD用杜邦头插线分别连接到实验板上单片机的20脚 23脚和40脚上,如上面的连接图,注意接线顺序。

6.C语言源程序
/******************************************************************
** 单片机与PC串口通信1
** 晶 振  频 率:11.0592M
** 线路->单片机实验开发板B
******************************************************************/
    #include  
    #include

    sbit PS0=P2^4;//数码管小数点后第1位    
    sbit PS1=P2^5;//数码管个位    
    sbit PS2=P2^6;//数码管十位   
    sbit PS3=P2^7;//数码管百位
    sfr  P_data=0x80;//P0口为显示数据输出口

    sbit P_K_L=P2^2;//键盘列

    sbit DQ=P3^6;//DS18B20数据接口
sbit P_L=P0^0;//测量指示

sbit JDQ1=P2^0;
sbit JDQ2=P2^1;

void delay(unsigned int);//延时函数
    void DS18B20_init(void);   //DS18B20初始化
unsigned int get_temper(void);    //读取温度程序
void DS18B20_write(unsigned char in_data); //DS18B20写数据函数
unsigned char DS18B20_read(void);////读取数据程序
unsigned int htd(unsigned int a); //进制转换函数
void display(unsigned int a);//显示函数

float temp;//温度寄存器
bit DS18B20; // 18B20存在标志,1---存在 0---不存在
    
unsigned char tab[10]={0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6};//字段转换表
    
void main(void)
    {
    unsigned int a,temp;                                                        
        TMOD=0x20;           //定时器1--方式2
        TL1=0xfa;            
        TH1=0xfa;            //11.0592MHZ晶振,波特率为4800
        SCON=0x50;           //方式1
        TR1=1;               //启动定时

temp=get_temper();//这段程序用于避开刚上电时显示85的问题
for(a=0;a<200;a++)
        delay(500);

while(1)
{
    temp=get_temper();//测量温度
    for(a=0;a<200;a++)//显示,兼有延时的作用
    display(htd(temp));
SBUF=(unsigned char)(temp>>8); //将温度发送给PC  
            while(TI!=1);
TI=0;
SBUF=(unsigned char)temp;
            while(TI!=1);
TI=0; if((temp/10)>50)
    JDQ1=0;//继电器1动作
else
    JDQ1=1;//继电器1复位
if((temp/10)<20)
    JDQ2=0;//继电器2动作
else
    JDQ2=1;//继电器1复位
}
    }

/****************************DS18B20读取温度函数**************************/
/*函数原型:void get_temper(void)
/*函数功能:DS18B20读取温度
/*输入参数:无
/*输出参数:无
/*调用模块:
/*建立时间:2005/11/14
/*作者:站长
/**********************************************************************/
unsigned int get_temper(void)
{
    unsigned char k,T_sign,T_L,T_H;
DS18B20_init();   //DS18B20初始化
    if(DS18B20)    //判断DS1820是否存在?若DS18B20不存在则返回
{
            DS18B20_write(0xcc);    // 跳过ROM匹配
            DS18B20_write(0x44);  //发出温度转换命令
    DS18B20_init();   //DS18B20初始化
        if(DS18B20)    //判断DS1820是否存在?若DS18B20不存在则返回
    {
                DS18B20_write(0xcc);//跳过ROM匹配
                DS18B20_write(0xbe);//发出读温度命令
T_L=DS18B20_read();//数据读出
T_H=DS18B20_read();
k=T_H&0xf8;  
                if(k==0xf8)
                    T_sign=1;   //温度是负数
                else
                    T_sign=0;  //温度是正数

                T_H=T_H&0x07;
                temp=(T_H*256+T_L)*10*0.0625;  //温度转换常数 乘以10 是因为要保留1位小数
return (temp);
            }
        }


}

/****************************DS18B20写数据函数**************************/
/*函数原型:void DS18B20_write(uchar in_data)
/*函数功能:DS18B20写数据
/*输入参数:要发送写入的数据
/*输出参数:无
/*调用模块:_cror_()
/*建立时间:2005/11/14
/*作者:站长
/**********************************************************************/
    void DS18B20_write(unsigned char in_data) //写DS18B20的子程序(有具体的时序要求)
    {  
        unsigned char i,out_data,k;
        out_data=in_data;
        for(i=1;i<9;i++)  //串行发送数据
        {
            DQ=0;
        DQ=1;
        _nop_();
            _nop_();
            k=out_data&0x01;
        if(k==0x01)  //判断数据  写1
        {
            DQ=1;
            }
        else   //写0
            {
            DQ=0;
        }
        delay(4); //延时62us
        DQ=1;
            out_data=_cror_(out_data,1);  //循环左移1位
        }
    }

/**************************DS18B20读函数**************************/
/*函数原型:void DS18B20_read()
/*函数功能:DS18B20读数据
/*输入参数:无
/*输出参数:读到的一字节内容
/*调用模块:delay()
/*建立时间:2005/11/14
/*作者:站长
/******************************************************************/
    unsigned char DS18B20_read()
    {
        unsigned char i,in_data,k;
        in_data=0;
        for(i=1;i<9;i++)  //串行发送数据
        {
            DQ=0;
        DQ=1;
        _nop_();
        _nop_();
            k=DQ; //读DQ端
        if(k==1)  //读到的数据是1
        {
            in_data=in_data|0x01;
        }
        else
        {
            in_data=in_data|0x00;
        }
        delay(3);  //延时51us
        DQ=1;
        in_data=_cror_(in_data,1); //循环右移1位
        }
        return(in_data);
    }

/**************************DS18B20初始化函数**************************/
/*函数原型:void DS18B20_init(void)
/*函数功能:DS18B20初始化
/*输入参数:无
/*输出参数:无
/*调用模块:delay()
/*建立时间:2005/11/14
/*作者:站长
/******************************************************************/  
   void DS18B20_init(void)
    {
    unsigned char a;
       DQ=1;//主机发出复位低脉冲
DQ=0;
delay(44); //延时540US
DQ=1;
for(a=0;a<0x36&&DQ==1;a++)
{
    a++;
    a--; //等待DS18B20回应
}
if(DQ)
DS18B20=0;  //18B20不存在
else
{  
DS18B20=1;  // 18B20存在
delay(120); //复位成功!延时240US
}
    }


/**************************数码管显示函数**************************/
/*函数原型:void display(void)
/*函数功能:数码管显示
/*输入参数:无
/*输出参数:无
/*调用模块:delay()
/*建立时间:2005/11/14
/*作者:站长
/******************************************************************/
    void display(unsigned int a)
    {
    bit b=P_K_L;
P_K_L=1;//防止按键干扰显示
        P_data=tab[a&0x0f];//显示小数点后第1位
        PS0=0;
    PS1=1;
PS2=1;
PS3=1;
    delay(200);
        P_data=tab[(a>>4)&0x0f]|0x01; //显示个位
        PS0=1;
    PS1=0;
    delay(200);
        P_data=tab[(a>>8)&0x0f];//显示十位
        PS1=1;
PS2=0;
    delay(200);
        //P_data=tab[(a>>12)&0x0f];//显示百位
        PS2=1;
//PS3=0;
    //delay(200);
//PS3=1;


P_K_L=b;//恢复按键
    P_data=0xff;//恢复数据口
    }


/**************************十六进制转十进制函数**************************/
/*函数原型:uint htd(uint a)
/*函数功能:十六进制转十进制
/*输入参数:要转换的数据
/*输出参数:转换后的数据
/*调用模块:无
/*建立时间:2005/11/14
/*作者:站长
/******************************************************************/
unsigned int htd(unsigned int a)
    {
    unsigned int b,c;
b=a%10;
c=b;
a=a/10;
b=a%10;
c=c+(b<<4);
a=a/10;
b=a%10;
c=c+(b<<8);
a=a/10;
b=a%10;
c=c+(b<<12);
    return c;
    }
/*******************************延时函数*********************************/
/*函数原型:delay(unsigned int delay_time)
/*函数功能:延时函数
/*输入参数:delay_time (输入要延时的时间)
/*输出参数:无
/*调用模块:无
/*建立时间:2005/10/21
/*作者:站长
/**********************************************************************/
void delay(unsigned int delay_time)   //延时子程序
{for(;delay_time>0;delay_time--)
{}
  }

keil工程文件打包下载chuankou1.rar


/******************************************************************
** 单片机与PC串口通信1
** 晶 振  频 率:11.0592M
** 线路->单片机实验开发板B
******************************************************************/

            ;单片机内存分配申明!

            A_BYTE   EQU 20H ;数码管小数点后第1位数存放内存位置
            B_BYTE   EQU 21H ;数码管个位数存放内存位置
            C_BYTE   EQU 22H ;数码管十位数存放内存位置

TEMPER_H EQU 23H  ;用于保存读出温度的高8位
            TEMPER_L EQU 24H  ;用于保存读出温度的低8位

            TEMP_H   EQU 28H  ;用于保存温度*0.625后高位
            TEMP_L   EQU 29H  ;用于保存温度*0.625后低位

            FLAG1    BIT 38H  ;是否检测到DS18B20标志位

DQ       BIT P3.6 ;18B20的数据接口

JDQ1     BIT P2.0 ;继电器1控制
            JDQ2     BIT P2.1 ;继电器2控制

PS0      BIT P2.4 ;数码管小数点后第1位    
            PS1      BIT P2.5 ;数码管个位    
            PS2      BIT P2.6 ;数码管十位   
            PS3      BIT P2.7 ;数码管百位
  

            ;进行温度显示,这里我们考虑用网站提供的两位数码管来显示温度
            ;显示范围00到99度,显示精度为1度
            ;因为12位转化时每一位的精度为0.0625度,我们不要求显示小数,所以可以抛弃TEMPER_L的
;低4位,将TEMPER_H中的低4位移入TEMPER_L中的高4位,这样获得一个新字节,这个字节就是
;实际测量获得的温度这个转化温度的方法非常简洁无需乘于0.0625系数
ORG 0000H
SJMP MAIN
            ORG 0030H
MAIN:       MOV SP,#60H          
            MOV SCON,#50H ;设置成串口1方式
            MOV TMOD,#20H ;波特率发生器T1工作在模式2上
            MOV TH1,#0FAH ;预置初值(按照波特率4800BPS预置初值)
            MOV TL1,#0FAH ;预置初值(按照波特率4800BPS预置初值)
            ;ORL   PCON, #80H;波特率加倍
            SETB TR1 ;启动定时器T1

LOOP:       ACALL GET_TEMPER;调用读温度子程序
MOV R3,TEMPER_H
MOV R4,TEMPER_L
MOV R7,#5 ;乘以5再除以8 等与乘以0.625
ACALL NMUL21
MOV R7,#8
ACALL NDIV31
MOV TEMP_L,R4
MOV TEMP_H,R3
MOV A,R3
MOV R2,A
MOV A,R4
MOV R3,A
ACALL HTD  ;转换成十进制
MOV A,R6
ANL A,#0FH
MOV A_BYTE,A  
MOV A,R6
SWAP A
ANL A,#0FH
MOV B_BYTE,A
MOV A,R5
ANL A,#0FH
MOV C_BYTE,A
            ACALL SEND ;调用串口显示子程序
            ACALL DISPLAY;调用数码管显示子程序
            SETB     C;判断温度>500(>50度)
            MOV      A,R6
            SUBB     A,#0
            MOV      A,R5
            SUBB     A,#05H
            JC       C0014
            CLR      JDQ1
            SETB     JDQ2
            SJMP     LOOP
C0014:      CLR      C
            MOV      A,R6
            SUBB     A,#0
            MOV      A,R5
            SUBB     A,#2H
            JNC      C0025
            SETB     JDQ1
            CLR      JDQ2
            SJMP     LOOP
C0025:      SETB     JDQ1
            SETB     JDQ2
            SJMP     LOOP
            
INIT_1820:  SETB DQ  ; 这是DS18B20复位初始化子程序
            NOP
            CLR DQ
            MOV R1,#3 ;主机发出延时537微秒的复位低脉冲
TSR1:       MOV R0,#107
            DJNZ R0,$
            DJNZ R1,TSR1
            SETB DQ ;然后拉高数据线
            NOP
            NOP
            NOP
            MOV R0,#25H
TSR2:       JNB DQ,TSR3 ;等待DS18B20回应
            DJNZ R0,TSR2
            AJMP TSR4 ; 延时
TSR3:       SETB FLAG1 ; 置标志位,表示DS1820存在
            AJMP TSR5
TSR4:       CLR FLAG1 ; 清标志位,表示DS1820不存在
            AJMP TSR7

TSR5:       MOV R0,#117
TSR6:       DJNZ R0,TSR6 ; 时序要求延时一段时间
TSR7:       SETB DQ
            RET

GET_TEMPER: SETB DQ  ; 读出转换后的温度值
            LCALL INIT_1820;先复位DS18B20
            JB FLAG1,TSS2
            RET ; 判断DS1820是否存在?若DS18B20不存在则返回
TSS2:       MOV A,#0CCH ; 跳过ROM匹配
            ACALL WRITE_1820
            MOV A,#44H ; 发出温度转换命令
            ACALL WRITE_1820
            ACALL DISPLAY  ;这里通过调用显示子程序实现延时一段时间,等待AD转换结束,12位的话750微秒

            ACALL INIT_1820;准备读温度前先复位

            MOV A,#0CCH ; 跳过ROM匹配
            ACALL WRITE_1820

            MOV A,#0BEH ; 发出读温度命令
            ACALL WRITE_1820

            ACALL READ_18200; 将读出的温度数据保存到TEMPER_L/TEMPER_H
            RET

WRITE_1820: MOV R2,#8;写DS18B20的子程序(有具体的时序要求),一共8位数据
            CLR C
WR1:        CLR DQ
            MOV R3,#5
            DJNZ R3,$
            RRC A
            MOV DQ,C
            MOV R3,#21
            DJNZ R3,$
            SETB DQ
            NOP
            DJNZ R2,WR1
            SETB DQ
            RET

READ_18200: MOV R4,#2 ; 读DS18B20的程序,从DS18B20中读出两个字节的温度数据,将温度高位和低位从DS18B20中读出
            MOV R1,#TEMPER_L ; 低位存入TEMPER_L,高位存入TEMPER_H
RE00:       MOV R2,#8;数据一共有8位
RE01:       CLR C
            SETB DQ
            NOP
            NOP
            CLR DQ
            NOP
            NOP
            NOP
            SETB DQ

            MOV R3,#8
RE10:       DJNZ R3,RE10
            MOV C,DQ
            MOV R3,#21
RE20:       DJNZ R3,RE20
            RRC A
            DJNZ R2,RE01
            MOV @R1,A
            DEC R1
            DJNZ R4,RE00
            RET


;----------------------
;串口发送数据子程序
;----------------------
SEND:       CLR TI
            MOV A,TEMP_H
            MOV SBUF,A
            JNB TI,$

            CLR TI
            MOV A,TEMP_L
            MOV SBUF,A
            JNB TI,$
            RET


DISPLAY:    MOV DPTR,#NUMTAB ;指定查表启始地址
            MOV R0,#4
DPL1:       MOV R1,#250 ;显示1000次
DPLOP:      mov a,A_BYTE ;取小数点后第1位数
            MOVC A,@A+DPTR ;查个位数的7段代码
            mov p0,a ;送出个位的7段代码
            CLR PS0
        SETB PS1
    SETB PS2
    SETB PS3
            acall d1ms ;显示1ms
            mov a,B_BYTE ;取个位数
            MOVC A,@A+DPTR ;查十位数的7段代码
ORL A,#01H
            mov p0,a ;送出十位的7段代码
            SETB PS0
        CLR PS1
            acall d1ms ;显示1ms
            mov a,C_BYTE ;取十位数
            MOVC A,@A+DPTR ;查十位数的7段代码
            mov p0,a ;送出十位的7段代码
            SETB PS1
        CLR PS2
            acall d1ms ;显示1ms
            SETB PS2
            djnz r1,dplop ;100次没完循环
            djnz r0,dpl1 ;4个100次没完循环
            ret


;单字节无符号数乘法程序 (R3R4*R7)=(R2R3R4)
;入口: R3,R4,R7
;占用资源: ACC,B
;堆栈需求: 2字节
;出口: R2,R3,R4
NMUL21 :    MOV A,R4
            MOV B,R7
            MUL AB
            MOV R4,A
            MOV A,B
            XCH A,R3
            MOV B,R7
            MUL AB
            ADD A,R3
            MOV R3,A
            CLR A
            ADDC A,B
            MOV R2,A
            CLR OV
            RET

;单字节无符号除法程序 (R2R3R4/R7)=(R2)R3R4 余数R7
;入口: R2,R3,R4,R7
;占用资源: ACC,B,F0
;堆栈需求: 3字节
;出口: (R2),R3,R4,R7,OV
NDIV31 :    MOV A,R2
            MOV B,R7
            DIV AB
            PUSH ACC
            MOV R2,B
            MOV B,#10H
NDV311 :    CLR C
            MOV A,R4
            RLC A
            MOV R4,A
            MOV A,R3
            RLC A
            MOV R3,A
            MOV A,R2
            RLC A
            MOV R2,A
            MOV F0,C
            CLR C
            SUBB A,R7
            JB F0,NDV312
            JC NDV313
NDV312 :    MOV R2,A
            INC R4
NDV313 :    DJNZ B,NDV311
            POP ACC
            CLR OV
            JZ NDV314
            SETB OV
NDV314 :    XCH A,R2
            MOV R7,A
            RET


HTD:        CLR     A ;R2和R3是程序数据入口
            MOV     R4,A           ;转换后的数放在R4,R5,R6
            MOV     R5,A           ;转换完后在分别屏蔽高位和低位取出数据
            MOV     R6,A
            MOV     R7,#10H
ZH:         CLR     C
            MOV     A,R3
            RLC     A
            MOV     R3,A
            MOV     A,R2
            RLC     A
            MOV     R2,A
            MOV     A,R6
            ADDC    A,R6
            DA      A
            MOV     R6,A
            MOV     A,R5
            ADDC    A,R5
            DA      A   
            MOV     R5,A
            MOV     A,R4
            ADDC    A,R4
            DA      A
            MOV     R4,A
            DJNZ    R7,ZH
            RET

D1MS:       MOV R7,#80 ;1MS延时
            DJNZ R7,$
            RET

numtab:     DB 0FCH,60H,0DAH,0F2H,66H,0B6H,0BEH,0E0H,0FEH,0F6H ;实验板上的7段数码管0~9数字的共阴显示代码

            END

上一篇:红外线遥控器声光测试器

下一篇:单片机与PC串口通信2

发表评论:

评论记录:

未查询到任何数据!

在线咨询

点击这里给我发消息 咨询专员

在线咨询

咨询电话

18906103328

电话咨询

微信扫一扫

微信联系
返回顶部