模拟风扇控制
解题思路
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;
}
//延时 无用 优化后舍弃
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;
}
实验结果:
PWM之前在学校实验室示波器中显示也是正常,但是没有截图。
感谢丁莉老师的指导!!