| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 2250 人关注过本帖
标题:请各位大神帮我看看我的程序哪里出错了,已经调试一周,急,谢谢。
只看楼主 加入收藏
大大大劼
Rank: 1
等 级:新手上路
帖 子:5
专家分:0
注 册:2015-6-13
结帖率:0
收藏
已结贴  问题点数:20 回复次数:4 
请各位大神帮我看看我的程序哪里出错了,已经调试一周,急,谢谢。
这个设计是基于单片机智能机节水灌溉系统。我想实现的是LCD1602第一行显示“sd:00% wd:000.0",第二行显示”SH:70%  SL:25%“,湿度(sd)由湿度传感器经AD转换显示在第一行,温度(wd)由温度传感器返回数据显示在第一行后半段。按键控制调整SH(湿度上限)和SL(湿度下限),三个按键,分别减一、加一和光标移位确定;当土壤湿度低于下限值时,报警电路工作,电机工作;当土壤湿度高于下限时,电机停止工作。现在的问题是单独测湿度,没问题;单独测温度时,只显示温度,其他显示值都不变;两端程序放在一起时也只显示温度。可以加Q私聊:990385284
程序如下:
#include <reg51.h>             //调用单片机头文件
#define uchar unsigned char  //无符号字符型 宏定义    变量范围0~255
#define uint  unsigned int     //无符号整型 宏定义    变量范围0~65535

#include <intrins.h>

sbit SCL=P1^4;        //SCL定义为P1口的第3位脚,连接ADC0832SCL脚
sbit DO=P1^5;        //DO定义为P1口的第4位脚,连接ADC0832DO脚
sbit CS=P1^3;        //CS定义为P1口的第4位脚,连接ADC0832CS脚

sbit DQ=P2^0;        //DQ定义为P0口的第0位脚
uint tvalue;
uint tflag;  //温度值
uchar data disdata[5];//定义显示

sbit beep = P3^3;   //蜂鸣器IO口定义
uint temperature,s_temp ;  //温度的变量
uchar sd;     //湿度等级
uchar s_high = 70,s_low = 25;    //湿度报警参数

sbit dianji = P1^6;     //电机IO定义

bit flag_300ms ;
uchar key_can;         //按键值的变量
uchar menu_1;        //菜单设计的变量

#define RdCommand 0x01 //定义ISP的操作命令
#define PrgCommand 0x02
#define EraseCommand 0x03
#define Error 1
#define Ok 0
#define WaitTime 0x01 //定义CPU的等待时间
sfr ISP_DATA=0xe2;  //寄存器申明
sfr ISP_ADDRH=0xe3;
sfr ISP_ADDRL=0xe4;
sfr ISP_CMD=0xe5;
sfr ISP_TRIG=0xe6;
sfr ISP_CONTR=0xe7;
uchar a_a;

//这三个引脚参考资料
sbit rs=P1^0;     //1602数据/命令选择引脚 H:数据          L:命令
sbit rw=P1^1;     //1602读写引脚             H:数据寄存器      L:指令寄存器
sbit e =P1^2;     //1602使能引脚          下降沿触发
uchar code table_num[]="0123456789abcdefg";

/********************************************************************
* 名称 : delay_uint()
* 功能 : 小延时。
* 输入 : 无
* 输出 : 无
***********************************************************************/
void delay_uint(uint q)
{
    while(q--);
}

/********************************************************************
* 名称 : write_com(uchar com)
* 功能 : 1602命令函数
* 输入 : 输入的命令值
* 输出 : 无
***********************************************************************/
void write_com(uchar com)
{
    e=0;
    rs=0;
    rw=0;
    P0=com;
    delay_uint(3);
    e=1;
    delay_uint(25);
    e=0;
}

/********************************************************************
* 名称 : write_data(uchar dat)
* 功能 : 1602写数据函数
* 输入 : 需要写入1602的数据
* 输出 : 无
***********************************************************************/
void write_data(uchar dat)
{
    e=0;
    rs=1;
    rw=0;
    P0=dat;
    delay_uint(3);
    e=1;
    delay_uint(25);
    e=0;   
}

