STC15系列单片机-环境监控设备


main.c

/**
 *	产品名称:环境监控设备
 *	产品定义:
 *	(1)单片机每隔1秒通过DS18B20温度传感器采集一次温度。
 *	(2)单片机每隔200毫秒采集一次DS1302时钟芯片的时间。
 *	(3)通过数码管实时显示时间,格式为日-小时-分-秒。
 *	(4)通过串口向上位机发送格式提示字符串,设置温度上限和下限;
 *		格式为xx-yy
 *	(5)可以通过串口设置温度上限和下限。
 *	(6)单片机将每次采集到的温度实时通过串口传送给上位机;
 *		如果温度超过阈值,都将给出警告提示。
 *	版本:debug
 *	完成时间:2015.4.5 17:00
 *	作者:宁静致远
 */

#include <stc15f2k60s2.h>
#include <stdio.h>
#include "stdint.h"
#include "DS1302.h"
#include "DS18B20.h"
#include "UART.h"
#include "digitalTube.h"
#include "timer.h"
//#include "main.h"

volatile bit flag1s = 0, flag200ms = 0;

uint8_t serialBuf[10];
volatile uint8_t front = 0, rear = 0;

void main() {
	int16_t temperature;
	uint8_t intPart, decPart;
	uint8_t maxTempInt = 21, maxTempDec = 0;
	uint8_t minTempInt = 20, minTempDec = 0;

	uint8_t intPart0, intPart1, decPart1;
	//bit tempSign;
	sTime_t stime;
	uint8_t preSec;	
	
	configTmr0(2);
	configUART(9600);	//设置正确的波特率
	startDS18B20();	//!!
	DS1302init();

	ES = 0;
	TI = 1;
	printf("input format: xx-yy\n");
	while (TI == 0);
	TI = 0;
	ES = 1;

	while (1) {
		if (flag1s) {	//温度每隔1s采样一次
			flag1s = 0;
			getDS18B20temperature(&temperature);
			startDS18B20();	//!!
			intPart = getIntPart(temperature);
			decPart = getDecPart(temperature);
			
			intPart1 = intPart / 10 + '0';
			intPart0 = intPart % 10 + '0';
			decPart1 = decPart  + '0';

			if (intPart > maxTempInt || (intPart == maxTempInt && decPart > maxTempDec)) {
				ES = 0;
				TI = 1;
				printf("warning: too high\n");
				while (TI == 0);
				TI = 0;
				ES = 1;
			} else if (intPart < minTempInt || (intPart == minTempInt && decPart < minTempDec)) {
				ES = 0;
				TI = 1;
				printf("warning: too low\n");
				while (TI == 0);
				TI = 0;
				ES = 1;	
			} else {
				ES = 0;
				TI = 1;
				//printf("The temp is %u %u\n", intPart, decPart);
				//printf("decPart: %hu\n", decPart);
				printf("The temperature is %c%c.%c\n", intPart1, intPart0, decPart1);
				while (TI == 0);
				TI = 0;
				ES = 1;
			}
		}
		if (flag200ms) {	//时间每隔200ms采样一次
			flag200ms = 0;
			getRealTime(&stime);
			
			if (stime.sec != preSec) {	//BCD码!为16进制!
				dspBuf[0] = stime.day >> 4;
				dspBuf[1] = stime.day & 0x0F;
				dspBuf[2] = stime.hour >> 4;
				dspBuf[3] = stime.hour & 0x0F;
				dspBuf[4] = stime.minute >> 4;
				dspBuf[5] = stime.minute & 0x0F;
				dspBuf[6] = stime.sec >> 4;
				dspBuf[7] = stime.sec & 0x0F;
				preSec = stime.sec;
			}
		}
		if (rear == 5) {
			rear = 0;
			minTempInt = (serialBuf[0] - '0') * 10 + 
						serialBuf[1] - '0';
			maxTempInt = (serialBuf[3] - '0') * 10 + 
						serialBuf[4] - '0';
		}

	}
}

void UARTreceive() {
	serialBuf[rear] = SBUF;
	if (rear == 9)
		rear = 0;
	else 
		rear++;
}

void UARTtransmit() { }

