风筝
发表于: 2018-8-16 22:28:09 | 显示全部楼层

本篇文章主要介绍如何使用PIC单片机从DHT11读取湿度和温度,并将其显示在LCD显示屏上。在这个例子中,我们使用的单片机型号是PIC16F628A。


所需的内容

要完成此项目,您需要以下内容:

●    使用安装有Microchip MPLAB X IDE和XC8 v1.34编译器的计算机。

●    PIC16F628单片机

●    LCD(HD4480或类似产品)

●    DHT11传感器

●    PICkit3烧写器

●    面包板和一些连接导线。


简介

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


要让DHT11和MCU相互通讯,需要同步它们。为了使它们同步,MCU在数据引脚上发送一个20us高脉冲的启动信号。在脉冲之后,MCU等待接收数据。在软件中,我们必须改变数据引脚的方向。您可以采用4引脚和3引脚布局的传感器,但我们使用的是3引脚版本。两者的性能没有区别,多余的引脚没有连接到任何东西。

dht11FB.jpg


硬件

制作小工具时要做的第一件事就是制作一个方块图。通过这种方式,您可以忽略您想要的以及您想要的方式。这是我们的小工具的框图:

humtemp.png

◼   我们希望DHT11将数据发送到MCU。

◼   我们希望MCU处理数据并将其显示在LCD上。

◼   我们希望能够使用ICSP对MCU进行编程。


原理图布局

原理图布局分为块:

pic16f628-dht11-lcd.png


Powerblock -  将电源调节到5伏。它使用的是LM7805。

ICSP - 这是一个1x5引脚接头,连接到MCU的编程引脚。我们使用此插头对MCU进行编程。

DHT11 - 这是一个1x3引脚接头,用于固定传感器。中间引脚连接到MCU,用于数据传输。

MCU - 这是PIC16F628A,它从DHT11接收数据并将其显示在LCD上

LCD - 这是一个16x02 LCD,显示湿度和温度。


我们正在使用MCU的内部4MHz振荡器。因此,电路中没有晶体或陶瓷谐振器。


软件

安装XC8编译器时,还安装了一些头文件和源文件。 在本篇文章中,我们使用了XC8编译器附带的LCD文件:XLCD.H和一堆源文件。 为了使事情变得更容易,我将所有源文件复制到一个文件中。 在我的Ubuntu安装中,我找到了XLCD源文件:

  1. /opt/microchip/xc8/v1.34/sources/pic18/plib/XLCD
复制代码

那里有10个文件,bysyxlcd.c、openxlcd.c、putrxlcd.c等等。 我将所有这些文件放在一个文件中,并将其命名为my_xlcd.c。 此文件现在包含所有函数。 myxlcd.c文件和xlcd.h文件被复制到项目文件夹中。 (xlcd.h文件位于:/opt/microchip/xc8/v1.34/include/plib)。 xlcd.h文件是一个标准文件,需要进行一些编辑。 我们需要更改MCU引脚的连接以匹配我们的设置:

  1. /* DATA_PORT defines the port to which the LCD data lines are connected */
  2. #define DATA_PORT                      PORTB
  3. #define TRIS_DATA_PORT                 TRISB

  4. /* CTRL_PORT defines the port where the control lines are connected.
  5. * These are just samples, change to match your application.
  6. */
  7. #define RW_PIN   PORTAbits.RA0                   /* PORT for RW */
  8. #define TRIS_RW  TRISAbits.TRISA0            /* TRIS for RW */

  9. #define RS_PIN   PORTAbits.RA1                  /* PORT for RS */
  10. #define TRIS_RS  TRISAbits.TRISA1            /* TRIS for RS */

  11. #define E_PIN    PORTAbits.RA7                 /* PORT for D  */
  12. #define TRIS_E   TRISAbits.TRISA7            /* TRIS for E  */
复制代码

这里,定义了LCD和MCU之间的连接。 这两个文件没有更多内容。 (my_xlcd.h和my_xlcd.c)


