如何使用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 * / / *三
在这里,单片机的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();
然后我们有功能。液晶显示器与单片机工作,我们需要做一些延迟函数。你的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); }
下一个开始的信号,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 } } }
的单片机发送起始信号时,当DHT11完成40位,我们需要一个中断功能:
无效中断tc_int (void){如果(PIR1bits.TMR2IF){/ /如果TMR2 PR2比赛中断标志兜售= 1;T2CONbits。TMR2ON = 0;/ /停止计时器PIR1bits。TMR2IF = 0;/ /清楚TMR0中断标志}}
最后我们需要主程序:
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. }
这是一种使用DHT11图片和液晶。
结论
我们使用这个DHT11 PIC16F628A单片机,我们显示在液晶显示温度和湿度。一些努力,你可以/调整代码转换为适合您最喜爱的单片机。程序占用32%的单片机的数据内存和程序内存的55%。这是因为小中型集成电路。
PIC16F628和PIC16F628A之间的差异之一是,“A”版本有一个内部振荡器。没有“A”的版本需要一个外部晶体或其他RC网络。如果你买一个PIC16F628,一定是“a”版本。另一个是过时了。
图片和视频
自己尝试这个项目!BOM。
PIC16F628是一个已知的部分数字由微芯片早已停止,但仍可以在eBay和其他网站。那将是一种耻辱,如果有人要求你而不是一部分一部分供他们使用,PIC16F628A。无车载振荡器的零件号“A”。“A”的部分有一个车载振荡器和部分你由于没有外部晶体或RC网络电路。就好了如果你更新你的列表或做一些电路部分提到的文本。
你好,我从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);
}