当前位置: 首页 > article >正文

51单片机学习第六课---B站UP主江协科技

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~125
	 LCD_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);		//延时500us
  onewire_DQ=1;
  i = 32;			//延时70us
  while (--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);//延时10us
   onewire_DQ=Bit;	//如果bit=0,则DQ继续拉低50us,加上前面10us,刚好满足60us.如果bit=1,则DQ相当10us后总线释放,接着继续释放50us
   	i = 24;
	while (--i);//延时50us
   onewire_DQ=1;

}
unsigned char onewire_receivebit()
{
   unsigned char i;
   unsigned char Bit;
   onewire_DQ=0;
   	i = 2;
	while (--i);//主机拉低总线5us
   onewire_DQ=1;
   	i = 2;
	while (--i);//主机释放总线5us
	Bit=onewire_DQ;//DS18B20将会发送0或1,此时主机读取数据
   	i = 24;
	while (--i);//延时50us
	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;
}





DS18B20.C

#include<regx52.h>
#include"onewire.h"

#define  DS18B20_SKIP_ROM       0xCC  
#define  DS18B20_CONVERT_T       0x44	
#define  DS18B20_READ_SCRATCHPAD     0xBE


void DS18B20_convert()	   
{
   onewire_init() ;	 //初始化
   onewire_sendbyte(DS18B20_SKIP_ROM); //跳过ROM
   onewire_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方开始,所以读取的值要除以16
   return 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);   //记住写入后要延时5ms
	 Delay(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);		//延时500us
  onewire_DQ=1;
  i = 32;			//延时70us
  while (--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);//延时10us
   onewire_DQ=Bit;	//如果bit=0,则DQ继续拉低50us,加上前面10us,刚好满足60us.如果bit=1,则DQ相当10us后总线释放,接着继续释放50us
   	i = 24;
	while (--i);//延时50us
	  EA=1;

   onewire_DQ=1;

}
unsigned char onewire_receivebit()
{
   unsigned char i;
   unsigned char Bit;
   onewire_DQ=0;
    EA=0;
   	i = 2;
	while (--i);//主机拉低总线5us
   onewire_DQ=1;
   	i = 2;
	while (--i);//主机释放总线5us
	Bit=onewire_DQ;//DS18B20将会发送0或1,此时主机读取数据
   	i = 24;
	while (--i);//延时50us
	 EA=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:对达林顿管还不是很清楚


http://www.kler.cn/a/328432.html

相关文章:

  • Python | Leetcode Python题解之第564题数组嵌套
  • 基于普中51单片机开发板的电子门铃设计( proteus仿真+程序+设计报告+讲解视频)
  • ([LeetCode仓颉解题报告] 661. 图片平滑器
  • 在 CentOS 7 上安装 MinIO 的步骤
  • sharding-jdbc自定义分片算法,表对应关系存储在mysql中,缓存到redis或者本地
  • 【原创】如何备份和还原Ubuntu系统,非常详细!!
  • 【STM32单片机_(HAL库)】4-4【定时器TIM】脉冲计数配置步骤及实验
  • 从0开始深度学习(6)——Pytorch动态图机制(前向传播、反向传播)
  • 基础算法--双指针【概念+图解+题解+解释】
  • Arduino UNO R3自学笔记12 之 Arduino在调试过程中串口的使用
  • 【Router】T750路由功能之VLAN划分功能介绍及实现
  • 论文笔记:LAFF 文本到视频检索的新基准
  • 【算法】链表:21.合并两个有序链表(easy)
  • 什么是信息增益比
  • MFC工控项目实例之十九手动测试界面输出信号切换
  • Python办公自动化之Excel
  • [C++] 小游戏 征伐 SLG DNF 0.0.1 版本 zty出品
  • ARM base instruction -- ic
  • 滚雪球学MySQL[2.3讲]:MySQL数据过滤与排序详解:WHERE条件、ORDER BY排序与LIMIT分页查询
  • 物联网智能项目研究
  • 如何创建AWS云账号
  • 思维+贪心,CF 1210B - Marcin and Training Camp
  • SD-WebUI forge支持flux模型。算力互联forge镜像使用教程
  • 【鸿蒙学习】深入了解UIAbility组件
  • Java在用增强for循环遍历集合时删除元素,抛出java.util.ConcurrentModificationException异常
  • 【Verilog学习日常】—牛客网刷题—Verilog企业真题—VL69