接下来是主程序。 它开始是一些INCLUDES、配置位、定义、变量和函数原型:

  1. // INCLUDES
  2. #include <stdio.h>               // Including Standard Input / Outputlibrary
  3. #include <stdlib.h>              // Including Standard library function
  4. #include <xc.h>                  // Including XC8 compiler library
  5. #include "my_xlcd.h"            // Including my custom LCD

  6. // CONFIG
  7. #pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTRC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
  8. #pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
  9. #pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
  10. #pragma config MCLRE = ON       // RA5/MCLR pin function select (RA5/MCLR pin function is MCLR)
  11. #pragma config BOREN = ON       // Brown-out Reset Enable bit (BOD Reset enabled)
  12. #pragma config LVP = ON         // Low-Voltage Programming Enable bit (RB4/PGM pin has PGM function, low-voltage programming enabled)
  13. #pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection off)
  14. #pragma config CP = OFF         // Code Protection bits (Program memory code protection off)

  15. // DEFINES
  16. #define _XTAL_FREQ 4000000          // Telling the compiler, that we are using 4MHz
  17. #define data PORTAbits.RA2          // Defining RA0 as datapin
  18. #define data_dir TRISAbits.TRISA2   // Definig TRISA0 as dataport

  19. // GLOBAL VARIABLES
  20. char message1[] = "Temp = 00.0 c";
  21. char message2[] = "RH   = 00.0 %";
  22. unsigned short TOUT = 0, CheckSum, i;
  23. unsigned short T_Byte1, T_Byte2, RH_Byte1, RH_Byte2;

  24. // PROTOTYES
  25. void init_XLCD(void);
  26. void DelayFor18TCY(void);
  27. void DelayPORXLCD(void);
  28. void DelayXLCD(void);
  29. void Delay10KTCYx(unsigned char);
  30. void StartSignal(void);
  31. unsigned short ReadByte();
  32. unsigned short CheckResponse();
复制代码

然后我们开始写相关函数。 为了使LCD与MCU一起工作,我们需要写一些延迟函数。 在XLCD.H文件的顶部,声明:

  * - 用户必须提供三个延迟例程:

  * - DelayFor18TCY()提供18 Tcy的延迟

  * - DelayPORXLCD()提供至少15ms的延迟

  * - DelayXLCD()提供至少5ms的延迟


我们需要添加第四个延迟函数,Delay10KTCYx


以下是LCD的初始化函数和延迟函数:

  1. // FUNCTIONS
  2. void init_XLCD(void){
  3.     OpenXLCD(FOUR_BIT & LINES_5X7);     // Sets 4-bit & 5x7 charachters
  4.     while(BusyXLCD());                  // Checks if LCD is busy
  5.     WriteCmdXLCD(0x06);                 // Moves cursor right
  6.     WriteCmdXLCD(0x0C);                 // Display on, cursor off
  7. }

  8. void DelayFor18TCY(void){               // as it says in the XLCD.H file
  9.     NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
  10.     NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); NOP();
  11.     return;
  12. }

  13. void DelayPORXLCD(void){               // as it says in the XLCD.H file
  14.     __delay_ms(15);
  15. }

  16. void DelayXLCD(void){                 // as it says in the XLCD.H file
  17.     __delay_ms(5);
  18. }

  19. void Delay10KTCYx(unsigned char){     // as it says in the XLCD.H file
  20.     __delay_ms(10);
  21. }
复制代码

接下来是Start signal、ReadbyteCheckResponse函数:

  1. void StartSignal(){
  2.     data_dir = 0;       // Sets TRISA2 to output
  3.     data = 0;           // Set RA2 to LOW
  4.     __delay_ms(18);     // Waits for 18 ms
  5.     data = 1;           // Sets RA2 HIGH
  6.     __delay_us(20);     // Waits for 20 ms
  7.     data_dir = 1;       // Sets TRISA2 to input
  8. }

  9. unsigned short ReadByte(){
  10.     unsigned short num = 0, t;
  11.     data_dir = 1;                       // Sets TRISA2 to input
  12.     for (i=0;i<8;i++){                  // Start loop
  13.         while(!data);                   // When data is not valid
  14.         TMR2 = 0;                       // Sets TMR2 to 0
  15.         T2CONbits.TMR2ON = 1;           // Start TMR2 from 0 when a low to high data pulse
  16.         while(data);                    // is detected, and wait until it falls low again
  17.         T2CONbits.TMR2ON = 0;           // Stop the TMR2 when the data pulse falls low
  18.         if(TMR2>40) num |= 1 << (7-i);  // If time > 40us, data is 1
  19.         }
  20.     return num;                         // Return 8-bit = 1-byte
  21. }

  22. unsigned short CheckResponse(){
  23.     TOUT = 0;
  24.     TMR2 = 0;
  25.     T2CONbits.TMR2ON = 1;       // Turn on TMR2
  26.     while(!data && !TOUT);      // While NOT data and NOT TOUT
  27.     if (TOUT) return 0;         // Return 0 => OK
  28.     else {
  29.         TMR2 = 0;               // Disable Timer 2
  30.         while(data && !TOUT);   // While data and NOT TOUT
  31.         if(TOUT) return 0;      // If Tout = 1 then return 0 => OK
  32.         else {
  33.             T2CONbits.TMR2ON = 0;   // Turn off TMR2
  34.             return 1;               // Return 1 => NOT OK   
  35.         }
  36.     }
  37. }
复制代码

