本帖最后由 glmyc 于 2014-11-2 16:43 编辑
本程序参考了论坛上部分程序与设计思想,本程序能实现在有人在附近时,显示年月日然后显示时分秒再显示温度与湿度,无人时自动关闭显示。
难的是在淘宝购买的8位串口LED数码管,没有ARDUINO程序参考,只有51程序,参考了网上应用后写了以下程序,对使用别人程序成果表示感谢!
#include <stdio.h>
#include <string.h> //字符串处理头文件
#include <DS1302.h> //数字时钟模块头文件
#include <dht11.h> //温湿度传感器头文件
dht11 DHT11;
uint8_t CE_PIN = 3; //时钟模块的RST接ARDUINO的3脚、DAT接4脚、CLK接5脚
uint8_t IO_PIN = 4;
uint8_t SCLK_PIN = 5;
int DHT11pin = 2; //DHT11 接在2脚
int red = 6; //红外线探测接6脚
int dio = 8; //8位串口LED数码管DIO接8脚、RCLK接9脚、SCLK接10脚
int rclk = 9;
int sclk = 10;
/* 日期变量缓存 */
char buf1[50]; //显示年月日缓冲区
char buf2[50]; //显示时分秒缓冲区
char buf3[50]; //显示温度与湿度缓冲区
char day[10];
/* 串口数据缓存 */
String comdata = "";
int numdata[7] = {0}, j = 0, mark = 0;
/* 创建 DS1302 对象 */
DS1302 rtc(CE_PIN, IO_PIN, SCLK_PIN);
char char_map[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0x8C, 0xBF, 0xC6, 0xA1, 0x86, 0xFF, 0xBF};
char index_map[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '-'};
void ledout(unsigned char chr)
{
unsigned char i;
for (i = 8; i >= 1; i--)
{
if (chr & 0x80) {
digitalWrite(dio, 1);
} else {
digitalWrite(dio, 0);
}
chr <<= 1;
digitalWrite(sclk, 0);
digitalWrite(sclk, 1);
}
}
void ledshow(const char* str)
{
int len = strlen(str);
int hasDot = 0;
for (int i = len - 1, m = 0; i >= 0; i--) {
char chr = str;
if (chr == '.') {
hasDot = 1;
continue;
}
int n = 0;
for (; n < 17; n++) {
if (chr == index_map[n])
break;
}
if (n != 17) {
unsigned char chr1 = char_map[n];
if (hasDot)
chr1 &= 0x7f; //小数点处理
ledout(chr1);
ledout((int)ceil(pow(2, m)));
digitalWrite(rclk, 0);
digitalWrite(rclk, 1);
}
m++;
hasDot = 0;
}
}
void print_time()
{
for (int l = 0; l < 100; l++) { //有人后一直显示较长时间L=100,就可以显示9分多钟
Time t = rtc.time(); /* 从 DS1302 获取当前时间 */
memset(day, 0, sizeof(day)); /* 将星期从数字转换为名称 */
int chk = DHT11.read(DHT11pin);
int humi = DHT11.humidity;
int temper = DHT11.temperature;
snprintf(buf1, sizeof(buf1), "%04d.%02d.%02d", t.yr, t.mon, t.date); //格式化日期字符串
snprintf(buf2, sizeof(buf2), "%02d %02d %02d", t.hr, t.min, t.sec); //格式化时间字符串
snprintf(buf3, sizeof(buf3), "% 4d% 4d", temper, humi); //格式化温湿度
Serial.println(buf1); //串口监视一下需要显示的数据
Serial.println(buf2);
Serial.println(buf3);
//下面是显示相应数据,需要维持一定时间才能显示
for (int i = 0; i < 500; i++) {
ledshow(buf1);
}
for (int i = 0; i < 500; i++) {
ledshow(buf2);
}
for (int i = 0; i < 500; i++) {
ledshow(buf3);
}
}
//下面处理没有人时显示
int redl = digitalRead(red);
if (!redl) {
for (int i = 0; i < 500; i++) {
ledshow("");
}
}
//snprintf(buf, sizeof(buf), "%s %04d-%02d-%02d %02d:%02d:%02d", day, t.yr, t.mon, t.date, t.hr, t.min, t.sec);
//Serial.println(buf); /* 输出日期到串口 */
}
void setup()
{
pinMode(dio, OUTPUT);
pinMode(rclk, OUTPUT);
pinMode(sclk, OUTPUT);
Serial.begin(9600);
//Serial.println("Reset");
rtc.write_protect(false);
rtc.halt(false);
}
void loop()
{
while (Serial.available() > 0) /* 当串口有数据的时候,将数据拼接到变量comdata */
{
comdata += char(Serial.read());
delay(2);
mark = 1;
}
if (mark == 1) /* 以逗号分隔分解comdata的字符串,分解结果变成转换成数字到numdata[]数组 */
{
Serial.print("You inputed : ");
Serial.println(comdata);
for (int i = 0; i < comdata.length() ; i++)
{
if (comdata == ',' || comdata == 0x10 || comdata == 0x13)
{
j++;
}
else
{
numdata[j] = numdata[j] * 10 + (comdata - '0');
}
}
Time t(numdata[0], numdata[1], numdata[2], numdata[3], numdata[4], numdata[5], numdata[6]); /* 将转换好的numdata凑成时间格式,写入DS1302 */
rtc.time(t);
mark = 0; j = 0;
comdata = String(""); /* 清空 comdata 变量,以便等待下一次输入 */
for (int i = 0; i < 7 ; i++) numdata = 0; /* 清空 numdata */
}
//有人后调用LED显示
int redl = digitalRead(red);
if (redl) {
print_time(); /* 打印当前时间 */
}
delay(1000);
} |