找回密码
 注册

QQ登录

只需一步,快速开始

搜索

51单片机浇花系统Proteus仿真和单片机C程序源码

[复制链接]
coolfire 发表于 2021-5-8 00:33:16 | 显示全部楼层 |阅读模式
本设计是基于AT89C51单片机和ADC0832的自动浇花系统。本设计的电路内部包含湿度采集和AD转换等主要功能。自动浇水系统设计的浇水部分是通过单片机程序设计浇水的上下限值与感应电路送入单片机的土壤湿度值相比较,当低于下限值时,单片机输出一个信号控制浇水,高于上限值时再由单片机输出一个信号控制停止浇水。这样可以帮助人们及时地给心爱的盆花浇水
浇花系统单片机C程序和仿真文件 .zip (437.95 KB, 售价: 3 E币)
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
1.png
动图演示
1.gif

单片机部分源程序如下:完整的请下载附件
  1. //程序头函数
  2. #include <reg52.h>
  3. #include <intrins.h>        //包含头文件
  4. //显示函数
  5. #include <display.h>
  6. #include "eeprom52.h"

  7. //宏定义
  8. #define uint unsigned int
  9. #define uchar unsigned char

  10. //管脚声明
  11. sbit LED_R= P2^2;                          //红色指示灯
  12. sbit LED_G= P2^0;                          //绿色指示灯
  13. sbit FENG = P2^5;                          //蜂鸣器
  14. sbit CS   = P1^4;
  15. sbit Clk = P1^2;
  16. sbit DATI = P1^3;
  17. sbit DATO = P1^3;                        //ADC0832引脚

  18. sbit san=P3^4;                                  //继电器
  19. //按键
  20. sbit Key1=P2^6;
  21. sbit Key2=P2^7;
  22. sbit Key3=P3^7;
  23. /*******************************定义全局变量********************************/
  24. unsigned char dat = 0;      //AD值
  25. unsigned char CH=0;       //通道变量
  26. unsigned int sum=0;                         //平均值计算时的总数
  27. unsigned char m=0;
  28. bit bdata flag;                                  //定义位变量
  29. uchar set;                                          //设置变量
  30. uchar full_range=153;                  //满量程AD数值
  31. //函数声明
  32. extern void Key();

  33. //湿度值变量
  34. uint temp=0;

  35. char MH=80,ML=20;                //上下限变量

  36. /******************把数据保存到单片机内部eeprom中******************/
  37. void write_eeprom()
  38. {
  39.         SectorErase(0x2000);
  40.         byte_write(0x2000, MH);
  41.         byte_write(0x2001, ML);
  42.         byte_write(0x2060, a_a);        
  43. }

  44. /******************把数据从单片机内部eeprom中读出来*****************/
  45. void read_eeprom()
  46. {
  47.         MH   = byte_read(0x2000);
  48.         ML   = byte_read(0x2001);
  49.         a_a      = byte_read(0x2060);
  50. }

  51. /**************开机自检eeprom初始化*****************/
  52. void init_eeprom()
  53. {
  54.         read_eeprom();                //先读
  55.         if(a_a != 1)                //新的单片机初始单片机内问eeprom
  56.         {
  57.                 MH  = 80;
  58.                 ML  = 20;
  59.                 a_a = 1;
  60.                 write_eeprom();           //保存数据
  61.         }        
  62. }

  63. /****************************************************************************
  64. 函数功能:AD转换子程序
  65. 入口参数:CH
  66. 出口参数:dat
  67. ****************************************************************************/
  68. unsigned char adc0832(unsigned char CH)
  69. {
  70.         unsigned char i,test,adval;
  71.         adval = 0x00;
  72.         test = 0x00;
  73.         Clk = 0;       //初始化
  74.         DATI = 1;
  75.         _nop_();
  76.         CS = 0;
  77.         _nop_();
  78.         Clk = 1;
  79.         _nop_();
  80.         
  81.         
  82.         if ( CH == 0x00 )      //通道选择
  83.         {
  84.                 Clk = 0;
  85.                 DATI = 1;      //通道0的第一位
  86.                 _nop_();
  87.                 Clk = 1;
  88.                 _nop_();
  89.                 Clk = 0;
  90.                 DATI = 0;      //通道0的第二位
  91.                 _nop_();
  92.                 Clk = 1;
  93.                 _nop_();
  94.         }
  95.         else
  96.         {
  97.                 Clk = 0;
  98.                 DATI = 1;      //通道1的第一位
  99.                 _nop_();
  100.                 Clk = 1;
  101.                 _nop_();
  102.                 Clk = 0;
  103.                 DATI = 1;      //通道1的第二位
  104.                 _nop_();
  105.                 Clk = 1;
  106.                 _nop_();
  107.         }
  108.         
  109.         Clk = 0;
  110.         DATI = 1;
  111.         for( i = 0;i < 8;i++ )      //读取前8位的值
  112.         {
  113.                 _nop_();
  114.                 adval <<= 1;
  115.                 Clk = 1;
  116.                 _nop_();
  117.                 Clk = 0;
  118.                 if (DATO)
  119.                 adval |= 0x01;
  120.                 else
  121.                 adval |= 0x00;
  122.         }
  123.         for (i = 0; i < 8; i++)      //读取后8位的值
  124.         {
  125.                 test >>= 1;
  126.                 if (DATO)
  127.                 test |= 0x80;
  128.                 else
  129.                 test |= 0x00;
  130.                 _nop_();
  131.                 Clk = 1;
  132.                 _nop_();
  133.                 Clk = 0;
  134.         }
  135.         if (adval == test)      //比较前8位与后8位的值,如果不相同舍去。若一直出现显示为零,请将该行去掉
  136.         dat = test;
  137.         nop_();
  138.         CS = 1;        //释放ADC0832
  139.         DATO = 1;
  140.         Clk = 1;
  141.         return dat;
  142. }

  143. void init()                                //定时器初始化函数
  144. {
  145.         TMOD=0x01;                        //定时器工作方式
  146.          TL0=0xb0;
  147.          TH0=0x3c;                        //赋初值50ms
  148.          EA=1;                                //打开中断总开关
  149.         ET0=1;                                //打开定时器0中断允许开关
  150.          TR0=1;                                //打开定时器0定时开关
  151. }

  152. void main()                                //主函数
  153. {
  154.         Init1602();                                                 //初始化液晶函数
  155.         init();                                                         //初始化定时器
  156.         init_eeprom();  //开始初始化保存的数据
  157.         while(1)                                                 //进入循环
  158.         {
  159.                 for(m=0;m<50;m++)                        //读50次AD值
  160.                 sum = adc0832(0)+sum;                //读到的AD值,将读到的数据累加到sum
  161.                 temp=sum/50;                                //跳出上面的for循环后,将累加的总数除以50得到平均值temp
  162.                 sum=0;                                                 //平均值计算完成后,将总数清零
  163.                 if(temp<=full_range)                //读取的AD数值小于满量程数值
  164.                 temp=(temp*100)/full_range;        //除以满量程数值,得到百分比
  165.                 else                                                //如果大于
  166.                 temp=100;                                        //直接赋值100%
  167.                 if(set==0)                                         //set为0,说明现在不是设置状态
  168.                 Display_1602(temp,MH,ML);         //显示AD数值和报警值
  169.                 if(temp<ML&&set==0)         //AD数值小于报警值
  170.                 {
  171.                         flag=1;                                         //打开报警
  172.                         san=0;                                         //打开继电器
  173.                         LED_G=1;                                          //绿灯熄灭
  174.                         LED_R=0;                                          //红灯点亮
  175.                 }
  176.                 else if(temp>MH&&set==0)//AD值大于报警值
  177.                 {
  178.                         flag=0;                                         //关闭报警
  179.                         san=1;                                         //关闭继电器
  180.                         LED_G=0;                                          //绿灯点亮
  181.                         LED_R=1;                                          //红灯熄灭
  182.                 }
  183.                 else
  184.                 {
  185.                         flag=0;                                                  //关闭报警
  186.                         LED_G=0;                                          //绿灯点亮
  187.                         LED_R=1;                                          //红灯熄灭
  188.                 }
  189.                 Key();                                                 //调用按键函数
  190.         }
  191. }

  192. void Key()                                          //按键函数
  193. {
  194.         if(Key1==0)                                  //设置键按下
  195.         {
  196.                 while(Key1==0);                  //按键松开
  197.                 FENG=0;                                  //蜂鸣器响
  198.                 set++;                                  //设置变量加
  199.                 flag=0;                                  //关闭报警
  200.                 TR0=0;                                  //关闭定时器
  201.         }
  202.         if(set==1)                                  //设置报警值时
  203.         {
  204.                 write_com(0x80+0x40+4);//位置
  205.                    write_com(0x0f);//打开显示 无光标 光标闪烁
  206.                 FENG=1;                                //关闭蜂鸣器
  207.         }
  208.         if(set==2)                                  //设置报警值时
  209.         {
  210.                 write_com(0x80+0x40+14);//位置
  211.                    write_com(0x0f);//打开显示 无光标 光标闪烁
  212.                 FENG=1;                                //关闭蜂鸣器
  213.         }
  214.         else if(set>=3)                //设置完成时
  215.         {
  216.                 set=0;                        //变量清零
  217.                 write_com(0x38);//屏幕初始化
  218.                 write_com(0x0c);//打开显示 无光标 无光标闪烁
  219.                 FENG=1;                        //关闭蜂鸣器
  220.                 flag=1;                        //打开报警
  221.                 TR0=1;                        //打开定时器
  222.         }
  223.         if(Key2==0&&set!=0)                        //设置报警值时加键按下
  224.         {
  225.                 while(Key2==0);                        //按键松开
  226.                 FENG=0;                                        //打开蜂鸣器
  227.                 if(set==1)
  228.                 {
  229.                         MH++;                                //报警值加
  230.                         if(MH>99)                //最大加到99
  231.                         MH=ML+1;                                //上限=下限+1
  232.                         write_com(0x80+0x40+3);           //选中液晶屏上的第二行第3列
  233.                         write_data('0'+MH/10);
  234.                         write_data('0'+MH%10);         //显示上限数值
  235.                         write_com(0x80+0x40+4);//闪烁位置
  236.                         FENG=1;                                                //关闭蜂鸣器
  237.                 }
  238.                 if(set==2)
  239.                 {
  240.                         ML++;                                //报警值加
  241.                         if(ML>=MH&&MH<99)                //下限值大于上限并且上限小于99时
  242.                         MH=ML+1;                                //上限=下限+1
  243.                         if(ML>98)                                //下限加到大于98
  244.                         ML=0;                                        //下限清零
  245.                         write_com(0x80+0x40+3);           //选中液晶屏上的第二行第3列
  246.                         write_data('0'+MH/10);
  247.                         write_data('0'+MH%10);
  248.                         write_com(0x80+0x40+13);           //选中液晶屏上的第二行第13列
  249.                         write_data('0'+ML/10);
  250.                         write_data('0'+ML%10);
  251.                         write_com(0x80+0x40+14);//闪烁位置
  252.                         FENG=1;                                                //关闭蜂鸣器
  253.                 }
  254.                 write_eeprom();                           //保存数据
  255.         }
  256.         if(Key3==0&&set!=0)                                //注释同加按键
  257.         {
  258.                 while(Key3==0);
  259.                 FENG=0;
  260.                 if(set==1)
  261.                 {
  262.                         MH--;                                //上限值减
  263.                         if(MH<=ML&&ML>0)                //上限小于下限且下限大于0时
  264.                         ML=MH-1;                                //下限=上限-1
  265.                         if(MH<1)                                //上限小于1时
  266.                         MH=99;                                        //上限赋值99
  267.                         write_com(0x80+0x40+3);           //选中液晶屏上的第二行第3列
  268.                         write_data('0'+MH/10);
  269.                         write_data('0'+MH%10);
  270.                         write_com(0x80+0x40+13);           //选中液晶屏上的第二行第13列
  271.                         write_data('0'+ML/10);
  272.                         write_data('0'+ML%10);
  273.                         write_com(0x80+0x40+4);//闪烁位置
  274.                         FENG=1;                                                //关闭蜂鸣器
  275.                 }
  276.                 if(set==2)
  277.                 {
  278.                         ML--;                                //下限值减
  279.                         if(ML<0)                //小于0时
  280.                         ML=MH-1;                                //下限-上限-1
  281.                         write_com(0x80+0x40+13);           //选中液晶屏上的第二行第13列
  282.                         write_data('0'+ML/10);
  283.                         write_data('0'+ML%10);
  284.                         write_com(0x80+0x40+14);//闪烁位置
  285.                         FENG=1;                                        //关闭蜂鸣器
  286.                 }
  287.                 write_eeprom();                           //保存数据
  288.         }
  289. }

  290. void  time1_int(void) interrupt 1                  //定时器工作函数
  291. {
  292.         uchar count;                                                  //定义计时变量
  293.         TL0=0xb0;
  294.          TH0=0x3c;                                                          //重新赋初值50ms
  295.           count++;                                                          //变量加一次就是50ms
  296.         if(count==10)                                                  //加到10次就是500ms
  297.         {
  298.                 if(flag==0)                                                  //flag=0时,也就是不开启报警
  299.                 FENG=1;                                                  //关闭蜂鸣器
  300.                 if(flag==1)                                                  //flag为1时,也就是打开报警
  301.                 FENG=0;                                                  //打开蜂鸣器
  302.         }

  303.            if(count==20)                                                  //计数20次,就是1s
  304.            {                                                                          //在1s时,红绿灯都是熄灭状态,蜂鸣器也是关闭状态,可以达到闪烁的目的
  305.                 count=0;                                                  //变量清零
  306.                 if(flag==0)                                                  //不是报警状态时
  307.                 FENG=1;                                                         
  308.                 if(flag==1)                                                  //报警状态时
  309.                 FENG=1;
  310.         }
  311. }
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|手机版|小黑屋|ELEOK |网站地图

GMT+8, 2024-3-29 02:55

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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