/********************************************************************
* 名称 : write_sfm2(uchar hang,uchar add,uchar date)
* 功能 : 显示2位十进制数,如果要让第一行,第五个字符开始显示"23" ,调用该函数如下
          write_sfm1(1,5,23)
* 输入 : 行,列,需要输入1602的数据
* 输出 : 无
***********************************************************************/
void write_sfm2(uchar hang,uchar add,uint date)
{
    if(hang==1)   
        write_com(0x80+add);
    else
        write_com(0x80+0x40+add);
    write_data(0x30+date/10%10);
    write_data(0x30+date%10);   
}

/********************************************************************
* 名称 : write_sfm1(uchar hang,uchar add,uchar date)
* 功能 : 显示1位十进制数,如果要让第一行,第五个字符开始显示"2" ,调用该函数如下
          write_sfm1(1,5,2)
* 输入 : 行,列,需要输入1602的数据
* 输出 : 无
***********************************************************************/
void write_sfm1(uchar hang,uchar add,uint date)
{
    if(hang==1)   
        write_com(0x80+add);
    else
        write_com(0x80+0x40+add);
            write_data(0x30+date);   
}

/********************************************************************
* 名称 : write_string(uchar hang,uchar add,uchar *p)
* 功能 : 改变液晶中某位的值,如果要让第一行,第五个字符开始显示"ab cd ef" ,调用该函数如下
          write_string(1,5,"ab cd ef;")
* 输入 : 行,列,需要输入1602的数据
* 输出 : 无
***********************************************************************/
void write_string(uchar hang,uchar add,uchar *p)
{
    if(hang==1)   
        write_com(0x80+add);
    else
        write_com(0x80+0x40+add);
        while(1)
        {
            if(*p == '\0')  break;
            write_data(*p);
            p++;
        }   
}

/********************************************************************
* 名称 : init_1602()
* 功能 : 初始化1602液晶
* 输入 : 无
* 输出 : 无
***********************************************************************/
void init_1602()
{
    write_com(0x38);
    write_com(0x38);
    write_com(0x0c);
    write_com(0x06);
    delay_uint(1000);
    write_string(1,0,"sd:00% wd:00.0");
    write_string(2,0,"SH:00%  SL:00% ");
    write_sfm2(2,4,s_high);        //显示湿度上限
    write_sfm2(2,12,s_low);           //显示湿度下限
}


/***********************1ms延时函数*****************************/
void delay_1ms(uint q)
{
    uint i,j;
    for(i=0;i<q;i++)
        for(j=0;j<120;j++);
}

/* ================ 打开 ISP,IAP 功能 ================= */
void ISP_IAP_enable(void)
{
     EA = 0;       /* 关中断   */
     ISP_CONTR = ISP_CONTR & 0x18;       /* 0001,1000 */
     ISP_CONTR = ISP_CONTR | WaitTime; /* 写入硬件延时 */
     ISP_CONTR = ISP_CONTR | 0x80;       /* ISPEN=1  */
}
/* =============== 关闭 ISP,IAP 功能 ================== */
void ISP_IAP_disable(void)
{
     ISP_CONTR = ISP_CONTR & 0x7f; /* ISPEN = 0 */
     ISP_TRIG = 0x00;
     EA   =   1;   /* 开中断 */
}
/* ================ 公用的触发代码 ==================== */
void ISPgoon(void)
{
     ISP_IAP_enable();   /* 打开 ISP,IAP 功能 */
     ISP_TRIG = 0x46;  /* 触发ISP_IAP命令字节1 */
     ISP_TRIG = 0xb9;  /* 触发ISP_IAP命令字节2 */
     _nop_();
}
/* ==================== 字节读 ======================== */
unsigned char byte_read(unsigned int byte_addr)
{
    EA = 0;
     ISP_ADDRH = (unsigned char)(byte_addr >> 8);/* 地址赋值 */
     ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff);
     ISP_CMD   = ISP_CMD & 0xf8;   /* 清除低3位  */
     ISP_CMD   = ISP_CMD | RdCommand; /* 写入读命令 */
     ISPgoon();       /* 触发执行  */
     ISP_IAP_disable();    /* 关闭ISP,IAP功能 */
     EA  = 1;
     return (ISP_DATA);    /* 返回读到的数据 */
}
/* ================== 扇区擦除 ======================== */
void SectorErase(unsigned int sector_addr)
{
     unsigned int iSectorAddr;
     iSectorAddr = (sector_addr & 0xfe00); /* 取扇区地址 */
     ISP_ADDRH = (unsigned char)(iSectorAddr >> 8);
     ISP_ADDRL = 0x00;
     ISP_CMD = ISP_CMD & 0xf8;   /* 清空低3位  */
     ISP_CMD = ISP_CMD | EraseCommand; /* 擦除命令3  */
     ISPgoon();       /* 触发执行  */
     ISP_IAP_disable();    /* 关闭ISP,IAP功能 */
}
/* ==================== 字节写 ======================== */
void byte_write(unsigned int byte_addr, unsigned char original_data)
{
     EA  = 0;
     SectorErase(byte_addr);
     ISP_ADDRH = (unsigned char)(byte_addr >> 8);  /* 取地址  */
     ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff);
     ISP_CMD  = ISP_CMD & 0xf8;    /* 清低3位 */
     ISP_CMD  = ISP_CMD | PrgCommand;  /* 写命令2 */
     ISP_DATA = original_data;   /* 写入数据准备 */
     ISPgoon();       /* 触发执行  */
     ISP_IAP_disable();     /* 关闭IAP功能 */
     EA =1;
}

