一、前言
从今天开始,笔者将向大家逐一讲解蓝桥杯的大部分竞赛模块,笔者将基于上一篇文章(蓝桥杯单片机设计与开发_标准模板)中讲解的标准模板编写程序。按照顺序(DS18B20、DS1302、PCF8591、AT24C02、PWM、串口通信、NE555以及超声波测距),为大家做出详细编程指导。
二、DS18B20 温度传感器
DS18B20 又叫温度传感器。笔者将基于蓝桥杯官方给的赛点资源包(蓝桥杯单片机设计与开发_赛点资源数据包)进行编程,为大家讲解编程调用各语句的含义,帮助大家编写温度传感器的程序,也便于大家记忆。
1、导入底层驱动代码
首先,创建工程和导入.c文件笔者已在文章(蓝桥杯单片机设计与开发_标准模板)中向大家详细介绍了,这里就不再赘述。
读者可下载赛点资源包(蓝桥杯单片机设计与开发_赛点资源数据包),解压后可得到以下图片所示文件。
我们双击打开文件“3-底层驱动代码参考”文件,将得到以下.c.h文件。接下来将包含DS18B20 的文件onewire.c 和 onewire.h 文件拷贝到工程所在文件夹中。
然后双击工程中 Source Group 1,将这两个文件导入,便可以开始编写程序了。
2、DS18B20驱动函数
首先,在编写驱动函数之前,我们需要对底层驱动代码 onewire.c 中的延迟函数 Delay_OneWire() 做出修改,将延迟时间增大 12 倍!。因为比赛使用的IAP15系列单片机速度比STC89C52系列单片机速度快12倍,如果不改时序上将出现问题,无法正常读取温度。
笔者采用一个 for 循环,在 while 循环中重复循环 12 次,达到延迟效果。
void Delay_OneWire(u16 t) //STC89C52RC
{
u8 num; //定义计数变量
while(t--)
for(num = 0;num <= 12;num++); //延迟时长扩大12倍
}
接下来,就开始在 onewire.c 文件中编写温度读取函数。我们可以打开赛点资源数据包中的文件“5-竞赛板芯片资料”。
打开“DS18B20”芯片手册。笔者将借助芯片手册中的资料编写温度读取函数并为大家讲解。
温度读取函数:在编写温度读取函数时,我们只需要通过调用底层驱动函数中的初始化、写入、读取函数。
int rd_temperature(void) //读取温度函数
{
int temp = 0; //定义温度读取返回值
u8 tmh,tml; //定义温度读取高八位和第八位
init_ds18b20(); //设备初始化
Write_DS18B20(0xcc); //跳过ROM地址指令
Write_DS18B20(0x44); //安装温度转换指令
init_ds18b20();
Write_DS18B20(0xcc); //跳过ROM地址指令
Write_DS18B20(0xbe); //安装温度读取指令
tml=Read_DS18B20(); //读取低八位
tmh=Read_DS18B20(); //读取高八位
//将温度高八位和低八位组合成16位int类型
temp = tmh;
temp <<= 8;
temp |= tml;
return temp; //返回温度读取值
}
其中,在写入函数 Write_DS18B20() 写入的指令可通过查阅芯片资料手册,不需要死记硬背。
在编写完温度传感器驱动函数后务必要在 onewire.h 文件中声明函数,才可在主函数中调用。
#ifndef __ONEWIRE_H
#define __ONEWIRE_H
int rd_temperature(); //声明函数
#endif
3、主函数调用
在主函数中调用温度传感器驱动函数,首先需要在主函数开头包含驱动 DS18B20 驱动函数的头文件。
#include "STC15F2K60S2.h" //头文件
#include "onewire.h" //包含DS18B20驱动头文件
温度数值转换函数
编写温度数据转换函数需要注意的是:读取温度数值需要再乘以 0.0625 转换成十进制温度值。笔者将读取温度值读取到小数点后四位,采用的方法是将乘以 0.0625 后的数据放大 10000 倍,再通过取余除数的方法得到各位小数值。因数值放大到百万级别,因此需要定义长整型数值。
得到各位数后,通过改变缓冲区 dspbuf 的数值,在数码管1~7中显示读取到的温度数值。
void datachange(long int temp) //读取温度数据转换函数
{
temp = temp*0.0625*10000; //放大10000倍,读取小数点后四位
dspbuf[1] = temp/1000000; //取温度的百位数
dspbuf[2] = temp%1000000/100000; //取温度的十位数
dspbuf[3] = temp%100000/10000+11; //取温度个位数并加上小数点
dspbuf[4] = temp%10000/1000; //取温度的小数点第一位
dspbuf[5] = temp%1000/100; //取温度的小数点第二位
dspbuf[6] = temp%100/10; //取温度的小数点第三位
dspbuf[7] = temp%10; //取温度的小数点第四位
}
除此之外,笔者将个位数后的小数点显示出来,采取的方法是在定义 tab 数组时,在后面再定义十个小数点点亮的数,即通过将 0~9 对应的高八位减去 8,即可点亮小数点 dp 位。再在数码管显示的缓冲区上加上 11,即可显示带小数点的数字。
u8 code tab[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10}; //定义数组存放数码管数字状态
中断函数
笔者在中断函数中定义每 50ms 产生一次中断,将温度读取标志位置 1,进行温度读取。
bit temp_flag = 0; //定义温度读取标志位
void timer0() interrupt 1 //定义中断模式1
{
static u8 t_20ms = 0; //定义静态变量计时20ms
static u8 t_50ms = 0; //定义静态变量计时50ms
display(); //数码管显示函数
t_20ms++; //计数自增
t_50ms++; //计数自增
if(t_20ms >= 10) //判断计时时间
{
t_20ms = 0; //计数清零
key_flag = 1; //按键标志位置1
}
if(t_50ms >= 10) //判断计时时间
{
t_50ms = 0; //计数清零
temp_flag = 1; //温度标志位置1
}
}
main主函数
笔者在主函数开头中定义温度读取开关变量 temp_w,通过与 1 异或,可实功能:按一次 S4 打开温度传感器,每 50ms 读取一次温度;再按一次 S4 关闭温度传感器。
void main() //主函数
{
u8 key_re; //定义变量读取按键返回值
u8 temp_w = 0; //定义温度读取开关变量
all_init(); //初始化函数
Timer0Init(); //定时器0初始化
while(1)
{
if(key_flag) //每20ms扫描一次按键
{
key_flag = 0; //标志位置0
key_re = Read_key(); //读取按键
if(key_re != 0xff) //判断按键是否按下
{
//判断按键
switch(key_re)
{
//放入需要执行的功能
case 4: temp_w ^= 1;break; //按一次按键打开/关闭温度传感器
}
}
}
if((temp_w) && (temp_flag)) //定义温度读取函数
{
temp_flag = 0; //清空标志位
datachange(rd_temperature()); //调用温度读取及转换函数
}
}
}
至此,本次 DS18B20 温度传感器程序已编写完毕。由于笔者近期事情比较多,更新文章较慢,请各位见谅。接下来几天笔者也将尽量早点将各个模块的编程都更新完毕!欢迎读者在评论区交流!!