所有关于电路
项目

如何使用DHT11 PIC16F628A和液晶吗

2015年8月07通过Jens Christoffersen

如何从DHT11读取湿度和温度并显示在液晶与PIC单片机。在这个例子中我们将使用PIC16F628A。

如何从DHT11读取湿度和温度并显示在液晶与PIC单片机。在这个例子中我们将使用PIC16F628A。

需求

为了完成这个项目,你需要以下几点:

  • 电脑芯片的X MPLAB IDE,与XC8 v1.34编译器安装。(我使用MPLAB X v3.05 XC8 v1.34)
  • PIC16F628单片机
  • 液晶显示器(HD4480或等效)
  • DHT11传感器
  • 一种程序的单片机(我使用PICkit3)
  • 部分中列出的Partslist鹰。
  • 如果你想电路试验板,你需要一个案板和一些跳线。

介绍

DHT11的湿度和温度传感器,使用一线发送40位的数据。第一16位整数和小数的湿度,接下来的16位整数和分数的温度,最后8位校验和。

让DHT11单片机在一起说话,他们需要同步。同步,单片机发送起始信号,我们是一个20高脉冲数据销。脉冲后,单片机等待接收的数据。在软件中,我们必须改变的方向数据销。你可以阅读更多关于DHT11的数据表。你可以得到传感器4-pin和3布局,但我们使用3版本。没有差异的表现2、额外的针并不是连接到任何东西。

硬件

第一聪明的事情时小工具是框图。这样你会得到你想要的忽视和你想要的样子。这是一个我们产品的框图:

(它可能有点多余框图的每一个小玩意,但是我发现它非常有用。)

我们希望DHT11向单片机发送数据。

我们希望单片机处理数据并显示在液晶。

我们希望能够与ICSP单片机程序。

原理图的布局

原理图的布局被分成块:

机械绞车 调节能力5伏特。它是使用LM7805。
ICSP 这是一个1 x5销头,连接到单片机的编程。我们用这个头单片机程序。
DHT11 这是一个1 x3销头,传感器。中间销连接到单片机,数据传输。
单片机 这是PIC16F628A DHT11的接收数据并显示在液晶
显示 这个16 x02液晶显示温度和湿度。

我们使用的是单片机的内部4 mhz振荡器。因此没有晶体或陶瓷谐振器电路中。

下面是生成的零件清单,从鹰:

部分 价值 设备 图书馆
C1 0.1超滤 c - eu025 - 050 x050 c025 - 050 x050 rcl 1
C2 100年佛罗里达大学 CPOL-EUE2.5-5 E2,盘中 rcl 1
C3 0.1超滤 c - eu025 - 050 x050 c025 - 050 x050 rcl 1
C4 100年佛罗里达大学 CPOL-EUE2.5-5 E2,盘中 rcl 1
C5 0.1超滤 c - eu025 - 050 x050 c025 - 050 x050 rcl 1
D1 1 n4004 1 n4004 DO41-10 二极管 1
IC2 7805年电视 7805年电视 TO220V 线性 1
IC3 PIC16F628 DIL18 DIL18 ic-package 1
JP1 ICSP PINHD-1X5 1 x05 微不足道的东西 1
JP2 16 x02液晶 PINHD-1X16 1乘16 微不足道的东西 1
JP3 DHT11 PINHD-1X3 1 x03 微不足道的东西 1
R1 10 k R-EU_0204/7 0204/7 rcl 1
R2 5 k TRIM_EU-LI10 LI10 1
R3 4 k7 R-EU_0204/7 0204/7 rcl 1
S1 重置 TAC_SWITCHPTH TACTILE-PTH SparkFun 1
X1 7-35vDC W237-10 w237 - 102 con - wago - 500 1

现在的硬件是好的,是时候该软件。

软件

当你安装XC8编译器,你也安装了一些头文件和源文件。在这个指南我们使用的液晶文件XC8编译器:XLCD。H和一群源文件。使事情变得更简单,我复制所有的源文件到一个文件中。Ubuntu安装我找到XLCD下源文件:

/ opt /芯片/ xc8 / v1.34 / / pic18 / plib / XLCD来源

