51单片机 简易温度采集与控制装置

MCU型号:IAP15F2K61S2

还好是1T的单片机,不知道换成普通的12T单片机会不会跪。。终于调统了,不过温度采集不太稳定,有1度的波动。

/*
**********************************************************************
                    简易温度采集与控制装置
文件名:main.c
功能概述:
    初始化数码管显示温度区间和当前温度,温度上限和温度下限默认为30度
    和20度,用户可以通过矩阵键盘输入自己设定的温度区间,键盘提供set和clear
    功能,首先按下set进入设置模式,
    输入错了可以倒退并修改。如果输入的区间不符合逻辑,即最大值比
    最小值还小,则L2灯常亮,提示用户输入错误,需重新倒退回输入,直到
    输入正确后L2灯才熄灭。输入完后按下set键返回温度实时显示模式。
    将当前温度和温度区间比较得到三个area,
    根据不同的area,L1灯分别以0.8s,0.4s,0.2s的频率闪烁。当温度超过
    温度上限时,继电器打开,执行相应的动作,否则关闭。
**********************************************************************
*/
#include "stc15f2k60s2.h"
#include "stdint.h"

extern pdata uint8_t dspBuf[8];
extern uint8_t tmr0LowByte, tmr0HighByte, tmr1LowByte, tmr1HighByte;

extern void keyDriver();
extern void keyScan();
extern void configTmr0Millis(uint8_t ms);
extern void configTmr1Millis(uint8_t ms);
extern void digitalTubeScan();
extern bit startDs18b20();
extern bit getDs18b20Temperature(int16_t * temp);
extern uint8_t getIntPart(int16_t temp);
extern uint8_t getDecPart(int16_t temp);
//extern void ledScan();

sbit led1 = P0^0;
sbit led2 = P0^1;
sbit relay = P0^4;

int16_t temperature;
uint8_t maxT = 30, minT = 20, intT, decT, area, nowArea;
bit flag1s = 0;
bit setData = 0;
uint16_t upper;	//timer1
code uint8_t dspInitMode1[8] = {
	11, 10, 10, 10, 10, 11, 10, 10
};					  //0  1  2	 3	4  5  6	 7
//code uint8_t next[8] = {0, 2, 6, 0, 0, 0, 7, 1};
//code uint8_t pre[8] =  {0, 7, 1, 0, 0, 0, 2, 6};
code uint8_t pos[5] = {0, 1, 2, 6, 7};

void init();
uint8_t calcArea();
void responseArea();
void operateRelay();

void main() {
	bit res;

	//init();
    configTmr0Millis(2);
	configTmr1Millis(10);
	startDs18b20();
    while (1) {
		keyDriver();
		if (flag1s) {
			flag1s = 0;
			res = getDs18b20Temperature(&temperature);
			if (res) {
				intT = getIntPart(temperature);
				decT = getDecPart(temperature);
				nowArea = calcArea();
				if (nowArea != area) {
					area = nowArea;
					responseArea();
				}

				if (setData == 0) {
					dspBuf[7] = decT;
					dspBuf[6] = decT % 10;
					dspBuf[5] = intT / 10;
					dspBuf[4] = 10;
					dspBuf[3] = 10;
					dspBuf[2] = 10;
					dspBuf[1] = area;
					dspBuf[0] = 11;
				}
			}
			startDs18b20();
		}
	}
}

void init() {
	uint8_t i;

	//minT = 20;
	//maxT = 30;
	for (i = 0; i < 8; i++)
		dspBuf[i] = dspInitMode1[i];
}

uint8_t calcArea() {
	if (intT < minT)
		return 0;
	else if (intT > maxT)
		return 2;
	else
		return 1;
}

void responseArea() {
	switch (area) {
	case 0:
		upper = 80;
		break;
	case 1:
		upper = 40;
		break;
	case 2:
		upper = 20;
	}
	operateRelay();
}

