PDF文件链接
链接地址:链接:https://pan.baidu.com/s/1qNA1aDIerGZU4Fpdy_blRw????? 提取码:9956
编程题解答
?思路:
??? 1.这题里面我们要用到数码管、定时器、LED、独立按键、DS18B20、PWM这几个部分。
??? 2.独立按键S4切换风速模式我们还是需要用到一个变量来计数,按下S4我们就让这个变量改变,当变量改变到什么时候时,我们执行数模式切换工作,这个功能我们通常运用if语句以及switch语句结合来实现。
3.独立按键的扫描我们还是用状态机的方法,也可以使用一些简单的if、else if语句还实现,但是都要记得在按下后给予一个返回值,这是用来识别是哪一个按键按下的标志。
4.数码管的display我们不用怎么说,就是按照以往的这个样子写,简单万能。
5.PWM的话还是简单的一个占空比的运用我们就不多说了。值得一提的是PWM的定时我们要选择100us,不然会不准确。
6.温度测量是比较容易出意外的,我在写的时候就好几次一直写不出来。温度测量一直不准确,原因是我们在定义变量的时候要统一变量的类型,比如我们在ds18b20.c中的读取温度的函数是float型的,但是我们在主函数中定于的接收温度的变量是char型的话则会造成干扰,无法读出准确的温度数据。这里需要强调的一点是我们就收温度数据最好是使用int型的变量接收,因为float型的数据在给int型的时候会直接省略小数点后面的数,而我们题目要求的是显示两位数的温度数据,所以我们直接用int型的数据进行接收。
?????????接下来开始码。头文件STC.h我们利用STC-ISP软件自动生成添加到工程文件夹中即可。HC138.h是我个人比较喜欢的自定义函数。
#include "STC.h"
void HC138(unsigned int n)
{
switch(n)
{
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;
}
}
?????????下面是主函数部分
#include "STC.h"
#include "HC138.h"
#include "ds18b20.h"
//======================== 0 1 2 3 4 5 6 7 8 9 10- 11. 12全黑 13C
code unsigned char tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xBF,0x7F,0xff,0xc6};
unsigned char dspcom;
unsigned char dspbuf[]={10,1,10,12,12,0,0,0};
unsigned char jm_mod=0,key_val=0;//jm_mod控制温度风速界面的变量
unsigned char dsp_time=0;
unsigned char fs_mod=1;//控制风速的变量
unsigned int n1=0,n2=0,n3=0;//定时机计时
unsigned int temper;//接受温度数据
unsigned char pwm_value = 2;
unsigned char pwm_counter = 0;
bit temp_flag;
sbit PWM_OUT = P3^4;
void display()
{
HC138(7);
P0=0xff;
P2&=0x1f;
HC138(6);
P0=1<<dspcom;
P2&=0x1f;
HC138(7);
P0=tab[dspbuf[dspcom]];
P2&=0x1f;
if(++dspcom==8)
{
dspcom=0;
}
}
void key_scanf()//独立按键的扫描方式,可以直接套用这个代码
{
static unsigned char key_st=0;
switch(key_st)
{
case 0:
if((P3&0x0f)!=0x0f)
key_st=1;
break;
case 1:
if((P3&0x0f)!=0x0f)
{
key_st=2;
if((P3&0x0F) == 0x0E) key_val = 7;
else if((P3&0x0F) == 0x0D) key_val = 6;
else if((P3&0x0F) == 0x0B) key_val = 5;
else if((P3&0x0F) == 0x07) key_val = 4;
}
else
{
key_st=0;
}
break;
case 2:
if((P3&0x0F) == 0x0F)
{
key_st = 0;
}
break;
}
}
void key_function()
{
static unsigned char add_time=0;
switch(key_val)
{
case 7://风速温度界面切换
if(jm_mod==0)
{
jm_mod=1;
}
else
{
jm_mod=0;
}
key_val=0;//每次都要清零,不然识别的就一直持续上一个按键的值
break;
case 6://S6按键的功能
dsp_time=0;
add_time=0;
key_val=0;
break;
case 5://S5按键按一次计时时间加60秒,最高120,再加清零
add_time+=60;
if(add_time==180)
{
add_time=0;
}
dsp_time=add_time;
key_val=0;
break;
case 4://S4按键按下切换风速模式
if(++fs_mod==4)
{
fs_mod=1;
}
key_val=0;
break;
}
}
void Timer0Init(void) //2毫秒@12.000MHz
{
HC138(5);
P0=0xaf;
P2&=0x1f;
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x40; //设置定时初始值
TH0 = 0xA2; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA=1;
ET0=1;
AUXR |= 0x40; //晶振12M时,定时器1定时100us,自动重装初值
TMOD &= 0x0F;
TL1 = 0x50;
TH1 = 0xFB;
TR1 = 1;
ET1=0;
}
void Timer0() interrupt 1
{
display();//2ms显示数码管
if(++n1==10)
{
n1=0;
temp_flag=1;
}//20ms测一次温度
if(++n2==10)
{
n2=0;
key_scanf();
}//20ms扫描一次键盘
if(++n3==500)
{
if(dsp_time!=0)
{
dsp_time--;
}
n3=0;
}//每秒减1
}
void Timer1() interrupt 3
{
//PWM_OUT输出200us高电平,800us低电平
//pwm_value的值不同,则输出的脉宽不一样
if(++pwm_counter <= pwm_value)
{
PWM_OUT = 1;
}
else
{
PWM_OUT = 0;
if(pwm_counter == 10)
{
pwm_counter = 0;
}
}
}
void LEDlight(unsigned int fs_mod)
{
if(fs_mod==1)
{
HC138(4);
P0=0xfe;
P2&=0x1f;
}
else if(fs_mod==2)
{
HC138(4);
P0=0xfd;
P2&=0x1f;
}
else if(fs_mod==3)
{
HC138(4);
P0=0xfb;
P2&=0x1f;
}
else
{
HC138(4);
P0=0xff;
P2&=0x1f;
}
}
void main()
{
float temperature;
Timer0Init();
while(1)
{
if(temp_flag==1)
{
temp_flag=0;
temperature=rd_temperature_f();
temper=temperature;
}
if(jm_mod==0)
{
dspbuf[1]=fs_mod;
dspbuf[5]=dsp_time/100;
dspbuf[6]=dsp_time%100/10;
dspbuf[7]=dsp_time%10;
}
else
{
dspbuf[1]=4;
dspbuf[4]=12;
dspbuf[5]=temper/10;
dspbuf[6]=temper%10;
dspbuf[7]=13;
}
key_function();
LEDlight(fs_mod);
}
}
??????? 下面是DS18B20的驱动代码ds18b20.c官方会在选手数据包中给出,需要注意的是我们要知道读取温度的函数float rd_temperature_f()如何编写并添加到其中,这是至关重要的。
/*
程序说明: 单总线驱动程序
软件环境: Keil uVision 4.10
硬件环境: CT107单片机综合实训平台 8051 12MHz
日 期: 2011-8-9
*/
#include "reg52.h"
sbit DQ = P1^4; //单总线接口
//单总线延时函数
void Delay_OneWire(unsigned int t)
{
unsigned char i;
while(t--){
for(i=0; i<8; 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);
DQ = 1;
Delay_OneWire(10);
initflag = DQ;
Delay_OneWire(5);
return initflag;
}
float rd_temperature_f(void)
{
unsigned int temp;
float temperature;
unsigned char low,high;
init_ds18b20();
Write_DS18B20(0xCC);
Write_DS18B20(0x44); //启动温度转换
//Delay_OneWire(200);
while (!DQ); //等待转换完成
init_ds18b20();
Write_DS18B20(0xCC);
Write_DS18B20(0xBE); //读取寄存器
low = Read_DS18B20(); //低字节
high = Read_DS18B20(); //高字节
/** 精度为0.0625摄氏度 */
temp = (high&0x0f);
temp <<= 8;
temp |= low;
temperature = temp*0.0625;
return temperature;
}
|