蓝桥杯C51试题学习:详解题目内容

因为C51只有一组数码管,但是我们需要显示的东西有很多,所以通过按键切换是我们必须要知道的

按键之间有嵌套,切换,计数,对于按键的使用我们是必须知道的

1. HC573锁存器的选择

我们在之前的基础上对其进行了优化,这样就不会出现冲突的问题

因为在使用前,我们直接把所有的给关闭了,当使用的时候先把P0给起来,在引到每个锁存器

/************锁存器选择******************
功能:打通功能需要的锁存器
参数:channel(选择锁存器) dat(一般为oxff 打开通道,但是我们可以去掉这个参数)
***************************************/
void SelectHC573(unsigned channel,unsigned char dat)
{
    P0 = dat;  //带设置参数数据
	switch(channel)
	{
		case 4:
			P2 = (P2 & 0x1f) | 0x80;		//Y4,选择LED控制
		break;
		case 5:
			P2 = (P2 & 0x1f) | 0xa0;		//Y5,选择蜂鸣器和继电器控制
		break;
		case 6:
			P2 = (P2 & 0x1f) | 0xc0;		//Y6,选择数码管位置
		break;
		case 7:
			P2 = (P2 & 0x1f) | 0xe0;		//Y7,选择数码管段码
		break;
		case 0:
			P2 = (P2 & 0x1f) | 0x00;		//在完成后关闭所有锁存器
		break;
	}
     P2 = (P2 & 0x1f) | 0x00;              // 修改完成,关闭全部锁存器    
}

2. 数码管位置选择与数码管显示

<1> 数码管选择是需要延时函数的。我们是利用余辉效果来进行显示的,所以在数码管显示之后我们需要进行延时,所以我们直接把延时函数放到单个数码管显示之后,这样子显示就变得简单了

<2>延时延时可以选择 char / int 两种类型,但是需要注意时间,如果时间太长会导致抖动,如果时间过短又会导致数码管变暗。

/****************数码管延时函数**************
功能:对数码管进行延时
参数:t--
*******************************************/

void DelaySMG(unsigned int t)
{
   while(t--);
}

/*************数码管显示函数***************
功能: 控制每个数码管的亮暗,在之前的基础上我们使用了延时函数,这样在主体显示就不用添加延时函数了
参数: value (内容) pos(位置)
****************************************/
void DisplaySMG_Bit(unsigned char value, unsigned char pos)
{
     SelectHC573(6,0x01<<pos);  //数码管段位
//P0 = 0X01 << pos
     SelectHC573(7,value);      //数码管内容
//P0 = value
     DelaySMG(500);             //延时
     SelectHC573(6,0x01<<pos);  //数码管段位
     SelectHC573(7,0xff);      //数码管消隐
}


//如果前面的锁存器没有设置P0的参数,则可以使用下面的老办法
void DisplaySMG_Bit(unsigned char value, unsigned char pos)
{
	P0 = 0xff;						//消隐
	SelectHC573(6);
	P0 = 0x01 << pos;			    //位置	
	SelectHC573(7);
	P0 = value;						//内容
}

/************控制全数码管*************
功能:在显示前后进行使用,进行数码管的初始化
参数 value(一般为0xff)
************************************/
void DisPlaySMG_All(unsigned char value)
{
  SelectHC573(6, 0xff);  //数码管段位
  SelectHC573(7,value);  //数码管内容   
}

既然需要控制数码管,我们就需要不同的标志位来进行记录

/***********数码管显示内容选择***********
功能:通过改变flag的参数来选择不同的锁存器
参数:无
***************************************/
void DisplaySMG_Select()
{
   switch(SMG_flag)
   {
		 case 1:
		 (显示时间的函数 DisplayTime);
         break;
		 
		 case 2:
	     (显示温度的函数 DisplayTemp);
		 break;
....

   }
}

3. 独立按键进行切换

只进行切换当前模式,不能改变当前的状态,所以我们需要在更换模式时,仍然保持数码管的显示,而进行标志位值的改变,当模式多时,我们就需要使用矩阵按键(参考上一篇文章的扫描)

