求求各位指導一下我維修的方向,程序仿真lcd1602不顯示任何字符,按鈕只有最后一列有反饋
所有程序:
dht11.h的程序:
// dht11.h
#ifndef __DHT11_H__
#define __DHT11_H__
#include "main.h"
void DHT11_Start(void);
unsigned char DHT11_Read(void);
float Read_TRH(UCHAR channel);
#endif
dht11.c的程序:
// dht11.c
#include "adc0832.h"
#include "delay.h"
#include "dht11.h"
#include "HW_key.h"
#include "main.h"
#include "lcd1602.h"
#include <intrins.h>
#include <reg52.h>
sbit DHT11_DATA = P1^7; // 定義數(shù)據(jù)引腳
// 函數(shù)聲明
void DHT11_Start(void) {
DHT11_DATA = 0;
Delay_ms(18);
DHT11_DATA = 1;
Delay_us(30);
}
unsigned char DHT11_Read(void) {
unsigned char i = 0;
unsigned char received_data = 0;
for(i = 0; i < 8; i++) { // 變量i必須在循環(huán)外聲明
received_data <<= 1;
while(!DHT11_DATA);
Delay_us(30);
if(DHT11_DATA)
received_data |= 0x01;
while(DHT11_DATA);
}
return received_data;
}
float Read_TRH(UCHAR channel) {
unsigned char dht_data[5]; // 重命名數(shù)組
unsigned char i; // 提前聲明循環(huán)變量
float temperature = 0.0;
float humidity = 0.0;
DHT11_Start();
for(i = 0; i < 5; i++) {
dht_data[i] = DHT11_Read(); // 使用新名稱
}
if(dht_data[4] == (dht_data[0] + dht_data[1] + dht_data[2] + dht_data[3])) {
if(channel == 1) {
temperature = dht_data[2];
temperature += dht_data[3] / 10.0;
if (dht_data[2] & 0x80) {
temperature = -((dht_data[2] & 0x7F) + dht_data[3] / 10.0);
}
return temperature;
}
else if(channel == 0) {
humidity = (dht_data[0] * 256.0 + dht_data[1]) / 10.0;
return humidity;
}
}
return 0.0;
}
adc0832.h的程序:
// adc0832.h
#ifndef __ADC0832_H__
#define __ADC0832_H__
#include "main.h"
sbit ADC0832_CS = P1^2; // 避免與其它模塊共用P1口
sbit ADC0832_CLK = P1^1;
sbit ADC0832_DI = P1^0;
sbit ADC0832_DO = P1^0;
// 函數(shù)聲明
unsigned char ADC0832_Read(unsigned char channel);
#endif // __ADC0832_H__
adc0832.c的程序:
// adc0832.c
#include "adc0832.h"
#include "delay.h"
#include "dht11.h"
#include "HW_key.h"
#include "main.h"
#include "lcd1602.h"
#include <intrins.h>
unsigned char ADC0832_Read(unsigned char channel) {
unsigned char i;
unsigned char adc_data = 0; // 變量名改為 adc_data
ADC0832_CS = 0;
ADC0832_CLK = 0;
ADC0832_DI = 1;
ADC0832_CLK = 1; _nop_(); ADC0832_CLK = 0;
ADC0832_DI = (channel >> 0) & 0x01;
ADC0832_CLK = 1; _nop_(); ADC0832_CLK = 0;
ADC0832_DI = (channel >> 1) & 0x01;
ADC0832_CLK = 1; _nop_(); ADC0832_CLK = 0;
for(i = 0; i < 8; i++) {
ADC0832_CLK = 1;
adc_data <<= 1; // 同步修改變量名
if(ADC0832_DO) {
adc_data |= 0x01; // 同步修改變量名
}
ADC0832_CLK = 0;
}
ADC0832_CS = 1;
return adc_data; // 同步修改變量名
}
delay.c的程序:
// delay.c
#include "adc0832.h"
#include "delay.h"
#include "dht11.h"
#include "HW_key.h"
#include "main.h"
#include "lcd1602.h"
#include <intrins.h>
void Delay_ms(u16 ms) {
u16 i, j;
for(i = 0; i < ms; i++)
for(j = 0; j < 120; j++);
}
void Delay_us(u16 us) {
while(us--) {
_nop_(); _nop_(); _nop_(); _nop_(); // 約1us(根據(jù)晶振頻率調整)
}
}
delay.h的程序:
// delay.h
#ifndef __DELAY_H__
#define __DELAY_H__
#include "main.h"
void Delay_ms(u16 ms);
void Delay_us(u16 us);
#endif // __DELAY_H__
lcd1602.c的程序:
#include "adc0832.h"
#include "delay.h"
#include "dht11.h"
#include "HW_key.h"
#include "main.h"
#include "lcd1602.h"
#include <intrins.h> // 包含_nop_()函數(shù)
// 全局變量定義(嚴格符合C89規(guī)范)
LCD_Command lcdQueue[LCD_QUEUE_SIZE];
unsigned char lcdQueueCount = 0;
unsigned char lcdQueueHead = 0;
unsigned char lcdQueueTail = 0;
// 定義尾指針
bit lcdBusy = 0;
// 命令寫入函數(shù)
void WriteCOMDATA(unsigned char lcd_data, unsigned char cmd) {
if(lcdQueueCount >= LCD_QUEUE_SIZE) return;
lcdQueue[lcdQueueTail].lcd_data = lcd_data;
lcdQueue[lcdQueueTail].isCommand = cmd;
lcdQueueTail = (lcdQueueTail + 1) % LCD_QUEUE_SIZE;
lcdQueueCount++;
}
// LCD初始化
void LCD_Init(void) {
Delay_ms(20);
WriteCOMDATA(0x38, 1); // 8位模式,雙行顯示
Delay_ms(5);
while (lcdQueueCount > 0);
WriteCOMDATA(0x0C, 1); // 顯示開,光標關
while (lcdQueueCount > 0);
WriteCOMDATA(0x06, 1); // 光標右移
WriteCOMDATA(0x01, 1); // 清屏
Delay_ms(5);
}
// 字符寫入函數(shù)
void WriteChar(unsigned char Row, unsigned char Col, unsigned char Num, unsigned char *pBuffer) {
unsigned char address, i;
// 計算地址
address = (Row == 1) ? (0x80 + Col) : (0xC0 + Col);
WriteCOMDATA(address, 1);
// 寫入數(shù)據(jù)
for(i = 0; i < Num; i++) {
WriteCOMDATA(*pBuffer++, 0);
}
}
// 命令處理函數(shù)(定時器中斷中調用)
void LCD_Process(void) interrupt 1 {
if(lcdQueueCount > 0 && !lcdBusy) {
LCD_Command cmd;
// 提取命令
cmd = lcdQueue[lcdQueueHead];
lcdQueueHead = (lcdQueueHead + 1) % LCD_QUEUE_SIZE;
lcdQueueCount--;
// 硬件操作
lcdBusy = 1;
RS = cmd.isCommand ? 0 : 1;
RW = 0;
LCD_PINDATA = cmd.lcd_data;
E = 1;
_nop_(); _nop_(); _nop_(); _nop_(); // 至少保持300ns
E = 0;
Delay_us(100); // 確保命令執(zhí)行完成
lcdBusy = 0;
}
}
lcd1602.h的程序:
#ifndef __LCD1602_H__
#define __LCD1602_H__
#include "main.h"
// 隊列長度定義
#define LCD_QUEUE_SIZE 16
// 命令結構體
typedef struct {
unsigned char lcd_data;
unsigned char isCommand;
} LCD_Command;
typedef unsigned char u8; // 添加u8類型定義
extern LCD_Command lcdQueue[LCD_QUEUE_SIZE];
extern unsigned char lcdQueueCount;
extern unsigned char lcdQueueHead;
extern unsigned char lcdQueueTail; // 新增聲明
extern bit lcdBusy;
// 函數(shù)聲明
void WriteCOMDATA(UCHAR lcd_data, UCHAR cmd);
void LCD_Init(void);
void WriteChar(UCHAR Row, UCHAR Col, UCHAR Num, UCHAR *pBuffer);
void LCD_Process(void) interrupt 1;;
#endif
HW_key.c的程序:
// HW_key.c
#include "adc0832.h"
#include "delay.h"
#include "dht11.h"
#include "HW_key.h"
#include "main.h"
#include "lcd1602.h"
#include <intrins.h>
UCHAR Key_row = 0x0F; // 初始化為無按鍵狀態(tài)
UCHAR KEY_ROW_SCAN(void) {
// 讀取行引腳狀態(tài)
Key_row = 0x0F; // 默認無按鍵
if (ROW1 == 0) Key_row &= ~0x08; // 第1行
if (ROW2 == 0) Key_row &= ~0x04; // 第2行
if (ROW3 == 0) Key_row &= ~0x02; // 第3行
if (ROW4 == 0) Key_row &= ~0x01; // 第4行
if (Key_row != 0x0F) { // 有按鍵按下
Delay_ms(10); // 消抖
if (Key_row != 0x0F) {
return Key_row;
}
}
return 0x0F; // 無按鍵按下
}
UCHAR KEY_SCAN(void) {
char key = 0;
char row = KEY_ROW_SCAN();
if(row != 0x0F) {
// 掃描列前復位
COL1 = 1; COL2 = 1; COL3 = 1; COL4 = 1;
// 掃描列
COL1 = 1; COL2 = 0; COL3 = 1; COL4 = 1;
if(!ROW1) key = '1';
else if(!ROW2) key = '2';
else if(!ROW3) key = '3';
else if(!ROW4) key = 'A';
COL1 = 0; COL2 = 1; COL3 = 1; COL4 = 1;
if(!ROW1) key = '4';
else if(!ROW2) key = '5';
else if(!ROW3) key = '6';
else if(!ROW4) key = 'B';
COL1 = 1; COL2 = 1; COL3 = 0; COL4 = 1;
if(!ROW1) key = '7';
else if(!ROW2) key = '8';
else if(!ROW3) key = '9';
else if(!ROW4) key = 'C';
COL1 = 1; COL2 = 1; COL3 = 1; COL4 = 0;
if(!ROW1) key = '*';
else if(!ROW2) key = '0';
else if(!ROW3) key = '#';
else if(!ROW4) key = 'D';
}
return key;
}
void HW_KEY_FUNCTION(void) {
char key = KEY_SCAN();
if(key != 0x0F) {
// 根據(jù)按鍵執(zhí)行相應操作
switch(key) {
// 第一行按鍵:調整溫度上限和下限閾值
case '1':
T1H = (T1H < 99) ? T1H + 1 : 99;
break;
case '2':
T1H = (T1H > T1L + 1) ? T1H - 1 : T1L + 1;
break;
case '3':
T1L = (T1L < T1H - 1) ? T1L + 1 : T1H - 1;
break;
case 'A':
T1L = (T1L > 0) ? T1L - 1 : 0;
break;
// 第二行按鍵:調整濕度上限和下限閾值
case '4':
R1H = (R1H < 99) ? R1H + 1 : 99;
break;
case '5':
R1H = (R1H > R1L + 1) ? R1H - 1 : R1L + 1;
break;
case '6':
R1L = (R1L < R1H - 1) ? R1L + 1 : R1H - 1;
break;
case 'B':
R1L = (R1L > 0) ? R1L - 1 : 0;
break;
// 第三行按鍵:調整PM2.5上限和下限閾值
case '7':
HPM = (HPM < 9999) ? HPM + 1 : 9999;
break;
case '8':
HPM = (HPM > 0) ? HPM - 1 : 0;
break;
case '9':
HPM = (HPM < 9999) ? HPM + 1 : 9999;
break;
case 'C':
HPM = (HPM > 0) ? HPM - 1 : 0;
break;
// 第四行按鍵:進入設置模式,確認操作,返回上一級操作,以及返回當前讀取的溫度、濕度和PM2.5頁面
case '*':
shezhi_flag = (shezhi_flag + 1) % 7; // 進入設置模式
break;
case '0':
shezhi_flag = 0; // 確認操作
break;
case '#':
shezhi_flag = 0; // 返回上一級操作
break;
case 'D':
shezhi_flag = 0; // 返回當前讀取的頁面
break;
default:
break;
}
}
}
HW_key.h的程序:
// HW_key.h
#ifndef __HW_KEY_H__
#define __HW_KEY_H__
#include "main.h"
extern UCHAR Key_row; // 全局變量聲明
UCHAR KEY_ROW_SCAN(void);
UCHAR KEY_SCAN(void);
void HW_KEY_FUNCTION(void);
#endif // __HW_KEY_H__
main.c的程序:
// main.c
#include "main.h"
#include "LCD1602.h"
#include "dht11.h"
#include "HW_key.h"
#include "adc0832.h"
#include "delay.h"
#include "keymap.h"
#include <stdio.h>
#include <string.h>
// 全局變量定義
int T1L = 12; // 溫度下限閾值初始值
int T1H = 35; // 溫度上限閾值初始值
int R1L = 15; // 濕度下限閾值初始值
int R1H = 60; // 濕度上限閾值初始值
int HPM = 75; // PM2.5 上限閾值初始值
UCHAR shezhi_flag = 0; // 設置模式標志
UCHAR Mode_flag = 0; // 工作模式標志
float pm1 = 0.0; // 溫度值
float pm2 = 0.0; // 濕度值
float PM = 0.0; // PM2.5 值
extern int T1L, T1H, R1L, R1H, HPM;
extern UCHAR shezhi_flag, Mode_flag;
// main.c 中實現(xiàn) read_data:
float read_data(UCHAR channel) {
return (float)ADC0832_Read(channel); // 調用 ADC0832_Read
}
// 主函數(shù)
void main(void) {
// 初始化各個模塊
Timer0_Init();
LCD_Init();
// 主循環(huán)
while(1) {
// 1. 讀取傳感器數(shù)據(jù)
pm1 = Read_TRH(1); // 讀取溫度,假設通道1為溫度
pm2 = Read_TRH(0); // 讀取濕度,假設通道0為濕度
PM = read_data(2); // 讀取PM2.5,假設通道2為PM2.5
// 2. 處理按鍵輸入
HW_KEY_FUNCTION();
// 3. 檢查閾值并控制報警
check_thresholds();
// 4. 更新LCD顯示
update_display();
// 5. 延時以穩(wěn)定讀取頻率
set_parameters();
Delay_ms(200); // 根據(jù)需要調整延時
}
}
// 檢查閾值并控制報警
void check_thresholds(void) {
bit temp_alarm = (pm1 > T1H || pm1 < T1L);
bit humi_alarm = (pm2 > R1H || pm2 < R1L);
bit pm_alarm = (PM > HPM);
BUZZER = (temp_alarm || humi_alarm || pm_alarm) ? 0 : 1;
LED1 = (pm1 > T1H) ? 0 : 1; // 溫度上限報警
LED2 = (pm1 < T1L) ? 0 : 1; // 溫度下限報警
LED3 = (pm2 > R1H) ? 0 : 1; // 濕度上限報警
LED4 = (pm2 < R1L) ? 0 : 1; // 濕度下限報警
LED5 = (PM > HPM) ? 0 : 1; // PM2.5報警
}
// 更新LCD顯示
void update_display(void) {
char buffer[16];
// 顯示溫度
sprintf(buffer, "T:%dC", (int)pm1);
WriteChar(1, 1, strlen(buffer), buffer);
// 顯示濕度
sprintf(buffer, "H:%d%%", (int)pm2);
WriteChar(1, 9, strlen(buffer), buffer);
// 顯示PM2.5
sprintf(buffer, "PM2.5:%d", (int)PM);
WriteChar(2, 1, strlen(buffer), buffer);
}
void Timer0_Init(void) {
TMOD |= 0x01; // 模式1(16位定時器)
TH0 = 0x3C; // 12MHz,50ms中斷
TL0 = 0xB0;
ET0 = 1; // 啟用中斷
EA = 1; // 全局中斷使能
TR0 = 1; // 啟動定時器0
}
// 設置參數(shù)處理函數(shù)
void set_parameters(void) {
// 根據(jù) shezhi_flag 設置不同的參數(shù)
// shezhi_flag = 0: 設置溫度上限
// shezhi_flag = 1: 設置溫度下限
// shezhi_flag = 2: 設置濕度上限
// shezhi_flag = 3: 設置濕度下限
// shezhi_flag = 4: 設置PM2.5上限
// shezhi_flag = 5: 設置PM2.5下限
// shezhi_flag = 6: 退出設置模式
switch(shezhi_flag) {
case 0:
// 設置溫度上限
T1H = (T1H < 99) ? T1H + 1 : 99;
break;
case 1:
// 設置溫度下限
T1L = (T1L < T1H - 1) ? T1L + 1 : T1H - 1;
break;
case 2:
// 設置濕度上限
R1H = (R1H < 99) ? R1H + 1 : 99;
break;
case 3:
// 設置濕度下限
R1L = (R1L < R1H - 1) ? R1L + 1 : R1H - 1;
break;
case 4:
// 設置PM2.5上限
HPM = (HPM < 9999) ? HPM + 1 : 9999;
break;
case 5:
// 設置PM2.5下限
// 這里假設沒有單獨的PM2.5下限設置,可以根據(jù)需要調整
// 例如:
// PM2.5_L = (PM2.5_L < HPM - 1) ? PM2.5_L + 1 : HPM - 1;
break;
case 6:
// 退出設置模式
shezhi_flag = 0;
break;
default:
shezhi_flag = 0;
break;
}
}
// 鍵盤掃描函數(shù)
main.h的程序:
// main.h
#ifndef __MAIN_H__
#define __MAIN_H__
#include <reg52.h>
#include <string.h>
// 統(tǒng)一硬件接口定義
sbit RS = P1^4; // LCD 控制引腳
sbit RW = P1^5;
sbit E = P1^6;
sbit COL1 = P3^4; // 鍵盤列
sbit COL2 = P3^5;
sbit COL3 = P3^6;
sbit COL4 = P3^7;
sbit ROW1 = P3^0; // 鍵盤行
sbit ROW2 = P3^1;
sbit ROW3 = P3^2;
sbit ROW4 = P3^3;
sbit LED1 = P2^0; // 溫度上限報警
sbit LED2 = P2^1; // 溫度下限報警
sbit LED3 = P2^2; // 濕度上限報警
sbit LED4 = P2^3; // 濕度下限報警
sbit LED5 = P2^4; // PM2.5 上限報警
sbit BUZZER = P1^3; // 蜂鳴器
#define LCD_PINDATA P0
typedef unsigned char UCHAR;
typedef unsigned int u16;
typedef unsigned long u32;
// 全局變量聲明(extern)
extern int T1H, T1L, R1H, R1L, HPM;
extern UCHAR shezhi_flag, Mode_flag;
void Timer0_Init(void); // 定時器初始化
float read_data(UCHAR channel); // 讀取PM2.5數(shù)據(jù)
void check_thresholds(void); // 閾值檢查
void update_display(void); // 顯示更新
void set_parameters(void); // 設置參數(shù)處理
UCHAR KEY_SCAN(void); // 按鍵掃描
void HW_KEY_FUNCTION(void); // 按鍵功能處理
#endif
|