/******************把数据保存到单片机内部eeprom中******************/
void write_eeprom()
{
    SectorErase(0x2000);
    byte_write(0x2000, s_high);
    byte_write(0x2001, s_low);
    byte_write(0x2060, a_a);   
}

/******************把数据从单片机内部eeprom中读出来*****************/
void read_eeprom()
{
    s_high   = byte_read(0x2000);
    s_low = byte_read(0x2001);
    a_a      = byte_read(0x2060);
}

/**************开机自检eeprom初始化*****************/
void init_eeprom()
{
    read_eeprom();        //先读
    if(a_a != 42)        //新的单片机初始单片机内问eeprom
    {
        s_high   = 70;
        s_low = 25;
        a_a = 42;
        write_eeprom();
    }   
}
 /***********读数模转换数据********************************************************/   
//请先了解ADC0832模数转换的串行协议,再来读本函数,主要是对应时序图来理解,本函数是模拟0832的串行协议进行的
                        //  1  0  0 通道
                        //  1  1  1 通道
unsigned char ad0832read(bit SGL,bit ODD)
{
    unsigned char i=0,value=0,value1=0;        
        SCL=0;
        DO=1;
        CS=0;        //开始
        SCL=1;        //第一个上升沿   
        SCL=0;
        DO=SGL;
        SCL=1;      //第二个上升沿
        SCL=0;
        DO=ODD;
        SCL=1;        //第三个上升沿
        SCL=0;        //第三个下降沿
        DO=1;
        for(i=0;i<8;i++)
        {
            SCL=0;
            SCL=1; //开始从第四个下降沿接收数据
            value<<=1;
            if(DO)
                value++;                        
        }
        for(i=0;i<8;i++)
        {            //接收校验数据
            value1>>=1;
            if(DO)
                value1+=0x80;
            SCL=1;
            SCL=0;
        }
        SCL=1;   
        if(value==value1)                //与校验数据比较,正确就返回数据,否则返回0   
            return value;
    return 0;
}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
















 
                                                         
 /******************************ds1820程序***************************************/
 void delay_18B20(unsigned int i)//延时1微秒
{
    while(i--);
 }
  void ds1820rst()/*ds1820复位*/
 {
 unsigned char x=0;
 DQ = 1;          //DQ复位
 delay_18B20(4); //延时
 DQ = 0;          //DQ拉低
 delay_18B20(100); //精确延时大于480us
 DQ = 1;          //拉高
 delay_18B20(40);
}
uchar ds1820rd()/*读数据*/
{
 unsigned char i=0;
 unsigned char dat = 0;
 for (i=8;i>0;i--)
 {   
  DQ = 0; //给脉冲信号
     dat>>=1;
      DQ = 1; //给脉冲信号
      if(DQ)
  dat|=0x80;
     delay_18B20(10);
 }
 return(dat);
}
void ds1820wr(uchar wdata)/*写数据*/
{
 unsigned char i=0;
 for (i=8; i>0; i--)
    {
     DQ = 0;
     DQ = wdata&0x01;
     delay_18B20(10);
     DQ = 1;
     wdata>>=1;
     }
}
read_temp()/*读取温度值并转换*/
{
 uchar a,b;
 ds1820rst();   
 ds1820wr(0xcc);//*跳过读序列号*/
 ds1820wr(0x44);//*启动温度转换*/
 ds1820rst();   
 ds1820wr(0xcc);//*跳过读序列号*/
 ds1820wr(0xbe);//*读取温度*/
 a=ds1820rd();
 b=ds1820rd();
 tvalue=b;
 tvalue<<=8;
 tvalue=tvalue|a;
     if(tvalue<0x0fff)
     tflag=0;
     else
    {
  tvalue=~tvalue+1;
  tflag=1;
    }
 tvalue=tvalue*(0.625);//温度值扩大10倍,精确到1位小数
 return(tvalue);
}