/*****************按键切换**********
功能:通过按键切换模式,也就是我们之前写过的
参数:无
**********************************/
void Key_Scan()
{
	if(S4 == 0)
		{
			Delay(200);                //消抖
			if(S4 == 0)
			{
				if(stat_flag == 1)     //初始默认的标志位为1——系统时间记录
				{
					stat_flag =2;      //转换模式类型
				}
				while(S4 == 0)
				{
					Display_SMGselect(); //按键按下后仍然能显示当前的数码管,这步是需要的
					Delay(500);
				}
			}
		}
 //模仿上面的操作,进行数码管的操作
   else if(S5 == 0)
		{
			Delay(200);
			if(S5 == 0)
			{
				if(stat_flag == 2)
				{
					stat_flag =1;
				}
				while(S5 == 0)
				{
				  Display_SMGselect();
					Delay(500);
				}
			}
		}
}

而进行切换的过程中,我们当前状态需要一直进行的,我们就在while循环中执行

4. 系统初始化函数

/*==================系统初始化函数======================
功能:关闭没用的器件,打开需要使用的。进行锁存器的选择
参数:无
=======================================================*/
void InitSystem()
{
	SelectHC573(5);   //关闭蜂鸣器,继电器
	P0 = 0x00;
	SelectHC573(4);   //打开灯光
	P0 = 0xff;
	SelectHC573(0);   //完成后关闭
}

5. 系统时间函数

我们通过定时器来进行时间计数,通过测试,按键切换不会改变系统运行时间的值,我们不需要记载,他会一直记录着

/*================定时器初始化函数====================
功能: 初始化定时器
参数: 无
=======================================================*/
void InitTimer0()
{
	TMOD = 0x21;			       // 定时器1/2一起赋值
	TH0 = (65535 - 50000) / 256;   // 0,05s
	TL0 = (65535 - 50000) % 256;

	ET0 = 1;					//使能定时器T0
	EA = 1;						//使能总中断
	TR0 = 1;					//启动定时器T0
}


/*===============定时器服务函数===================
功能:利用定时器进行计数
参数:无
=======================================================*/
void ServiceTimer0() interrupt 1
{
	TH0 = (65535 - 50000) / 256; //0.05s
	TL0 = (65535 - 50000) % 256;
	
	count++;
	if(count == 20)
	{
		count = 0;
		t_s++;
	}
	if(t_s == 60)
	{
		t_s = 0;
		t_m++;
		if(t_m == 60)
		{
			t_m = 0;
			t_h++;
		}
	}
}

6.系统时间函数显示

中断初始化的配置:

 <1> 配置工作模式,即对TMOD寄存器编程。
 <2> 计算技术初值,即对THx和TLx寄存器进行赋值。
 <3> 使能定时/计数器中断,即ET0或ET1置1。
 <4> 打开总中断,即EA =1。
 <5> 启动定时器,即TR0或TR1置1。

中断服务函数:

<1> 如果不是自动重装模式,需要对THx和TLx重新赋值。
<2> 进行间隔定时到达的逻辑处理(越少越好)
 

void DisplayTime()
{    
//注意的是,如果使用新版的数码管显示函数,就不再需要再延时了
    DisPlay_All(0xff);      //消隐
	DisplaySMG_Bit(SMG_NoDot[t_s%10],7);		
	DelaySMG(500);
	DisplaySMG_Bit(SMG_NoDot[t_s/10],6);	
	DelaySMG(500);
	DisplaySMG_Bit(SMG_NoDot[16],5);				
	DelaySMG(500);
	
	DisplaySMG_Bit(SMG_NoDot[t_m%10],4);		
	DelaySMG(500);
	DisplaySMG_Bit(SMG_NoDot[t_m/10],3);		
	DelaySMG(500);
	DisplaySMG_Bit(SMG_NoDot[16],2);				
	DelaySMG(500);
	
	DisplaySMG_Bit(SMG_NoDot[t_h%10],1);		
	DelaySMG(500);
	DisplaySMG_Bit(SMG_NoDot[t_h/10],0);		
	DelaySMG(500);
	DisPlay_All(0xff);     //结尾再来一次
}

同时,在老师的视频内容中有说到,在延时的时候需要继续显示一下数码管的内容

void DisplayTmp(unsigned int t)
{
    while(t--)
   {
     DisplayTemp();
    }
]

实际测试之后,我们没有在温度显示函数里面再进行延时,也是可以正常显示的

7- 温度读取函数

