环境
软件
- uVision V4.02
- ISIS Professional 7.8
芯片
- AT89C51
- DS18B20
- L298
实现效果
将温度传感器中的数值在LCD显示出来并且在不同温度时控制电机顺时针或逆时针旋转
相关代码及资源
操作小记
DS18B20相关函数
#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 delay_ms(INT16U x)
{
INT8U i;
while(x--)
{
for(i=0;i<120;i++);
}
}
*/
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;
}
}
LCD1602相关函数
#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的读数据压力,我们并不是实时进行数据采集,而是在一个时段内去采集一次,这个就是用定时器来做
#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;
float tempv; //温度值
INT8U buff[17]; //缓冲区
void T0_interrupt() interrupt 1 //INT0 0, T0 1, INT1 2, T1 3, Serial T 4
{
count++;
TL0 = ((INT16U)(65536-(INT16U)(11.0592/12*500)))%256; //t0 low delay->500us
TH0 = ((INT16U)(65536-(INT16U)(11.0592/12*500)))%256; //t0 high
if(count==10) //增加延时 -> 50ms
{
count=0;
if(Read_temperature()==1) //顺序程序设计会把执行语句作为延时
{
count=0;
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
EA = 1; //总开关
ET0 = 1; //分开关
TR0 = 1; //定时器开关
while(1);//避免跑飞
}