/*******************************************************************/

void ds1820disp()//温度值显示
{  
   disdata[0]=tvalue/1000;//百位数
   disdata[1]=tvalue%1000/100;//十位数
   disdata[2]=tvalue%100/10;//个位数
   disdata[3]=tvalue%10;//小数位
   write_sfm1(1,10,disdata[0]);
   write_sfm1(1,11,disdata[1]);
   write_sfm1(1,12,disdata[2]);
   write_sfm1(1,14,disdata[3]);
 /*  if(tflag==0)
      flagdat=0x20;//正温度不显示符号
      else
        flagdat=0x2d;//负温度显示负号:-
        if(disdata[0]==0x30)
      {
  disdata[0]=0x20;//如果百位为0,不显示
      if(disdata[1]==0x30)
      {
   disdata[1]=0x20;//如果百位为0,十位为0也不显示
      }
     }
     wr_com(0xc0);
     wr_dat(flagdat);//显示符号?
     wr_com(0xc1);
     wr_dat(disdata[0]);//显示百位
     wr_com(0xc2);
     wr_dat(disdata[1]);//显示十位
     wr_com(0xc3);
     wr_dat(disdata[2]);//显示个位
     wr_com(0xc4);
     wr_dat(0x2e);//显示小数点
     wr_com(0xc5);
     wr_dat(disdata[3]);//显示小数位
     */
}



/*************定时器0初始化程序***************/
void time_init()      
{
    EA   = 1;           //开总中断
    TMOD = 0X01;      //定时器0、定时器1工作方式1
    ET0  = 1;          //开定时器0中断
    TR0  = 1;          //允许定时器0定时
}


/********************独立按键程序*****************/
uchar key_can;     //按键值

void key()     //独立按键程序
{
    static uchar key_new;
    key_can = 20;                   //按键值还原
    P3 |= 0xf0;
    if((P3 & 0xf0) != 0xf0)        //按键按下
    {
        delay_1ms(1);             //按键消抖动
        if(((P3 & 0xf0) != 0xf0) && (key_new == 1))
        {                        //确认是按键按下
            key_new = 0;
            switch(P3 & 0xf0)
            {
                case 0xe0: key_can = 4; break;       //得到k1键值
                case 0xd0: key_can = 3; break;       //得到k2键值
                case 0xb0: key_can = 2; break;       //得到k3键值
                case 0x70: key_can = 1; break;       //得到k4键值
            }
            
                    
        }            
    }
    else
        key_new = 1;   
}

/****************按键处理显示函数***************/
void key_with()
{
    if(key_can == 1)     //设置键
    {
        menu_1 ++;
        if(menu_1 >= 3)
        {
            menu_1 = 0;
            init_1602() ;  //初始化显示
        }
    }
    if(menu_1 == 1)            //设置湿度上限
    {
        if(key_can == 2)
        {
            s_high ++ ;        //湿度上限值加1
            if(s_high > 99)
                s_high = 99;
        }
        if(key_can == 3)
        {
            s_high -- ;        //湿度上限值减1
            if(s_high <= s_low)
                s_high = s_low + 1 ;
        }
        write_sfm2(2,4,s_high);        //显示湿度上限
        write_sfm2(2,12,s_low);           //显示湿度下限
        write_com(0x80+0x40+4);           //将光标移动到第2行第到3位
        write_com(0x0f);                  //显示光标并且闪烁
        write_eeprom();       //保存数据                    

    }   
    if(menu_1 == 2)            //设置湿度下限
    {
        if(key_can == 2)
        {
            s_low ++ ;      //湿度下限值加1
            if(s_low >= s_high)
                s_low = s_high - 1;
        }
        if(key_can == 3)
        {
            s_low --;      //湿度下限值减1
            if(s_low <= 1)
                s_low = 1;
        }
        write_sfm2(2,4,s_high);        //显示湿度上限
        write_sfm2(2,12,s_low);           //显示湿度下限
        write_com(0x80+0x40+12);           //将光标移动到第2行第到3位
        write_com(0x0f);                  //显示光标并且闪烁
        write_eeprom();       //保存数据                    
    }   
}  

