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 <reg52.h> #include <intrins.h> #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; }
/* ********************************************** 文件名: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; }
/* ********************************************************** 文件名: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; //切换至下一个行索引,为下一次扫描做好准备 }