void tmr0ISR() interrupt 1 {
	static uint16_t cnt = 0;

	TL0 = tmr0LowByte;
	TH0 = tmr0HighByte;

	digitalTubeScan();
	if (cnt == 499) {
		cnt = 0;
		flag1s = 1;
	} else {
		cnt++;
	}
	if ((cnt+1) % 100 == 0)
		flag200ms = 1;
}


DS1302.h

#ifndef _DS1302_H
#define _DS1302_H

sbit DS1302_CE = P1^3;		//!!!检查引脚是否正确!
sbit DS1302_SCLK = P1^7;
sbit DS1302_IO = P2^3;

typedef struct sTime {  //日期时间结构体定义
    uint16_t year;  //年
    uint8_t mon;   //月
    uint8_t day;   //日
    uint8_t hour;  //时
    uint8_t minute;   //分
    uint8_t sec;   //秒
    uint8_t week;  //星期
} sTime_t;

void DS1302byteWrite(uint8_t dat);
uint8_t DS1302byteRead();
void DS1302singleWrite(uint8_t reg, uint8_t dat);
uint8_t DS1302singleRead(uint8_t reg);
void DS1302burstWrite(uint8_t * dat);
void DS1302burstRead(uint8_t * dat);
void getRealTime(sTime_t * time);
void setRealTime(sTime_t * time);
void DS1302init();

#endif // _DS1302_H


DS1302.c

/*
 * 文件名:DS1302.c
 * 描  述:实时时钟芯片DS1302驱动模块
 */

#include <stc15f2k60s2.h>
#include "stdint.h"
#include "DS1302.h"

/* 发送一个字节到DS1302通信总线上 */
void DS1302byteWrite(uint8_t dat) {
    uint8_t mask;

    for (mask = 0x01; mask != 0; mask <<= 1) {   //低位在前,逐位移出
        if ((mask & dat) != 0) //首先输出该位数据
            DS1302_IO = 1;
        else
            DS1302_IO = 0;
        DS1302_SCLK = 1;       //然后拉高时钟
        DS1302_SCLK = 0;       //再拉低时钟,完成一个位的操作
    }
    DS1302_IO = 1;           //最后确保释放IO引脚
}
/* 由DS1302通信总线上读取一个字节 */
uint8_t DS1302byteRead() {
    uint8_t mask, dat = 0;

    for (mask = 0x01; mask != 0; mask <<= 1) {   //低位在前,逐位读取
        if (DS1302_IO != 0) {   //首先读取此时的IO引脚,并设置dat中的对应位
            dat |= mask;
        }
        DS1302_SCLK = 1;       //然后拉高时钟
        DS1302_SCLK = 0;       //再拉低时钟,完成一个位的操作
    }
    return dat;              //最后返回读到的字节数据
}
/* 用单次写操作向某一寄存器写入一个字节,reg-寄存器地址,dat-待写入字节 */
void DS1302singleWrite(uint8_t reg, uint8_t dat) {
    DS1302_CE = 1;                   //使能片选信号
    DS1302byteWrite((reg << 1) | 0x80);  //发送写寄存器指令
    DS1302byteWrite(dat);            //写入字节数据
    DS1302_CE = 0;                   //除能片选信号
}
/* 用单次读操作从某一寄存器读取一个字节,reg-寄存器地址,返回值-读到的字节 */
uint8_t DS1302singleRead(uint8_t reg) {
    uint8_t dat;

    DS1302_CE = 1;                   //使能片选信号
    DS1302byteWrite((reg << 1) | 0x81);  //发送读寄存器指令
    dat = DS1302byteRead();          //读取字节数据
    DS1302_CE = 0;                   //除能片选信号

    return dat;
}
/* 用突发模式连续写入8个寄存器数据,dat-待写入数据指针 */
void DS1302burstWrite(uint8_t * dat) {
    uint8_t i;

    DS1302_CE = 1;
    DS1302byteWrite(0xBE);  //发送突发写寄存器指令
    for (i = 0; i < 8; i++) {   //连续写入8字节数据
        DS1302byteWrite(dat[i]);
    }
    DS1302_CE = 0;
}
/* 用突发模式连续读取8个寄存器的数据,dat-读取数据的接收指针 */
void DS1302burstRead(uint8_t * dat) {
    uint8_t i;

    DS1302_CE = 1;
    DS1302byteWrite(0xBF);  //发送突发读寄存器指令
    for (i = 0; i < 8; i++) {   //连续读取8个字节
        dat[i] = DS1302byteRead();
    }
    DS1302_CE = 0;
}
/* 获取实时时间,即读取DS1302当前时间并转换为时间结构体格式 */
void getRealTime(sTime_t * time) {
    uint8_t buf[8];

    DS1302burstRead(buf);
    time->year = buf[6] + 0x2000;
    time->mon  = buf[4];
    time->day  = buf[3];
    time->hour = buf[2];
    time->minute = buf[1];
    time->sec  = buf[0];
    time->week = buf[5];
}
/* 设定实时时间,时间结构体格式的设定时间转换为数组并写入DS1302 */
void setRealTime(sTime_t * time) {
    uint8_t buf[8];

    buf[7] = 0;
    buf[6] = time->year;
    buf[5] = time->week;
    buf[4] = time->mon;
    buf[3] = time->day;
    buf[2] = time->hour;
    buf[1] = time->minute;
    buf[0] = time->sec;
    DS1302burstWrite(buf);
}
/* DS1302初始化,如发生掉电则重新设置初始时间 */
void DS1302init() {
    uint8_t dat;
    sTime_t code InitTime[] = {  //2015年4月5日 12:30:00 星期日
								 //2013年10月8日 12:30:00 星期二
        0x2015, 0x04, 0x05, 0x12, 0x30, 0x00, 0x07
		//0x2013, 0x10, 0x08, 0x12, 0x30, 0x00, 0x02
    };

    DS1302_CE = 0;  //初始化DS1302通信引脚
    DS1302_SCLK = 0;
    dat = DS1302singleRead(0);  //读取秒寄存器
    if ((dat & 0x80) != 0) {   //由秒寄存器最高位CH的值判断DS1302是否已停止
        DS1302singleWrite(7, 0x00);  //撤销写保护以允许写入数据
        setRealTime(&InitTime);      //设置DS1302为默认的初始时间
    }
}


