main.c
/**
* 产品名称:环境监控设备
* 产品定义:
* (1)单片机每隔1秒通过DS18B20温度传感器采集一次温度。
* (2)单片机每隔200毫秒采集一次DS1302时钟芯片的时间。
* (3)通过数码管实时显示时间,格式为日-小时-分-秒。
* (4)通过串口向上位机发送格式提示字符串,设置温度上限和下限;
* 格式为xx-yy
* (5)可以通过串口设置温度上限和下限。
* (6)单片机将每次采集到的温度实时通过串口传送给上位机;
* 如果温度超过阈值,都将给出警告提示。
* 版本:debug
* 完成时间:2015.4.5 17:00
* 作者:宁静致远
*/
#include
#include
#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
#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
#include
#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
#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
}
}
#ifndef _DIGITAL_TUBE_H
#define _DIGITAL_TUBE_H
extern uint8_t code tab[];
extern uint8_t dspBuf[8];
void digitalTubeScan();
#endif
digitalTube.c
#include
#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
#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