温度控制直流电机转速
模拟电路图
工程所需文件的目录
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资料、单片机、安卓可免费领取资源。