突发奇想,于是便写了一个小程序用于控制台灯,这几天功能也在不断的完善中,目前基本已经完成.下面进行功能的简述的代码的分析.

整体设计包含下位机程序和上位机程序.下位机用的c语言,上位机用的c# .功能显示见视频

整个系统功能包括:定时采集室温在电脑右下角显示,可联网校准电子时钟,可以电脑端快捷键控制台灯.视频中展示的顺序为

1,自动获取温度,图标动态显示室温 2,手动获取温度 3,按钮控制台灯 4 ,快捷键控制台灯 5,联网校准电子时钟 6最后展示

在任何界面只要按下快捷键便可以打开台灯(windows hook).

下面进行整个系统代码和原理的介绍.

下位机,

硬件上 ,包括  51单片机,ds1302,18b20,uln2003,pl2303 .硬件连接图如下:

下位机程序分析:

 /************************************************************************/
// 本程序作者 HennSun ,转载请表明出处.
//
/************************************************************************/
#include <reg52.h>
#include "uart.h"
#include "18b20.h"
#include "ds1302.h"
#define buff_size 5
sbit jdq=P1^;
sbit key_led=P3^;
unsigned int num;
unsigned char control=,set_time=;
unsigned char time[buff_size]; //用于设定时间
extern unsigned int temp;
extern unsigned char flag_get; /*----------初始化定时器---------*/ void init_timer()
{
TMOD =0x01;//定时器设置 T0工作于方式1 16位
TH0=0xef;
TL0=0xf0;
ET0=; //定时器 0 中断允许 .
TR0=; // run the timer0 这个中断会让单片机查询中断向量表.
EA = ; //打开总中断
} //显示 open 字符
void disp_open()
{
unsigned int i=;
while(i--)
{
P2=;
P0=0x3f; //'O'
delay1();
P0=0X00; P2=;
P0=0x73; //'P'
delay1();
P0=0X00; P2=;
P0=0x79; //'E'
delay1();
P0=0X00; P2=;
P0=0x37; //'N'
delay1();
P0=0X00;
} }
// 显示close 字符
void disp_close()
{
unsigned int i=;
while(i--)
{
P2=;
P0=0x39; //'C'
delay1();
P0=0X00; P2=;
P0=0x38; //'L'
delay1();
P0=0X00; P2=;
P0=0x3f; //'O'
delay1();
P0=0X00; P2=;
P0=0x6d; //'S'
delay1();
P0=0X00; P2=;
P0=0x79; //'E'
delay1();
P0=0X00;
} } /*----------------------------------------------------------------------------------------
这是主函数部分
--------------------------------------------------------------------------------------*/
void main()
{
unsigned int TempH,TempL;
unsigned char H, L ;
jdq=;
init_timer();
init_ds1302();
UARTinit(); while()
{
if(flag_get) //定时读取当前温度
{ temp=ReadTemperature(); //这个函数8ms if(temp&0x8000)
{
temp=~temp; // 取反加1
temp +=;
}
TempH=temp>>;
TempL=temp&0x0F;
TempL=TempL*/;//小数近似处理 H=(unsigned char)TempH;
L=(unsigned char)TempL;
/**/
send_char_com('a');
send_char_com(H);
send_char_com(L);
send_char_com('e');
flag_get=; } //这个循环用11ms
if(control)
{
jdq=~jdq;
if(jdq)
{
send_char_com('o');
send_char_com('e');
disp_open();
}
else
{
send_char_com('c');
send_char_com('e');
disp_close();
}
control=;
}
if(set_time)
{
if((time[]<0x60)||(time[]<0x60)&&(time[]<0x24))
{
set_ds1302(time[],time[],time[]); // s , m ,h
//不知为何时间定时器自动停止. ,数组越界
set_time=;
}
}
if(!key_led)
{
control=;
}
//添加时钟显示代码
get_ds1302(); //2.23ms
} //不进第一个if 时间为 2ms 进入 13ms 这里指周期
} /******************************************************************/
/* 定时器中断 */
/******************************************************************/
void tim(void) interrupt using //中断用于温度检测
{
TR0=; //关闭定时器
TH0=0x0f;//定时器重装值 定时器有没有中断标志位??,未清零?
TL0=0x00;
flag_get=;//标志位有效
} void UART_SER() interrupt
{
unsigned char Temp;
static unsigned char flag=;
if(RI)
{
RI=;
Temp=SBUF;
switch(Temp)
{
case 's':
control=;
break;
case 't':
//set_time=1;
flag=buff_size;
break;
case 'w':
TR0=;
break;
default:
break;
}
if(flag)
{
flag--;
time[flag]=Temp; //全局变量
if(time[]=='e')
{
time[]=0x11;
set_time=;
}
}
} }

