/** * 51单片机项目:多功能记录仪 * 文件名:main.h */ #ifndef _MAIN_H #define _MAIN_H typedef struct msg { uint8_t hour; //时 uint8_t minute; //分 uint8_t second; //秒 uint8_t tempIntPart; //温度 uint8_t humidity; //湿度 uint8_t resTime; //物品停留时间 } msg_t; typedef void (code * pFn)(); //定义函数指针类型,该指针指向code存储区 void sys_init(); void samplingDS1302(); void samplingPCF8591(); void samplingDS18B20(); void writeAndReadEEPROM(); void keyAction(uint8_t keyCode); //void printTime(); //void printTemAndHum(); //void printResT(); void dispMode0(); void dispMode1(); void dispMode2(); void LED_init(); void LEDchangeMode(); void LED3toggle(); #endif
/** * 项目名称:多功能记录仪 * 功能概述:能测量实时时间、温度、湿度、物品停留时间; * 能从EEPROM存/取测量到的数据; * 能通过串口和上位机通信。 * 工作模式0:自动传输模式(上电默认) * 工作模式1:自动记录模式 * 用户操作: * (1)按键S5切换工作模式 * (2)按键S4切换显示模式 * (3)当记录仪工作在两种模式下时,只有当用户发送字符"AAASSS"给单片机, * 单片机才把数据传送给上位机显示。 * * 文件名:main.c */ #include <stc15f2k60s2.h> #include <string.h> #include "stdint.h" #include "timer.h" #include "digitalTube.h" #include "independentKey.h" #include "Serial.h" #include "I2C.h" #include "EEPROM.h" #include "PCF8591.h" #include "OneWire.h" #include "DS18B20.h" #include "DS1302.h" #include "main.h" //sbit LED_1 = P0^0; //sbit LED_2 = P0^1; //sbit LED_3 = P0^2; volatile bit flag200ms = 0, flag300ms = 0, flag1s = 0; //周期性任务的标志 pFn code disptr[3] = { dispMode0, dispMode1, dispMode2 }; //显示模式 uint8_t disptrIndex = 0; bit workingMode = 0; //为0表示自动传输模式;为1表示自动记录模式 bit isShading = 0; //是否被遮光的标志 msg_t message; uint8_t SerialBuf[7], SerialBufIndex = 0; //串口数据缓存 uint8_t leds_state = ~0x01; //上电默认为模式1 void main() { sys_init(); while (1) { keyDriver(); if (flag200ms) { //200ms采集一次实时时间 flag200ms = 0; samplingDS1302(); } if (flag300ms) { //300ms采集一次模拟量 flag300ms = 0; samplingPCF8591(); } if (flag1s) { //1s采集一次温度 flag1s = 0; samplingDS18B20(); if (workingMode) { //如果工作于自动记录模式 writeAndReadEEPROM(); } } } } void sys_init() { tmr0_init(2); DS18B20_start(); DS1302init(); Serial_init(1200); //baudrate=1200 LED_init(); } void samplingDS1302() { //200ms sTime_t time; static uint8_t preSec; DS1302_getRealTime(&time); if (time.sec != preSec) { //秒有变化 message.hour = (time.hour >> 4) * 10 + (time.hour & 0x0F); //将BCD码解码 message.minute = (time.minute >> 4) * 10 + (time.minute & 0x0F); message.second = (time.sec >> 4) * 10 + (time.sec & 0x0F); if (disptrIndex == 0) { dispMode0(); } preSec = time.sec; } } void samplingPCF8591() { //300ms uint8_t chn1Sample, chn3Sample; static uint8_t cnt300ms = 0; chn1Sample = PCF8591_getADCvalue(1); //通道1的采样值 chn3Sample = PCF8591_getADCvalue(3); //通道3的采样值 message.humidity = (uint8_t)((uint16_t)chn3Sample * 99 / 255); if (chn1Sample < 128) { //如果遮光 cnt300ms++; isShading = 1; if ((cnt300ms * 3 / 10) != ((cnt300ms - 1) * 3 / 10)) { //如果秒数有变化则闪烁 LED3toggle(); //在这里闪烁更及时一些 } } else { //没有遮光 if (isShading) { //如果之前遮光(上升沿) message.resTime = cnt300ms * 3 / 10; cnt300ms = 0; //本次遮挡完毕,重置计时次数 } isShading = 0; } if (disptrIndex == 1) { //如果显示模式是1,则更新湿度显示 dspBuf[5] = message.humidity / 10; dspBuf[6] = message.humidity % 10; } else if (disptrIndex == 2) { //如果显示模式是2,则更新物品停留时间显示 dspBuf[6] = message.resTime / 10; dspBuf[7] = message.resTime % 10; } } void samplingDS18B20() { //1s int16_t temperature; uint8_t tempIntPart, tempDecPart; DS18B20_getTemperature(&temperature); DS18B20_start(); //!!!重新启动 tempIntPart = getIntPart(temperature); tempDecPart = getDecPart(temperature); if (tempDecPart >= 5) //四舍五入 tempIntPart++; message.tempIntPart = tempIntPart; if (disptrIndex == 1) { //如果是显示模式1,则更新温度显示 dspBuf[0] = message.tempIntPart / 10; dspBuf[1] = message.tempIntPart % 10; } /* if (isShading) { //如果被遮光,则LED3一秒钟闪烁一次 LED3toggle(); } */ } void writeAndReadEEPROM() { static uint8_t EEPROMwritingIndex = 0, EEPROMreadingIndex = 0; EEPROMwrite((uint8_t *)&message, EEPROMwritingIndex, sizeof (msg_t)); EEPROMwritingIndex += sizeof (msg_t); //这个EEPROM一共是256字节的存储空间 EEPROMread((uint8_t *)&message, EEPROMreadingIndex, sizeof (msg_t)); //写入后再读出 EEPROMreadingIndex += sizeof (msg_t); } void keyAction(uint8_t keyCode) { switch (keyCode) { case 4: if (disptrIndex == 2) { disptrIndex = 0; } else { disptrIndex++; } disptr[disptrIndex](); break; case 5: workingMode = ~workingMode; LEDchangeMode(); break; } } void Serial_receive() { SerialBuf[SerialBufIndex] = SBUF; if (SerialBufIndex == 5) { if (strncmp(SerialBuf, "AAASSS", 6) == 0) { //%bu用于输出uint8_t(byte unsigned) myprintf("{%bu-%bu-%bu}", message.hour, message.minute, message.second); myprintf("{%buC--%buH}", message.tempIntPart, message.humidity); if (workingMode == 0) { //如果工作于模式0 if (isShading) //如果现在被遮光了 myprintf("{--1--}\n"); else myprintf("{--0--}\n"); } else { //否则打印前一次的停留时间 myprintf("{--%bus}\n", message.resTime); } } SerialBufIndex = 0; } else { SerialBufIndex++; } } void Serial_transmit() { } void dispMode0() { static bit flag = 0; dspBuf[0] = message.hour / 10; //已经解码了 dspBuf[1] = message.hour % 10; dspBuf[2] = (flag ? 11 : 10); dspBuf[3] = message.minute / 10; dspBuf[4] = message.minute % 10; dspBuf[5] = (flag ? 11 : 10); dspBuf[6] = message.second / 10; dspBuf[7] = message.second % 10; flag = ~flag; } void dispMode1() { dspBuf[0] = message.tempIntPart / 10; dspBuf[1] = message.tempIntPart % 10; dspBuf[2] = 12; //C dspBuf[3] = 11; //- dspBuf[4] = 11; //- dspBuf[5] = message.humidity / 10; dspBuf[6] = message.humidity % 10; dspBuf[7] = 13; //H } void dispMode2() { dspBuf[0] = 11; dspBuf[1] = 10; dspBuf[2] = 10; dspBuf[3] = 0; dspBuf[4] = 0; dspBuf[5] = 0; dspBuf[6] = message.resTime / 10; dspBuf[7] = message.resTime % 10; } void LED_init() { P2 = (P2 & 0x1F) | 0x80; P0 = leds_state; P2 &= 0x1F; } void LEDchangeMode() { leds_state ^= 0x03; //将最低两位反转 P2 = (P2 & 0x1F) | 0x80; P0 = leds_state; P2 &= 0x1F; } void LED3toggle() { leds_state ^= 0x04; //将倒数第三位反转 P2 = (P2 & 0x1F) | 0x80; P0 = leds_state; P2 &= 0x1F; } void tmr0ISR() interrupt 1 { static uint16_t cnt = 0; TL0 = tmr0LowByte; TH0 = tmr0HighByte; cnt++; digitalTubeScan(); if (cnt & 0x01) keyScan(); if (cnt % 100 == 0) { flag200ms = 1; } if (cnt % 150 == 0) { flag300ms = 1; } if (cnt == 500) { cnt = 0; flag1s = 1; } }