现在的蓝桥杯单片机组已经不考电路设计了,所以这个题的编程部分就比较简单,一般来说在DS18B20驱动写好的情况下,两个多小时就可以写好。
一看题目,这个题需要用到DS18B20测温度,数码管和LED显示,以及独立按键进行设置等等。
有难度的一点在PWM输出,要求PWM频率在1Kz,由于我们在DS18B20的程序中有关中断的操作,所以想要完美的输出相应占空比的PWM,需要更改DS18B20中的开关总中断的位置。
代码下载链接:https://download.csdn.net/download/xiaomo_haa/11002294
在第一次调试的时候,我是将DS18B20中的关中断 EA = 0 改为了禁止定时器0中断 ET0 = 0。这时使用逻辑分析仪观察波形,输出完美PWM波,但是我改为控制 EA 后,观察占空比20%时候的波形,有的部分占空比不是20%。
附上占空比为20%时候的波形图
控制ET0时
控制EA时
可以看到这个时候由于关总中断的影响,造成这个高电平时间减少,占空比小于20%
main.c
#include
#include "sys.h"
bit flag_2ms = 0, flag_500ms = 0;
bit flag_fan = 0, flag_temper = 0;
u8 mode = 1, modebackup = 1;
signed char min = 2, sec = 0; //time
int temper_int = 0; //temperture
void main(void)
{
int temper = 0;
bit res;
AllInit();
Timer0Init();
Start18B20();
EA = 1;
while(1)
{
TubeShow();
KeyPress();
if((sec == 0) && (min == 0))
flag_fan = 0;
else
flag_fan = 1;
if(flag_2ms)
{
flag_2ms = 0;
KeyScan();
}
if(flag_500ms) //show temperture
{
flag_500ms = 0;
res = Get18B20Temp(&temper);
if(res)
{
temper >>= 4;
if((temper > 0) && (temper < 75))
temper_int = temper;
}
Start18B20();
}
}
}
sys.c
#include "sys.h"
void AllInit(void)
{
P2 = (P2 & 0x1f) | 0x80; //open Y4C
P0 = 0xff;
P2 = (P2 & 0x1f) | 0xc0; //open Y6C
P0 = 0x00;
P2 = (P2 & 0x1f) | 0xa0; //open Y5C
P0 = 0x00;
P2 = P2 & 0x1f;
}
void Timer0Init(void) //100微秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xAE; //设置定时初值
TH0 = 0xFB; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
}
void Timer0(void) interrupt 1
{
static u8 T0count1 = 0, T0count3 = 0;
static u16 T0count2 = 0, T0count4 = 0;
u8 temp;
T0count1 ++;
if(flag_temper)
T0count4 ++;
else
T0count4 = 0;
if(flag_fan)
{
T0count2 ++;
T0count3 ++;
}
if(T0count1 >= 20) //2ms
{
T0count1 = 0;
flag_2ms = 1;
}
if(T0count4 >= 2000) //500ms show temperture
{
T0count4 = 0;
flag_500ms = 1;
}
if(flag_fan)
{
switch(modebackup)
{
case 1: temp = 2; break;
case 2: temp = 3; break;
case 3: temp = 7; break;
}
if(T0count3 <= temp)
PWM = 1;
else
{
PWM = 0;
if(T0count3 >= 10)
T0count3 = 0;
}
}
else
T0count3 = 0;
if(T0count2 >= 10000) //1s
{
T0count2 = 0;
sec --;
if(sec < 0) //sec
{
sec = 59;
min --;
if(min < 0) //min
{
min = 0; //stop
min = 0; //stop
flag_fan = 0;
}
}
}
LEDWork();
TubeScan();
}
sys.h
#ifndef _SYS_H_
#define _SYS_H_
#include
#include
#include "ds18B20.h"
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
//External variables
extern bit flag_2ms, flag_500ms;
extern bit flag_fan, flag_temper;
extern u8 mode, modebackup;
extern signed char min, sec;
extern int temper_int;
//Pin
sbit S7 = P3^0;
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;
sbit PWM = P3^4;
//Function
void AllInit(void);
void Timer0Init(void);
void TubeScan(void);
void TubeShow(void);
void LEDWork(void);
void KeyScan(void);
void KeyAction(unsigned char key);
void KeyPress(void);
#endif
display.c
#include "sys.h"
unsigned char code table[]={0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8,
0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e,
0xff, 0xbf};
u8 TubeBuff[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
u8 smg1, smg2, smg3, smg4, smg5, smg6, smg7, smg8;
void TubeScan(void)
{
static u8 index = 0;
P2 = (P2 & 0x1f) | 0xe0;
P0 = 0xff;
P2 = (P2 & 0x1f) | 0xc0;
P0 = 0x01 << index;
P2 = (P2 & 0x1f) | 0xe0;
P0 = TubeBuff[index];
P2 = P2 & 0x1f;
index ++;
index &= 0x07;
}
void TubeShow(void)
{
if((mode >= 1) && (mode <= 3))
{
smg1 = smg3 = 17; //-
smg2 = mode;
smg4 = 16; //shut down
smg5 = min / 10; //min
smg6 = min % 10;
smg7 = sec / 10; //sec
smg8 = sec % 10;
}
else if(mode == 4)
{
smg1 = smg3 = 17; //-
smg2 = mode;
smg4 = smg5 = 16; //shut down
smg6 = temper_int / 10;
smg7 = temper_int % 10;
smg8 = 12; //c
}
TubeBuff[0] = table[smg1];
TubeBuff[1] = table[smg2];
TubeBuff[2] = table[smg3];
TubeBuff[3] = table[smg4];
TubeBuff[4] = table[smg5];
TubeBuff[5] = table[smg6];
if(mode != 4)
TubeBuff[5] &= 0x7f;
TubeBuff[6] = table[smg7];
TubeBuff[7] = table[smg8];
}
void LEDWork(void)
{
u8 dat;
dat = _crol_(0x7f, modebackup);
P0 = 0xff;
P2 = (P2 & 0x1f) | 0x80;
if((sec != 0) || (min != 0))
P0 = dat;
P2 = P2 & 0x1f;
}
key.c
#include "sys.h"
u8 KeySta[] = {1, 1, 1, 1};
u8 KeyBackup[] = {1, 1, 1, 1};
u8 KeyBuff[] = {0xff, 0xff, 0xff, 0xff};
void KeyScan(void)
{
u8 i;
KeyBuff[0] = (KeyBuff[0] << 1) | S7;
KeyBuff[1] = (KeyBuff[1] << 1) | S6;
KeyBuff[2] = (KeyBuff[2] << 1) | S5;
KeyBuff[3] = (KeyBuff[3] << 1) | S4;
for(i = 0; i < 4; i ++)
{
if(KeyBuff[i] == 0xff) //Key release
KeySta[i] = 1;
else if(KeyBuff[i] == 0x00) //Key press
KeySta[i] = 0;
else
{}
}
}
void KeyAction(unsigned char key)
{
if(key == 0) //S7 temperture
{
if(mode != 4)
{
mode = 4;
flag_500ms = 1;
flag_temper = 1;
}
else
{
flag_temper = 0;
mode = modebackup;
}
}
else if(key == 1) //S6 stop
{
sec = 0;
min = 0;
flag_fan = 0;
}
else if(key == 2) //S5 minter plus
{
min ++;
if(min > 99)
min = 99;
}
else if(key == 3) //S4 mode change
{
if(mode == 4)
{
modebackup ++;
if(modebackup == 4)
modebackup = 1;
}
else
{
mode ++;
if(mode == 4)
mode = 1;
modebackup = mode; //backup mode
}
}
}
void KeyPress(void)
{
u8 i;
for(i = 0; i < 4; i ++)
{
if(KeySta[i] != KeyBackup[i])
{
if(KeySta[i] == 0) //action when key press
KeyAction(i);
KeyBackup[i] = KeySta[i];
}
}
}
ds18b20.c
#include "sys.h"
sbit DS18B20_IO = P1^4;
/*******************************************************************************
* 函数名 :Delayus
* 输入值 :unsigned int us
* 返回值 :none
* 作者 :小默haa
* 时间 :2019年2月17日
* 功能描述:1T单片机延时指定us
* 备注 :最大形参65535,即最大延时65ms
*******************************************************************************/
void Delayus(unsigned int us)
{
do{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
}while(--us);
}
/*******************************************************************************
* 函数名 :Get18B20Ack
* 输入值 :none
* 返回值 :none
* 作者 :小默haa
* 时间 :2019年2月27日
* 功能描述:复位总线,获取18B20存在脉冲,以启动一次读写操作
* 备注 :
*******************************************************************************/
bit Get18B20Ack(void)
{
bit ack;
DS18B20_IO = 0; //产生500us的复位脉冲
Delayus(500);
DS18B20_IO = 1; //延时60us
// EA = 0; //禁止总中断
ET0 = 0;
Delayus(60);
ack = DS18B20_IO; //读取存在脉冲
while(!DS18B20_IO); //等待存在脉冲结束
// EA = 1; //重新使能总中断
ET0 = 1;
return ack;
}
/*******************************************************************************
* 函数名 :DS18B20Write
* 输入值 :unsigned char dat
* 返回值 :none
* 作者 :小默haa
* 时间 :2019年2月27日
* 功能描述:向18B20写入一个字节
* 备注 :dat为待写入字节
*******************************************************************************/
void DS18B20Write(unsigned char dat)
{
unsigned char mask;
for(mask = 0x01; mask != 0; mask <<= 1) //低位在先,依次移出8个bit
{
// EA = 0;
ET0 = 0;
DS18B20_IO = 0; //产生2us低电平脉冲
Delayus(2);
if(dat & mask) //输出该bit值
DS18B20_IO = 1;
else
DS18B20_IO = 0;
// EA = 1;
ET0 = 1;
Delayus(60); //延时60us
DS18B20_IO = 1; //拉高通信引脚
}
}
/*******************************************************************************
* 函数名 :DS18B20Read
* 输入值 :none
* 返回值 :unsigend char dat
* 作者 :小默haa
* 时间 :2019年2月27日
* 功能描述:从18B20读取一个字节
* 备注 :返回值为读取到的字节
*******************************************************************************/
unsigned char DS18B20Read(void)
{
unsigned char mask, dat = 0;
for(mask = 0x01; mask != 0; mask <<= 1) //低位在先,依次采集8个bit
{
// EA = 0;
ET0 = 0;
DS18B20_IO = 0; //产生2us低电平脉冲
Delayus(2);
DS18B20_IO = 1; //结束低电平脉冲,等待18B20输出数据
Delayus(2); //延时2us
if(DS18B20_IO) //读取通信引脚上的值
dat |= mask;
// EA = 1;
ET0 = 1;
Delayus(60); //再延时60us
}
return dat;
}
/*******************************************************************************
* 函数名 :Start18B20
* 输入值 :none
* 返回值 :bit ~ack
* 作者 :小默haa
* 时间 :2019年2月27日
* 功能描述:启动一次18B20温度转换
* 备注 :返回值为是否启动成功
*******************************************************************************/
bit Start18B20()
{
bit ack;
static bit flag = 1;
ack = Get18B20Ack(); //执行总线复位,并获取18B20应答
if(ack == 0) //如18B20正确应答,则启动一次转换
{
DS18B20Write(0xCC); //跳过ROM操作
if(flag)
{
flag = 0;
DS18B20Write(0x4e); //写暂存器指令4E
DS18B20Write(0x4b); //写高速缓存器TH高温限值75度
DS18B20Write(0x00); //写高速缓存器TL低温限值0度
DS18B20Write(0x1f); //写配置寄存器4
//0x1f : 0.5000°C 转换时间93.75ms
//0x3f : 0.2000°C 转换时间187.5ms
//0x5f : 0.1250°C 转换时间375ms
//0x7f : 0.0625°C 转换时间750ms
}
ack = Get18B20Ack(); //执行总线复位,并获取18B20应答
if(ack == 0) //如18B20正确应答,则启动一次转换
{
DS18B20Write(0xCC); //跳过ROM操作
DS18B20Write(0x44); //启动一次温度转换
}
}
return ~ack; //ack == 0 表示操作成功,所以返回值对其取反
}
/*******************************************************************************
* 函数名 :Get18B20Temp
* 输入值 :int *temp
* 返回值 :bit ~ack
* 作者 :小默haa
* 时间 :2019年2月27日
* 功能描述:读取18B20转换的温度值
* 备注 :返回值为是否读取成功
*******************************************************************************/
bit Get18B20Temp(int *temp)
{
bit ack;
unsigned char LSB, MSB; //16bit温度值的低字节和高字节
ack = Get18B20Ack(); //执行总线复位,并获取18B20应答
if(ack == 0) //如18B20正确应答,则读取温度值
{
DS18B20Write(0xCC); //跳过ROM操作
DS18B20Write(0xBE); //发送读命令
LSB = DS18B20Read(); //读温度值的低字节
MSB = DS18B20Read(); //读温度值的高字节
*temp = ( MSB << 8) + LSB; //合成16bit的整数
}
return ~ack; //ack == 0 表示操作应答,所以返回值为1其取反值
}
ds18b20.h
#ifndef __DS18B20_H
#define __DS18B20_H
//单总线延时函数
void Delayus(unsigned int us);
bit Get18B20Ack(void);
void DS18B20Write(unsigned char dat);
unsigned char DS18B20Read(void);
bit Start18B20();
bit Get18B20Temp(int *temp);
#endif