void keyAction(uint8_t keyCode) {

	//static uint8_t index = 1;
	static uint8_t cnt = 0;

	if (keyCode == 's') {	//如果按的是设置键
		if (setData == 0) {
			init();
			//index = 1;
			cnt = 0;
		} else if (cnt == 4) {

			dspBuf[0] = 11;
			dspBuf[1] = area;
			dspBuf[2] = 10;
			dspBuf[3] = 10;
			dspBuf[4] = 10;
			//dspBuf[5] = 10;
			//dspBuf[5] = temperature / 10;
			//dspBuf[6] = temperature % 10;
			//dspBuf[7] = decT;

		}
		setData = ~setData;
	} else if (0 <= keyCode && keyCode <= 9 && setData && cnt < 4) {
		cnt++;
		dspBuf[pos[cnt]] = keyCode;
		if (cnt == 2) {
			maxT = dspBuf[1]*10 + keyCode;
		}
		else if (cnt == 4){
			minT = dspBuf[6]*10 + keyCode;
			//area = calcArea();
			nowArea = calcArea();
			if (nowArea != area) {
				area = nowArea;
				responseArea();
			}
		}
	} else if (keyCode == 'c' && setData && cnt > 0) {
		dspBuf[pos[cnt]] = 10;
		cnt--;
	}
}

void setLeds() {
	static bit flag = 1;
	uint8_t tmp = 0xFF;

	if (maxT < minT) {
		tmp &= ~0x02;
	}
	if (flag) {
		tmp ^= 0x01;
	}
	P0 = 0xFF;	//消隐
	P2 = (P2 & 0x1F) | 0x80;	//选择led小灯
	P0 = tmp;
	P2 &= 0x1F;
	flag = ~flag;
}

void operateRelay() {
	uint8_t tmp;

	if (area == 2)
		tmp = 0x10;
	else
		tmp = 0x00;
	P0 = 0x00;
	P2 = (P2 & 0x1F) | 0xA0;	//选择电磁器件
	P0 = tmp;
	P2 &= 0x1F;
}

void tmr0Isr() interrupt 1 {	//2ms
	static uint16_t cnt = 0;

    TL0 = tmr0LowByte;
    TH0 = tmr0HighByte;
	digitalTubeScan();

	if (cnt == 499) {
		cnt = 0;
		flag1s = 1;
	} else {
		if (cnt & 0x01)
			keyScan();
		cnt++;
	}
}

void tmr1Isr() interrupt 3 {	//10ms
	static uint16_t cnt = 0;

	TL1 = tmr1LowByte;
	TH1 = tmr1HighByte;
	if (cnt < upper) {
		cnt++;
	} else {
		cnt = 0;
		setLeds();
	}
}

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

sbit ds18b20_io = P1^4;  //DS18B20通信引脚(先检查一下引脚是不是对的)
/* 软件延时函数,延时时间(t*10)us */
void delayX10us(uint16_t t) {
    t *= 6;
    do {
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
    } while (--t);
}
/* 复位总线,获取存在脉冲,以启动一次读写操作 */
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;
}



/*
**********************************************************
	文件名:keyBoard.c
**********************************************************
*/
#include "stc15f2k60s2.h"
#include "stdint.h"

sbit keyRow0 = P3^0;
sbit keyRow1 = P3^1;
sbit keyRow2 = P3^2;
sbit keyRow3 = P3^3;
//sbit keyCol0 = P3^7;
//sbit keyCol1 = P3^6;
sbit keyCol0 = P4^4;
sbit keyCol1 = P4^2;
sbit keyCol2 = P3^5;
sbit keyCol3 = P3^4;

code uint8_t keyMap[4][4] = {
    {0, 1, 2, 19},
    {3, 4, 5, 18},
    {6, 7, 8, 17},
    {9, 's', 'c', 16}
};
pdata uint8_t keyState[4][4] = {  //全部矩阵按键的当前状态
    {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}
};

extern void keyAction(uint8_t keyCode);

