找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4213|回复: 4
收起左侧

51单片机风扇驱动源程序

[复制链接]
ID:396717 发表于 2019-6-3 19:31 | 显示全部楼层 |阅读模式
自己写的一个有关51单片机控制电机风扇的程序,有LCD1602、ds18b20、红外遥控,还有E2PROM保存按键值的程序,整体的程序结构有点乱,大家可以取一些需要的内容参考,欢迎大家指出不足!

单片机源程序如下:
  1. #include<reg51.h>
  2. #include<intrins.h>                         //包含头文件
  3. #define uchar unsigned char
  4. #define uint unsigned int                 //宏定义
  5. #include "eeprom52.h"
  6. #define LCD1602_DB         P0
  7. sbit LCD1602_RS = P2^6;//“RD”接单片机P2.6, 0=输入指令,1=输入数据         
  8. sbit LCD1602_RW = P2^5;//“WR”接单片机P2.5,0=向LCD写入指令或数据,1=从LCD读取信息
  9. sbit LCD1602_E  = P2^7;//“LCDE”接单片机P2.7,下降沿有效的使能信号
  10. sbit IO_18B20=P3^7;
  11. sbit IN1=P1^0;
  12. sbit IN2=P1^1;
  13. sbit ENA=P1^2;
  14. sbit key1=P2^1;//设置温度
  15. sbit key2=P2^2;//温度加
  16. sbit key3=P2^3;//温度减
  17. bit flag1s=0;//1s定时标志
  18. unsigned char T0RH=0;
  19. unsigned char T0RL=0;

  20. int temp;//读取到的当前温度值
  21. unsigned char len;
  22. int intT,decT;//温度值的整数和小数部分
  23. unsigned char str[12];
  24. unsigned char d1,d2,d3;//显示数据暂存变量
  25. unsigned char flag;
  26. unsigned int shang,xia; //对比温度暂存变量
  27. void Compare();
  28. void GetTemp();
  29. void ConfigTimer0(unsigned int ms);
  30. unsigned char IntToString(unsigned char *str,int dat);
  31. extern bit Start18B20();
  32. extern bit Get18B20Temp(int *temp);
  33. extern void InitLcd1602();
  34. extern void LcdShowStr(unsigned char x,unsigned char y,unsigned char *str);
  35. /******************把数据保存到单片机内部eeprom中******************/
  36. void write_eeprom()
  37. {
  38.         SectorErase(0x2000);                //清除扇区
  39.         byte_write(0x2000, shang);        //写上限数值到扇区
  40.         byte_write(0x2001, xia);        //写下限数值到扇区
  41.         byte_write(0x2060, a_a);        //写初始变量到扇区指定位置
  42. }

  43. /******************把数据从单片机内部eeprom中读出来*****************/
  44. void read_eeprom()
  45. {
  46.         shang   = byte_read(0x2000);                 //从扇区读取上限数据
  47.         xia = byte_read(0x2001);                         //从扇区读取下限数据
  48.         a_a      = byte_read(0x2060);                 //从扇区读取初始变量
  49. }

  50. /**************开机自检eeprom初始化*****************/
  51. void init_eeprom()
  52. {
  53.         read_eeprom();                //先读扇区的数据
  54.         if(a_a != 1)                //判断是否是新单片机(原理:新的单片机扇区里的数据都是0,这里判断是否不等于1。如果是不等于1,就是等于0,那就是新单片机了,就会执行下面的上下限值初始化数值的语句,并让a_a变成1,下次开机就会知道是用过的单片机了就会读取EEPROM里的上下限数据了)
  55.         {
  56.                 shang   = 30;        //上限数值初始为30
  57.                 xia = 20;                //下限数值初始为20
  58.                 a_a = 1;                //初始值变量赋值1,下次开机就会直接读取EEPROM内的上下限数据
  59.                 write_eeprom();           //将初始的数据保存进单片机的EEPROM
  60.         }       
  61. }

  62. /**************LCD1602*****************/
  63. /* 等待液晶准备好 */
  64. void LcdWaitReady()
  65. {
  66.     unsigned char sta;
  67.    
  68.     LCD1602_DB = 0xFF;                         //DB0~DB8为11111111
  69.     LCD1602_RS = 0;                                 //数据和指令选择控制端
  70.     LCD1602_RW = 1;                                 //读操作
  71.     do {
  72.         LCD1602_E = 1;
  73.         sta = LCD1602_DB; //读取状态字
  74.         LCD1602_E = 0;
  75.     } while (sta & 0x80); //bit7等于1表示液晶正忙,重复检测直到其等于0为止
  76. }
  77. /* 向LCD1602液晶写入一字节命令,cmd-待写入命令值 */
  78. void LcdWriteCmd(unsigned char cmd)
  79. {
  80.     LcdWaitReady();
  81.     LCD1602_RS = 0;
  82.     LCD1602_RW = 0;
  83.     LCD1602_DB = cmd;
  84.     LCD1602_E  = 1;
  85.     LCD1602_E  = 0;
  86. }
  87. /* 向LCD1602液晶写入一字节数据,dat-待写入数据值 */
  88. void LcdWriteDat(unsigned char dat)
  89. {
  90.     LcdWaitReady();
  91.     LCD1602_RS = 1;
  92.     LCD1602_RW = 0;
  93.     LCD1602_DB = dat;
  94.     LCD1602_E  = 1;
  95.     LCD1602_E  = 0;
  96. }
  97. /* 设置显示RAM起始地址,亦即光标位置,(x,y)-对应屏幕上的字符坐标 */
  98. void LcdSetCursor(unsigned char x, unsigned char y)
  99. {
  100.     unsigned char addr;
  101.    
  102.     if (y == 0)  //由输入的屏幕坐标计算显示RAM的地址
  103.         addr = 0x00 + x;  //第一行字符地址从0x00起始
  104.     else
  105.         addr = 0x40 + x;  //第二行字符地址从0x40起始
  106.     LcdWriteCmd(addr | 0x80);  //设置RAM地址
  107. }
  108. /* 在液晶上显示字符串,(x,y)-对应屏幕上的起始坐标,str-字符串指针 */
  109. void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str)
  110. {
  111.     LcdSetCursor(x, y);   //设置起始地址
  112.     while (*str != '\0')  //连续写入字符串数据,直到检测到结束符
  113.     {
  114.         LcdWriteDat(*str++);
  115.     }
  116. }
  117. /* 初始化1602液晶 */
  118. void InitLcd1602()
  119. {
  120.     LcdWriteCmd(0x38);  //16*2显示,5*7点阵,8位数据接口
  121.     LcdWriteCmd(0x0C);  //显示器开,光标关闭
  122.     LcdWriteCmd(0x06);  //文字不动,地址自动+1
  123.     LcdWriteCmd(0x01);  //清屏
  124. }
  125. //sbit IO_18B20=P3^2;

  126. /*软件延时函数,延时时间(t*10)us*/
  127. void DelayX10us(unsigned char t)
  128. {
  129.         do{
  130.                 _nop_();
  131.                 _nop_();
  132.                 _nop_();
  133.                 _nop_();
  134.                 _nop_();
  135.                 _nop_();
  136.                 _nop_();
  137.                 _nop_();
  138.         }while(--t);
  139. }
  140. /*复位总线,获取存在脉冲,以启动一次读写操作*/
  141. bit Get18B20Ack()
  142. {
  143.         bit ack;
  144.        
  145.         EA=0;                                   //禁止总中断
  146.         IO_18B20=0;                        //产生500us复位脉冲
  147.         DelayX10us(50);
  148.         IO_18B20=1;
  149.         DelayX10us(6);                //延时60us
  150.         ack=IO_18B20;                //读取存在脉冲
  151.         while(!IO_18B20);   //等待存在脉冲结束
  152.         EA=1;                                //重新使能总中断
  153.         return ack;
  154. }
  155. /*向DS18B20写入一个字节,dat-待写入字节*/
  156. void Write18B20(unsigned char dat)
  157. {
  158.         unsigned char mask;
  159.         EA=0;
  160.         for(mask=0x01;mask!=0;mask<<=1)//低位在先,依次移出8个bit
  161.         {
  162.                 IO_18B20=0;//产生2us低电平脉冲
  163.                 _nop_();
  164.                 _nop_();
  165.                 if((mask&dat)==0)//输出该bit值
  166.                         IO_18B20=0;
  167.                 else
  168.                         IO_18B20=1;
  169.                 DelayX10us(6);//延时60us
  170.                 IO_18B20=1;//拉高通信引脚
  171.         }
  172.         EA=1;
  173. }
  174. /*从DS18B20读取一个字节,返回值-读到的字节*/
  175. unsigned char Read18B20()
  176. {
  177.         unsigned char dat;
  178.         unsigned char mask;

  179.         EA=0;
  180.         for(mask=0x01;mask!=0;mask<<=1)//低位在先,依次采集8个bit
  181.         {
  182.                 IO_18B20=0;//产生2us低电平脉冲
  183.                 _nop_();
  184.                 _nop_();
  185.                 IO_18B20=1;//结束低电平脉冲,等待18B20输出数据
  186.                 _nop_(); //延时2us
  187.                 _nop_();
  188.                 if(!IO_18B20)//读取通信引脚上的值
  189.                         dat &= ~mask;
  190.                 else
  191.                         dat |= mask;
  192.                 DelayX10us(6);//再延时60us
  193.         }
  194.         EA=1;
  195.         return dat;
  196. }
  197. /*启动一次18B20温度转换,返回值-表示是否启动成功*/
  198. bit Start18B20()
  199. {
  200.         bit ack;
  201.         ack=Get18B20Ack();//执行总线复位,并获取18B20应答
  202.         if(ack==0)
  203.         {
  204.                 Write18B20(0xCC);
  205.                 Write18B20(0x44);
  206.         }
  207.         return ~ack;
  208. }
  209. /*读取DS18B20转换的温度值,返回值-表示是否读取成功*/
  210. bit Get18B20Temp(int *temp)
  211. {
  212.         bit ack;
  213.         unsigned char LSB,MSB;//16bit温度值的低字节和高字节

  214.         ack=Get18B20Ack();//执行总线复位,并获取18B20应答
  215.         if(ack==0)
  216.         {
  217.                 Write18B20(0xCC);//跳过ROM操作
  218.                 Write18B20(0xBE);//发送读命令
  219.                 LSB=Read18B20();//读温度值的低字节
  220.                 MSB=Read18B20();//读温度值的高字节
  221.                 *temp=((int)MSB<<8)+LSB;//合成为16bit整型数
  222.         }
  223.         return ~ack;
  224. }
  225. void main()
  226. {
  227.         bit res;

  228.         EA=1;
  229.         ConfigTimer0(10);//T0定时10ms
  230.         Start18B20();//启动DS18B20
  231.         InitLcd1602();//初始化液晶

  232.         while(1)
  233.         {               
  234.                 if(flag1s)//每秒更新一次温度
  235.                 {
  236.                         flag1s=0;
  237.                         res=Get18B20Temp(&temp);//读取当前温度
  238.                         if(res)//读取成功时,刷新当前温度显示
  239.                         {
  240.                                 GetTemp();
  241.                        
  242.                                 LcdShowStr(0,0,(unsigned char *)"Welcome to use");//显示字符及温度值
  243.                                 LcdShowStr(0,1,"Current T:");
  244.                                 LcdShowStr(10,1,str);
  245.                                         Compare();
  246.                         }
  247.                         else //读取失败时,提示错误信息
  248.                         {
  249.                                 LcdShowStr(0,0,"error!");

  250.                         }
  251.                         Start18B20();//重新启动下一次转换                                         
  252.                 }
  253.         }
  254. }
  255. /*温度获取函数,获取当前环境温度值并保存在str数组中*/
  256. void GetTemp()
  257. {
  258.         intT=temp>>4;//分离出温度值整数部分
  259.         decT=temp &0x0F;//分离出温度值小数部分
  260.                        
  261.         len=IntToString(str,intT);//整数部分转换成字符串
  262.                        
  263.         str[len++]='.';
  264.         decT=(decT%10)/16;//二进制的小数部分转换为1位十进制位
  265.         str[len++]=decT+'0';//十进制小数位再转换为ASCII字符
  266.         while(len<6)//用空格补齐到6个字符长度
  267.         {
  268.                 str[len++]=' ';
  269.         }
  270.         str[len++]='\0';
  271. }
  272. /*延时函数,用于PWM控制*/
  273. void delay(unsigned int z)
  274. {
  275.         unsigned int x,y;
  276.         for(x=z;x>0;x--)
  277.                 for(y=110;y>0;y--);
  278. }
  279. /*比较函数,通过温度值的比较设置电机的转速*/
  280. void Compare()
  281. {
  282.         unsigned int i=0;
  283.         unsigned char j;

  284.         if((intT>= 24) && (intT<26))   //以两度为一个温差范围,并设温度范围索引
  285.         {
  286.                 j=0;       
  287.         }
  288.         else if((intT>=26) &&(intT<28))
  289.         {
  290.                 j=1;
  291.         }
  292.         else if((intT>=28) &&(intT<30))
  293.         {
  294.                 j=2;
  295.         }
  296.         else if(intT>=30)
  297.         {
  298.                 j=3;
  299.         }
  300.         switch(j)                  //根据温度索引设置电机转速
  301.         {
  302.                 case 0:        IN1=1;
  303.                                 IN2=0;
  304.                                   for(i=0;i<200;i++)
  305.                               {
  306.                                         ENA=1;
  307.                                      delay(20);
  308.                                   ENA=0;
  309.                                         delay(30);
  310.                                 }
  311.                                 break;
  312.        
  313.                 case 1:        IN1=1;
  314.                                 IN2=0;
  315.                                   for(i=0;i<200;i++)
  316.                               {
  317.                                         ENA=1;
  318.                                      delay(30);
  319.                                   ENA=0;
  320.                                         delay(30);
  321.                                 }
  322.                                 break;         
  323.        
  324.                 case 2:        IN1=1;
  325.                                 IN2=0;
  326.                                   for(i=0;i<200;i++)
  327.                               {
  328.                                         ENA=1;
  329.                                      delay(55);                         
  330.                                   ENA=0;
  331.                                         delay(30);
  332.                                 }
  333.                                 break;         
  334.                                                        
  335.                 case 3:        IN1=1;
  336.                                 IN2=0;
  337.                               ENA=1;
  338.                                 break;

  339.                 default:break;                  
  340.         }
  341. }  

  342. /*整型数转换为字符串,str-字符串指针,dat-待转换数,返回值-字符串长度*/
  343. unsigned char IntToString(unsigned char *str,int dat)
  344. {
  345.         signed char i=0;
  346.         unsigned char len=0;
  347.         unsigned char buf[6];

  348.         if(dat<0)//如果为负数,首先取绝对值,并在指针上添加负号
  349.         {
  350.                  dat=-dat;
  351.                 *str++='-';
  352.                 len++;
  353.         }
  354.         do{           //先转换为低位在前的十进制数组
  355.                 buf[i++]=dat%10;
  356.                 dat /=10;
  357.         }while(dat>0);
  358.         len += i;//i最后的值就是有效字符的个数
  359.         while(i-->0)//将数组值转换为ASCII码反向拷贝到接收指针上
  360.         {
  361.                 *str++=buf[i]+'0';
  362.         }
  363.         *str='\0';
  364.         return len;
  365. }
  366. void ConfigTimer0(unsigned int ms)
  367. {
  368.         unsigned long tmp;

  369.         tmp=11059200/12;
  370.         tmp=(tmp*ms)/1000;
  371.         tmp=65536-tmp;
  372.         tmp=tmp+12;
  373.         T0RH=(unsigned char)(tmp>>8);
  374.         T0RL=(unsigned char)tmp;
  375.         TMOD &= 0xF0;
  376.         TMOD |= 0x01;
  377.         TH0=T0RH;
  378.         TL0=T0RL;
  379.         ET0=1;
  380.         TR0=1;
  381. }
  382. void InterruptTimer0() interrupt 1
  383. {
  384.         static unsigned char tmr1s=0;

  385.         TH0=T0RH;
  386.         TL0=T0RL;
  387.         tmr1s++;
  388.         if(tmr1s>=100)
  389.         {
  390.                 tmr1s=0;
  391.                 flag1s=1;
  392.         }                 

  393. }
  394. void zi_keyscan()//自动模式按键扫描函数
  395. {
  396.         if(key1==0)                                                          //设置键按下
  397.         {
  398.                 delay(80);                                                  //延时去抖
  399.                 if(key1==0)
  400.                 {
  401.                         flag=1;                                  //再次判断按键,按下的话进入设置状态
  402.                         while(key1==0);//松手检测                  //按键释放
  403.                 }
  404.         }
  405.         while(flag==1)                                                  //进入设置上限状态
  406.         {
  407.                 d1=18;d2=shang/10;d3=shang%10;          //显示字母H 和上限温度值
  408.                 if(key1==0)                                                  //判断设置键是否按下
  409.                 {
  410.                         delay(80);                                          //延时去抖
  411.                         if(key1==0)
  412.                         {
  413.                                 flag=2;                          //按键按下,进入设置下限模式
  414.                                 while(key1==0);//松手检测
  415.                         }
  416.                 }
  417.                 if(key2==0)                                                  //加键按下
  418.                 {
  419.                         delay(80);                                          //延时去抖
  420.                         if(key2==0)                                          //加键按下
  421.                         {
  422.                                 shang+=1;                                  //上限加1
  423.                                 if(shang>=100)shang=100;  //上限最大加到100
  424.                                 while(key2==0);//松手检测
  425.                         }
  426.                 }
  427.                 if(key3==0)                                                  //减键按下
  428.                 {
  429.                         delay(80);                                          //延时去抖
  430.                         if(key3==0)                                          //减键按下
  431.                         {
  432.                                 shang-=1;                                  //上限减1
  433.                                 if(shang<=10)shang=10;          //上限最小减到10
  434.                                 while(key3==0);//松手检测
  435.                         }
  436.                 }               
  437.         }
  438.         while(flag==2)                                                  //设置下限
  439.         {
  440.                 d1=17;d2=xia/10;d3=xia%10;                  //显示字母L 显示下限温度值
  441.                 if(key1==0)
  442.                 {
  443.                         delay(80);
  444.                         if(key1==0)
  445.                         {
  446.                                 flag=0;
  447.                                 while(key1==0);//松手检测
  448.                                 write_eeprom();                           //保存数据       
  449.                         }
  450.                 }
  451.                 if(key2==0)
  452.                 {
  453.                         delay(80);
  454.                         if(key2==0)
  455.                         {
  456.                                 xia+=1;
  457.                                 if(xia>=99)xia=99;
  458.                                 while(key2==0);//松手检测
  459.                         }
  460.                 }
  461.                 if(key3==0)
  462.                 {
  463.                         delay(80);
  464.                         if(key3==0)
  465.                         {
  466.                                 xia-=1;
  467.                                 if(xia<=0)xia=0;
  468.                                 while(key3==0);//松手检测
  469.                         }
  470.                 }               
  471.         }
  472. }                                                                                                                       
复制代码

所有资料51hei提供下载:
51单片机风扇.rar (57.84 KB, 下载次数: 37)

评分

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

查看全部评分

回复

使用道具 举报

ID:396717 发表于 2019-6-7 20:56 | 显示全部楼层
啊呀!!!发错程序了,发成了修改之前的程序,这个程序是不对的,大家在看的时候注意了!!!!!!!!!
回复

使用道具 举报

ID:698943 发表于 2020-2-27 12:17 | 显示全部楼层
赚钱买八爪鱼 发表于 2019-6-7 20:56
啊呀!!!发错程序了,发成了修改之前的程序,这个程序是不对的,大家在看的时候注意了!!!!!!!!!

哪里错了
回复

使用道具 举报

ID:592703 发表于 2020-2-28 18:05 | 显示全部楼层
学习一下!!谢谢大佬!
回复

使用道具 举报

ID:432653 发表于 2020-3-1 14:13 | 显示全部楼层
第5行和39行显示错误
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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