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;
}