蓝桥杯第七届省赛 模拟风扇控制系统
程序框架:
main函数:
两个界面:温度显示,时间倒计时
common函数:
定时器中断:控制LED,控制数码管显示,记录时间
scan_button() :S4,S5,S6,S7实现对应功能
onewire.c
/*
程序说明: 单总线驱动程序
软件环境: Keil uVision 4.10
硬件环境: CT107单片机综合实训平台(外部晶振12MHz) STC89C52RC单片机
日 期: 2011-8-9
*/
#include "reg52.h"
#include "onewire.h"
#include "intrins.h"
sbit DQ = P1^4; //单总线接口
//单总线延时函数
void Delay_OneWire(unsigned int t); //先声明
//通过单总线向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);
DQ = 1;
Delay_OneWire(10);
initflag = DQ;
Delay_OneWire(5);
return initflag;
}
//添加部分*************************************************
void Delay_OneWire(unsigned int t) //STC89C52RC
{
t*=11; //修改延时,增加到原来的11倍
while(t--);
}
float read_temp()
{
float temp;
unsigned char low,high;
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<<8|low)*0.0625;
return temp;
}
common.c
#include<common.h>
uchar dsp_buff[8]={11,10,11,10};
uchar L1,L2,L3; //控制LED1,L2,L3
uchar count_key; //控制按键刷新率
uchar mode_work=wind_sleep; //工作模式
uchar temp=0,level=0; //温度,工作模式区间
uchar PWM_duty; //PWM占空比
uint count_sec=0; //控制倒计时
uint remain_time; //剩余工作时间
uint count_temp; //控制温度刷新率
bit interface=work; //显示界面
uchar dsp_code[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf,0xc6}; //数字0~9,关闭,-
void system_init()
{
uchar i;
P0=0xff;P2=0x80;P2=0;
P0=0x00;P2=0xa0;P2=0;
for(i=0;i<70;i++) //读取温度,待温度读取稳定后再显示
temp=read_temp()+0.5;
Timer0Init();
}
void Timer0Init(void) //100微秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xAE; //设置定时初值
TH0 = 0xFB; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;
EA=1;
}
void tm0(void) interrupt 1
{
static uchar bit_com=0,count_dsp=0;
if(++count_dsp<=PWM_duty) //控制占空比
P34=1; //题目要求P34输出脉冲调制信号
else
P34=0;
if(count_dsp==10) //每隔1ms对外设进行一次引脚操作
{
count_dsp=0;
P0=~(4*L3+2*L2+L1);P2=0x80;P2=0; //控制led
P0=0;P2=0xc0;P2=0;
P0=dsp_code[dsp_buff[bit_com]];P2=0xe0;P2=0;
P0=1<<bit_com;P2=0xc0;P2=0;
if(bit_com==7)
bit_com=0;
else
bit_com++;
}
if(++count_sec==10000)
{
count_sec=0;
if(remain_time>0) //注意先判断再自减,防止溢出
--remain_time; //每隔1s自减一次
}
++count_key;
++count_temp;
}
void scan_button(void)
{
static uchar key_stat=0;
uchar key_val=0,key_x=0,key_y=0;
P3=0x0f;P4=0x00; //行扫描
if(!P30) key_x=3;
else if(!P31) key_x=2;
else if(!P32) key_x=1;
else if(!P33) key_x=0;
P3=0xf0;P4=0xff;
if(!P34) key_y=4;
else if(!P35) key_y=3;
else if(!P42) key_y=2;
else if(!P44) key_y=1;
key_val=key_x+key_y*4; //综合行列扫描的结果,判断具体位置
switch(key_stat)
{
case 0:
if(key_val!=0) key_stat=1; //第一次检测到有按键按下,状态为1
break;
case 1:
if(key_val==0) key_stat=0; //第二次(10ms后)若检测到无按键按下。即认为为抖动,返回状态0
else
{
key_stat=2;
if(key_val==7) //按下S7,显示当前室温
{
interface=~interface;
}
if(interface==work)
{
switch(key_val)
{
case 4: //按下S4为工作模式切换,3种模式循环切换
if(++mode_work==14)
mode_work=11;
break;
case 5: //按下S5为定时按键,0,1,2分钟循环切换
count_sec=0;
if(level==0)
remain_time=60;
else if(level==1)
remain_time=120;
else if(level==2)
remain_time=0;
if(++level==3)
level=0;
break;
case 6: //按下S6为停止按键
remain_time=0;
level=0;
}
}
}
case 2:
if(key_val==0) key_stat=0;
}
}
main.c
#include<main.h>
extern uchar dsp_buff[];
extern uchar L1,L2,L3; //控制LED1,L2,L3
extern uchar count_key; //控制按键刷新率
extern uchar mode_work; //工作模式
extern uchar temp,level; //温度,工作模式区间
extern uchar PWM_duty; //PWM占空比
extern uint count_sec; //控制倒计时
extern uint remain_time; //剩余工作时间
extern uint count_temp; //控制温度刷新率
extern bit interface; //显示界面
extern uchar dsp_code[]; //数字0~9,关闭,-
void main()
{
system_init();
while(1)
{
if(interface==work) //工作界面显示
{
if(mode_work==wind_sleep)
{
dsp_buff[1]=1;
}
else if(mode_work==wind_nature)
{
dsp_buff[1]=2;
}
else if(mode_work==wind_normal)
{
dsp_buff[1]=3;
}
dsp_buff[4]=remain_time/1000%10;
dsp_buff[5]=remain_time/100%10;
dsp_buff[6]=remain_time/10%10;
dsp_buff[7]=remain_time%10;
}
else if(interface==mesure) //室温显示界面
{
if(count_temp>7499) //750ms刷新一次温度
{
count_temp=0;
temp=read_temp()+0.5;
}
dsp_buff[1]=4;
dsp_buff[4]=10;
dsp_buff[5]=temp/10;
dsp_buff[6]=temp%10;
dsp_buff[7]=12; //数码管第七位显示“C”
}
if(remain_time==0)
{
L1=L2=L3=0; //熄灭所有LED
PWM_duty=0;
}
else
{
if(mode_work==wind_sleep)
{
L1=1; //点亮L1
L2=L3=0; //熄灭L2,L3
PWM_duty=2; //PWM占空比为20%
}
else if(mode_work==wind_nature)
{
L2=1;
L1=L3=0;
PWM_duty=3; //PWM占空比为30%
}
else if(mode_work==wind_normal)
{
L3=1;
L1=L2=0;
PWM_duty=7; //PWM占空比为70%
}
}
if(count_key>99) //10ms刷新一次按键,相当于消抖10ms
{
count_key=0;
scan_button();
}
}
}