18b20.c

 #include "reg52.h"
#include "18b20.h"
/******************************************************************/
/* 定义端口 */
/******************************************************************/
sbit DQ=P1^;//ds18b20 端口
unsigned int temp;
unsigned char flag_get= ; /******************************************************************/
/* 延时函数 */
/******************************************************************/
void delay(unsigned int i)//延时函数
{
while(i--);
} /******************************************************************/
/* 初始化 */
/******************************************************************/
void Init_DS18B20(void)
{
unsigned char x=;
DQ = ; //DQ复位
delay(); //稍做延时
DQ = ; //单片机将DQ拉低
delay(); //精确延时 大于 480us
DQ = ; //拉高总线
delay();
x=DQ; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
delay();
} /******************************************************************/
/* 读一个字节 */
/******************************************************************/
unsigned char ReadOneChar(void)
{
unsigned char i=;
unsigned char dat = ;
for (i=;i>;i--)
{
DQ = ; // 给脉冲信号
dat>>=;
DQ = ; // 给脉冲信号
if(DQ)
dat|=0x80;
delay();
}
return(dat);
} /******************************************************************/
/* 写一个字节 */
/******************************************************************/
void WriteOneChar(unsigned char dat)
{
unsigned char i=;
for (i=; i>; i--)
{
DQ = ;
DQ = dat&0x01;
delay();
DQ = ;
dat>>=;
}
delay();
} /******************************************************************/
/* 读取温度 */
/******************************************************************/
unsigned int ReadTemperature(void)
{
unsigned char a=;
unsigned int b=;
unsigned int t=;
Init_DS18B20();
WriteOneChar(0xCC); // 跳过读序号列号的操作
WriteOneChar(0x44); // 启动温度转换
delay();
Init_DS18B20();
WriteOneChar(0xCC); //跳过读序号列号的操作
WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
a=ReadOneChar(); //低位
b=ReadOneChar(); //高位 b<<=;
t=a+b; return(t);
}

ds1302.c

 #include <reg52.h>
#include "ds1302.h" //===以下IO定义请根据您硬件的连接修改===
sbit T_RST=P3^;//ds1302-5
sbit T_IO=P3^;//ds1302-6
sbit T_CLK=P3^;//ds1302-7
sbit ACC0=ACC^;
sbit ACC7=ACC^;//累加器A 51单片机原理中有介绍 unsigned char a,b,clock_ss,clock_sg,clock_fs,clock_fg,clock_ms,clock_mg; int hour,mie,sei; unsigned char clk_time[]; //秒,分,时寄存器初始值
code unsigned char ledmap[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};
//数码管段码 /******************DS1302:写入操作(上升沿)*********************/
void write_byte(unsigned char da)
{
unsigned char i;
ACC=da;//
for(i=;i>;i--)
{
T_IO=ACC0;
T_CLK=;
T_CLK=;
ACC=ACC>>;//
}
}
/******************DS1302:读取操作(下降沿)*****************/
unsigned char read_byte(void)
{
unsigned char i;
for(i=;i<;i++)//00000001 假设ACC=00000000
{
ACC=ACC>>;//01000000
T_CLK = ;
T_CLK = ;
ACC7 = T_IO;//
}
return(ACC); } /******************DS1302:写入数据(先送地址,再写数据)***************************/
void write_1302(unsigned char addr,unsigned char da)
{
T_RST=; //停止工作
T_CLK=;
T_RST=; //重新工作
write_byte(addr); //写入地址 write_byte(da);
T_RST=;
T_CLK=;
} /******************DS1302:读取数据(先送地址,再读数据)**************************/
unsigned char read_1302(unsigned char addr)
{
unsigned char temp;
T_RST=; //停止工作
T_CLK=;
T_RST=; //重新工作
write_byte(addr); //写入地址
temp=read_byte();
T_RST=;
T_CLK=; //停止工作
return(temp);
} /***********************延时程序=a*1ms**************************************/
void delay1(unsigned char a)
{
unsigned int i;
while(a-- !=)
{ // led_disp();
for(i=;i<;i++); //
}
} /***********************显示程序**********************************************/ /* DS1302秒,分,时寄存器是BCD码形式: 用16求商和余进行"高4位"和"低4位"分离 */
/****************************************************************************/
void led_disp()
{
clock_ms=clk_time[]/ ;
clock_mg=clk_time[]%; clock_fs=clk_time[]/ ;
clock_fg=clk_time[]%; mie=clock_fs*+ clock_fg; //这个有什么用? clock_ss=clk_time[]/ ;
clock_sg=clk_time[]%;//BCD*to*10
hour=clock_ss*+ clock_sg; //用16求商和余进行"高4位"和"低4位"分离 P2=;
P0=ledmap[clock_ss];
delay1();
P0=0X00;
P2=;
P0=ledmap[clock_sg];//时个位
delay1();
P0=0X00;
P2=;
P0=ledmap[];//显示"-"数组里的 0x40
delay1();
P0=0X00;
P2=;
P0=ledmap[clock_fs];//分十位
delay1();
P0=0X00;
P2=;
P0=ledmap[clock_fg];//时个位
delay1();P0=0X00;
P2=;
P0=ledmap[];//显示"-"数组里的 0x40
delay1();
P0=0X00;
P2=;
P0=ledmap[clock_ms];//秒十位
delay1();
P0=0X00;
P2=;
P0=ledmap[clock_mg];
delay1();
P0=0X00;
}
void init_ds1302()
{
write_1302(0x8e,0x80); //WP=1 写保护,加上这个操作之后断电重新上电是正确的时间.
}
void get_ds1302()
{
unsigned char temp=0x81;
unsigned char i;
for(i=;i<;i++)//分别把秒分时数据读出分3次读好一次地址加2" temp+=2;"
{
clk_time[i]=read_1302(temp);
temp+=;
}
led_disp();
}
//添加设置时间的代码 ,结合key
void set_ds1302(unsigned m,unsigned char f,unsigned char s)
{
write_1302(0x8e,0x00); //WP=0 写操作
/**/
write_1302(0x80,m);//0x80是写秒数据此处写进"01"秒
write_1302(0x82,f);//0x82是写分数据
write_1302(0x84,s);//0x84是写时数据 write_1302(0x8e,0x80); //WP=1 写保护
delay1();
}

