温度控制直流电机转速(DS18B20与steppermoter与LCD1602)

模拟电路图

在这里插入图片描述

在这里插入图片描述

工程所需文件的目录

在这里插入图片描述

LCD1602.c(因为所接的管脚没变,所以用回以前的即可)

#include<reg51.h>
#include<intrins.h>

#define INT8U unsigned char
#define INT16U unsigned int

sbit RS=P2^0;
sbit RW=P2^1;
sbit EN=P2^2;

void delay_ms(INT16U x)
{
	INT8U i;
	while(x--)
	{
		for(i=0;i<120;i++);
	}
}

void Busy_Wait()
{
	INT8U LCD_Status;
	do
	{
		P0=0xFF;
		EN=0;RS=0;RW=1;
		EN=1; LCD_Status=P0;
		EN=0;
	}
	while(LCD_Status&0x80);//1000 0000
}

void Write_LCD_Command(INT8U cmd)
{
	Busy_Wait();
	EN=0;RS=0;RW=0;
	P0=cmd;
	EN=1;_nop_();EN=0;
}

void Write_LCD_Data(INT8U data1)
{
	Busy_Wait();
	EN=0;RS=1;RW=0;
	P0=data1;
	EN=1;_nop_();EN=0;
}

void LCD_String(INT8U r,INT8U c,INT8U *str)
{
	INT8U i=0;
	INT8U code DDRAM[]={0x80,0xC0};
	Write_LCD_Command(DDRAM[r]|c);
	for(i=0;i<16&&str[i];i++)
	{
		Write_LCD_Data(str[i]);
	}
	for(;i<16;i++)
		Write_LCD_Data(' ');
}

void LCD_Initialize()
{
	Write_LCD_Command(0x38);delay_ms(1);//置功能位,8位,双行,每一个字符占5*7	0011 1000
	Write_LCD_Command(0x01);delay_ms(1);//清屏 
	Write_LCD_Command(0x06);delay_ms(1);//字符进入模式,屏幕不动,字符后移
	Write_LCD_Command(0x0C);delay_ms(1);//开显示,关光标
}

DS18B20.c(用回以前的即可,但管脚从P3.4变成了P3.3,需要修改)

#include<reg51.h>//register
#include<intrins.h>//_nop_() _crol_()
#define INT8U unsigned char
#define INT16U unsigned int
#define delay4us();	{_nop_();_nop_();_nop_();_nop_();}

extern void delay_ms(INT16U x);

sbit DQ=P3^3;  //管脚部分改变了
INT8U Temp_Value[]={0x00,0x00};	//温度数据的低8位与高8位

void delayx(INT16U x)
{
	while(x--);
}

/***********AT89C51的主频一定要设为11.0592MHz*****/
INT8U Init_DS18B20()//初始化和检测DS18B20
{
	INT8U DQ_status;
	DQ=1; delayx(8);//delay77us
	DQ=0; delayx(90);//>delay480us
	DQ=1; delayx(5);//>delay15us
	DQ_status=DQ; delayx(90);
	
	return DQ_status;
}


INT8U Readonebyte()//读取DS18B20中的1个字节的数据
{
	INT8U i,datatemp=0x00;
	for(i=0x01;i!=0x00;i<<=1)//100000000
	{
		DQ=0;_nop_();  
		DQ=1;_nop_();
		if(DQ) datatemp=datatemp|i; 
		delayx(8);
	}
	return datatemp;

}

void Writeonebyte(INT8U dat)//dat>>1 00001010 1CY ACC
{ 
	INT8U i;
	for(i=0;i<8;i++)
	{
		DQ=1;_nop_(); 
		DQ=0;_nop_();
		dat=dat>>1;  //PSW
		DQ=CY;
		delayx(8); 
	 
	}
}

