找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 216|回复: 1
打印 上一主题 下一主题
收起左侧

求助单片机仿真程序,找不到修复的地方

[复制链接]
跳转到指定楼层
楼主
求求各位指导一下我维修的方向,程序仿真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;  // 定义数据引脚

// 函数声明
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必须在循环外声明
        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]; // 重命名数组
    unsigned char i; // 提前声明循环变量
    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;

// 函数声明
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(根据晶振频率调整)
    }
}       





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_()函数

// 全局变量定义(严格符合C89规范)
LCD_Command lcdQueue[LCD_QUEUE_SIZE];
unsigned char lcdQueueCount = 0;
unsigned char lcdQueueHead = 0;
unsigned char lcdQueueTail = 0;
  // 定义尾指针
bit lcdBusy = 0;
// 命令写入函数
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);
}

// 字符写入函数
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);

    // 写入数据
    for(i = 0; i < Num; i++) {
        WriteCOMDATA(*pBuffer++, 0);
    }
}

// 命令处理函数(定时器中断中调用)
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);  // 确保命令执行完成

        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;

// 函数声明
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; // 初始化为无按键状态

UCHAR KEY_ROW_SCAN(void) {
    // 读取行引脚状态
    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) {
        // 根据按键执行相应操作
        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 中实现 read_data:
float read_data(UCHAR channel) {
    return (float)ADC0832_Read(channel);  // 调用 ADC0832_Read
}

// 主函数
void main(void) {
    // 初始化各个模块
        Timer0_Init();
    LCD_Init();


    // 主循环
    while(1) {
        // 1. 读取传感器数据
        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. 延时以稳定读取频率
                set_parameters();
        Delay_ms(200); // 根据需要调整延时
    }
}

// 检查阈值并控制报警
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
}
// 设置参数处理函数
void set_parameters(void) {
    // 根据 shezhi_flag 设置不同的参数
    // 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下限设置,可以根据需要调整
            // 例如:
            // 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;
    }
}

// 键盘扫描函数









main.h的程序:
// main.h
#ifndef __MAIN_H__
#define __MAIN_H__

#include <reg52.h>
#include <string.h>

// 统一硬件接口定义
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数据
void check_thresholds(void);      // 阈值检查
void update_display(void);        // 显示更新
void set_parameters(void);        // 设置参数处理
UCHAR KEY_SCAN(void);             // 按键扫描
void HW_KEY_FUNCTION(void);       // 按键功能处理

#endif

51hei图片_20250422142052.png (167 KB, 下载次数: 0)

51hei图片_20250422142052.png
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:584814 发表于 2025-4-27 11:10 | 只看该作者
1、在本论坛找现成的;
2、上含仿真的全部工程文件
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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