串口部分程序没有比较好写,我便不贴上来了.程序往上位机传输数据时,我这里没有考虑负数.所以如果需要使用本程序需要注意这一点.

这个是下位机程序开发日志:

已经实现串口控制台灯的开关.

下面添加串口测温功能

2013.11.
目前系统有个奇怪的问题, 不能打开串口接收中断但是不发送 ,且发送不能少于2个byte .
当关闭ES 时不会出现这个问题 .
在初始化时 TI 置位会引用跳到串口接收中断部分 ,稍过后没有此问题. 每次发生 接收中断时系统运算减慢,过片刻正常. 2013.11.
设置日期的格式 't''h''m''s''e'
发送的数据 均为 0x00格式 比如说 设置为 :00:01 则发送 't''0x20''0x00''0x01''e' 关于首次初始化问题 思路是将1302的某个寄存器定义为是否首次开机检测标志,比如存入0xaa数值。
上电时读取1302的这个寄存器,如果是0xaa,说明不是首次,便不再初始化,否则初始化,并向开机定义的寄存器中写入0xaa。
我这里直接对写保护位写 1. 2013.11.
添加发送'w'获取温度 返回的数据 'a''H''L''e'
2013.11.
添加返回台灯状态 'c''e' 'o''e'
添加握手信息 开机是请求获取一次温度 ,
2013.11.
添加 修改 second
2013.11.
上述提到问题已经更正

上位机程序分析,程序界面如图:

上位机程序有几个我自认为的亮点. 1,可以联网校准电子时钟. 2,可以在右下角显示温度 . 3,可以在任何状态下按下快捷键控制台灯.这里主要讲解这三部分功能.我这里把打包好的程序共享给大家,有需要源码的可以在下面留言.