DS18B20.h

#ifndef _DS18B20_H
#define _DS18B20_H

sbit DS18B20_IO = P1^4; //DS18B20通信引脚

//#ifndef _1T
//void delayX10us(uint8_t t);
//#else
void delayX10us(uint16_t t);
//#endif // _1T
bit getDS18B20ack();
void writeDS18B20(uint8_t dat);
uint8_t readDS18B20();
bit startDS18B20();
bit getDS18B20temperature(int16_t * temp);
uint8_t getIntPart(int16_t temp);
uint8_t getDecPart(int16_t temp);
bit getSign(int16_t temp);

#endif // _DS18B20_H


DS18B20.c

/**
 * 文件名:DS18B20.c
 * 描  述:温度传感器DS18B20驱动模块
 */
#include <stc15f2k60s2.h>
#include <intrins.h>
#include "stdint.h"
#include "DS18B20.h"

/* 软件延时函数,延时时间(t*10)us */
//#ifndef _1T
/*
void delayX10us(uint8_t t) {    //时钟晶振11.0592MHz
    do {
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
    } while (--t);
}
*/
//#else
void delayX10us(uint16_t t) {   //注意!uint8_t会溢出!
    t *= 6;
    do {
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
    } while (--t);
}
//#endif // 1T
/* 复位总线,获取存在脉冲,以启动一次读写操作 */
bit getDS18B20ack() {
    bit ack;

    EA = 0;   //禁止总中断
    DS18B20_IO = 0;     //产生500us复位脉冲
    delayX10us(50);
    DS18B20_IO = 1;
    delayX10us(6);    //延时60us
    ack = DS18B20_IO;   //读取存在脉冲
    while (!DS18B20_IO); //等待存在脉冲结束
    EA = 1;   //重新使能总中断

    return ack;
}
/* 向DS18B20写入一个字节,dat-待写入字节 */
void writeDS18B20(uint8_t dat) {
    uint8_t mask;

    EA = 0;   //禁止总中断
    //低位在先,依次移出8个bit
    for (mask = 0x01; mask != 0; mask <<= 1) {
        DS18B20_IO = 0;         //产生2us低电平脉冲
        _nop_();
        _nop_();
        if ((mask & dat) == 0)  //输出该bit值
            DS18B20_IO = 0;
        else
            DS18B20_IO = 1;
        delayX10us(6);        //延时60us
        DS18B20_IO = 1;         //拉高通信引脚
    }
    EA = 1;   //重新使能总中断
}
/* 从DS18B20读取一个字节,返回值-读到的字节 */
uint8_t readDS18B20() {
    uint8_t dat, mask;

    EA = 0;   //禁止总中断
    //低位在先,依次采集8个bit
    for (mask = 0x01; mask != 0; mask <<= 1) {
        DS18B20_IO = 0;         //产生2us低电平脉冲
        _nop_();
        _nop_();
        DS18B20_IO = 1;         //结束低电平脉冲,等待18B20输出数据
        _nop_();              //延时2us
        _nop_();
        if (DS18B20_IO)        //读取通信引脚上的值
            dat |= mask;
        else
            dat &= ~mask;
        delayX10us(6);        //再延时60us
    }
    EA = 1;   //重新使能总中断

    return dat;
}
/* 启动一次18B20温度转换,返回值-表示是否启动成功 */
bit startDS18B20() {
    bit ack;

    ack = getDS18B20ack();   //执行总线复位,并获取18B20应答
    //如18B20正确应答,则启动一次转换
    if (ack == 0) {
        writeDS18B20(0xCC);  //跳过ROM操作
        writeDS18B20(0x44);  //启动一次温度转换
    }
    return ~ack;   //ack==0表示操作成功,所以返回值对其取反
}
/* 读取DS18B20转换的温度值,返回值-表示是否读取成功 */
bit getDS18B20temperature(int16_t * temp) { //温度有正负,有符号
    bit ack;
    uint8_t lowByte, highByte; //16bit温度值的低字节和高字节

    ack = getDS18B20ack();    //执行总线复位,并获取18B20应答
    //如18B20正确应答,则读取温度值
    if (ack == 0) {
        writeDS18B20(0xCC);   //跳过ROM操作
        writeDS18B20(0xBE);   //发送读命令
        lowByte = readDS18B20();  //读温度值的低字节
        highByte = readDS18B20();  //读温度值的高字节
        *temp = ((int16_t)highByte << 8) | lowByte;  //合成为16bit有符号整型数
    }
    return ~ack;  //ack==0表示操作应答,所以返回值为其取反值
}

