DS18B20
1、基本知识讲解
2、DS18B20读取温度值
main.c
#include<regx52.h>
#include"delay.h"
#include"LCD1602.h"
#include"key.h"
#include"DS18B20.h"float T;
void main ()
{LCD_Init();LCD_ShowString(1,1,"temp");while(1){DS18B20_convert();T=DS18B20_read();if(T<0){LCD_ShowChar(2,1,'-'); //显示负号T=-T;}else{LCD_ShowChar(2,1,'+'); //显示正号T=T;}LCD_ShowNum(2,2,T,3); //显示正整数 ,精度是3,-55~125LCD_ShowChar(2,5,'.'); //显示小数点LCD_ShowNum(2,6,(unsigned long)(T*10000)%10000,4);//显示小数后面的数字,精度是4位 ,0.0623}}
onewire.c
#include<REGX52.h>
sbit onewire_DQ=P3^7;
unsigned char onewire_init()
{
unsigned char ackbit;
unsigned char i;onewire_DQ=1;onewire_DQ=0;i = 247;while (--i); //延时500usonewire_DQ=1;i = 32; //延时70uswhile (--i);ackbit=onewire_DQ;i = 247; //延时500us,这里从机拉低60-240us会自动释放总线while (--i);return ackbit;
}
void onewire_sendbit(unsigned char Bit)
{unsigned char i;onewire_DQ=0;i = 4;while (--i);//延时10usonewire_DQ=Bit; //如果bit=0,则DQ继续拉低50us,加上前面10us,刚好满足60us.如果bit=1,则DQ相当10us后总线释放,接着继续释放50usi = 24;while (--i);//延时50usonewire_DQ=1;}
unsigned char onewire_receivebit()
{unsigned char i;unsigned char Bit;onewire_DQ=0;i = 2;while (--i);//主机拉低总线5usonewire_DQ=1;i = 2;while (--i);//主机释放总线5usBit=onewire_DQ;//DS18B20将会发送0或1,此时主机读取数据i = 24;while (--i);//延时50usreturn Bit;
}
void onewire_sendbyte(unsigned char byte)
{
unsigned char i;
for(i=0;i<8;i++)
{onewire_sendbit(byte&(0x01<<i)); //取一位用与
}}
unsigned char onewire_receivebyte()
{
unsigned char i;
unsigned char byte=0x00;
for(i=0;i<8;i++)
{if(onewire_receivebit()){byte=byte|(0x01<<i); //取整体用或}
}
return byte;
}
DS18B20.C
#include<regx52.h>
#include"onewire.h"#define DS18B20_SKIP_ROM 0xCC
#define DS18B20_CONVERT_T 0x44
#define DS18B20_READ_SCRATCHPAD 0xBEvoid DS18B20_convert()
{onewire_init() ; //初始化onewire_sendbyte(DS18B20_SKIP_ROM); //跳过ROMonewire_sendbyte(DS18B20_CONVERT_T); //温度转换
}float DS18B20_read()
{ unsigned char TLSB,TMSB;int temp;float T;onewire_init() ;onewire_sendbyte(DS18B20_SKIP_ROM);onewire_sendbyte(DS18B20_READ_SCRATCHPAD);//温度读取TLSB=onewire_receivebyte(); //读取低八位TMSB=onewire_receivebyte(); //读取高八位temp=(TMSB<<8)|TLSB; //把低八位和高八位整合成一个数T=temp/16.0; //由于存储小数的缘故,最低位不是从2的0次方开始,而是2的-4方开始,所以读取的值要除以16return T;
}
3、DS18B20温度告警器
按键K1实现对温度上限值的加加,K2实现对温度上限值的减减,按键K3实现对温度下限值的加加,K4实现对温度下限值的减减,运用at24c02对温度上限值和下限值进行存储。超过上限值LCD1602显示ov:h,低于下限值LCD1602显示ov:l。
main.c
#include<regx52.h>
#include"delay.h"
#include"LCD1602.h"
#include"key.h"
#include"DS18B20.h"
#include"at24c02.h"
#include"timer0.h"
char Tlow,Thigh; //char类型表示数据位-127~128,满足DS18B20的测温范围-55~125
float T,Tshow;
unsigned char keynum;
void main ()
{ DS18B20_convert();Delay(1000);Thigh=at24c02_readbyte(0); //一开始就读取AT24C02里的数据,这个时候还没有写入Tlow=at24c02_readbyte(1);if(Thigh>125||Tlow<-55||Thigh<=Tlow){ Thigh=25;Tlow=5;} //读出的数据可能会超出范围,所以当超出范围时,赋初值LCD_Init();Timer0_Init();LCD_ShowString(1,1,"T:");LCD_ShowString(2,1,"TH:");LCD_ShowString(2,9,"TL:");LCD_ShowSignedNum(2,4,Thigh,3);LCD_ShowSignedNum(2,12,Tlow,3);while(1){keynum=key();DS18B20_convert();T=DS18B20_read();if(T<0) {LCD_ShowChar(1,3,'-');Tshow=-T;}//为什么要定一个Tshow,主要是当T为负数时,要转为正数,这样Tshow就始终是正数if(T>0) {LCD_ShowChar(1,3,'+');Tshow=T;} //因为shownum只能显示正整数,而且要显示小数部分,转成正整数方便转换LCD_ShowNum(1,4,Tshow,3);LCD_ShowChar(1,7,'.'); LCD_ShowNum(1,8,(unsigned long)(Tshow*100)%100,2);if(keynum){if(keynum==1){Thigh++;if(Thigh>125){Thigh=125;} //温度上限值不能超过DS18B20的上限}if(keynum==2){Thigh--;if(Thigh<=Tlow) //温度上限值减减不能减到小于温度下限值{Thigh++;}}if(keynum==3){Tlow++;if(Tlow>=Thigh) //温度下限值加加不能加到大于温度上限值{Tlow--;}}if(keynum==4){Tlow--;if(Tlow<-55){Tlow=-55;} //温度下限值不能超过DS18B20的下限}at24c02_writebyte(0,Thigh); //记住写入后要延时5msDelay(5);at24c02_writebyte(1,Tlow);Delay(5);LCD_ShowSignedNum(2,4,Thigh,3);LCD_ShowSignedNum(2,12,Tlow,3);
}if(T>Thigh){LCD_ShowString(1,13,"ov:H");} //实际温度超过设定上限值告警else if(T<Tlow){LCD_ShowString(1,13,"ov:L");} //实际温度低于设定下限值告警else{LCD_ShowString(1,13," ");}}}void Timer0_Routine() interrupt 1
{static unsigned int count; TL0 = 0x18; TH0 = 0xFC;count++;
if(count>=20)
{count=0;key_loop();}}
onewire.c
这里增加一步关闭中断,再打开中断
#include <REGX52.H>
sbit onewire_DQ=P3^7;
unsigned char onewire_init()
{
unsigned char ackbit;
unsigned char i;onewire_DQ=1;onewire_DQ=0;EA=0;//单总线计时时不能进入中断,因为延时是us级别,中断之后再返回会计时不准,所以这里要关掉总中断,计时完后再打开。i = 247;while (--i); //延时500usonewire_DQ=1;i = 32; //延时70uswhile (--i);ackbit=onewire_DQ;i = 247; //延时500us,这里从机拉低60-240us会自动释放总线while (--i);EA=1;return ackbit;
}
void onewire_sendbit(unsigned char Bit)
{unsigned char i;onewire_DQ=0;EA=0;i = 4;while (--i);//延时10usonewire_DQ=Bit; //如果bit=0,则DQ继续拉低50us,加上前面10us,刚好满足60us.如果bit=1,则DQ相当10us后总线释放,接着继续释放50usi = 24;while (--i);//延时50usEA=1;onewire_DQ=1;}
unsigned char onewire_receivebit()
{unsigned char i;unsigned char Bit;onewire_DQ=0;EA=0;i = 2;while (--i);//主机拉低总线5usonewire_DQ=1;i = 2;while (--i);//主机释放总线5usBit=onewire_DQ;//DS18B20将会发送0或1,此时主机读取数据i = 24;while (--i);//延时50usEA=1;return Bit;
}
void onewire_sendbyte(unsigned char byte)
{
unsigned char i;
for(i=0;i<8;i++)
{onewire_sendbit(byte&(0x01<<i)); //取一位用与
}}
unsigned char onewire_receivebyte()
{
unsigned char i;
unsigned char byte=0x00;
for(i=0;i<8;i++)
{if(onewire_receivebit()){byte=byte|(0x01<<i); //取整体用或}
}
return byte;
}
LCD1602
1、基本知识讲解
2、字符、字符串
2、LCD1602.c代码
#include<regx52.h>
sbit lcd_RS=P2^6;
sbit lcd_RW=P2^5;
sbit lcd_EN=P2^7;
#define port P0
void LCD_Delay() //@12.000MHz 1ms //延时函数
{unsigned char data i, j;i = 2;j = 239;do{while (--j);} while (--i);
}void lcd_write_command(unsigned char command) //写命令
{lcd_RS=0;lcd_RW=0;port=command;lcd_EN=1;LCD_Delay();//因为这里E脉冲宽度时间是us级别,而单片机执行一次命令是us级别,所以这里检测不到,所以加延时函数lcd_EN=0;LCD_Delay();}
void lcd_write_Data(unsigned char Data) //写数据
{lcd_RS=1;lcd_RW=0;port=Data;lcd_EN=1;LCD_Delay();//因为这里E脉冲宽度时间是us级别,而单片机执行一次命令是us级别,所以这里检测不到,所以加延时函数lcd_EN=0;LCD_Delay();}void lcd_init() //初始化
{lcd_write_command(0x38);lcd_write_command(0x0C);lcd_write_command(0x06);lcd_write_command(0x01);
}void LCD_setcursor(unsigned char line,unsigned char column) //定义光标位置,在第几行第几列
{if(line==1){lcd_write_command(0x80|column-1);}else{lcd_write_command(0x80|(column-1)+0x40);}
}void LCD_ShowChar(unsigned char line,unsigned char column,unsigned char Char) //显示一个字符
{LCD_setcursor(line,column);lcd_write_Data(Char);
}
void LCD_ShowString(unsigned char line,unsigned char column,unsigned char *String) //显示字符串
{unsigned char i;LCD_setcursor(line,column);for(i=0;String[i]!='\0';i++)
{
lcd_write_Data(String[i]);
}}
unsigned int pow(x,y) //定义一个幂函数 例如x=6,y=4,则result=1*6*6*6*6=6^4
{unsigned char result=1;unsigned int i;for(i=0;i<y;i++){result*=x;}return result;
}
void LCD_ShowNum(unsigned char line,unsigned char column,unsigned int num,unsigned char length) //显示十进制数字
{unsigned char i;LCD_setcursor(line,column);for(i=length;i>0;i--){lcd_write_Data(0x30+num/(pow(10,i-1))%10);}}
void LCD_ShowsignNum(unsigned char line,unsigned char column, int num,unsigned char length)//显示有符号十进制数字
{unsigned char i;unsigned int num1;LCD_setcursor(line,column);if(num>=0){lcd_write_Data('+');num1=num;}else{lcd_write_Data('-');num1=-num;//有符号int的负数最小值为-32768,正数最大值为32767,取反会超出范围,所以定义一个无符号int num1}for(i=length;i>0;i--){lcd_write_Data(0x30+num1/(pow(10,i-1))%10);
}
}
void LCD_ShowHexNum(unsigned char line,unsigned char column, unsigned int num,unsigned char length) //显示十六进制数
{unsigned char i;unsigned char SingleNum;LCD_setcursor(line,column);for(i=length;i>0;i--){SingleNum=num/(pow(16,i-1))%16;if(SingleNum<10){lcd_write_Data(0x30+SingleNum); }else{{lcd_write_Data(0x41+SingleNum-10); }}}}
void LCD_ShowBinNum(unsigned char line,unsigned char column, unsigned int num,unsigned char length) //显示二进制数
{unsigned char i;LCD_setcursor(line,column);for(i=length;i>0;i--){lcd_write_Data(0x30+num/(pow(2,i-1))%2);}}
main.c
#include<regx52.h>
#include"LCD1602.h"
#include"delay.h"
void main ()
{lcd_init();LCD_ShowChar(2,4,'A');
// LCD_ShowString(1,3,"hello");LCD_ShowNum(2,6,66,2);LCD_ShowsignNum(2,10,-77,2);
// LCD_ShowHexNum(1,8,0x55,2);LCD_ShowBinNum(1,1, 0x55,8);LCD_ShowString(1,16,"welcome to my home!");
while(1)
{lcd_write_command(0x1c); //流动字幕,移屏Delay(500);
}}
直流电机
1、基本知识讲解
2、LED呼吸灯
main.c
#include<regx52.h>sbit LED=P2^0;void Delay(unsigned int ms)
{while(ms--);}
void main ()
{while(1)
{
unsigned char i,t;
for(i=100;i>0;i--){for(t=0;t<20;t++){ LED=0;Delay(i);LED=1;Delay(100-i);}}
for(i=0;i<100;i++){for(t=0;t<20;t++){ LED=0;Delay(i);LED=1;Delay(100-i);}}}
}
3、直流电机调速
按K1键实现电机的调速,并在数码管上显示档数。
main.c
#include<regx52.h>
#include"key.h"
#include"nixie.h"
#include"Timer0.h"
sbit motor=P1^0;
unsigned char counter,compare,keynum,speed;void main ()
{Timer0_Init();while(1){keynum=key();if(keynum==1){speed++;speed%=4;if(speed==0){ compare=0;}if(speed==1){ compare=5;}if(speed==2){ compare=50;}if(speed==3){ compare=100;}}nixie (0,speed);}
}void Timer0_Routine() interrupt 1
{TL0 = 0x9C; TH0 = 0xFF;counter++;counter%=100;if(counter<compare){motor=1;}else{motor=0;}}
ps:对达林顿管还不是很清楚