亮点功能1,联系校准电子时钟:

        private void set_auto_Click(object sender, EventArgs e)
{
set_auto.Enabled = false; //关闭按键
set_time.Enabled = false;
WebRequest wrt = null;
WebResponse wrp = null;
try
{
wrt = WebRequest.Create("http://www.time.ac.cn/timeflash.asp?user=flash");
wrt.Credentials = CredentialCache.DefaultCredentials; wrp = wrt.GetResponse();
StreamReader sr = new StreamReader(wrp.GetResponseStream(), Encoding.UTF8);
string html = sr.ReadToEnd(); sr.Close();
wrp.Close(); int yearIndex = html.IndexOf("<year>") + ;
int monthIndex = html.IndexOf("<month>") + ;
int dayIndex = html.IndexOf("<day>") + ;
int hourIndex = html.IndexOf("<hour>") + ;
int miniteIndex = html.IndexOf("<minite>") + ;
int secondIndex = html.IndexOf("<second>") + ; string year = html.Substring(yearIndex, html.IndexOf("</year>") - yearIndex);
string month = html.Substring(monthIndex, html.IndexOf("</month>") - monthIndex); ;
string day = html.Substring(dayIndex, html.IndexOf("</day>") - dayIndex);
string hour = html.Substring(hourIndex, html.IndexOf("</hour>") - hourIndex);
string minite = html.Substring(miniteIndex, html.IndexOf("</minite>") - miniteIndex);
string second = html.Substring(secondIndex, html.IndexOf("</second>") - secondIndex);
set_time_function(hour,minite,second);
textBox1.Text = hour + ":" + minite + ":" + second; }
catch (WebException web)
{
MessageBox.Show(web.Message);
}
catch (Exception xx)
{
MessageBox.Show(xx.Message);
}
finally
{
if (wrp != null)
wrp.Close();
if (wrt != null)
wrt.Abort();
}
set_auto.Enabled = true; //打开按键
set_time.Enabled = true;
}

这个功能代码我是参考下面[参考博客]部分的程序 ,实现了网络时间的获取,获取的格式为string 类型.这里如果想进行ds1302时间的设置,需要进行一下转码,方法如下:

 /// <summary>
/// 这里进行编码转化 ,ds1302 每一位是16进制数据.如果你想设置成12点, 需要发送 0x12 .
/// </summary>
/// <param name="code"></param>
/// <returns></returns>
private byte Transcoding(string code )
{
byte[] bit = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,
0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59};
return bit[int.Parse(code)< ? int.Parse(code):] ;
}

亮点二,右下角动态显示温度

  这个代码直接用的这个作者的http://www.codeproject.com/Articles/9361/WeatherNotify   ,有兴趣的可以直接到这里查看.

亮点三,c# hook

  代码参考第五条引用.原程序是有一点小错误,这里的更正方法如下:

  在globalKeyboardHook.cs  文件中定义的委托下面添加这一句   private keyboardHookProc _keyboardHookProc;    //新添加的

  在 hook() 方法体中的代码更改为

 /*
IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, hInstance, 0);
*/
//把引掉的部分更改为下面的
IntPtr hInstance = LoadLibrary("User32");
_keyboardHookProc = new keyboardHookProc(hookProc);
hhook = SetWindowsHookEx(WH_KEYBOARD_LL, _keyboardHookProc, hInstance, );

如果想按下快捷键不对其它的程序产生影响,可以去掉这个方法体 public int hookProc(int code, int wParam, ref keyboardHookStruct lParam){}中的这一句

/*
if (kea.Handled)
return 1;
*/

好了,整个系统差不多介绍完了.虽然程序不太,但涉及到许多的知识 .需要上位机的源代码的可以留言.

博文为本人所写,转载请表明出处 电脑控制台灯

参考博客:

http://www.cnblogs.com/slyzly/articles/2108877.html

http://www.codeproject.com/Articles/9361/WeatherNotify

http://www.cnblogs.com/hocylan/archive/2008/01/14/1038390.html

http://bbs.csdn.net/topics/100169052

http://www.codeproject.com/Articles/19004/A-Simple-C-Global-Low-Level-Keyboard-Hook