void keyDriver() {  //在主循环中调用
    uint8_t i, j;
    static uint8_t backup[4][4] = { //矩阵按键上一次的状态
        {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}
    };

    for (i = 0; i < 4; i++)
        for (j = 0; j < 4; j++) //依次判断每一个按键
            if (keyState[i][j] != backup[i][j]) {   //如果这个按键当前的状态和上一次的状态不同
                if (keyState[i][j] == 0)    //如果当前的状态是按下去了(在按键的前沿触发执行程序)
                    keyAction(keyMap[i][j]);
                backup[i][j] = keyState[i][j];  //备份当前的状态
            }
}

void keyScan() {    //每执行一次扫一行,每一个按键的采样周期为4个定时器周期
    static uint8_t i = 0; //按键扫描的行索引
    static uint8_t keyBuf[4][4] = {   //每一个按键的流水时序采样状态,保存8个样本点
        {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF},
        {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}
    };
    uint8_t j;    //按键扫描的列索引

	P3 = ~(1 << i);		//选择当前行(0有效)
    keyBuf[i][0] = (keyBuf[i][0] << 1) | keyCol0;   //流水保存采样结果
    keyBuf[i][1] = (keyBuf[i][1] << 1) | keyCol1;
    keyBuf[i][2] = (keyBuf[i][2] << 1) | keyCol2;
    keyBuf[i][3] = (keyBuf[i][3] << 1) | keyCol3;
    for (j = 0; j < 4; j++) {   //读取当前行各按键的采样信息,由此更新按键的当前状态
        if ((keyBuf[i][j] & 0x0F) == 0x00)   //取最近的4个样本点,这里一定要加括号,否则编译会出问题
            keyState[i][j] = 0;
        else if ((keyBuf[i][j] & 0x0F) == 0x0F)
            keyState[i][j] = 1;
    }
    i = (i + 1) & 0x03; //切换至下一个行索引,为下一次扫描做好准备
}

/*
**********************************************
	文件名:digitalTube.c
**********************************************
*/
#include "stc15f2k60s2.h"
#include "stdint.h"

sbit led1 = P0^0;
sbit led2 = P0^1;

code uint8_t tab[] = {    //  0    1    2    3    4    5    6    7    8    9	null	fenGeFu
    0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xFF,0xBF
};
pdata 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;
}
/*
void ledScan() {
		static bit flag = 0;

		P2 = (P2 & 0x1F) | 0x80;
		if (flag)
			P0 = 0xFE;
		else
			P0 = 0xFF;
		//led1 = ~led1;
		P2 &= 0x1F;
		flag = ~flag;
}
*/

/*
**********************************************************
	文件名:timer.c
**********************************************************
*/
#include "stc15f2k60s2.h"
#include "stdint.h"
#define MACHINE_CYCLE 11059200

uint8_t tmr0LowByte,tmr0HighByte;
uint8_t	tmr1LowByte, tmr1HighByte;

//timer0
void configTmr0Millis(uint8_t ms) {
    uint32_t tmp;

    tmp = 11059200; 
    tmp = ((uint32_t)ms * tmp) / 1000;
    tmp = 65536 - tmp;
    tmp += 12;
    tmr0LowByte = (uint8_t)tmp;
    tmr0HighByte = (uint8_t)(tmp >> 8);
	AUXR |= 0x80;		//定时器时钟1T模式
    TMOD &= 0xF0;
    TMOD |= 0x01;
    TL0 = tmr0LowByte;
    TH0 = tmr0HighByte;
    EA = 1;
    ET0 = 1;
    TR0 = 1;
}
//timer1
void configTmr1Millis(uint8_t ms) {
    uint32_t tmp;

    tmp = 11059200; 
    tmp = ((uint32_t)ms * tmp) / 1000;
    tmp = 65536 - tmp;
    tmp += 12;
    tmr1LowByte = (uint8_t)tmp;
    tmr1HighByte = (uint8_t)(tmp >> 8);
	AUXR |= 0x40;		//定时器时钟1T模式
    TMOD &= 0x0F;
    TMOD |= 0x10;
    TL1 = tmr1LowByte;
    TH1 = tmr1HighByte;
    EA = 1;
    ET1 = 1;
    TR1 = 1;
}


你可能感兴趣的:(51单片机)