为了掌握MCU何时发送启动信号,以及当DHT11完成40位时,我们需要一个中断函数:

  1. void interrupt tc_int(void){
  2.     if(PIR1bits.TMR2IF){            // If TMR2 to PR2 match Interrupt Flag     
  3.         TOUT = 1;
  4.         T2CONbits.TMR2ON = 0;       // Stop timer
  5.         PIR1bits.TMR2IF = 0;        // Clear TMR0 interrupt flag
  6.     }
  7. }
复制代码

最后我们需要main程序:

  1. int main(int argc, char** argv) {
  2.     unsigned short check;
  3.     TRISB = 0b00000000;         // TRISB output
  4.     PORTB = 0b00000000;         // PORTB low
  5.     TRISA = 0b00000001;         // TRISA output
  6.     PORTA = 0b00000000;         // PORTA low
  7.    
  8.     CMCON = 0x07;               // Comparators off
  9.    
  10.     // TIMER
  11.     INTCONbits.GIE = 1;         // Enable global interrupt
  12.     INTCONbits.PEIE = 1;        // Enable peripheral interrupt
  13.     PIE1bits.TMR2IE = 1;        // Enable Timer2 interrupt
  14.     T2CON = 0;                  // Prescaler 1:1 and Timer2 is off initially
  15.     PIR1bits.TMR2IF = 0;        // Clear TMR INT flag bit
  16.     TMR2 = 0;
  17.    
  18.     init_XLCD();                // Initialize the LCD
  19.     putrsXLCD("  Hello World.");    // Welcome text
  20.     SetDDRamAddr(0x40);             // Move cursor to line 2
  21.     putrsXLCD("  I'm alive.");
  22.     __delay_ms(250);
  23.     do {
  24.         __delay_ms(1000);
  25.         StartSignal();              // Send the Startsignal
  26.         check = CheckResponse();    // Assign check with 0 = OK, or 1 = NOT OK
  27.         if(!check) {                // OK check = 1 => NOT OK
  28.             WriteCmdXLCD(0x01);     // Clear screen, set cursor in 0,0   
  29.             putrsXLCD("No response.");  // Write error message
  30.             SetDDRamAddr(0x40);         
  31.             putrsXLCD("Please check.");
  32.             }
  33.         else {                      // IF chack = 0 => OK
  34.    
  35.         RH_Byte1 = ReadByte();      // Read first byte
  36.         RH_Byte2 = ReadByte();      // Read second byte
  37.         T_Byte1 = ReadByte();       // Read third byte
  38.         T_Byte2 = ReadByte();       // Read fourth byte
  39.         CheckSum = ReadByte();      // Read checksum
  40.         // Checks if all bytes is equal to the checksum
  41.         if (CheckSum == ((RH_Byte1 + RH_Byte2 + T_Byte1 + T_Byte2) & 0xFF))
  42.         {
  43.             message1[7] = T_Byte1/10 + 48;      // Extract the tens place
  44.             message1[8] = T_Byte1 + 48;      // Extract the ones place
  45.             message1[10]= T_Byte2/10 + 48;      // Extract the decimal
  46.             message1[11] = 223;                 // ASCII code for degree symbol         
  47.             message2[7] = RH_Byte1/10 + 48;     // Extract the tens place
  48.             message2[8] = RH_Byte1 + 48;     // Extract the ones place
  49.             message2[10] = RH_Byte2/10 + 48;    // Extract the decimal

  50.             WriteCmdXLCD(0x01);
  51.             putrsXLCD(message1);    // Write the temp to LCD
  52.             SetDDRamAddr(0x40);
  53.             putrsXLCD(message2);    // Write the humidity to LCD
  54.         }
  55.         else {                      // Checksum is not correct
  56.             WriteCmdXLCD(0x01);
  57.             putrsXLCD("Checksum error!");
  58.             SetDDRamAddr(0x40);
  59.             putrsXLCD("Please wait.");
  60.         }      
  61.         }
  62.     } while (1);    // Do it forever.
  63. }
复制代码

以上是使用PIC单片机读取DHT11数据的一种方法。

DHT11closeup1.jpg


PIC16F628DHT11LCDbb.jpg


总结

我们使用PIC16F628A单片机读取DHT11温湿度传感器,然后在LCD上显示温度和湿度。 您可以通过一些代码调整以适合您喜欢的MCU。

跳转到指定楼层
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题 10 | 回复: 13



手机版|

GMT+8, 2024-12-22 13:08 , Processed in 0.045782 second(s), 8 queries , Gzip On, MemCache On. Powered by Discuz! X3.5

YiBoard一板网 © 2015-2022 地址:河北省石家庄市长安区高营大街 ( 冀ICP备18020117号 )

快速回复 返回顶部 返回列表