电脑控制台灯(c# hook,显示室温,联网校正时间)的更多相关文章

  1. 电脑控制Android设备的软件——Total Control

    最早开始搞Android开发时,为了调试方便,想找一个Android下的远程控制软件,支持在电脑端远程控制和同步显示Android设备.先后试了360手机助手.Mobizen.Vysor和Mirror ...

  2. 使用Scrcpy实现电脑控制安卓手机

    很多时候我们想要在电脑上使用一些手机软件,使用模拟器当然是一种选择,但是这些模拟器要不然不免费,要不然广告多不放心.Scrcpy是一个开源免费的软件,通过abd命令实现了安卓手机投屏和控制功能,并且支 ...

  3. 使用C#模拟键盘输入、鼠标移动和点击、设置光标位置及控制应用程序的显示

    1.模拟键盘输入(SendKeys) 功能:将一个或多个按键消息发送到活动窗口,就如同在键盘上进行输入一样. 语法:SendKeys.Send(string keys);SendKeys.SendWa ...

  4. spi接口的ds1302时钟芯片控制在lcd1602上显示

    spi接口的ds1302时钟芯片控制在lcd1602上显示                                                                        ...

  5. JS控制HTML元素的显示和隐藏

    JS控制HTML元素的显示和隐藏 利用来JS控制页面控件显示和隐藏有两种方法,两种方法分别利用HTML的style中的两个属性,两种方法的不同之处在于控件隐藏后是否还在页面上占空位. 方法一: 1 2 ...

  6. js控制不同的时间段显示不同的css样式

    js控制不同的时间段显示不同的css样式 js函数,可以放到单独的js文件中也可以放到当前页的<head>标记之内 function getCSS(){        datetoday ...

  7. CSS控制长文本内容显示(截取的地方用省略号代替)

    自动换行问题,正常字符的换行是比较合理的,而连续的数字和英文字符常常将容器撑大,下面介绍的是CSS如何实现处理的方法. 现实中经常出现一些内容比较长的文本,为了使整体布局美观,需要将文本内容控制在一行 ...

  8. NGUI---使用脚本控制聊天系统的内容显示,输入事件交互

    在我的笔记Unity3D里面之 简单聊天系统一 里面已经介绍怎么创建聊天系统的背景.给聊天系统添加滚动条,设置Anchor锚点.以及设计聊天系统的输入框. 效果图如下所示: 现在我们要做的就是使用脚本 ...

  9. 功能整合(一):滚动条的变相隐藏、js控制div的渐变显示、滚动条监听

    1.滚动条的变相隐藏 思路: 1.  把body的横向,纵向的超出部分隐藏,宽设置100%:高设置100%.就没有body的滚动条了, 2.  然后把最外层的div的宽设置的比body的宽宽一点,把d ...

随机推荐

  1. DateFomrat Mask in ASPxTextbox increases width ,How to disable display of dxeErrorCell on ASPxTextBox

    让ASPxTextbox显示yyyy-MM-dd, 需设置 <MaskSettings Mask="yyyy-MM-dd" />.但是会导致ASPxTextbox宽度变 ...

  2. WCF初探-22:WCF中使用Message类(上)

    前言 从我们学习WCF以来,就一直强调WCF是基于消息的通信机制.但是由于WCF给我们做了高级封装,以至于我们在使用WCF的时候很少了解到消息的内部机制.由于WCF的架构的可扩展性,针对一些特殊情况, ...

  3. OC语言BLOCK和协议

    OC语言BLOCK和协议 一.BOLCK (一)简介 BLOCK是什么?苹果推荐的类型,效率高,在运行中保存代码.用来封装和保存代码,有点像函数,BLOCK可以在任何时候执行. BOLCK和函数的相似 ...

  4. iOS开发UI篇—ios应用数据存储方式(偏好设置)

    iOS开发UI篇—ios应用数据存储方式(偏好设置) 一.简单介绍 很多iOS应用都支持偏好设置,比如保存用户名.密码.字体大小等设置,iOS提供了一套标准的解决方案来为应用加入偏好设置功能 每个应用 ...

  5. DTO概念

    在开发过程中用到了DTO,简单了解了一下. DTO:数据传输对象,用来连接表现层和应用层之间的数据交互.数据传输对象是没有行为的POJO对象,它的目的只是为了对领域对象进行数据封装,实现层与层之间的数 ...

  6. C++ Primer----智能指针类 2

    指针带给了 C++巨大的灵活性,然而同样也带来无数的问题,悬挂指针,内存泄漏等. int *pInt = new int(1); // Do not forget delete pInt; 智能指针就 ...

  7. 集合运算(A-B)U(B-A)

    实质是两个数组的合并(顺序表最好是有序的) #include<iostream> using namespace std; //创建顺序表 void create(int A[],int ...

  8. OpenSSL - 文件和字符MD5加密实现

    OpenSSL安装: 1.github下载最新的OpenSSL:https://github.com/openssl/openssl 2.在linux解压压缩包 3.安装OpenSSL ./confi ...

  9. js Math 对象的方法

    Math对象与JavaScript其他对象不同,因为用户不能生成所使用对象的副本,相反脚本汇集了简单Math对象的属性和方法.Math对象实际上存在于每个窗口和框架中,但是对脚本没有影响,程序员把这种 ...

  10. sqlserver OpenRowSet 对应的三种数据库驱动

    在使用sqlserver数据库的OpenRowSet函数时,会遇到三种驱动方式: 1. MSDASQL驱动SELECT TOP 10 * FROM OPENROWSET('MSDASQL', 'DRI ...