/*********温度读取函数************
功能:进行温度读取(具体在上一篇文章讲过,之后会把内容移动过来)
参数:无
******************************/
void Read_DS18B20_temp()
{
	unsigned char LSB,MSB;
	
	init_ds18b20();
	Write_DS18B20(0XCC);
	Write_DS18B20(0X44);
	
	//Delay_temp(1000);
	
	init_ds18b20();
	Write_DS18B20(0XCC);
	Write_DS18B20(0Xbe);
	
	LSB = Read_DS18B20();
	MSB = Read_DS18B20();
	
	temp = 0x000;
	temp = MSB;
	temp <<= 8;
	temp = temp | LSB;
	
	if((temp & 0xf800) == 0x0000)
	{
		temp>>=4;
		
		temp = temp *10;
		temp = temp +(LSB&0x0f)*0.625;
	}
	
}

需要注意的是,在数码管显示温度之前,我们都要在显示函数前进行温度的读取,也就是把它写在 DisplayTemp 前面

温度显示函数

void DisplayTemp()
{
    Read_DS18B20_temp();    
    DisPlay_All(0xff);    
	ShowSMG_bit(7,SMGnodot_CA[temp%10]);
	DelaySMG(400);
	ShowSMG_bit(6,SMGdot_CA[(temp%100)/10]);
	DelaySMG(400);
	ShowSMG_bit(5,SMGnodot_CA[temp/100]);
	DelaySMG(400);
	
	ShowSMG_bit(4,0XFF);
	DelaySMG(400);
	ShowSMG_bit(3,0XFF);
	DelaySMG(400);
	ShowSMG_bit(2,0XFF);
	DelaySMG(400);
	ShowSMG_bit(1,0XFF);
	DelaySMG(400);
	ShowSMG_bit(0,0XFF);
	DelaySMG(400);
    DisPlay_All(0xff);   
}  

DS18B20 温度的底层代码

onewire.c文件

#include "onewire.h"
#include "reg52.h"

sbit DQ = P1^4;  


void Delay_OneWire(unsigned int t)  
{
	while(t--);
}


void Write_DS18B20(unsigned char dat)
{
	char i;
	for(i=0;i<8;i++)
	{
		DQ = 0;
		DQ = dat&0x01;
		Delay_OneWire(50);
		DQ = 1;
		dat >>= 1;
	}
	Delay_OneWire(50
	);
}


unsigned char Read_DS18B20(void)
{
	unsigned char i;
	unsigned char dat;
  
	for(i=0;i<8;i++)
	{
		DQ = 0;
		dat >>= 1;
		DQ = 1;
		if(DQ)
		{
			dat |= 0x80;
		}	    
		Delay_OneWire(50);
	}
	return dat;
}


bit init_ds18b20(void)
{
  	bit initflag = 0;
  	
  	DQ = 1;
  	Delay_OneWire(120);
  	DQ = 0;
  	Delay_OneWire(800);
  	DQ = 1;
  	Delay_OneWire(100); 
    initflag = DQ;     
  	Delay_OneWire(50);
  
  	return initflag;
}

onewire.h文件

我们之后也可以把前面写的函数给封装到文件里

#ifndef __ONEWIRE_H
#define __ONEWIRE_H


unsigned char rd_temperature(void);  
bit init_ds18b20(void); 
void Write_DS18B20(unsigned char dat);
unsigned char Read_DS18B20(void);
	
#endif

8-实时时钟DS1302

DS1302有关日历和时钟的寄存器有12个,我们最常用的有7个。

 

 什么是BCD码?
   就是用十六进制来表示十进制。什么意思?怎么理解?
   例如,十六进制数0x13的值为整数19,但BCD码表示的是整数13

 DS1302将地址和读写控制放到一个字节里面,形成一个控制字,格式如下:

我们往DS1304里面写入一个8为的数据(指令),把它分为上面8个

 通过上面的控制字格式,大家就可以明白为什么DS1302读寄存器和写寄存器的地址是不一样的了,因为这个地址包含了读写控制位。为了方便程序设计,我们把

读寄存器地址写寄存器地址日历时钟寄存器方面用三个数组定义。

BCD码,用16进制来表示10进制  

0x30(秒) 0x50(50分) 如上图所示,依次类推

底层驱动代码实现可参考如下:

DS1302.c

unsigned char DS1302_ReadByte(unsigned char addr)
{
        unsigned char n,dat,tmp;
        RST = 0;
        _nop_();
        SCLK = 0;
        _nop_();
        RST = 1;
        _nop_();

        for(n=0; n<8; n++)         //发送要读出数据的内存地址
        {
                DSIO = addr & 0x01;
                addr >>= 1;
                SCLK = 1;
                _nop_();
                SCLK = 0;
                _nop_();
        }
        
        for(n=0; n<8; n++)         //读出该地址内存的数据
        {
                tmp = DSIO;
                dat = (dat>>1) | (tmp<<7);
                SCLK = 1;
                _nop_();
                SCLK = 0;
                _nop_();
        }

        RST = 0;
        _nop_();
        SCLK = 1;
        _nop_();
        DSIO = 0;
        _nop_();
        DSIO = 1;
        _nop_();
        return dat;        
}

void DS1302_WriteByte(unsigned char addr, unsigned char dat)
{
        unsigned char n;
        RST = 0;
        _nop_();
        SCLK = 0;
        _nop_();
        RST = 1;
        _nop_();        

        for (n=0; n<8; n++)         //发送要写入数据的内存地址
        {
                DSIO = addr & 0x01;
                addr >>= 1;
                SCLK = 1;
                _nop_();
                SCLK = 0;
                _nop_();
        }
        for (n=0; n<8; n++)         //将指定内容写入该地址的内存
        {
                DSIO = dat & 0x01;
                dat >>= 1;
                SCLK = 1;
                _nop_();
                SCLK = 0;
                _nop_();
        }                 
        RST = 0;
        _nop_();
}

有了上面两个SPI底层代码,我们读出DS1302的数据就变得非常简单了

我们可以参考下面的源码:

#include "reg52.h"  
#include "intrins.h"

sbit HC138_A = P2^5;        
sbit HC138_B = P2^6;        
sbit HC138_C = P2^7;        

sbit SCLK = P1^7; 
sbit RST =  P1^3; 
sbit DSIO = P2^3;
unsigned char code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
unsigned char code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
unsigned char TIME[7] = {0x30, 0x50, 0x23, 0x17, 0x02, 0x06, 0x18};

unsigned char code SMG_NoDot[18] = 
    {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
     0x80,0x90,0x88,0x80,0xc6,0xc0,0x86,0x8e,
     0xbf,0x7f};

void DelaySMG(unsigned int time)
{
        while(time--);
}

void Init74HC138(unsigned char n)
{
        switch(n)
        {
                case 4:
                        HC138_A = 0;
                        HC138_B = 0;
                        HC138_C = 1;
                        break;
                case 5:
                        HC138_A = 1;
                        HC138_B = 0;
                        HC138_C = 1;
                        break;
                case 6:
                        HC138_A = 0;
                        HC138_B = 1;
                        HC138_C = 1;
                        break;
                case 7:
                        HC138_A = 1;
                        HC138_B = 1;
                        HC138_C = 1;
                        break;
                case 8:
                        HC138_A = 0;
                        HC138_B = 0;
                        HC138_C = 0;
                        break;
        }
}

void DispaySMG_Bit(unsigned char value, unsigned char pos)
{
        Init74HC138(6);
        P0 = (0x01 << pos);
        Init74HC138(7);
        P0 = value;
}

void DS1302_WriteByte(unsigned char addr, unsigned char dat)
{
        unsigned char n;
        RST = 0;
        _nop_();
        SCLK = 0;
        _nop_();
        RST = 1;
        _nop_();        

        for (n=0; n<8; n++)
        {
                DSIO = addr & 0x01;
                addr >>= 1;
                SCLK = 1;
                _nop_();
                SCLK = 0;
                _nop_();
        }
        for (n=0; n<8; n++)
        {
                DSIO = dat & 0x01;
                dat >>= 1;
                SCLK = 1;
                _nop_();
                SCLK = 0;
                _nop_();
        }                 
        RST = 0;
        _nop_();
}

unsigned char DS1302_ReadByte(unsigned char addr)
{
        unsigned char n,dat,tmp;
        RST = 0;
        _nop_();
        SCLK = 0;
        _nop_();
        RST = 1;
        _nop_();

        for(n=0; n<8; n++)
        {
                DSIO = addr & 0x01;
                addr >>= 1;
                SCLK = 1;
                _nop_();
                SCLK = 0;
                _nop_();
        }
        
        for(n=0; n<8; n++)
        {
                tmp = DSIO;
                dat = (dat>>1) | (tmp<<7);
                SCLK = 1;
                _nop_();
                SCLK = 0;
                _nop_();
        }

        RST = 0;
        _nop_();
        SCLK = 1;
        _nop_();
        DSIO = 0;
        _nop_();
        DSIO = 1;
        _nop_();
        return dat;        
}


//DS1302的初始化
void DS1302_Config()
{
        unsigned char n;
        DS1302_WriteByte(0x8E,0x00); //写入保护
        for (n=0; n<7; n++) 
        {
               //写入时分秒年月日
                DS1302_WriteByte(WRITE_RTC_ADDR[n],TIME[n]);        
        }
        DS1302_WriteByte(0x8E,0x80); 
}

//DS1302读取当前时间
void DS1302_ReadTime()
{
        unsigned char n;
        for (n=0; n<7; n++) 
        {     
               //读取的内存地址,读7个时分秒年月日
                TIME[n] = DS1302_ReadByte(READ_RTC_ADDR[n]);
        }                
}

//数码管显示年月日
void XMF_ShowRealTime()
{
 //小时
        DispaySMG_Bit(SMG_NoDot[TIME[2]/16],0);        
        DelaySMG(500);
        DispaySMG_Bit(0xff,0);                        
        DispaySMG_Bit(SMG_NoDot[TIME[2]&0x0f],1);
        DelaySMG(500);
        DispaySMG_Bit(0xff,1);
        DispaySMG_Bit(SMG_NoDot[16],2);
        DelaySMG(500);
        DispaySMG_Bit(0xff,2);

//分钟
        DispaySMG_Bit(SMG_NoDot[TIME[1]/16],3);
        DelaySMG(500);
        DispaySMG_Bit(0xff,3);
        DispaySMG_Bit(SMG_NoDot[TIME[1]&0x0f],4);
        DelaySMG(500);
        DispaySMG_Bit(0xff,4);
        DispaySMG_Bit(SMG_NoDot[16],5);
        DelaySMG(500);
        DispaySMG_Bit(0xff,5);

//秒
        DispaySMG_Bit(SMG_NoDot[TIME[0]/16],6);
        DelaySMG(500);

        DispaySMG_Bit(0xff,6); //消隐
        DispaySMG_Bit(SMG_NoDot[TIME[0]&0x0f],7); //&0x0f可以改为 %16
        DelaySMG(500);
//关闭全部数码管,不关闭会导致亮度可能不同
        DispaySMG_Bit(0xff,7);
}


void main()
{
        DS1302_Config(); //DS1302初始化
        while(1)
        { 
          // 显示前需要先读取1302的数据
                DS1302_ReadTime();
                XMF_ShowRealTime();
        }
}

9- 串口中断

TH1TL1:设置波特率参数。
TMOD:设置定时器1的工作模式。
SBUF:串行通信数据的发送和接收缓冲器。
SCON:串行接口控制寄存器。

TR1: 定时器

ES: 串口中断

EA: 总中断

/*=================串口初始化函数========================
功能:将串口设置为模式1,波特率9600,允许接收
参数
=======================================================*/
void InitUart()
{
	TMOD = 0x21;			//T0与T1一起赋值
	TH1 = 0xfd;				//设置9600波特率
	TL1 = 0xfd;
	TR1 = 1;					// 启动定时器1
	
	SCON = 0x50;			//8位UART
	AUXR = 0x00;			//辅助寄存器
	
	ES = 1;						//使能串口中断
	EA = 1;						//使能总中断
}
/*=================串口中断服务函数====================
功能:接收上位机所发送的字符
=======================================================*/
void ServiceUart() interrupt 4
{
	if(RI == 1)
	{
		command = SBUF;		//½«½ÓÊÕµ½µÄÊý¾Ý±£´æµ½command±äÁ¿
		RI = 0;						//½«½ÓÊÕÍê³É±êÖ¾RIÇå0
	}
}
/*=================串口服务函数====================
功能:接收上位机发送的数据并保持在command里
参数:无
=======================================================*/
void SendByte(unsigned char dat)
{
	SBUF = dat;
	while(TI == 0);
	TI = 0;
}
 
void SendString(unsigned char *str)
{
	while(*str != '\0')
	{
		SendByte(*str++);
	}
}
 
/*===============串口信息接收执行函数==================
功能:接收上位机消息,进行灯光控制
参数:无
=======================================================*/
void ExecuteCommand()
{
	if(command != 0x00)							//接收的消息不为空
	{
		switch(command & 0xf0)				    //将命令类型取出
		{
			case 0xa0:									//远程控制灯光
				SelectHC573(4);
				stat_led = (stat_led | 0x0f) & (~command | 0xf0);
				P0 = stat_led;
				SelectHC573(0);
				command = 0x00;
			break;
			
			case 0xb0:									//读取系统运行时间
				SendByte((t_h / 10 << 4) | (t_h % 10));
				SendByte((t_m / 10 << 4) | (t_m % 10));
				SendByte((t_s / 10 << 4) | (t_s % 10));
				command = 0x00;
			break;
		}
	}
}

10-AD-DA

(参考江科大自化协)

AD: 模-数转化~ DA:数-模转化

现象:根据可调电阻,可以改变LCD(在我们使用的板子中改变的为数码管的数字),电压的大小。

· AD转换通常有多个输入通道,多个开关连接至AD转换

· AD/DA与单片机数据传输可使用并口,也可以使用串口

· 可将AD/DA模块集成在单片机内,这样直接写入就可以AD/DA转换,单片机的IO口可直接复写为AD/DA的通道。

试题: 配置要求

内部振荡器频率设置为 12mhz

键盘工作模式跳线J15配置为BTN独立按键模式

扩展方式跳线J13配置为IO模式

· 显示功能

(1)频率显示界面

(2)电压显示界面

· 按键功能

(1) S4:定义为显示界面切换

(2) S5:定义为DAC输出模式切换

(3) S6:LED功能控制按键

(4) S7:数码管功能控制

/****************ÒýÈëÍ·ÎļþÓ붨Òå±äÁ¿************
±à³Ìģʽ:I/Oģʽ
************************************************/
#include "reg52.h"
#include "iic.h"

sbit S7 = P3^0;
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;

//-----¹²ÑôÊýÂë¹ÜµÄ¶ÎÂë±àÂë±í£¨ÎÞСÊýµã£©----
unsigned char code SMG_DM_NoDot[19]={0xc0,0xf9,
	  0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
    0x88,0x80,0xc6,0xc0,0x86,0x8e,0xbf,0x7f,0xc1};

// Êý×Ö0. ~ 9.
unsigned char code SMG_DM_dot[10]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};

unsigned int count_f = 0;     //NE555ÐźÅƵÂʼÆÊý
unsigned char count_t = 0;    //¶¨Ê±Æ÷ÖжϼÆÊý
unsigned int dat_f = 0;       //²âÁ¿ÆµÂÊÊýÖµ
unsigned int dat_v = 0;       //²âÁ¿µçѹÊýÖµ
unsigned char dat_rb2 = 0;    //µçѹ²ÉÑùÊýÖµ

bit F_DIS=0;           // ƵÂʺ͵çѹÏÔʾÇл»±êÖ¾
bit F_VOL=0;           // DACµçѹÊä³öÇл»
bit F_SMG=0;           // ÊýÂë¹ÜÏÔʾÇл»
bit F_LED=0;           // LEDÇл»
bit F_DAC=0;           // ADC²ÉÑùºÍDACÊä³öÇл»

/****************ÑÓʱº¯ÊýºÍËø´æÆ÷Ñ¡Ôñº¯Êý************
************************************************/
// ÊýÂë¹ÜÑÓʱº¯Êý
void DelaySMG(unsigned int t)
{
	while(t--);
}

// Ëø´æÆ÷Ñ¡Ôñº¯Êý
void SelectHC573(unsigned char channel)
{
	switch(channel)
	{
		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 DisPlaySMG_All(unsigned char value)
{
  SelectHC573(6);  //?????
	P0 = 0xff;
  SelectHC573(7); 
	P0 = value;
}

// ÊýÂë¹ÜÏÔʾº¯Êý
void DisplaySMG_Bit(unsigned char pos,unsigned char value)
{
	P0 = 0xff;            // ÏûÒþ
	SelectHC573(6);       // λÖÃ
	P0 = 0x01 << pos ;
	SelectHC573(7);       // Êý×Ö
	P0 = value;
	
}



/********ADC²ÉÑùº¯ÊýºÍDACÊä³öº¯Êý***********
********************************************/

//ADC²ÉÑùº¯Êý
void ReadData_ADC()
{
	IIC_Start();
	IIC_SendByte(0x90);  //É豸дÈëµØÖ·
	IIC_WaitAck();
	IIC_SendByte(0x43);  //ADCÉèÖà £¡£¡£¡£¡£¡£¡
  IIC_WaitAck();
	IIC_Stop();
	
	IIC_Start();
	IIC_SendByte(0x91);  //É豸дÈëµØÖ·
	IIC_WaitAck();
  dat_rb2 = IIC_RecByte();
	IIC_Ack(0);
	IIC_Stop();
  
  dat_v = dat_rb2*2;    // ¼ÆËãʵ¼Êµçѹ	
}

// DACÊä³öÆ÷º¯Êý
void SetData_DAC(unsigned char dat)
{
	IIC_Start();
	IIC_SendByte(0x90);  //É豸дÈëµØÖ·
	IIC_WaitAck();
	IIC_SendByte(0x40);  //ADCÉèÖà £¡£¡£¡£¡£¡£¡
  IIC_WaitAck();
	IIC_SendByte(dat); 
	IIC_WaitAck();
	IIC_Stop();
}


/********¶¨Ê±Æ÷³õʼ»¯º¯Êý*********/

void InitTimerX()
{
	//¶¨Ê±Æ÷0¼ÆÊý£¬Ä£Ê½2£»¶¨Ê±Æ÷1¶¨Ê±,ģʽ1  TMOD
	
	TH0 = 0XFF;
	TL0 = 0XFF;  
	
	TH1 =(65535 - 50000) / 256;   //¶¨Ê±0.05S
	TL1 =(65535 - 50000) % 256;
	
	TMOD = 0X16;
	
	ET0 = 1;   //ʹÄܶ¨Ê±Æ÷T0
	ET1 = 1;   //ʹÄܶ¨Ê±Æ÷T1
	EA = 1;    //ʹÄÜÖжÏ
	
	TR0 = 1;   //Æô¶¯¶¨Ê±Æ÷0
	TR1 = 1;   //Æô¶¯¶¨Ê±Æ÷1

}

// ¶¨Ê±Æ÷ÖжϷþÎñº¯Êý
void Service_Timer0() interrupt 1
{
	count_f++;    //ÀÛ¼ÆNE555Ä£¿éÊä³öÐźŸöÊý
}

void Service_Timer1() interrupt 3
{
	count_t++;
	if(count_f % 5 == 0)   //ÿ0,5sË¢ÐÂÒ»´ÎADCµçѹÊý¾Ý
	{
		F_DAC = ~F_DAC;
	}
	if(count_t == 20)       //ÿ1sË¢ÐÂÒ»´ÎƵÂÊÊý¾Ý
	{
		dat_f = count_f;
		count_f = 0;
		count_t = 0;
	}
}
	
/*********µçѹÊý¾ÝÓëƵÂÊÊý¾ÝÏÔʾº¯Êý*********/
// µçѹÏÔʾº¯Êý
void DisplaySMG_V()
{
	DisPlaySMG_All(0xff);
	
	DisplaySMG_Bit(0,SMG_DM_NoDot[18]);
	DelaySMG(500);

	DisplaySMG_Bit(5,SMG_DM_dot[(dat_v / 100) % 10]);
	DelaySMG(500);
	DisplaySMG_Bit(6,SMG_DM_NoDot[(dat_v / 10) % 10]);
	DelaySMG(500);
	DisplaySMG_Bit(7,SMG_DM_NoDot[dat_v % 10]);
	DelaySMG(500);
	
	DisPlaySMG_All(0xff);
	
}

// ƵÂÊÏÔʾº¯Êý
void DisplaySMG_F()
{
	DisPlaySMG_All(0xff);
	DisplaySMG_Bit(0,SMG_DM_NoDot[15]);
	
	if(dat_f > 9999)
	DisplaySMG_Bit(3,SMG_DM_NoDot[dat_f / 10000]);
	
	if(dat_f > 999)
	DisplaySMG_Bit(4,SMG_DM_NoDot[(dat_f / 1000) % 10]);
	
	if(dat_f > 99)
	DisplaySMG_Bit(5,SMG_DM_NoDot[(dat_f / 100) % 10]);
	
	if(dat_f > 9)
	DisplaySMG_Bit(6,SMG_DM_NoDot[(dat_f / 10) % 10]);
	
	DisplaySMG_Bit(7,SMG_DM_NoDot[dat_f % 10]);
	
	DisPlaySMG_All(0xff);
}

/*********µçѹÓëƵÂʵÄ״ָ̬ʾ*********/
// ÔÝʱֹͣ£¬ÏȲ»Ê¹Óã¬ÏÈֻʹÓÃÊýÂë¹Ü


//ÊýÂë¹ÜÏÔʾº¯Êý
void Display()
{
	if(F_SMG == 0)
	{
		if(F_DIS == 0)
			DisplaySMG_V();
		else 
			DisplaySMG_F();
	}
	else //ÊýÂë¹Ü¹Ø±Õ
	{
		SelectHC573(6); 
		P0 = 0xff;
		SelectHC573(7); 
		P0 = 0xff;
	}
	
	SelectHC573(0);
}


// °´¼üɨÃ躯Êý
void Scan_Keys()
{
	if(S4 == 0)
	{
		DelaySMG(100);     //֮ǰÎÒÃÇҲ˵¹ý£¬°´¼üÇл»ÊÇÒ»¸ö£¬µ«ÊÇ·ÖÌõ¼þµÄÏÔʾҪµ¥¶Àд³öÀ´£¬²»¹ÜÄÄÖÖÇé¿ö¶¼ÒªÒ»Ö±ÏÔʾ
		F_DIS = ~F_DIS;
		while(S4 == 0)
			Display();
	}
	
	if(S5 == 0)
	{
		DelaySMG(100);     //֮ǰÎÒÃÇҲ˵¹ý£¬°´¼üÇл»ÊÇÒ»¸ö£¬µ«ÊÇ·ÖÌõ¼þµÄÏÔʾҪµ¥¶Àд³öÀ´£¬²»¹ÜÄÄÖÖÇé¿ö¶¼ÒªÒ»Ö±ÏÔʾ
		F_VOL = ~F_VOL;
		while(S5 == 0)
			Display();
	}
	
		if(S7 == 0)
	{
		DelaySMG(100);     //֮ǰÎÒÃÇҲ˵¹ý£¬°´¼üÇл»ÊÇÒ»¸ö£¬µ«ÊÇ·ÖÌõ¼þµÄÏÔʾҪµ¥¶Àд³öÀ´£¬²»¹ÜÄÄÖÖÇé¿ö¶¼ÒªÒ»Ö±ÏÔʾ
		F_SMG = ~F_SMG;
		while(S7 == 0)
			Display();
	}
}

// ³õʼ»¯º¯Êý

void InitSystem()
{
	SelectHC573(5);
	P0 = 0x00;
	SelectHC573(4);
	P0 = 0xff;
	SelectHC573(0);
  InitTimerX();
}

void main()
{
	InitSystem();
	while(1)
	{
		Scan_Keys();
		if(F_DAC == 0)
		{
			ReadData_ADC();
		}
		else
		{
			if(F_VOL == 0)
			{
				SetData_DAC(102);    //Êä³ö2vµçѹ
			}
			else
			{
				SetData_DAC(dat_rb2);
			}
		}
		Display();
	}
}

NE555定时器概述

· 在NE555内部。有3个5k电阻分压

· 基本原理:

低电平触发端TRIG和高电平THR:

两者电压均小于各自的参考电压,U0 = 1,放电管截至

两者电压均大于于各自的参考电压,U0 = 0,放电管导通

` NE555是一个纯硬件设计。其功能已经确定了,在这个板子上,555相当于一个信号发生电路。通过Rb3可改变输出信号频率

#include "reg52.h"
#include "absscc.h"

unsigned int count_f = 0;
unsigned int dat_f = 0;
unsigned char count_t = 0;

void Init_Timer()
{
	//¶¨Ê±Æ÷0ÓÃ×÷¼ÆÊý£¬8λÖØ×°·½Ê½
	TH0 = 0xff;
	TL0 = 0xff;
	
	//¶¨Ê±Æ÷1ÓÃ×÷¶¨Ê±£¬¶¨Ê±Îª0.05s
	TH1 = (65535 - 50000) / 256;
	TL1 = (65535 - 50000) % 256;
	
	TMOD = 0x16;
	
	ET0 = 1;
	ET1 = 1;
	EA = 1;
	
	TR0 = 1;
	TR1 = 1;
	
}

void Service_T0() interrupt 1
{
	count_f++;
}

void Service_T1() interrupt 3
{
		TH1 = (65535 - 50000) / 256;
	  TL1 = (65535 - 50000) % 256;
	  
	  count_t++;
	  if(count_t == 20)
		{
			dat_f = count_f;
			count_f = 0;
			count_t = 0;
		}
	
}

在上面的试题中我们有数码管显示函数,在这里我们就只体现了555的计数功能

物联沃分享整理
物联沃-IOTWORD物联网 » 蓝桥杯C51试题学习:详解题目内容

发表评论