INT8U Read_temperature()
{
	if(Init_DS18B20()==1) return 0;
	else
	{
		Writeonebyte(0xCC);//跳检序列号
		Writeonebyte(0x44);//启动转换
		Init_DS18B20(); 
		Writeonebyte(0xCC);//跳检序列号 因为只有一个DS18B20
		Writeonebyte(0xBE);//读温度寄存器里的第0,1字节
		Temp_Value[0] = Readonebyte(); 
		Temp_Value[1] = Readonebyte();
		
		return 1;
	}
}

在这里插入图片描述

steppermoterMain1.c(顺序程序设计方式,会把执行语句作为延时,不科学)

clude<reg51.h>
#include<intrins.h>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>

#define INT8U unsigned char	  //8位
#define INT16U unsigned int	  //16位
//导入要引用的函数
extern void delay_ms(INT16U x);	   //延时函数
extern void LCD_Initialize();	   //初始化函数
extern void LCD_String(INT8U r,INT8U c,INT8U *str);	//LCD字符串显示函数
extern INT8U Temp_Value[];		   //外部数组声明
extern void delayx(INT16U x);	   //延时函数
extern INT8U Read_temperature();   //读取温度的函数

sbit MA=P1^0; //直流电机A端
sbit MB=P1^1; //直流电机B端
sbit PWM=P1^2; //pulse width modification 脉冲宽度调制 功能调速

void main()
{
	float tempv = 0.0;
	INT8U temp_buff[17];
	
	LCD_Initialize();
	LCD_String(0, 0, "  RECENT TEMP   ");	  //显示屏中的第一行显示内容(16个)
	LCD_String(1, 0, "     WAITING....");	  //显示屏中的第二行显示内容
	Read_temperature();	  //读取温度值
	delay_ms(500);		  //硬件都要延时一会,给它反应的时间
	
	while(1)   //用死循环防止跑飞
	{
		if(Read_temperature())	//能读到温度则执行下面的内容
		{
			tempv = (((int)Temp_Value[1]<<8) | (int)Temp_Value[0]) * 0.0625; //将读取到的温度值转化为16位,0.0625是精度
			sprintf(temp_buff, "TEMP:  %5.1f\xDF\x43", tempv);//格式化(tempV以这种格式拷贝到temp_buff),.2是两个小数点,\xDF\x43对应字符集里面的℃
			LCD_String(1, 0, temp_buff); //将格式化后的温度值在显示屏上显示
			
			//下面开始对电动机作处理
			if(tempv>=75) tempv = 75;	 //正转等于75度时电动机全速转动
			if(tempv<=0) tempv = 0;		 //反转等于0度时电动机全速转动
			
			if(tempv>=45)		 //大于等于45度时,加速正转
			{
				MA = 1;
				MB = 0;
				
				if(tempv==45) PWM = 0;	//等于45度时停止
				else if(tempv==75) PWM = 1;	 //等于75度全速正转动
				else  //实现正转动时,手动升温加速,降温减速的效果
				{
					PWM = 1; delay_ms(tempv-45); //电机驱动:温度越高延时越长,给力的时间越长,电机逐渐加速正转动
					PWM = 0; delay_ms(75-tempv); //电机驱动:温度越低延时越长,不给力的时间越长,电机慢慢停止
				}
			}
			else if(tempv<=10)	 //大于等于10度时,加速反转
			{
				MA = 0;
				MB = 1;
				
				if(tempv==10) PWM = 0;	//等于10度时停止
				else if(tempv==0) PWM = 1;	//等于0度全速反转动
				else
				{
					PWM = 1; delay_ms(10-tempv); //电机驱动:10-0度数范围内,温度越低延时越长,给力的时间越长,电机逐渐加速反转动
					PWM = 0; delay_ms(tempv);	 //电机驱动:10-0度数范围内,温度越高延时越长,不给力的时间越长,电机慢慢停止
				}
			}
			else	 //10度到45度之间逐渐停止
			{
				MA = 0;
				MB = 0;
				PWM = 0;
			}		
		}
		delay_ms(50);
	}
}

该版本写法运行仿真时有缺陷,可以用来作思路参考,但实际运用中不建议使用,建议用下面的版本!!!

