找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5391|回复: 1
收起左侧

基于单片机的自动浇花系统程序及注解

[复制链接]
ID:490924 发表于 2019-3-14 18:11 | 显示全部楼层 |阅读模式
电路原理图如下:

原理图

原理图

清单

清单

PCB布板

PCB布板

PCB布板副本

PCB布板副本


单片机源程序如下:
  1. 程序及注解
  2. #include <reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
  3. #include "intrins.h"                                                                                          

  4. #define     u8                          unsigned char
  5. #define     u16                   unsigned int
  6. #define     uchar                          unsigned char
  7. #define     uint                   unsigned int

  8. uchar yushe_Moisture=20;                        //Moisture预设值下限
  9. uchar yushe_MoistureH=40;                        //Moisture预设值上限
  10. u8  Moisture;                                                                 //用于读取ADC数据

  11. //运行模式  
  12. uchar Mode=0;                                                                 //=1是设置湿度阀值        =0是正常监控模式
  13. uchar Mode_1=0;                                                                 //0:自动 1;手动
  14. //管脚声明
  15. //管脚声明
  16. sbit BUZZER= P1^6;                 //蜂鸣器
  17. sbit relay = P2^5;                 //继电器
  18. /********************************************************************
  19. * 名称 : delay_1ms()
  20. * 功能 : 延时1ms函数
  21. * 输入 : q
  22. * 输出 : 无
  23. ***********************************************************************/
  24. void delay_ms(uint q)
  25. {
  26.         uint i,j;
  27.         for(i=0;i<q;i++)
  28.                 for(j=0;j<110;j++);
  29. }
  30. /***********************************************************************************************************
  31. LCD1602相关函数
  32. ***********************************************************************************************************/

  33. //LCD管脚声明 (RW引脚实物直接接地,因为本设计只用到液晶的写操作,RW引脚一直是低电平)
  34. sbit LCDRS = P2^7;
  35. sbit LCDEN = P2^6;
  36. //LCD延时
  37. void LCDdelay(uint z)                  //该延时大约100us(不精确,液晶操作的延时不要求很精确)
  38. {
  39.   uint x,y;
  40.   for(x=z;x>0;x--)
  41.     for(y=10;y>0;y--);
  42. }
  43. //写命令
  44. void write_com(uchar com)
  45. {
  46.   LCDRS=0;                                 
  47.   P0=com;
  48.   LCDdelay(5);
  49.   LCDEN=1;
  50.   LCDdelay(5);
  51.   LCDEN=0;
  52. }
  53. //写数据
  54. void write_data(uchar date)
  55. {
  56.   LCDRS=1;
  57. //        LCD_WriteData(date);
  58.   P0=date;
  59.   LCDdelay(5);
  60.   LCDEN=1;
  61.   LCDdelay(5);
  62.   LCDEN=0;
  63. }

  64. /*------------------------------------------------
  65.               选择写入位置
  66. ------------------------------------------------*/
  67. void SelectPosition(unsigned char x,unsigned char y)
  68. {     
  69.         if (x == 0)
  70.         {     
  71.                 write_com(0x80 + y);     //表示第一行
  72.         }
  73.         else
  74.         {      
  75.                 write_com(0xC0 + y);      //表示第二行
  76.         }        
  77. }
  78. /*------------------------------------------------
  79.               写入字符串函数
  80. ------------------------------------------------*/
  81. void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s)
  82. {     
  83.         SelectPosition(x,y) ;
  84.         while (*s)
  85.         {     
  86.                 write_data( *s);     
  87.                 s ++;     
  88.         }
  89. }
  90. //========================================================================
  91. // 函数: void LCD_Write_Char(u8 x,u8 y,u16 s,u8 l)
  92. // 应用: LCD_Write_Char(0,1,366,4) ;
  93. // 描述: 在第0行第一个字节位置显示366的后4位,显示结果为 0366
  94. // 参数: x:行,y:列,s:要显示的字,l:显示的位数
  95. // 返回: none.
  96. // 版本: VER1.0
  97. // 日期: 2013-4-1
  98. // 备注: 最大显示65535
  99. //========================================================================
  100. void LCD_Write_Char(u8 x,u8 y,u16 s,u8 l)
  101. {     
  102.         SelectPosition(x,y) ;

  103.         if(l>=5)
  104.                 write_data(0x30+s/10000%10);        //万位
  105.         if(l>=4)
  106.                 write_data(0x30+s/1000%10);                //千位
  107.         if(l>=3)
  108.                 write_data(0x30+s/100%10);                //百位
  109.         if(l>=2)
  110.                 write_data(0x30+s/10%10);                        //十位
  111.         if(l>=1)
  112.                 write_data(0x30+s%10);                //个位

  113. }
  114. /*1602指令简介
  115.   write_com(0x38);//屏幕初始化
  116.   write_com(0x0c);//打开显示 无光标 无光标闪烁
  117.   write_com(0x0d);//打开显示 阴影闪烁
  118.   write_com(0x0d);//打开显示 阴影闪烁
  119. */
  120. //1602初始化
  121. void Init1602()
  122. {
  123.   uchar i=0;
  124.   write_com(0x38);//屏幕初始化
  125.   write_com(0x0c);//打开显示 无光标 无光标闪烁
  126.   write_com(0x06);//当读或写一个字符是指针后一一位
  127.   write_com(0x01);//清屏
  128.       
  129. }

  130. void Display_1602(yushe_Moisture,yushe_MoistureH,temp)
  131. {
  132.       
  133.         //显示预设湿度
  134.         LCD_Write_Char(0,12,yushe_MoistureH,3) ;
  135.         LCD_Write_Char(1,12,yushe_Moisture,3) ;
  136.         //时时湿度
  137.         LCD_Write_Char(0,3,temp,3) ;
  138. }



  139. /***********************************************************************************************************
  140. ADC0832相关函数
  141. ***********************************************************************************************************/
  142. sbit ADCS         =P1^3; //ADC0832 片选
  143. sbit ADCLK  =P1^0; //ADC0832 时钟
  144. sbit ADDI         =P1^1; //ADC0832 数据输入                /*因为单片机的管脚是双向的,且ADC0832的数据输入输出不同时进行,
  145. sbit ADDO         =P1^1; //ADC0832 数据输出                /*为节省单片机引脚,简化电路所以输入输出连接在同一个引脚上



  146. //========================================================================
  147. // 函数: unsigned int Adc0832(unsigned char channel)
  148. // 应用:                 temp=Adc0832(0);
  149. // 描述: 读取0通道的AD值
  150. // 参数: channel:通道0和通道1选择
  151. // 返回: 选取通道的AD值
  152. // 版本: VER1.0
  153. // 日期: 2015-05-29
  154. // 备注:
  155. //========================================================================
  156. unsigned int Adc0832(unsigned char channel)
  157. {
  158.         uchar i=0;
  159.         uchar j;
  160.         uint dat=0;
  161.         uchar ndat=0;
  162.         uchar  Vot=0;

  163.         if(channel==0)channel=2;
  164.         if(channel==1)channel=3;
  165.         ADDI=1;
  166.         _nop_();
  167.         _nop_();
  168.         ADCS=0;//拉低CS端
  169.         _nop_();
  170.         _nop_();
  171.         ADCLK=1;//拉高CLK端
  172.         _nop_();
  173.         _nop_();
  174.         ADCLK=0;//拉低CLK端,形成下降沿1
  175.         _nop_();
  176.         _nop_();
  177.         ADCLK=1;//拉高CLK端
  178.         ADDI=channel&0x1;
  179.         _nop_();
  180.         _nop_();
  181.         ADCLK=0;//拉低CLK端,形成下降沿2
  182.         _nop_();
  183.         _nop_();
  184.         ADCLK=1;//拉高CLK端
  185.         ADDI=(channel>>1)&0x1;
  186.         _nop_();
  187.         _nop_();
  188.         ADCLK=0;//拉低CLK端,形成下降沿3
  189.         ADDI=1;//控制命令结束
  190.         _nop_();
  191.         _nop_();
  192.         dat=0;
  193.         for(i=0;i<8;i++)
  194.         {
  195.                 dat|=ADDO;//收数据
  196.                 ADCLK=1;
  197.                 _nop_();
  198.                 _nop_();
  199.                 ADCLK=0;//形成一次时钟脉冲
  200.                 _nop_();
  201.                 _nop_();
  202.                 dat<<=1;
  203.                 if(i==7)dat|=ADDO;
  204.         }
  205.         for(i=0;i<8;i++)
  206.         {
  207.                 j=0;
  208.                 j=j|ADDO;//收数据
  209.                 ADCLK=1;
  210.                 _nop_();
  211.                 _nop_();
  212.                 ADCLK=0;//形成一次时钟脉冲
  213.                 _nop_();
  214.                 _nop_();
  215.                 j=j<<7;
  216.                 ndat=ndat|j;
  217.                 if(i<7)ndat>>=1;
  218.         }
  219.         ADCS=1;//拉低CS端
  220.         ADCLK=0;//拉低CLK端
  221.         ADDO=1;//拉高数据端,回到初始状态
  222.         dat<<=8;
  223.         dat|=ndat;

  224.         return(dat);            //return ad data
  225. }


  226. /***********************************************************************************************************
  227. 按键检测相关函数
  228. ***********************************************************************************************************/
  229. //按键
  230. sbit Key1=P1^5;                                 //设置键
  231. sbit Key2=P3^3;                                 //加按键
  232. sbit Key3=P3^4;                                 //减按键



  233. #define KEY_SET                 1                //设置
  234. #define KEY_ADD                        2                //加
  235. #define KEY_MINUS                3                //减


  236. //========================================================================
  237. // 函数: u8 Key_Scan()
  238. // 应用: temp=u8 Key_Scan();
  239. // 描述: 按键扫描并返回按下的键值
  240. // 参数: NONE
  241. // 返回: 按下的键值
  242. // 版本: VER1.0
  243. // 日期: 2015-05-29
  244. // 备注: 该函数带松手检测,按下键返回一次键值后返回0,直至第二次按键按下
  245. //========================================================================
  246. u8 Key_Scan()
  247. {         
  248.         static u8 key_up=1;//按键按松开标志
  249.         if(key_up&&(Key1==0||Key2==0||Key3==0))
  250.         {
  251.                 delay_ms(10);//去抖动
  252.                 key_up=0;
  253.                 if(Key1==0)                        return 1;
  254.                 else if(Key2==0)return 2;
  255.                 else if(Key3==0)return 3;
  256.         }
  257.         else if(Key1==1&&Key2==1&&Key3==1)
  258.                 key_up=1;            
  259.         return 0;// 无按键按下
  260. }






  261. /*------------------------------------------------
  262.                     STC内部EEPROM程序
  263. ------------------------------------------------*/

  264. /*Declare SFR associated with the IAP */
  265. sfr IAP_DATA    =   0xE2;           //Flash data register
  266. sfr IAP_ADDRH   =   0xE3;           //Flash address HIGH
  267. sfr IAP_ADDRL   =   0xE4;           //Flash address LOW
  268. sfr IAP_CMD     =   0xE5;           //Flash command register
  269. sfr IAP_TRIG    =   0xE6;           //Flash command trigger
  270. sfr IAP_CONTR   =   0xE7;           //Flash control register

  271. /*Define ISP/IAP/EEPROM command*/
  272. #define CMD_IDLE    0               //Stand-By
  273. #define CMD_READ    1               //u8-Read
  274. #define CMD_PROGRAM 2               //u8-Program
  275. #define CMD_ERASE   3               //Sector-Erase

  276. /*Define ISP/IAP/EEPROM operation const for IAP_CONTR*/
  277. //#define ENABLE_IAP 0x80           //if SYSCLK<40MHz
  278. #define ENABLE_IAP   0x81           //if SYSCLK<20MHz
  279. //#define ENABLE_IAP x82            //if SYSCLK<10MHz
  280. //#define ENABLE_IAP 0x83           //if SYSCLK<5MHz
  281. #define ERROR   0
  282. #define OK      1

  283. //Start address for STC89C51xx EEPROM
  284. //注:51和58EEPROM地址不一样;
  285. #define IAP_ADDRESS 0x2000




  286. ///*----------------------------
  287. //Software delay function
  288. //----------------------------*/
  289. //void Delay(u8 n)
  290. //{
  291. //    u16 x;

  292. //    while (n--)
  293. //    {
  294. //        x = 0;
  295. //        while (++x);
  296. //    }
  297. //}

  298. /*----------------------------
  299. Disable ISP/IAP/EEPROM function
  300. Make MCU in a safe state
  301. ----------------------------*/
  302. /*----------------------------
  303. 关闭EEPROM操作
  304. ----------------------------*/
  305. void IapIdle()
  306. {
  307.     IAP_CONTR = 0;                  //Close IAP function
  308.     IAP_CMD = 0;                    //Clear command to standby
  309.     IAP_TRIG = 0;                   //Clear trigger register
  310.     IAP_ADDRH = 0x80;               //Data ptr point to non-EEPROM area
  311.     IAP_ADDRL = 0;                  //Clear IAP address to prevent misuse
  312. }

  313. /*----------------------------
  314. Read one u8 from ISP/IAP/EEPROM area
  315. Input: addr (ISP/IAP/EEPROM address)
  316. Output:Flash data
  317. ----------------------------*/
  318. /*----------------------------
  319. 从EEPROM读取一个字节
  320. Input: addr (EEPROM 地址)
  321. Output:读出的数据
  322. ----------------------------*/
  323. u8 IapReadByte(u16 addr)
  324. {
  325.     u8 dat;                       //Data buffer

  326.     IAP_CONTR = ENABLE_IAP;         //Open IAP function, and set wait time
  327.     IAP_CMD = CMD_READ;             //Set ISP/IAP/EEPROM READ command
  328.     IAP_ADDRL = addr;               //Set ISP/IAP/EEPROM address low
  329.     IAP_ADDRH = addr >> 8;          //Set ISP/IAP/EEPROM address high
  330.     IAP_TRIG = 0x46;                //Send trigger command1 (0x46)
  331.     IAP_TRIG = 0xb9;                //Send trigger command2 (0xb9)
  332.     _nop_();                        //MCU will hold here until ISP/IAP/EEPROM operation complete
  333.     dat = IAP_DATA;                 //Read ISP/IAP/EEPROM data
  334.     IapIdle();                      //Close ISP/IAP/EEPROM function

  335.     return dat;                     //Return Flash data
  336. }

  337. /*----------------------------
  338. Program one u8 to ISP/IAP/EEPROM area
  339. Input: addr (ISP/IAP/EEPROM address)
  340.        dat (ISP/IAP/EEPROM data)
  341. Output:-
  342. ----------------------------*/
  343. /*----------------------------
  344. 写一个字节到EEPROM
  345. Input: addr (EEPROM 地址)
  346.        dat (写入EEPROM 的数据)
  347. Output:-
  348. ----------------------------*/
  349. void IapProgramByte(u16 addr, u8 dat)
  350. {
  351.     IAP_CONTR = ENABLE_IAP;         //Open IAP function, and set wait time
  352.     IAP_CMD = CMD_PROGRAM;          //Set ISP/IAP/EEPROM PROGRAM command
  353.     IAP_ADDRL = addr;               //Set ISP/IAP/EEPROM address low
  354.     IAP_ADDRH = addr >> 8;          //Set ISP/IAP/EEPROM address high
  355.     IAP_DATA = dat;                 //Write ISP/IAP/EEPROM data
  356.     IAP_TRIG = 0x46;                //Send trigger command1 (0x46)
  357.     IAP_TRIG = 0xb9;                //Send trigger command2 (0xb9)
  358.     _nop_();                        //MCU will hold here until ISP/IAP/EEPROM operation complete
  359.     IapIdle();
  360. }

  361. /*----------------------------
  362. Erase one sector area
  363. Input: addr (ISP/IAP/EEPROM address)
  364. Output:-
  365. ----------------------------*/
  366. /*----------------------------
  367. 擦除一个扇区
  368. Input: addr (EEPROM扇区首地址)
  369. Output:-
  370. ----------------------------*/
  371. void IapEraseSector(u16 addr)
  372. {
  373.     IAP_CONTR = ENABLE_IAP;         //Open IAP function, and set wait time
  374.     IAP_CMD = CMD_ERASE;            //Set ISP/IAP/EEPROM ERASE command
  375.     IAP_ADDRL = addr;               //Set ISP/IAP/EEPROM address low
  376.     IAP_ADDRH = addr >> 8;          //Set ISP/IAP/EEPROM address high
  377.     IAP_TRIG = 0x46;                //Send trigger command1 (0x46)
  378.     IAP_TRIG = 0xb9;                //Send trigger command2 (0xb9)
  379.     _nop_();                        //MCU will hold here until ISP/IAP/EEPROM operation complete
  380.     IapIdle();
  381. }




  382. u8 SC;//首次判断
  383. /******************把数据保存到单片机内部eeprom中******************/
  384. void write_eeprom()
  385. {
  386.                 IapEraseSector(IAP_ADDRESS);    //Erase current sector
  387.                 IapProgramByte(IAP_ADDRESS+0, yushe_Moisture);
  388.                 IapProgramByte(IAP_ADDRESS+1, yushe_MoistureH);
  389.                 IapProgramByte(IAP_ADDRESS+100, SC);
  390. }

  391. /******************把数据从单片机内部eeprom中读出来*****************/
  392. void read_eeprom()
  393. {
  394.         yushe_Moisture        =        IapReadByte(IAP_ADDRESS+0);
  395.         yushe_MoistureH        =        IapReadByte(IAP_ADDRESS+1);
  396.         SC        =        IapReadByte(IAP_ADDRESS+100);
  397. }

  398. /**************开机自检eeprom初始化*****************/
  399. void init_eeprom()
  400. {
  401.         read_eeprom();                //先读
  402.         if(SC != 2)                //新的单片机初始单片机内问eeprom
  403.         {
  404.                 yushe_Moisture        =        20;
  405.                 yushe_MoistureH        =        40;
  406.                 SC = 2;
  407.                 write_eeprom();
  408.         }      
  409. }


  410. void main (void)
  411. {
  412.         u8 key;
  413.         u8 i=0;
  414.         u8 j=0;
  415.         Moisture=Adc0832(0);                                //读取湿度值
  416.         Moisture=100-(Moisture*100/256);                                //读取湿度值
  417.         Init1602();                          //调用初始化显示函数
  418.         LCD_Write_String(0,0,"Ms:000% SEH:000%");  //开机界面
  419.         LCD_Write_String(1,0,"MODE:A  SEL:000%");  //
  420.         init_eeprom();
  421.         delay_ms(1000);
  422.         Moisture=Adc0832(0);                                //读取湿度值
  423.         Moisture=100-(Moisture*100/256);                                //读取湿度值
  424.         while (1)                                                //主循环
  425.         {
  426.                 key=Key_Scan();                                        //按键扫描
  427.                 Moisture=Adc0832(0);                                //读取湿度值
  428.                 Moisture=100-(Moisture*100/256);                                //读取湿度值
  429.                 if(key==KEY_SET)
  430.                 {
  431.                         Mode++;
  432.                 }
  433.                 switch(Mode)                                                //判断模式的值
  434.                 {
  435.                         case 0:                                                                //监控模式
  436.                         {
  437.                                 if(key==KEY_ADD)
  438.                                 {
  439.                                         Mode_1=!Mode_1;
  440.                                 }
  441.                                 if(Mode_1)
  442.                                 {
  443.                                         if(key==KEY_MINUS)
  444.                                         {
  445.                                                 relay=!relay;
  446.                                                 BUZZER=relay;
  447.                                         }
  448.                                 }
  449.                                 if(Mode_1)
  450.                                         LCD_Write_String(1,5,"H  ");  //
  451.                                 else
  452.                                         LCD_Write_String(1,5,"A  ");  //
  453.                                 Display_1602(yushe_Moisture,yushe_MoistureH,Moisture);  //显示值
  454.                                 if(!Mode_1)
  455.                                 {
  456.                                         if(Moisture>=yushe_MoistureH)//
  457.                                         {                             
  458.                                                 BUZZER=1;                                          //
  459.                                                 relay=1;
  460.                                         }                             
  461.                                         if(Moisture<=yushe_Moisture)//
  462.                                         {                             
  463.                                                 j++;
  464.                                                 if(j<10)
  465.                                                 {
  466.                                                         BUZZER=1;                                          //
  467.                                                 }
  468.                                                 else if(j<20)
  469.                                                 {
  470.                                                         BUZZER=0;               
  471.                                                 }                                                        //
  472.                                                 else j=0;
  473.                                                 relay=0;
  474.                                         }
  475.                                 }
  476.                                 break;
  477.                         }
  478.                         case 1:                                //预设湿度模式
  479.                         {
  480.                                 BUZZER=1;                                          //
  481.                                 SelectPosition(0,11) ;                                //指定位置      
  482.                            write_com(0x0d);                                                        //打开显示 无光标 光标闪烁
  483.                                 if(key==KEY_ADD)                                                        //加键按下
  484.                                 {
  485.                                         if(yushe_MoistureH>=99)        //当阀值加到大于等于99时
  486.                                         yushe_MoistureH=99;            //阀值固定为99
  487.                                         yushe_MoistureH++;                                            //预设湿度值(阀值)加1,最大为100
  488.                                         LCD_Write_Char(0,12,yushe_MoistureH,3) ;//显示预设湿度
  489.                                 }
  490.                                 if(key==KEY_MINUS)                                                //减键按下
  491.                                 {
  492.                                         if(yushe_MoistureH<=1)                                        //当湿度上限值减小到1时
  493.                                                 yushe_MoistureH=1;                  //固定为1
  494.                                         yushe_MoistureH--;                                                        //预设温度值减一,最小为0         
  495.                                         LCD_Write_Char(0,12,yushe_MoistureH,3) ;//显示预设湿度
  496.                                 }
  497.                                 break;
  498.                         }
  499.                         case 2:                                //预设湿度模式
  500.                         {
  501.                                 BUZZER=1;                                          //
  502.                                 SelectPosition(1,11) ;                                //指定位置      
  503.                            write_com(0x0d);                                                        //打开显示 无光标 光标闪烁
  504.                                 if(key==KEY_ADD)                                                        //加键按下
  505.                                 {
  506.                                         if(yushe_Moisture>=99)        //当阀值加到大于等于99时
  507.                                         yushe_Moisture=99;            //阀值固定为99
  508.                                         yushe_Moisture++;                                            //预设湿度值(阀值)加1,最大为100
  509.                                         LCD_Write_Char(1,12,yushe_Moisture,3) ;//显示预设湿度
  510.                                 }
  511.                                 if(key==KEY_MINUS)                                                //减键按下
  512.                                 {
  513.                                         if(yushe_Moisture<=1)                                        //当湿度上限值减小到1时
  514.                                                 yushe_Moisture=1;                  //固定为1
  515.                                         yushe_Moisture--;                                                        //预设温度值减一,最小为0         
  516.                                         LCD_Write_Char(1,12,yushe_Moisture,3) ;//显示预设湿度
  517.                                 }
  518.                                 break;
  519.                         }
  520.                         default        :      
  521.                         {
  522.                                 write_com(0x38);//屏幕初始化
  523.                                 write_com(0x0c);//打开显示 无光标 无光标闪烁
  524.                                 write_eeprom();
  525.                                 Mode=0;                        //恢复正常模式
  526.                                 break;
  527.                         }
  528.                 }
  529.         }
  530. }
复制代码

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:374200 发表于 2019-3-14 20:59 来自手机 | 显示全部楼层
能把源码和pcb文件打包分享吗?谢谢
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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