/****************报警函数***************/
void clock_h_l()
{
    static uchar value,value1;
    if(sd <= s_low)
    {
        value ++;
        if(value >= 2)
        {
            value = 10;
            beep = ~beep;      //蜂鸣器报警
            dianji = 0;       //打开电机
        }
    }else
        beep = 1;   //关闭蜂鸣器
   
    if(sd >= s_high)
    {
        value1 ++;
        if(value1 >= 2)
        {
            value1 = 10;
            beep = 1;   //关闭蜂鸣器
            dianji = 1;       //关机电机
        }
    }else
        value1 = 0;
}

/***************主函数*****************/
void main()
{
    init_1602();               //1602液晶初始化
    init_eeprom();                  //读eeprom数据
    time_init();                    //初始化定时器
            
    while(1)
    {      
        read_temp();//读取温度值
        ds1820disp();//显示温度值
               
        key();                    //独立按键程序
        if(key_can < 10)
        {
            key_with();            //按键按下要执行的程序
        }
        if(flag_300ms == 1)
        {        
            flag_300ms = 0;      
            clock_h_l();     //报警函数
            if(beep == 1)
            {
                sd = ad0832read(1,0);    //读出湿度
                sd = 99 - sd * 99 / 255;
            }
            if(menu_1 == 0)
            {
                write_sfm2(1,3,sd);           //显示湿度等级
            }
        }                           
        delay_1ms(1);
    }
}

/*************定时器0中断服务程序***************/
void time0_int() interrupt 1
{   
    static uchar value;
    TH0 = 0x3c;
    TL0 = 0xb0;     // 50ms
    value ++;     
    if(value % 6 == 0)
    {
        flag_300ms = 1;       //300ms
        value = 0;
    }
}
附上单独测试湿度的结果图和单独测试温度的结果图
结果图.rar (983.84 KB)
搜索更多相关主题的帖子: 温度传感器 节水灌溉 智能机 单片机 
2015-06-13 19:12
wmf2014
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:216
帖 子:2039
专家分:11273
注 册:2014-12-6
收藏
得分:20 
没有调试环境,就没细看你的代码,你既然单个可以运行,揉在一起运行也应该没问题,我觉得用一个定时中断分时运行两个不同功能的代码可能能解决冲突。再这个应转到单片机版块。

能编个毛线衣吗?
2015-06-13 20:59
大大大劼
Rank: 1
等 级:新手上路
帖 子:5
专家分:0
注 册:2015-6-13
收藏
得分:0 
回复 2楼 wmf2014
谢谢,我试一下
2015-06-13 21:43
大大大劼
Rank: 1
等 级:新手上路
帖 子:5
专家分:0
注 册:2015-6-13
收藏
得分:0 
回复 2楼 wmf2014
我又遇到了一个问题,单独显示湿度没有问题,但显示的位置稍有移动,就不显示了,湿度值变成一直99%。能帮我看看吗?因为毕设要用,只有三天了,什么感谢;我的QQ:990385284,可以加Q聊
2015-06-14 09:05
大大大劼
Rank: 1
等 级:新手上路
帖 子:5
专家分:0
注 册:2015-6-13
收藏
得分:0 
回复 2楼 wmf2014
主要看一下LCD显示程序,温度和湿度的显示都是围绕着它写的,谢谢
2015-06-14 09:30
快速回复:请各位大神帮我看看我的程序哪里出错了,已经调试一周,急,谢谢。
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.033422 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved