模拟风扇控制

蓝桥杯第七届--模拟风扇控制(代码、思路)-LMLPHP
蓝桥杯第七届--模拟风扇控制(代码、思路)-LMLPHP
蓝桥杯第七届--模拟风扇控制(代码、思路)-LMLPHP
蓝桥杯第七届--模拟风扇控制(代码、思路)-LMLPHP


解题思路

1.首先写出DS18B20的代码,显示出温度。具体请看蓝桥杯官方范例DS18B20的范程。
2.在此上面加上键扫描,read_key
3.在keycan进行对LED灯的相关操作,
4.可以另外写一个函数装填数码管的值(在这里直接在display中装载)
此次数码管显示的方法是官方范例提供,我觉得十分巧妙,应用性广,如果有更好的欢迎大家指正!!!



main.c

#include "stc15f2k60s2.h"
#include "onewire.h"
#define uchar unsigned char
#define uint unsigned int	

code unsigned char tab[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf,0xc6};
uchar dspbuf[8] = {10, 10, 10, 10, 10, 10, 10, 10};
uchar temper_flag = 0;
uchar temperature;
uchar flag;
uchar key5Num = 0,pwm,pwmnum = 0;
uint time = 0;
uchar count = 0,temp;

void display();
void keycan(uchar);
unsigned char read_key(void);
//close buzz and led
void cls_buzz()
{
	P2 = (P2 & 0x1f) | 0xa0;
	P0 = 0x00;
	P2 = 0x1f;
}
void cls_led()
{
	P2 = (P2 & 0x1f) | 0x80;
	P0 = 0xff;
	P2 = 0x1f;
}
//主函数
void main()
{
	cls_buzz();
	cls_led();
	AUXR |= 0x80;
	TMOD = 0xf0;
	TL0 = 0xcd;	//定时100us
	TH0 = 0xd4;	//
	TF0 = 0;
	TR0 = 1;
	ET0 = 1;
	EA = 1;
	while(1)
	{
		if(temper_flag)
		{
			temper_flag = 0;
			temperature = rd_temperature(); //读取温度

		}
		keycan(read_key()); //read是键扫描
	}
}

void time0(void) interrupt 1
{
	static unsigned char intr;
	static long int num = 0;
	if(++intr == 10)
	{
		intr = 0;
		temper_flag = 1;
	}

	if(num >= 1000 & time != 0)	//time-- 的条件 
	{
		num = 0;
		time -= 1;
	}
	num++;
	//占空比20%
	if(pwm == 2) //pwm is flag
	{
		pwmnum += 1;
		if(pwmnum > 2) //要求1Khz 即1ms pwmnum计数10即为1ms
		{
			P34 = 0;
			if (pwmnum == 10)pwmnum = 0;
		}
		else
		{
			P34 = 1;
		}
	}


		if(pwm == 3)
	{
		pwmnum += 1;
		if(pwmnum > 3)
		{
			P34 = 0;
			if (pwmnum == 10)pwmnum = 0;
		}
		else
		{
			P34 = 1;
		}
	}


		if(pwm == 7)
	{
		pwmnum += 1;
		if(pwmnum > 7)
		{
			P34 = 0;
			if (pwmnum == 10)pwmnum = 0;
		}
		else
		{
			P34 = 1;
		}
	}

	display();
}

