蓝桥杯单片机组--第十二届省赛第一场

 

 

 

 


#include<reg52.h>
#include"iic.h"
#include"onewire.h"
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
void read_temp();
void display_temp();
sfr P4=0xc0;//矩阵按键P4^4替换P3^7,P4^2替换P3^6
sfr AUXR=0x80;//
sbit h3=P3^2;//矩阵键盘第三行
sbit h4=P3^3;//矩阵键盘第四行
sbit l1=P4^4;//矩阵键盘第1列
sbit l2=P4^2;//矩阵键盘第2列

sbit led1=P0^0;//定义led灯
sbit led2=P0^1;
sbit led3=P0^2;
sbit led4=P0^3;
uint dac=325;//dac输出界面下的dac变量
uint lsb,msb;//温度寄存器的低8位和高8位
uint temp=0;  //温度显示界面下温度变量
uint state0=0; //按键s4状态变量
uint state1=0;//dac输出模式状态
uint canshu=25;//温度参数界面初始值
uchar table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
uchar point_table[]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};
void keyscan();
//**************温度读取函数中的延时函数*******
//因为在读取温度时候延时也得不断扫描数码管
void Delayms(uint i)		//@12.000MHz
{
 //i=i*12;
 while(i--)
 {
  display_temp();	//在温度读取函数中的延时需要包括显示函数
 }
}
//********************************

//******普通延时函数**************
void delaysmg(uint i)
{
 while(i--);

}
//********************************

//*******译码器选通函数***********
void hc138(uint z)
{
 switch(z)
 {
  case 4:P2=P2&0x1f|0x80;break;
  case 5:P2=P2&0x1f|0xa0;break;
  case 6:P2=P2&0x1f|0xc0;break;
  case 7:P2=P2&0x1f|0xe0;break;
  case 0:P2=P2&0x1f|0x00;break;
 }
}
//********************************

//******初始化外设函数************
void initsystem()
{
 P0=0xff;
 hc138(4);
 hc138(0);	//关闭LED

 P0=0x00;
 hc138(5);	 //关闭蜂鸣器
 hc138(0);
}
//********************************

//********数码管选通函数***********
void selectsmg(uint we,uint du)
{
 P0=0x01<<we;  //P0送入位选值,然后打开138译码器选通位选
 hc138(6);	   //138选通数码管位选
 hc138(0);	   //然后关闭138译码器选通

 P0=du;		 //P0送入段码值,打开段选
 hc138(7);	 //138译码器选通段选
 delaysmg(500);	//延时一段时间,因为后面要把它给关闭,长一点的话亮一点
 P0=0xff; 	  //然后关闭数码管段码显示
 hc138(0);	 //然后关闭138译码器选通
}
//*********************************

void delaysmg1(uint z)
{
 while(z--);
}

//******D/A转换 写进去的数字 函数 iic通讯******
void write_dac(uint dat)
{
 IIC_Start();
 IIC_SendByte(0x90);  //pcf8591写操作地址
 //IIC_WaitAck();	  //可不用写等待应答
 IIC_SendByte(0x40);  //选择dac输出通道,第6位为1打开D/A
 //IIC_WaitAck();
 IIC_SendByte(dat);	  //选择要从单片机给pcf8591芯片的数字量
 //IIC_WaitAck();
 IIC_Ack(0);	      //iic总线产生非应答
 IIC_Stop();   	      //停止通讯
}
//**********************************

//*******读取环境温度函数-单总线通讯*******
void read_temp()
{
 init_ds18b20();	 //单片机告诉dsb20要用它了,初始化一下
 Write_DS18B20(0xcc);//跳过ROM指令,意思只用1个ds18b20,不用再选地址了
 Write_DS18B20(0x44);//开始温度转换
 //Delayms(2);	     //延时,延时长短决定读取温度间隔缝隙

 init_ds18b20();	 //再次初始化
 Write_DS18B20(0xcc); //跳过ROM指令
 Write_DS18B20(0xbe); //读取高速暂存器
 lsb=Read_DS18B20();  //读取低8位
 msb=Read_DS18B20();  //读取高8位

 //要求保留两位小数
 temp=(msb<<8)|lsb;//此时temp16位包括整数和小数部分
 temp=temp>>4;//此时整数部分右移4位,消除了小数部分,且乘了分辨率0.0625
 temp=temp*100;//整数部分扩大100倍,现在可看作是10进制数
 temp=temp+(lsb&0x0f)*6.25;//整数部分加上(小数部分乘以分辨率和100倍)
 //最后temp现在是一个4位数的整数

}
//************************************