uint8_t getIntPart(int16_t temp) {  //温度是16位有符号数
    if (temp & 0x8000)  //温度是负数
        temp = -temp;   //取绝对值
    temp >>= 4;
    return (uint8_t)temp;
}

uint8_t getDecPart(int16_t temp) {  //精确到十进制的一位小数(截尾处理)
    uint8_t lowByte;

    if (temp & 0x8000)  //温度是负数
        temp = -temp;   //取绝对值
    lowByte = temp;     //取低字节
    lowByte &= 0x0F;    //高4位清0
    return (lowByte * 10) >> 4; //乘以10,除以16
}

bit getSign(int16_t temp) {   //温度是16位有符号数
    return temp & 0x8000;
}

UART.h

/**
 * 文件名:UART.h
 * 描  述:UART驱动模块
 */

#ifndef _UART_H_
#define _UART_H_

void configUART(uint16_t baud);

extern void UARTreceive();
extern void UARTtransmit();

#endif // _UART_H_

UART.c

/**
 * 文件名:UART.c
 * 描  述:UART驱动模块
 */

#include <stc15f2k60s2.h>
#include "stdint.h"
#include "UART.h"

/* 串口配置函数,baud-通信波特率 */
void configUART(uint16_t baud) {
	PCON &= 0x7F;		//波特率不倍速
    SCON = 0x50;    //配置串口为模式1,并使能串行接收(SM0=0,SM1=1,REN=1)
	AUXR &= 0xBF;		//定时器1时钟为Fosc/12,即12T
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
    TMOD &= 0x0F;   //清零T1的控制位
    TMOD |= 0x20;   //配置T1为模式2
    TL1 = 256 - 11059200 / 12 / 32 / baud;  //计算T1初值
    TH1 = TL1;      //重载值等于初值
    EA = 1;         //使能总中断
    ET1 = 0;        //禁止T1中断
    ES  = 1;        //使能串口中断
    TR1 = 1;        //启动T1
}
/* UART中断服务函数 */
void UART_ISR() interrupt 4 {
    if (RI) {   //接收到字节
        RI = 0;  //手动清零接收中断标志位
        UARTreceive();  //从SBUF中取出数据
    }
    if (TI) {   //字节发送完毕
        TI = 0;  //手动清零发送中断标志位
        UARTtransmit(); //将数据赋值给SBUF
    }
}