void keycan(uchar key_value)
{
	uchar i;
		if(count >= 3)
			count = 0;
	switch(key_value)
	{
		case 4:
		{
			flag = 0;			//优化
			dspbuf[2] = dspbuf[0] = 11;		//通过count计数来显示模式 1 2 3
			count += 1;
			temp = count;			//temp是为了存储一下模式
			dspbuf[1] = count;
			if(count == 1)
			{
				P2 = (P2 & 0x1f) | 0x80; //选led灯
				P0 = 0xfe;
				P2 = 0x1f;
				pwm = 2;
			}
			else if(count == 2)
			{
				P2 = (P2 & 0x1f) | 0x80;
				P0 = 0xfd;
				P2 = 0x1f;
				pwm = 3;
			}
			else if(count == 3)
			{
				P2 = (P2 & 0x1f) | 0x80;
				P0 = 0xfb;
				P2 = 0x1f;
				pwm = 7;
			}
			break;
		}
		case 5:
		{
			flag = 0;	//优化
			time += 60;

			break;
		}
		case 6:
		{
			for(i = 0; i < 8; i++)	//复位 全部恢复原状态
				dspbuf[i] = 10;
			time = 0;
			count = 0;
			key5Num = 0;
			P2 = (P2 & 0x1f) | 0x80;
			P0 = 0xff;			//led
			P2 = 0x1f;
			break;
		}
		case 7:
		{
			flag = (flag + 1) % 2;		//偶数为模式奇数 显示温度
			break;
		}
		case 0:break;
	}
}
//显示函数
void display()
{
	static unsigned char dspcom = 0;
	if(key5Num == 1){
		if(flag == 0)
		{
			dspbuf[1] = temp;
			dspbuf[7] = time % 10;
			dspbuf[4] = time / 1000;
			dspbuf[5] = (time / 100) - (dspbuf[4] * 10);
			dspbuf[6] = (time / 10) - (dspbuf[4] * 100) - (dspbuf[5] * 10);
		}
		else
		{

			dspbuf[2] = dspbuf[0] = 11;			//按一下才会变需要修改
			dspbuf[1] = 4;
			dspbuf[4] = 10;
			dspbuf[5] = temperature / 10;
			dspbuf[6] = temperature % 10;
			dspbuf[7] = 12;
		}
	}
	else
	{
		dspbuf[4] = 10;
		dspbuf[5] = 10;
		dspbuf[6] = 10;
		dspbuf[7] = 10;
	}
	P2 = ((P2&0x1f)|0xE0);   //段选573
	P0 = 0xff;               //消隐段码
	P2 &= 0x1f;

	P0 = 1<<dspcom;	         //循环位选
	P2 = ((P2&0x1f)|0xC0);
	P2 &= 0x1f;

	P0 = tab[dspbuf[dspcom]];//显示段码
  P2 = ((P2&0x1f)|0xE0);
	P2 &= 0x1f;

    if(++dspcom == 8){
        dspcom = 0;
    }
}
//按键扫描函数
unsigned char read_key(void)
{	//state0:充当消抖 state1:有按键按下 state2:检查按键是否松开
    uchar temp;
		static unsigned char state = 0;
    uchar key_value = 0;
	  temp = P3&0x0f;
    switch(state)
		{
			case 0:
			{
				if(P3 != 0x0f) //有按键按下
				state=1;
			}break;
			case 1:
			{
				if(P3 != 0x0f){
				switch(temp)
				{
					case 0x0e:
					{
						key_value = 7;state = 2;  //S7
					}break;
					case 0x0d:
					{
						key_value = 6;state = 2;  //S6
					}break;
					case 0x0b:
					{
						key_value = 5;state = 2;			//S5
							key5Num = 1;
					}break;
					case 0x07:
					{
						key_value = 4;state = 2;  //S4 
					}break;
				}
			}
				else
					state = 0;

			}break;
			case 2:
			{
				if(P3 == 0xff)
					state = 0;
			}break;
		}
    return key_value;
}
//延时 无用 优化后舍弃
 /*void delay()
 {
	 uchar i,j;
	 for(i = 0; i < 5; i++)
		for(j = 0; j<110; j++);
 }*/

onewire.c

#include "reg52.h"

sbit DQ = P1^4;

单总线延时函数
void Delay_OneWire(unsigned int t)
{
	unsigned char i;
	while(t--){
		for(i=0;i<12;i++);
	}
}

//通过单总线向DS18B20写一个字节
void Write_DS18B20(unsigned char dat)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		DQ = 0;
		DQ = dat&0x01;
		Delay_OneWire(5);
		DQ = 1;
		dat >>= 1;
	}
	Delay_OneWire(5);

}

//从DS18B20读取一个字节
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(5);
	}
	return dat;
}

//DS18B20初始化
bit init_ds18b20(void)
{
  	bit initflag = 0;

  	DQ = 1;
  	Delay_OneWire(12);
  	DQ = 0;
  	Delay_OneWire(80); // 延时大于480us
  	DQ = 1;
  	Delay_OneWire(10);  // 14
  	initflag = DQ;     // initflag等于1初始化失败
  	Delay_OneWire(5);

  	return initflag;
}

//DS18B20温度采集程序:整数
unsigned char rd_temperature(void)
{
    unsigned char low,high;
  	char temp;  //这是一个有符号的数

  	init_ds18b20();
  	Write_DS18B20(0xCC);
  	Write_DS18B20(0x44); //启动温度转换
  	Delay_OneWire(200);

  	init_ds18b20();
  	Write_DS18B20(0xCC);
  	Write_DS18B20(0xBE); //读取寄存器

  	low = Read_DS18B20(); //低字节
  	high = Read_DS18B20(); //高字节

  	temp = high<<4;   //只取了整数部分和符号位
  	temp |= (low>>4);

  	return temp;
}

实验结果:

蓝桥杯第七届--模拟风扇控制(代码、思路)-LMLPHP
蓝桥杯第七届--模拟风扇控制(代码、思路)-LMLPHP
蓝桥杯第七届--模拟风扇控制(代码、思路)-LMLPHP
PWM之前在学校实验室示波器中显示也是正常,但是没有截图。


感谢丁莉老师的指导!!

09-12 17:14