//**********显示温度函数---4位数显示*************
void display_temp()
{

 selectsmg(0,0xc6);//显示c
 delaysmg(200);
 selectsmg(1,0xff);
 delaysmg(200);
 selectsmg(2,0xff);
 delaysmg(200);
 selectsmg(3,0xff);
 delaysmg(200);
 selectsmg(4,table[temp/1000]);//四位数温度处理
 delaysmg(200);
 selectsmg(5,point_table[temp/100%10]);
 delaysmg(200);
 selectsmg(6,table[temp/10%10]);
 delaysmg(200);
 selectsmg(7,table[temp%10]);
 delaysmg(200);
 
}
//****************************

//********参数设置函数--两位数显示*************
void display_set()
{
 selectsmg(0,0x8c);//显示p
 delaysmg1(200);
 selectsmg(1,0xff);
 delaysmg1(200);
 selectsmg(2,0xff);
 delaysmg1(200);
 selectsmg(3,0xff);
 delaysmg1(200);
 selectsmg(4,0xff);
 delaysmg1(200);
 selectsmg(5,0xff);
 delaysmg1(200);
 selectsmg(6,table[canshu/10]);
 delaysmg1(200);
 selectsmg(7,table[canshu%10]);
 delaysmg1(200);
}
//**********************

//********dac输出显示---3位数显示*********
void display_dac()
{
 selectsmg(0,0x08);
 delaysmg1(200);
 selectsmg(1,0xff);
 delaysmg(200);
 selectsmg(2,0xff);
 delaysmg(200);
 selectsmg(3,0xff);
 delaysmg(200);
 selectsmg(4,0xff);
 delaysmg(200);
 selectsmg(5,point_table[dac/100]);
 delaysmg(200);
 selectsmg(6,table[dac/10%10]);
 delaysmg(200);
 selectsmg(7,table[dac%10]);
 delaysmg(200);
}
//*********************************

//******按键处理函数**********************
void keyscan()
{
//2*2矩阵键盘:
//s4按键按下
 l1=l2=1;  //第一二列为1
 h3=1;h4=0;	//第三行为1,第4行为0
 if(l1==0)//如果s4按下
 {
  if(state0==0)//如果state0为0,即处于温度显示界面
  {
   state0=1;   //第一次按下变为1
  while(l1==0)
  {
  display_temp(); //防止按键按下时,打断温度显示函数
  }
  }
  //
  else if(state0==1)
  { 
   state0=2;   	//改变s4控制的状态量
   while(l1==0)
   {
	display_set(); //防止按键按下时,打断设置显示函数
   }
  }
 //
  else			  //state0为2时
  {
   state0=0;	  //改变s4控制的状态量
   while(l1==0)
   {
	display_dac(); //防止按键按下时,打断dac显示函数
   }
  }
 }
 //
 if(state0==1)	//在参数设置状态下,按下s8才有效
 {
  h3=h4=1;
  l1=1;l2=0;//按下s8
  if(h4==0)
  {  
   canshu--;  
  } 
  while(h4==0)
  {
  display_set();	//松手检测,没有的话会一次按下多次加
  }
 //
 h3=h4=1;
 l1=1;l2=0;//按下s9
 if(h3==0)
 {  
  canshu++;
 } 
 while(h3==0)
 {
  display_set();	//松手检测,没有的话会一次按下多次加
 }
 }
 //
 h3=h4=1;
 l1=0;l2=1;//s5按下
 if(h3==0)
 {
  if(state1==0)
  {
   state1=1;
  while(h3==0)
  {
   if(state0==0)
   {
   display_temp();
   }
   else if(state0==1)
   {
   display_set();
   }
   else if(state0==2)
   {
	display_dac();
   }
  }
  }
  //
  else if(state1==1)
  {
   state1=0;
   while(h3==0)
  {
   if(state0==0)
   {
   display_temp();
   }
   else if(state0==1)
   {
   display_set();
   }
   else if(state0==2)
   {
	display_dac();
   }
  }
  }
 }
}