在这里插入图片描述

steppermoterMain2.c(定时采样版本,空调一直采用太耗电了,这里相比于上面加了定时器和中断设置)

 #include<reg51.h>
 #include<intrins.h>
 #include<string.h>
 #include<stdlib.h>
 #include<stdio.h>
 #define INT8U unsigned char
 #define INT16U unsigned int

extern void delay_ms(INT16U x);
extern void LCD_Initialize();
extern void LCD_String(INT8U r,INT8U c,INT8U *str);
extern INT8U Temp_Value[];
extern void delayx(INT16U x);
extern INT8U Read_temperature();

 sbit MA=P1^0;//直流电机A端 
 sbit MB=P1^1;//直流电机B端 
 sbit PWM=P1^2;//pulse width modification 脉冲宽度调制 功能调速
 static int count=0;  //定义count用来在定时器中进行计数 
  float tempv;
 INT8U buff[17];
 void T0_INTERRRUPT() interrupt 1 //中断函数标识位,四个中断位: INT0 0 T1 3 Serial T 4
 {
	 count++;
	 //因为没自动刷新功能,所以要一开始就給它个初始值 
	 TH0=(INT16U)(65536-(INT16U)(11.0592/12*500))%256;   //每500us加一次count 
	 TL0=(INT16U)(65536-(INT16U)(11.0592/12*500))/256;
	 if(count==100)  //每0.05s执行一次 
	 {
	 count=0;
	 
  if(Read_temperature()==1) //顺序程序设计会把执行语句作为延时
 {
   tempv=(((int)Temp_Value[1]<<8)|((int)Temp_Value[0]))*0.0625;
   sprintf(buff,"temp:  %5.1f\xDF\x43",tempv);  
   LCD_String(1,0,buff);
   if(tempv>=75)
   tempv=75;//正转75度是全速了  temp speed
   if(tempv<=0)
   tempv=0;//反转0度是全速了
   if(tempv>=45)
   {   MA=1;
       MB=0;
	   if(tempv==45)
	   {  
          PWM=0;
	   }
	   else if(tempv==75)
	   {  
           PWM=1;
	   }
	   else
	   {   
           PWM=1;delay_ms(tempv-45); //给力
		   PWM=0;delay_ms(75-tempv);//不给力
	   }
   }
   else if(tempv<=10)
   {   MA=0;
       MB=1;
	   if(tempv==10)
	   {  
          PWM=0;
	   }
	   else if(tempv==0)
	   {  
           PWM=1;
	   }
	   else
	   {   
           PWM=1;delay_ms(10-tempv); //给力
		   PWM=0;delay_ms(tempv-0);//不给力
	   }
   
   }
   else
   {   MA=0;
       MB=0;
   }
 }
 }
	 }
 
 
 void main()
 { 
  LCD_Initialize();	
  LCD_String(0,0,"  recent temp");
  LCD_String(1,0,"  Waiting.......");
  Read_temperature();
  delay_ms(1500);
	 TMOD=0x01;    //模式 :定时器16位,计数最大是65535 
	 //设置定时的时间,TH0与TL0的关系是爸爸给儿子钱的关系 
	 TH0=(INT16U)(65536-(INT16U)(11.0592/12*500))%256;   //小于256的都是低八位 
	 TL0=(INT16U)(65536-(INT16U)(11.0592/12*500))/256;   //大于256的都是高八位
	 
	 //只有当两个开关都合上时才能接到上面的中断函数运行 
	 EA=1;  //中断总开关 
	 ET0=1; //中断分开关
	 
	 TR0=1; //定时器开关 
	 
  while(1)//避免跑飞
  {

  }
 
 }

注:中断函数属于内部函数,不用自己调用,中断总开关与中断分开关闭合后,系统会自动调用
在这里插入图片描述
喜欢的朋友可以关注我的个人公众号,后台回复java资料、单片机、安卓可免费领取资源。
在这里插入图片描述

  • 2
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值