有10个文件,bysyxlcd。c, openxlcd。c, putrxlcd。c等等。我把所有这些文件放在一个文件中,我称之为my_xlcd.c。这个文件现在持有的所有功能。myxlcd。c文件和xlcd。h文件复制到项目文件夹中。(xlcd。h文件是在这里找到:/ opt /芯片/ xc8 / v1.34 / include / plib)。xlcd。h file is a standard file that needs a little bit of editing. We need to change the connections for the MCU's pins to match our setup:

/ * DATA_PORT定义的端口液晶数据连接* / #行定义DATA_PORT PORTB # define TRIS_DATA_PORT TRISB / * CTRL_PORT定义控制线路连接的端口。*这些只是样品,改变以匹配您的应用程序。* / # define RW_PIN PORTAbits。RA0 RW * / / *端口# define TRIS_RW TRISAbits。TRISA0三RW * / / * # define RS_PIN PORTAbits。RA1 RS * / / *端口# define TRIS_RS TRISAbits。TRISA1三RS * / / * # define E_PIN PORTAbits。RA7 D * / / *端口# define TRIS_E TRISAbits。TRISA7 E * / / *三

DHT11.zip

在这里,单片机的LCD和定义之间的联系。没有什么更多的以这两个文件。(my_xlcd。h和my_xlcd.c)

下一个是主程序。它开始与一些包括,配置位,定义,变量和函数原型:

/ /包含# include <stdio。h > / /包括标准输入/ Outputlibrary <stdlib的# include。h > / /包括# include <xc标准库函数。h > / / #包括“my_xlcd包括XC8编译器库。h”/ /包括我定制的液晶/ /配置# pragma配置FOSC = INTOSCIO / /振荡器选择位(INTRC振荡器:I / O功能RA6 / OSC2 / CLKOUT销,I / O功能RA7 / OSC1 / CLKIN) # pragma配置WDTE =了/ /看门狗定时器使钻头(WDT禁用)# pragma配置PWRTE = / /升高定时器使钻头(PWRT启用)# pragma配置MCLRE = / / RA5 / MCLR销功能选择(RA5 / MCLR MCLR销函数)# pragma配置BOREN = / /暗光复位使钻头(BOD重置启用)# pragma配置LVP = / /低压编程使钻头(RB4 / PGM销PGM功能,低压编程启用)# pragma配置CPD = / /数据代码保护钻头(数据记忆代码保护)# pragma配置CP =了/ /代码保护比特(程序内存的代码保护)/ /定义# define _XTAL_FREQ 4000000 / /告诉编译器,我们使用4 mhz PORTAbits #定义数据。红警2 / /定义RA0 datapin # define data_dir TRISAbits。TRISA2 / / Definig TRISA0 dataport / /消息1全局变量char [] = Temp = 00.0 c”;char message2 [] = " RH = 00.0%”;无符号短兜售= 0,校验和,我;无符号短T_Byte1、T_Byte2 RH_Byte1 RH_Byte2;/ / PROTOTYES空白init_XLCD(无效);空白DelayFor18TCY(无效);空白DelayPORXLCD(无效); void DelayXLCD(void); void Delay10KTCYx(unsigned char); void StartSignal(void); unsigned short ReadByte(); unsigned short CheckResponse();

DHT112.zip

然后我们有功能。液晶显示器与单片机工作,我们需要做一些延迟函数。你的XLCD在前。H文件说:


*——用户必须提供三个延迟例程:
* - DelayFor18TCY()提供了一个18 Tcy延迟
* - DelayPORXLCD()提供了至少15毫秒的延迟
* - DelayXLCD()提供至少5毫秒的延迟

我们需要添加第四个delayfunction Delay10KTCYx

这是液晶的初始化函数和延迟函数:

/ /函数void init_XLCD (void) {OpenXLCD (FOUR_BIT & LINES_5X7);/ /设置4比特& 5 x7 charachters而(BusyXLCD ());/ /检查液晶忙WriteCmdXLCD (0 x06);/ /移动光标右WriteCmdXLCD (0 x0c);/ /显示,光标}无效DelayFor18TCY (void) {/ / XLCD说。H文件NOP ();NOP ();NOP ();NOP ();NOP ();NOP (); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); return; } void DelayPORXLCD(void){ // as it says in the XLCD.H file __delay_ms(15); } void DelayXLCD(void){ // as it says in the XLCD.H file __delay_ms(5); } void Delay10KTCYx(unsigned char){ // as it says in the XLCD.H file __delay_ms(10); }

DHT113.zip

下一个开始的信号,Readbyte,和CheckResponse功能:

空白StartSignal () {data_dir = 0;/ /输出数据集TRISA2 = 0;/ /设置红警2低__delay_ms (18);/ /等待18女士数据= 1;/ /设置红警2高__delay_us (20);/ /等待20 ms data_dir = 1;/ /设置TRISA2输入}无符号短ReadByte(){无符号短num = 0, t;data_dir = 1;/ /设置TRISA2输入(i = 0;我< 8;我+ +){/ /开始循环,(!数据);/ /当数据是无效TMR2 = 0; // Sets TMR2 to 0 T2CONbits.TMR2ON = 1; // Start TMR2 from 0 when a low to high data pulse while(data); // is detected, and wait until it falls low again T2CONbits.TMR2ON = 0; // Stop the TMR2 when the data pulse falls low if(TMR2>40) num |= 1 << (7-i); // If time > 40us, data is 1 } return num; // Return 8-bit = 1-byte } unsigned short CheckResponse(){ TOUT = 0; TMR2 = 0; T2CONbits.TMR2ON = 1; // Turn on TMR2 while(!data && !TOUT); // While NOT data and NOT TOUT if (TOUT) return 0; // Return 0 => OK else { TMR2 = 0; // Disable Timer 2 while(data && !TOUT); // While data and NOT TOUT if(TOUT) return 0; // If Tout = 1 then return 0 => OK else { T2CONbits.TMR2ON = 0; // Turn off TMR2 return 1; // Return 1 => NOT OK } } }

DHT114.zip

的单片机发送起始信号时,当DHT11完成40位,我们需要一个中断功能:

无效中断tc_int (void){如果(PIR1bits.TMR2IF){/ /如果TMR2 PR2比赛中断标志兜售= 1;T2CONbits。TMR2ON = 0;/ /停止计时器PIR1bits。TMR2IF = 0;/ /清楚TMR0中断标志}}

DHT115.zip

最后我们需要主程序:

int主要(int命令行参数个数,char * * argv){无符号短检查;TRISB = 0 b00000000;/ /输出TRISB PORTB = 0 b00000000;/ / PORTB低TRISA = 0 b00000001;/ / TRISA输出门= 0 b00000000;/ /门低CMCON = 0 x07;/ / / /计时器INTCONbits比较器。给= 1;/ /启用全局中断INTCONbits。PEIE = 1;/ /启用中断PIE1bits外围。TMR2IE = 1;/ /启用Timer2中断T2CON = 0; // Prescaler 1:1 and Timer2 is off initially PIR1bits.TMR2IF = 0; // Clear TMR INT flag bit TMR2 = 0; init_XLCD(); // Initialize the LCD putrsXLCD(" Hello World."); // Welcome text SetDDRamAddr(0x40); // Move cursor to line 2 putrsXLCD(" I'm alive."); __delay_ms(250); do { __delay_ms(1000); StartSignal(); // Send the Startsignal check = CheckResponse(); // Assign check with 0 = OK, or 1 = NOT OK if(!check) { // OK check = 1 => NOT OK WriteCmdXLCD(0x01); // Clear screen, set cursor in 0,0 putrsXLCD("No response."); // Write error message SetDDRamAddr(0x40); putrsXLCD("Please check."); } else { // IF chack = 0 => OK RH_Byte1 = ReadByte(); // Read first byte RH_Byte2 = ReadByte(); // Read second byte T_Byte1 = ReadByte(); // Read third byte T_Byte2 = ReadByte(); // Read fourth byte CheckSum = ReadByte(); // Read checksum // Checks if all bytes is equal to the checksum if (CheckSum == ((RH_Byte1 + RH_Byte2 + T_Byte1 + T_Byte2) & 0xFF)) { message1[7] = T_Byte1/10 + 48; // Extract the tens place message1[8] = T_Byte1 + 48; // Extract the ones place message1[10]= T_Byte2/10 + 48; // Extract the decimal message1[11] = 223; // ASCII code for degree symbol message2[7] = RH_Byte1/10 + 48; // Extract the tens place message2[8] = RH_Byte1 + 48; // Extract the ones place message2[10] = RH_Byte2/10 + 48; // Extract the decimal WriteCmdXLCD(0x01); putrsXLCD(message1); // Write the temp to LCD SetDDRamAddr(0x40); putrsXLCD(message2); // Write the humidity to LCD } else { // Checksum is not correct WriteCmdXLCD(0x01); putrsXLCD("Checksum error!"); SetDDRamAddr(0x40); putrsXLCD("Please wait."); } } } while (1); // Do it forever. }

DHT116.zip

这是一种使用DHT11图片和液晶。

结论

我们使用这个DHT11 PIC16F628A单片机,我们显示在液晶显示温度和湿度。一些努力,你可以/调整代码转换为适合您最喜爱的单片机。程序占用32%的单片机的数据内存和程序内存的55%。这是因为小中型集成电路。

PIC16F628和PIC16F628A之间的差异之一是,“A”版本有一个内部振荡器。没有“A”的版本需要一个外部晶体或其他RC网络。如果你买一个PIC16F628,一定是“a”版本。另一个是过时了。

图片和视频

自己尝试这个项目!BOM。

8的评论
  • gophert 2015年8月07

    PIC16F628是一个已知的部分数字由微芯片早已停止,但仍可以在eBay和其他网站。那将是一种耻辱,如果有人要求你而不是一部分一部分供他们使用,PIC16F628A。无车载振荡器的零件号“A”。“A”的部分有一个车载振荡器和部分你由于没有外部晶体或RC网络电路。就好了如果你更新你的列表或做一些电路部分提到的文本。

    喜欢的。 回复
  • 年代
    苏米特妖怪 2016年6月30日

    你好,我从DHT11读取湿度和温度并显示在UART终端与PIC单片机(PIC16f1829)。但是把只是从传感器没有响应,请。罚款错误代码。

    # include
    # include < stdlib.h >
    # include < stdio . h >


    #定义_XTAL_FREQ 32000000
    # pragma配置FOSC = INTOSC
    # pragma配置WDTE =了/ /看门狗定时器使钻头(WDT启用)
    # pragma配置PWRTE =了/ /升高定时器使钻头(PWRT禁用)
    # pragma配置BOREN = / /暗光复位使钻头(BOR启用)
    # pragma配置LVP =了/ /软件低压(单电源)串行编程使钻头(RB3数字I / O,高压MCLR必须用于编程)
    # pragma配置CPD = / /数据EEPROM作为代码保护钻头(数据eepm代码保护)
    # pragma配置了关于= / / Flash程序内存允许写入位(写保护;所有程序内存可以写入EECON控制)
    # pragma配置CP =了/ / Flash程序内存代码保护钻头(代码保护)
    # pragma配置PLLEN = / /锁相环使(4 x锁相环禁用)


    消息1 char [] = " Temp = 00.0 C”;
    char message2 [] = " RH = 00.0%”;
    无符号短兜售= 0,校验和,我;
    无符号短T_Byte1、T_Byte2 RH_Byte1 RH_Byte2;


    空白InitUART(空白)
    {
    TRISC4 = 0;/ / TX销
    TRISC5 = 1;/ / RX销

    SPBRG = ((_XTAL_FREQ / 16) / 9600) - 1;
    BRGH = 1;/ /快速的波特率
    / / BRG16 = 0;
    同步= 0;/ /异步
    口头的= 1;/ /启用串口别针
    CREN = 1;/ /启用接待
    中国= 0;/ /没有影响
    TXIE = 0;/ /禁用tx中断

    TX9 = 0;/ / 8位传输
    RX9 = 0;/ / 8位接待
    TXEN = 0;/ /重置发射机
    TXEN = 1;/ /启用发射机
    }


    空白SendByteSerially (unsigned char字节)/ /串口写入一个字符
    {
    / /等待之前的传输来完成
    而(! TXIF);
    TXREG =字节;

    / / Lcd_Write_Char (Y);
    }

    无符号字符ReceiveByteSerially (void) / /从串口读取一个字符
    {
    如果(OERR) / /如果在运行错误,然后重置接收机
    {
    CREN = 0;
    CREN = 1;
    }

    而(! RCIF);/ /等待传输接收

    返回RCREG;
    }

    空白SendStringSerially (const unsigned char * st)
    {
    而(* st)
    SendByteSerially (* st + +);
    }

    空白StartSignal () {
    TRISA& = ~ 0 x01;

    PORTAbits。RA0 = 0;/ /数据输出端口

    __delay_ms (25);
    PORTAbits。RA0 = 1;

    __delay_us (40);
    TRISA | = 0 x01;/ /输入数据端口
    }

    无符号短CheckResponse () {
    兜售= 0;
    TMR2 = 0;
    TMR2ON = 1;/ /开始计时
    而(! PORTAbits。RA0 & & !宣传);
    如果(宣传)返回0;
    其他{
    TMR2 = 0;
    而(PORTAbits。RA0 & & !宣传);
    如果(宣传)返回0;
    其他{
    TMR2ON = 0;
    返回1;
    }
    }
    }

    无符号短ReadByte () {
    无符号短num = 0, t;
    TRISA | = 0 x01;
    (我= 0;我< 8;我+ +){
    而(! PORTAbits.RA0);
    TMR2 = 0;
    TMR2ON = 1;
    而(PORTAbits.RA0);
    TMR2ON = 0;
    如果(TMR2 > 40) num | = 1 < <(我);/ /如果时间> 40,数据是1
    }
    返回num;
    }

    无效中断ISR () {
    如果(TMR2IF) {
    兜售= 1;
    TMR2ON = 0;/ /停止计时器
    TMR2IF = 0;/ /清楚TMR0中断标志
    }
    }

    void main () {

    无符号短检查;
    int缓冲区;
    APFCON0 = 0 x84; / /替代函数使TX RX
    ANSELA& = ~ 0 x01; / /数字选择号
    OPTION_REG | = 0 x80;
    OSCCON = 0 x70; / /内部振荡器频率selec
    InitUART ();
    __delay_ms (100);
    SendStringSerially(“开始”);

    TMR2IE = 1;/ /启用Timer2中断
    T2CON = 0;/ /预定标器1:1,Timer2最初是关闭的
    TMR2IF = 0;/ /清楚咯INT国旗
    TMR2 = 0;

    给= 1;/ /启用全局中断
    PEIE = 1;/ /启用外部中断

    {做
    __delay_ms (1000);
    StartSignal ();
    检查= CheckResponse ();
    如果(检查){
    SendStringSerially(“没有响应”);
    SendStringSerially(“从传感器”);
    SendStringSerially (“\ r \ n”);
    }
    其他的
    {

    RH_Byte1 = ReadByte ();
    RH_Byte2 = ReadByte ();
    T_Byte1 = ReadByte ();
    T_Byte2 = ReadByte ();
    校验和= ReadByte ();

    / /数据接收检查错误
    如果(校验和= = ((RH_Byte1 + RH_Byte2 + T_Byte1 + T_Byte2) & 0 xff))
    {
    将消息[7]= T_Byte1/10 + 48;
    将消息[8]= T_Byte1 + 48;
    将消息[10]= T_Byte2/10 + 48;
    message2 [7] = RH_Byte1/10 + 48;
    message2 [8] = RH_Byte1 + 48;
    message2 [10] = RH_Byte2/10 + 48;
    将消息[11]= 223;/ /程度的象征



    buf = atoi(消息);
    SendStringSerially (buf);
    SendStringSerially (" \ r \ n ");

    buf = atoi (message2);
    SendStringSerially (buf);
    SendStringSerially (" \ r \ n ");
    }
    其他{
    SendStringSerially(“再次尝试…”);
    SendStringSerially (" \ r \ n ");
    SendStringSerially(“校验和错误!”);
    SendStringSerially (" \ r \ n ");
    }
    }

    },(1);
    }

    喜欢的。 回复