//**************LED显示函数*****************
void led()//不同显示状态下led亮位置不同
{ 
 if(state0==0) //显示温度界面时
 {
  P0=0xff;	  //防止数码管和led冲突,没有的话led会受到数码管影响
  led2=0;  	    //led2亮  
  hc138(4);
  hc138(0);        
 }
 else if(state0==1)	//参数设置界面时
 { 
  P0=0xff;		   //防止数码管和led冲突,没有的话led会受到数码管影响 
  led3=0;
  hc138(4);
  hc138(0);    	           
 }
 else 				  //dac输出界面时
 {
  P0=0xff;			   //防止数码管和led冲突,没有的话led会受到数码管影响
  led4=0;
  hc138(4);
  hc138(0);  	           
 }
 if(state1==0)	//在dac输出格式模式1下
 {   
  led1=0;	   //led1亮
  hc138(4);
  hc138(0);  
 }
 else 		  //在dac输出格式模式2下
 { 
 led1=1;	 //led1灭
 hc138(4);
 hc138(0);  
 }
}
//*****************************

//因为读取出来的温度处理成为了四位数,也就是千位数,和正常比扩大了100倍
//所以在处理dac中,与温度相比的数值也应该扩大100倍
//******dac数模输出模式1***********
void dac_moshi1()
{
 if(temp<(canshu*100)) //环境温度小于设定参数
 {
   dac=0*100;	  //赋值给dac数码管显示函数变量
   write_dac(0);  //dac写入数字量0  ---对应模拟量0v
 }
 else if(temp>(canshu*100)) //环境温度大于设定参数
 {
 dac=5*100;		   //赋值给dac显示变量
 write_dac(5*51);  //dac写入255,因为pcf8591是8位精度的,所以模拟量5v对应数字量255
 } 
}
//****************************************************//
//**********dac数模转换模式2****************
void dac_moshi2()
{
 if(temp<=20*100) //环境温度小于20度时
 {
  dac=1*100;//dac显示界面为1
  write_dac(1.0*51);//写入pcf8591的数字量为51,对应模拟量DA引脚输出1v
 }
 else if(temp>=40*100) //环境温度大于40度时
 {
  dac=4*100;	  //dac显示界面为4
  write_dac(4.0*51); //写入pcf8591数字量为4*51
 }
 else				//环境温度大于20小于40时
 //注意由于我们读出的温度是扩大了100倍的,所以在一次函数中temp要除100
 dac=(3.0/20.0*((float)temp/100)-2)*100;	 //赋值给数码管显示dac输出相对应的电压
 write_dac((3.0/20.0*((float)temp/100)-2)*51);	//将数字量写入pcf8591,使其转化为相对应模拟量 
//注意被除数要写成浮点型,这样在除的时候才会有小数
}
//************************************
//************************************
void main()
{ 
 initsystem();		//初始化系统
 while(1)
 {
 keyscan();//循环扫描按键
 led(); 
 if(state0==0) //state0处于状态0,即数码管处于温度显示界面
 {  
  read_temp();	 //读取环境温度
  display_temp(); //显示环境温度
  }
  else if(state0==1) //state0处于1状态,即数码管处于参数设置界面
  {
   display_set();  //显示参数设置  
  }
  else			   //state0处于2状态,即数码管处于dac输出界面
  {  
   display_dac();  //显示dac输出
  }
   ///
  if(state1==0)	//state1处于0状态,即dac输出处于模式1
  {
   dac_moshi1();  //dac模式1设置
  }
  else if(state1==1) //state1处于1状态,即dac输出处于模式2
  {
   dac_moshi2();   //dac模式2设置
  }
  }
 } 

//led和数码管冲突--粗暴解决方法,直接在显示时将P0=0xff
//按键s4从温度显示界面转到参数设置界面非常不灵敏(按很多下才可以转换)解决方法:温度读取函数中延时写小一点。


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值