真题内容取自: FILWY_M
设计任务及要求
实现代码
注意:①注意修改驱动代码时要留意一下onewire.h中单总线延时函数,是
STC89C52RC
,还是15系列
的,15系列的单片机速度比51快8~12倍,需要修改对应的延时函数
。②onewire.h中需要我们自己编写读取温度函数,有两种实现对温度保留两位小数的操作,一种在rd_temperature_f中实现对温度的放大100倍,还有一种是使用浮点数,在函数外得到温度的两个小数的保留。如下,看个人使用习惯采用
函数内保留两位小数
void rd_temperature_f()
{
unsigned char low, high;
init_ds18b20(); // 初始化
Write_DS18B20(0xCC); // 跳过 ROM
Write_DS18B20(0x44); // 转换温度
init_ds18b20();
Write_DS18B20(0xCC);
Write_DS18B20(0xBE); // 读暂存器
low = Read_DS18B20(); // 低字节
high = Read_DS18B20(); // 高字节
current_temperature = high;
current_temperature <<= 8;
current_temperature |= low;
if (current_temperature & 0xf800 == 0x0000)//温度为正
{
current_temperature >>= 4;//拿到温度的整数部分
current_temperature *= 100;//温度保留
current_temperature = current_temperature + (low & 0x0f) * 6.25;
}
}
函数外保留两位小数
//注意这边是浮点型float!!!
//主函数中使用参数uint curr_temp = rd_temperature_f()拿到两位小数
float rd_temperature_f(void)
{
unsigned int temp;
float temperature;
unsigned char low,high;
init_ds18b20();
Write_DS18B20(0xCC); // 仅有一个DS18B20,故跳过 ROM
Write_DS18B20(0x44); //启动温度转换
//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;
}
复制实验代码顺序
- 新建文件夹中建立
三个.c
文件,两个.h
文件分别将下面文件复制到keil中去 - 注意选择生成.hex文件
实验代码
- main.c
#include "STC15F2K60S2.h"
#include "onewire.h" //单总线函数库
#include "iic.h"
#define uchar unsigned char
#define uint unsigned int
unsigned char dspcom = 0;//位选线
unsigned char dspbuf[8] = {10,10,10,10,10,10,10,10};//显示缓冲区
code unsigned char tab[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xc6,0x88,0x8c};
//tab[11] = 'C',tab[12] = 'A', tab[13] = 'P';
unsigned int curr_temp, temp_para=25, v_val;
unsigned char key_value=0xff,interface,mod = 1,ad_val;
bit flag_temp = 0;//温度读取标志
bit flag_key = 0;//按键读取标志
float temperature;
void display(void); //数码管显示
void key_scanf(void); //按键扫描
void key_proc(void); //按键处理
void close_peripheral(); //关外设
void Timer0Init(void); //1毫秒@12.000MHz
void dac_pcf8591(unsigned char dat); //数字信号转化为模拟的电压信号
//主函数
void main(void)
{
close_peripheral();//关外设
Timer0Init();//定时器0初始化
while(1)
{
if(flag_key)//20ms扫描键盘
{
flag_key = 0;
key_scanf();
}
key_proc();
if(interface==0)
{
//当前处于温度显示界面,指示灯L2点亮,否则熄灭
P2 = (P2 & 0x1f) | 0x80;
P0 = 0xfd;
P2 &= 0x1f;
if(flag_temp)
{
flag_temp = 0;
temperature = rd_temperature_f();
curr_temp=temperature*100;
dspbuf[0] = 11;//字符'C'
dspbuf[4] = curr_temp/1000;
dspbuf[5] = curr_temp%1000/100;
dspbuf[6] = curr_temp%1000%100/10;
dspbuf[7] = curr_temp%10;
}
}
if(interface==1)
{
当前处于参数设置界面,指示灯L3点亮,否则熄灭。
P2 = (P2 & 0x1f) | 0x80;
P0 = 0xfb;
P2 &= 0x1f;
dspbuf[0] = 13;//字符'P'
dspbuf[1] = 10;
dspbuf[2] = 10;
dspbuf[3] = 10;
dspbuf[4] = 10;
dspbuf[5] = 10;
dspbuf[6] = temp_para/10;
dspbuf[7] = temp_para%10;
}
if(interface==2)
{
//DAC界面,L4点亮
P2 = (P2 & 0x1f) | 0x80;
P0 = ~(0x08);
P2 &= 0x1f;
if (mod == 1)//模式1
{
//且处于模式1,L1同时亮
P2 = (P2 & 0x1f) | 0x80;
P0 = ~(0x09);
P2 &= 0x1f;
temperature = rd_temperature_f();
curr_temp=temperature*100;
if(curr_temp<temp_para*100)
{
dac_pcf8591(0x00);
v_val=0;
}
if(curr_temp>=temp_para*100)
{
dac_pcf8591(0xff);
v_val=500;
}
}
else if (mod == 2)//模式2
{
temperature = rd_temperature_f();
curr_temp=temperature*100;
if(curr_temp<2000)
{
dac_pcf8591(51);
v_val=100;
}
if((curr_temp>=2000)&&(curr_temp<4000))
{
v_val= (3*curr_temp/20)-200;
ad_val = v_val*51/100;
dac_pcf8591(ad_val);
}
if(curr_temp>=4000)
{
dac_pcf8591(204);
v_val=400;
}
}
dspbuf[0] = 12;//字符'A'
dspbuf[1] = 10;
dspbuf[2] = 10;
dspbuf[3] = 10;
dspbuf[4] = 10;
dspbuf[5] = v_val/100;
dspbuf[6] = v_val%100/10;
dspbuf[7] = v_val%10;
}
}
}
//定时器0中断服务函数
void isr_timer_0(void) interrupt 1
{
static int intr1, intr2;
display();
if(++intr1== 20)
{
intr1 = 0;
flag_key = 1; //20ms按键扫描标志位置1
}
if(++intr2== 500)
{
intr2 = 0;
flag_temp = 1; //500ms温度读取标志位置1
}
}
void key_proc(void)
{
switch(key_value)
{
case 12:
interface++;
interface=interface%3;
key_value=0xff;
break;
case 9:
if (interface == 1)
temp_para++;
key_value=0xff;
break;
case 13:
if (interface == 1)
temp_para--;
key_value=0xff;
break;
case 8:
mod++;
if (mod == 3)
mod = 1;
key_value=0xff;
break;
}
}
//按键识别--行列扫描法(先行再列)
void key_scanf(void)
{
unsigned char row;
static unsigned char key_state=0;
switch(key_state)
{
case 0:
{
P32 = 1, P33 = 1, P42 = 0; P44 = 0;
if((P32 != 1) || (P33 != 1)) //有按键按下
key_state=1;
}break;
case 1:
{
P32 = 1, P33 = 1, P42 = 0; P44 = 0;
if((P32 != 1) || (P33 != 1)) //有按键按下
{
if(P32 == 0)row = 3;
if(P33 == 0)row = 4;//确定行
switch(row)
{
case 3:{P32 = 0, P33 = 0, P42 = 1; P44 = 1;
if(P44 == 0) {key_value=8;key_state=2;}
else if(P42 == 0) {key_value=9;key_state=2;}
}break;
case 4:{P32 = 0, P33 = 0, P42 = 1; P44 = 1;
if(P44 == 0) {key_value=12;key_state=2;}
else if(P42 == 0) {key_value=13;key_state=2;}
}break;
}
}
else
{
key_state=0;
}
}break;
case 2:
{
P32 = 1, P33 = 1, P42 = 0; P44 = 0;
if((P32 == 1) && (P33 == 1)) //按键放开
key_state=0;
}break;
}
}
//显示函数
void display(void)
{
//消隐
P2 = (P2&0x1f) | 0xe0;
P0 = 0xff;
P2 &= 0x1f;
//位选
P2 = (P2&0x1f) | 0xc0;
P0 = 1<<dspcom;
P2 &= 0x1f;
//段选
P2 = ((P2&0x1f)|0xE0);
P0 = tab[dspbuf[dspcom]];
P2 &= 0x1f;
if(((interface==0)||(interface==2)) && (dspcom == 5))
{
P2 = ((P2&0x1f)|0xE0);
P0 = (tab[dspbuf[dspcom]])&0x7f;//添加小数点
P2 &= 0x1f;
}
if(++dspcom == 8)
{
dspcom = 0;
}
}
void close_peripheral()
{
//初始化led为全灭
P2 = (P2 & 0x1f) | 0x80;
P0 = 0xff;
//初始化继电器,蜂鸣器不吸附,不发声
P2 = (P2 & 0x1f) | 0xa0;
P0 = 0xaf;
P2 &= 0x1f;
}
//软件中的定时器模式16位自动重载
void Timer0Init(void) //1毫秒@12.000MHz
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //打开定时器0中断允许
EA = 1; //打开总中断
}
void dac_pcf8591(unsigned char dat)//数字信号转化为模拟的电压信号
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x40); //DAC输出模式,允许 DAC, ADC 通道 0
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
}
- iic.c
/*
程序说明: IIC总线驱动程序
软件环境: Keil uVision 4.10
硬件环境: CT107单片机综合实训平台 8051,12MHz
日 期: 2011-8-9
*/
#include "reg52.h"
#include "intrins.h"
#define DELAY_TIME 5
#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1
//总线引脚定义
sbit SDA = P2^1; /* 数据线 */
sbit SCL = P2^0; /* 时钟线 */
void IIC_Delay(unsigned char i)
{
do{_nop_();}
while(i--);
}
//总线启动条件
void IIC_Start(void)
{
SDA = 1;
SCL = 1;
IIC_Delay(DELAY_TIME);
SDA = 0;
IIC_Delay(DELAY_TIME);
SCL = 0;
}
//总线停止条件
void IIC_Stop(void)
{
SDA = 0;
SCL = 1;
IIC_Delay(DELAY_TIME);
SDA = 1;
IIC_Delay(DELAY_TIME);
}
//发送应答
void IIC_SendAck(bit ackbit)
{
SCL = 0;
SDA = ackbit; // 0:应答,1:非应答
IIC_Delay(DELAY_TIME);
SCL = 1;
IIC_Delay(DELAY_TIME);
SCL = 0;
SDA = 1;
IIC_Delay(DELAY_TIME);
}
//等待应答
bit IIC_WaitAck(void)
{
bit ackbit;
SCL = 1;
IIC_Delay(DELAY_TIME);
ackbit = SDA;
SCL = 0;
IIC_Delay(DELAY_TIME);
return ackbit;
}
//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
unsigned char i;
for(i=0; i<8; i++)
{
SCL = 0;
IIC_Delay(DELAY_TIME);
if(byt & 0x80) SDA = 1;
else SDA = 0;
IIC_Delay(DELAY_TIME);
SCL = 1;
byt <<= 1;
IIC_Delay(DELAY_TIME);
}
SCL = 0;
}
//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
unsigned char i, da;
for(i=0; i<8; i++)
{
SCL = 1;
IIC_Delay(DELAY_TIME);
da <<= 1;
if(SDA) da |= 1;
SCL = 0;
IIC_Delay(DELAY_TIME);
}
return da;
}
- IIC.H
#ifndef _IIC_H
#define _IIC_H
void IIC_Start(void);
void IIC_Stop(void);
bit IIC_WaitAck(void);
void IIC_SendAck(bit ackbit);
void IIC_SendByte(unsigned char byt);
unsigned char IIC_RecByte(void);
#endif
- onewire.c
/*
程序说明: 单总线驱动程序
软件环境: Keil uVision 4.10
硬件环境: CT107单片机综合实训平台(外部晶振12MHz) STC89C52RC单片机
日 期: 2011-8-9
*/
#include "reg52.h"
sbit DQ = P1^4; //单总线接口
//单总线延时函数
void Delay_OneWire(unsigned int t) //STC89C52RC
{
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);
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); // 仅有一个DS18B20,故跳过 ROM
Write_DS18B20(0x44); //启动温度转换
//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;
}
- ONEWIRE.H
#ifndef __ONEWIRE_H
#define __ONEWIRE_H
void Write_DS18B20(unsigned char dat);
unsigned char Read_DS18B20(void);
float rd_temperature_f(void);
bit init_ds18b20();
#endif