digitalTube.h

#ifndef _DIGITAL_TUBE_H
#define _DIGITAL_TUBE_H


extern uint8_t code tab[];
extern uint8_t dspBuf[8];

void digitalTubeScan();

#endif

digitalTube.c

#include <stc15f2k60s2.h>
#include "stdint.h"
#include "digitalTube.h"

uint8_t code tab[] = {    //  0    1    2    3    4    5    6    7    8    9	null
    0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xFF
};
uint8_t dspBuf[8] = {
    10, 10, 10, 10, 10, 10, 10, 10
};  //显示缓冲区

void digitalTubeScan() {
    static uint8_t index = 0;

    P2 = (P2 & 0x1F) | 0xE0;    //使能具体值
    P0 = 0xFF;                    //消隐
    P2 &= 0x1F;                    //锁存

    P2 = (P2 & 0x1F) | 0xC0;    //使能位选
    P0 = (1 << index);            //数码管选择是1有效
    P2 &= 0x1F;

    P2 = (P2 & 0x1F) | 0xE0;    //使能具体值
    P0 = tab[dspBuf[index]];    //
    P2 &= 0x1F;

    index = (index + 1) & 0x07;
}

timer.h

#ifndef _TIMER_H
#define _TIMER_H

#define SYS_MCLK 11059200

extern uint8_t tmr0LowByte, tmr0HighByte;
//extern uint8_t tmr1LowByte, tmr1HighByte;

void configTmr0(uint8_t ms);
//void configTmr1(uint8_t ms);

#endif

timer.c

#include <stc15f2k60s2.h>
#include "stdint.h"
#include "timer.h"

uint8_t tmr0LowByte, tmr0HighByte;
//uint8_t tmr1LowByte, tmr1HighByte;

void configTmr0(uint8_t ms) {	//!!8bits
	uint32_t tmp;	//小心溢出

	tmp = ms * SYS_MCLK / 12 / 1000;
	tmp = 65536 - tmp;
	tmr0LowByte = (uint8_t)tmp;
	tmr0HighByte = (uint8_t)(tmp >> 8);

	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;
	TMOD |= 0x01;
	TL0 = tmr0LowByte;
	TH0 = tmr0HighByte;
	EA = 1;
	ET0 = 1;
	TR0 = 1;
}
/*
void configTmr1(uint8_t ms) {	//!!8bits
	uint32_t tmp;

	tmp = ms * SYS_MCLK / 12 / 1000;
	tmp = 65536 - tmp;
	tmr1LowByte = (uint8_t)tmp;
	tmr1HighByte = (uint8_t)(tmp >> 8);

	AUXR &= 0xBF;
	TMOD &= 0x0F;
	TMOD |= 0x10;
	TL1 = tmr1LowByte;
	TH1 = tmr1HighByte;
	EA = 1;
	ET1 = 1;
	TR1 = 1;
}
*/

stdint.h

#ifndef STDINT_H_INCLUDED
#define STDINT_H_INCLUDED

typedef unsigned char uint8_t;
typedef unsigned int uint16_t;
typedef unsigned long uint32_t;
typedef signed char int8_t;
typedef signed int int16_t;
typedef signed long int32_t;

#endif // STDINT_H_INCLUDED



你可能感兴趣的:(STC15系列单片机-环境监控设备)