电路原理图如下:
原理图
清单
PCB布板
PCB布板副本
单片机源程序如下:
- 程序及注解
- #include <reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
- #include "intrins.h"
- #define u8 unsigned char
- #define u16 unsigned int
- #define uchar unsigned char
- #define uint unsigned int
- uchar yushe_Moisture=20; //Moisture预设值下限
- uchar yushe_MoistureH=40; //Moisture预设值上限
- u8 Moisture; //用于读取ADC数据
- //运行模式
- uchar Mode=0; //=1是设置湿度阀值 =0是正常监控模式
- uchar Mode_1=0; //0:自动 1;手动
- //管脚声明
- //管脚声明
- sbit BUZZER= P1^6; //蜂鸣器
- sbit relay = P2^5; //继电器
- /********************************************************************
- * 名称 : delay_1ms()
- * 功能 : 延时1ms函数
- * 输入 : q
- * 输出 : 无
- ***********************************************************************/
- void delay_ms(uint q)
- {
- uint i,j;
- for(i=0;i<q;i++)
- for(j=0;j<110;j++);
- }
- /***********************************************************************************************************
- LCD1602相关函数
- ***********************************************************************************************************/
- //LCD管脚声明 (RW引脚实物直接接地,因为本设计只用到液晶的写操作,RW引脚一直是低电平)
- sbit LCDRS = P2^7;
- sbit LCDEN = P2^6;
- //LCD延时
- void LCDdelay(uint z) //该延时大约100us(不精确,液晶操作的延时不要求很精确)
- {
- uint x,y;
- for(x=z;x>0;x--)
- for(y=10;y>0;y--);
- }
- //写命令
- void write_com(uchar com)
- {
- LCDRS=0;
- P0=com;
- LCDdelay(5);
- LCDEN=1;
- LCDdelay(5);
- LCDEN=0;
- }
- //写数据
- void write_data(uchar date)
- {
- LCDRS=1;
- // LCD_WriteData(date);
- P0=date;
- LCDdelay(5);
- LCDEN=1;
- LCDdelay(5);
- LCDEN=0;
- }
- /*------------------------------------------------
- 选择写入位置
- ------------------------------------------------*/
- void SelectPosition(unsigned char x,unsigned char y)
- {
- if (x == 0)
- {
- write_com(0x80 + y); //表示第一行
- }
- else
- {
- write_com(0xC0 + y); //表示第二行
- }
- }
- /*------------------------------------------------
- 写入字符串函数
- ------------------------------------------------*/
- void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s)
- {
- SelectPosition(x,y) ;
- while (*s)
- {
- write_data( *s);
- s ++;
- }
- }
- //========================================================================
- // 函数: void LCD_Write_Char(u8 x,u8 y,u16 s,u8 l)
- // 应用: LCD_Write_Char(0,1,366,4) ;
- // 描述: 在第0行第一个字节位置显示366的后4位,显示结果为 0366
- // 参数: x:行,y:列,s:要显示的字,l:显示的位数
- // 返回: none.
- // 版本: VER1.0
- // 日期: 2013-4-1
- // 备注: 最大显示65535
- //========================================================================
- void LCD_Write_Char(u8 x,u8 y,u16 s,u8 l)
- {
- SelectPosition(x,y) ;
- if(l>=5)
- write_data(0x30+s/10000%10); //万位
- if(l>=4)
- write_data(0x30+s/1000%10); //千位
- if(l>=3)
- write_data(0x30+s/100%10); //百位
- if(l>=2)
- write_data(0x30+s/10%10); //十位
- if(l>=1)
- write_data(0x30+s%10); //个位
- }
- /*1602指令简介
- write_com(0x38);//屏幕初始化
- write_com(0x0c);//打开显示 无光标 无光标闪烁
- write_com(0x0d);//打开显示 阴影闪烁
- write_com(0x0d);//打开显示 阴影闪烁
- */
- //1602初始化
- void Init1602()
- {
- uchar i=0;
- write_com(0x38);//屏幕初始化
- write_com(0x0c);//打开显示 无光标 无光标闪烁
- write_com(0x06);//当读或写一个字符是指针后一一位
- write_com(0x01);//清屏
-
- }
- void Display_1602(yushe_Moisture,yushe_MoistureH,temp)
- {
-
- //显示预设湿度
- LCD_Write_Char(0,12,yushe_MoistureH,3) ;
- LCD_Write_Char(1,12,yushe_Moisture,3) ;
- //时时湿度
- LCD_Write_Char(0,3,temp,3) ;
- }
- /***********************************************************************************************************
- ADC0832相关函数
- ***********************************************************************************************************/
- sbit ADCS =P1^3; //ADC0832 片选
- sbit ADCLK =P1^0; //ADC0832 时钟
- sbit ADDI =P1^1; //ADC0832 数据输入 /*因为单片机的管脚是双向的,且ADC0832的数据输入输出不同时进行,
- sbit ADDO =P1^1; //ADC0832 数据输出 /*为节省单片机引脚,简化电路所以输入输出连接在同一个引脚上
- //========================================================================
- // 函数: unsigned int Adc0832(unsigned char channel)
- // 应用: temp=Adc0832(0);
- // 描述: 读取0通道的AD值
- // 参数: channel:通道0和通道1选择
- // 返回: 选取通道的AD值
- // 版本: VER1.0
- // 日期: 2015-05-29
- // 备注:
- //========================================================================
- unsigned int Adc0832(unsigned char channel)
- {
- uchar i=0;
- uchar j;
- uint dat=0;
- uchar ndat=0;
- uchar Vot=0;
- if(channel==0)channel=2;
- if(channel==1)channel=3;
- ADDI=1;
- _nop_();
- _nop_();
- ADCS=0;//拉低CS端
- _nop_();
- _nop_();
- ADCLK=1;//拉高CLK端
- _nop_();
- _nop_();
- ADCLK=0;//拉低CLK端,形成下降沿1
- _nop_();
- _nop_();
- ADCLK=1;//拉高CLK端
- ADDI=channel&0x1;
- _nop_();
- _nop_();
- ADCLK=0;//拉低CLK端,形成下降沿2
- _nop_();
- _nop_();
- ADCLK=1;//拉高CLK端
- ADDI=(channel>>1)&0x1;
- _nop_();
- _nop_();
- ADCLK=0;//拉低CLK端,形成下降沿3
- ADDI=1;//控制命令结束
- _nop_();
- _nop_();
- dat=0;
- for(i=0;i<8;i++)
- {
- dat|=ADDO;//收数据
- ADCLK=1;
- _nop_();
- _nop_();
- ADCLK=0;//形成一次时钟脉冲
- _nop_();
- _nop_();
- dat<<=1;
- if(i==7)dat|=ADDO;
- }
- for(i=0;i<8;i++)
- {
- j=0;
- j=j|ADDO;//收数据
- ADCLK=1;
- _nop_();
- _nop_();
- ADCLK=0;//形成一次时钟脉冲
- _nop_();
- _nop_();
- j=j<<7;
- ndat=ndat|j;
- if(i<7)ndat>>=1;
- }
- ADCS=1;//拉低CS端
- ADCLK=0;//拉低CLK端
- ADDO=1;//拉高数据端,回到初始状态
- dat<<=8;
- dat|=ndat;
- return(dat); //return ad data
- }
- /***********************************************************************************************************
- 按键检测相关函数
- ***********************************************************************************************************/
- //按键
- sbit Key1=P1^5; //设置键
- sbit Key2=P3^3; //加按键
- sbit Key3=P3^4; //减按键
- #define KEY_SET 1 //设置
- #define KEY_ADD 2 //加
- #define KEY_MINUS 3 //减
- //========================================================================
- // 函数: u8 Key_Scan()
- // 应用: temp=u8 Key_Scan();
- // 描述: 按键扫描并返回按下的键值
- // 参数: NONE
- // 返回: 按下的键值
- // 版本: VER1.0
- // 日期: 2015-05-29
- // 备注: 该函数带松手检测,按下键返回一次键值后返回0,直至第二次按键按下
- //========================================================================
- u8 Key_Scan()
- {
- static u8 key_up=1;//按键按松开标志
- if(key_up&&(Key1==0||Key2==0||Key3==0))
- {
- delay_ms(10);//去抖动
- key_up=0;
- if(Key1==0) return 1;
- else if(Key2==0)return 2;
- else if(Key3==0)return 3;
- }
- else if(Key1==1&&Key2==1&&Key3==1)
- key_up=1;
- return 0;// 无按键按下
- }
- /*------------------------------------------------
- STC内部EEPROM程序
- ------------------------------------------------*/
- /*Declare SFR associated with the IAP */
- sfr IAP_DATA = 0xE2; //Flash data register
- sfr IAP_ADDRH = 0xE3; //Flash address HIGH
- sfr IAP_ADDRL = 0xE4; //Flash address LOW
- sfr IAP_CMD = 0xE5; //Flash command register
- sfr IAP_TRIG = 0xE6; //Flash command trigger
- sfr IAP_CONTR = 0xE7; //Flash control register
- /*Define ISP/IAP/EEPROM command*/
- #define CMD_IDLE 0 //Stand-By
- #define CMD_READ 1 //u8-Read
- #define CMD_PROGRAM 2 //u8-Program
- #define CMD_ERASE 3 //Sector-Erase
- /*Define ISP/IAP/EEPROM operation const for IAP_CONTR*/
- //#define ENABLE_IAP 0x80 //if SYSCLK<40MHz
- #define ENABLE_IAP 0x81 //if SYSCLK<20MHz
- //#define ENABLE_IAP x82 //if SYSCLK<10MHz
- //#define ENABLE_IAP 0x83 //if SYSCLK<5MHz
- #define ERROR 0
- #define OK 1
- //Start address for STC89C51xx EEPROM
- //注:51和58EEPROM地址不一样;
- #define IAP_ADDRESS 0x2000
- ///*----------------------------
- //Software delay function
- //----------------------------*/
- //void Delay(u8 n)
- //{
- // u16 x;
- // while (n--)
- // {
- // x = 0;
- // while (++x);
- // }
- //}
- /*----------------------------
- Disable ISP/IAP/EEPROM function
- Make MCU in a safe state
- ----------------------------*/
- /*----------------------------
- 关闭EEPROM操作
- ----------------------------*/
- void IapIdle()
- {
- IAP_CONTR = 0; //Close IAP function
- IAP_CMD = 0; //Clear command to standby
- IAP_TRIG = 0; //Clear trigger register
- IAP_ADDRH = 0x80; //Data ptr point to non-EEPROM area
- IAP_ADDRL = 0; //Clear IAP address to prevent misuse
- }
- /*----------------------------
- Read one u8 from ISP/IAP/EEPROM area
- Input: addr (ISP/IAP/EEPROM address)
- Output:Flash data
- ----------------------------*/
- /*----------------------------
- 从EEPROM读取一个字节
- Input: addr (EEPROM 地址)
- Output:读出的数据
- ----------------------------*/
- u8 IapReadByte(u16 addr)
- {
- u8 dat; //Data buffer
- IAP_CONTR = ENABLE_IAP; //Open IAP function, and set wait time
- IAP_CMD = CMD_READ; //Set ISP/IAP/EEPROM READ command
- IAP_ADDRL = addr; //Set ISP/IAP/EEPROM address low
- IAP_ADDRH = addr >> 8; //Set ISP/IAP/EEPROM address high
- IAP_TRIG = 0x46; //Send trigger command1 (0x46)
- IAP_TRIG = 0xb9; //Send trigger command2 (0xb9)
- _nop_(); //MCU will hold here until ISP/IAP/EEPROM operation complete
- dat = IAP_DATA; //Read ISP/IAP/EEPROM data
- IapIdle(); //Close ISP/IAP/EEPROM function
- return dat; //Return Flash data
- }
- /*----------------------------
- Program one u8 to ISP/IAP/EEPROM area
- Input: addr (ISP/IAP/EEPROM address)
- dat (ISP/IAP/EEPROM data)
- Output:-
- ----------------------------*/
- /*----------------------------
- 写一个字节到EEPROM
- Input: addr (EEPROM 地址)
- dat (写入EEPROM 的数据)
- Output:-
- ----------------------------*/
- void IapProgramByte(u16 addr, u8 dat)
- {
- IAP_CONTR = ENABLE_IAP; //Open IAP function, and set wait time
- IAP_CMD = CMD_PROGRAM; //Set ISP/IAP/EEPROM PROGRAM command
- IAP_ADDRL = addr; //Set ISP/IAP/EEPROM address low
- IAP_ADDRH = addr >> 8; //Set ISP/IAP/EEPROM address high
- IAP_DATA = dat; //Write ISP/IAP/EEPROM data
- IAP_TRIG = 0x46; //Send trigger command1 (0x46)
- IAP_TRIG = 0xb9; //Send trigger command2 (0xb9)
- _nop_(); //MCU will hold here until ISP/IAP/EEPROM operation complete
- IapIdle();
- }
- /*----------------------------
- Erase one sector area
- Input: addr (ISP/IAP/EEPROM address)
- Output:-
- ----------------------------*/
- /*----------------------------
- 擦除一个扇区
- Input: addr (EEPROM扇区首地址)
- Output:-
- ----------------------------*/
- void IapEraseSector(u16 addr)
- {
- IAP_CONTR = ENABLE_IAP; //Open IAP function, and set wait time
- IAP_CMD = CMD_ERASE; //Set ISP/IAP/EEPROM ERASE command
- IAP_ADDRL = addr; //Set ISP/IAP/EEPROM address low
- IAP_ADDRH = addr >> 8; //Set ISP/IAP/EEPROM address high
- IAP_TRIG = 0x46; //Send trigger command1 (0x46)
- IAP_TRIG = 0xb9; //Send trigger command2 (0xb9)
- _nop_(); //MCU will hold here until ISP/IAP/EEPROM operation complete
- IapIdle();
- }
- u8 SC;//首次判断
- /******************把数据保存到单片机内部eeprom中******************/
- void write_eeprom()
- {
- IapEraseSector(IAP_ADDRESS); //Erase current sector
- IapProgramByte(IAP_ADDRESS+0, yushe_Moisture);
- IapProgramByte(IAP_ADDRESS+1, yushe_MoistureH);
- IapProgramByte(IAP_ADDRESS+100, SC);
- }
- /******************把数据从单片机内部eeprom中读出来*****************/
- void read_eeprom()
- {
- yushe_Moisture = IapReadByte(IAP_ADDRESS+0);
- yushe_MoistureH = IapReadByte(IAP_ADDRESS+1);
- SC = IapReadByte(IAP_ADDRESS+100);
- }
- /**************开机自检eeprom初始化*****************/
- void init_eeprom()
- {
- read_eeprom(); //先读
- if(SC != 2) //新的单片机初始单片机内问eeprom
- {
- yushe_Moisture = 20;
- yushe_MoistureH = 40;
- SC = 2;
- write_eeprom();
- }
- }
- void main (void)
- {
- u8 key;
- u8 i=0;
- u8 j=0;
- Moisture=Adc0832(0); //读取湿度值
- Moisture=100-(Moisture*100/256); //读取湿度值
- Init1602(); //调用初始化显示函数
- LCD_Write_String(0,0,"Ms:000% SEH:000%"); //开机界面
- LCD_Write_String(1,0,"MODE:A SEL:000%"); //
- init_eeprom();
- delay_ms(1000);
- Moisture=Adc0832(0); //读取湿度值
- Moisture=100-(Moisture*100/256); //读取湿度值
- while (1) //主循环
- {
- key=Key_Scan(); //按键扫描
- Moisture=Adc0832(0); //读取湿度值
- Moisture=100-(Moisture*100/256); //读取湿度值
- if(key==KEY_SET)
- {
- Mode++;
- }
- switch(Mode) //判断模式的值
- {
- case 0: //监控模式
- {
- if(key==KEY_ADD)
- {
- Mode_1=!Mode_1;
- }
- if(Mode_1)
- {
- if(key==KEY_MINUS)
- {
- relay=!relay;
- BUZZER=relay;
- }
- }
- if(Mode_1)
- LCD_Write_String(1,5,"H "); //
- else
- LCD_Write_String(1,5,"A "); //
- Display_1602(yushe_Moisture,yushe_MoistureH,Moisture); //显示值
- if(!Mode_1)
- {
- if(Moisture>=yushe_MoistureH)//
- {
- BUZZER=1; //
- relay=1;
- }
- if(Moisture<=yushe_Moisture)//
- {
- j++;
- if(j<10)
- {
- BUZZER=1; //
- }
- else if(j<20)
- {
- BUZZER=0;
- } //
- else j=0;
- relay=0;
- }
- }
- break;
- }
- case 1: //预设湿度模式
- {
- BUZZER=1; //
- SelectPosition(0,11) ; //指定位置
- write_com(0x0d); //打开显示 无光标 光标闪烁
- if(key==KEY_ADD) //加键按下
- {
- if(yushe_MoistureH>=99) //当阀值加到大于等于99时
- yushe_MoistureH=99; //阀值固定为99
- yushe_MoistureH++; //预设湿度值(阀值)加1,最大为100
- LCD_Write_Char(0,12,yushe_MoistureH,3) ;//显示预设湿度
- }
- if(key==KEY_MINUS) //减键按下
- {
- if(yushe_MoistureH<=1) //当湿度上限值减小到1时
- yushe_MoistureH=1; //固定为1
- yushe_MoistureH--; //预设温度值减一,最小为0
- LCD_Write_Char(0,12,yushe_MoistureH,3) ;//显示预设湿度
- }
- break;
- }
- case 2: //预设湿度模式
- {
- BUZZER=1; //
- SelectPosition(1,11) ; //指定位置
- write_com(0x0d); //打开显示 无光标 光标闪烁
- if(key==KEY_ADD) //加键按下
- {
- if(yushe_Moisture>=99) //当阀值加到大于等于99时
- yushe_Moisture=99; //阀值固定为99
- yushe_Moisture++; //预设湿度值(阀值)加1,最大为100
- LCD_Write_Char(1,12,yushe_Moisture,3) ;//显示预设湿度
- }
- if(key==KEY_MINUS) //减键按下
- {
- if(yushe_Moisture<=1) //当湿度上限值减小到1时
- yushe_Moisture=1; //固定为1
- yushe_Moisture--; //预设温度值减一,最小为0
- LCD_Write_Char(1,12,yushe_Moisture,3) ;//显示预设湿度
- }
- break;
- }
- default :
- {
- write_com(0x38);//屏幕初始化
- write_com(0x0c);//打开显示 无光标 无光标闪烁
- write_eeprom();
- Mode=0; //恢复正常模式
- break;
- }
- }
- }
- }
复制代码
|