• 电脑控制台灯(c# hook,显示室温,联网校正时间)


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

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

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

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

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

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

    下位机,

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

     下位机程序分析:

      1 /************************************************************************/
      2 //     本程序作者 HennSun ,转载请表明出处. 
      3 //
      4 /************************************************************************/
      5 #include <reg52.h>
      6 #include "uart.h"
      7 #include "18b20.h"
      8 #include "ds1302.h"
      9 #define buff_size 5
     10 sbit jdq=P1^0;
     11 sbit key_led=P3^3;
     12 unsigned int num;
     13 unsigned char control=0,set_time=0;
     14 unsigned char time[buff_size];           //用于设定时间
     15 extern unsigned int temp;
     16 extern unsigned char flag_get;
     17 
     18 /*----------初始化定时器---------*/
     19 
     20 void init_timer()
     21 {
     22     TMOD =0x01;//定时器设置     T0工作于方式1 16位
     23     TH0=0xef;
     24     TL0=0xf0;
     25     ET0=1;       //定时器 0 中断允许 .
     26     TR0=1;        // run the timer0     这个中断会让单片机查询中断向量表.
     27     EA    = 1;                  //打开总中断
     28 }
     29 
     30 //显示 open 字符
     31 void disp_open()
     32 {
     33     unsigned int i=400;
     34     while(i--)
     35     {
     36         P2=2;
     37         P0=0x3f;  //'O'
     38         delay1(1);
     39         P0=0X00;
     40         
     41         P2=3;
     42         P0=0x73;  //'P'
     43         delay1(1);
     44         P0=0X00;
     45         
     46         P2=4;
     47         P0=0x79;   //'E'
     48         delay1(1);
     49         P0=0X00;
     50         
     51         P2=5;
     52         P0=0x37;   //'N'
     53         delay1(1);
     54         P0=0X00;
     55     }
     56 
     57 }
     58 // 显示close 字符
     59 void disp_close()
     60 {
     61     unsigned int i=400;
     62     while(i--)
     63     {
     64         P2=2;
     65         P0=0x39;  //'C'
     66         delay1(1);
     67         P0=0X00;
     68         
     69         P2=3;
     70         P0=0x38;  //'L'
     71         delay1(1);
     72         P0=0X00;
     73         
     74         P2=4;
     75         P0=0x3f;   //'O'
     76         delay1(1);
     77         P0=0X00;
     78         
     79         P2=5;
     80         P0=0x6d;   //'S'
     81         delay1(1);
     82         P0=0X00;
     83         
     84         P2=6;
     85         P0=0x79;   //'E'
     86         delay1(1);
     87         P0=0X00;
     88     }
     89     
     90 }
     91 
     92 
     93 /*----------------------------------------------------------------------------------------
     94                             这是主函数部分
     95 --------------------------------------------------------------------------------------*/
     96 void main()
     97 {
     98     unsigned int TempH,TempL;
     99     unsigned char H, L ;
    100     jdq=0;
    101     init_timer();
    102     init_ds1302();
    103     UARTinit();
    104     
    105     while(1)
    106     {    
    107         if(flag_get)       //定时读取当前温度
    108         {
    109             
    110             temp=ReadTemperature();   //这个函数8ms
    111             
    112             if(temp&0x8000)
    113             {
    114                 temp=~temp;  // 取反加1
    115                 temp +=1;
    116             }
    117             TempH=temp>>4;
    118             TempL=temp&0x0F;
    119             TempL=TempL*6/10;//小数近似处理
    120             
    121             H=(unsigned char)TempH;
    122             L=(unsigned char)TempL;
    123             /**/
    124             send_char_com('a');
    125             send_char_com(H);
    126             send_char_com(L);
    127             send_char_com('e');
    128             flag_get=0; 
    129             
    130         }     //这个循环用11ms         
    131         if(control)
    132         {
    133             jdq=~jdq;
    134             if(jdq)
    135             {
    136                 send_char_com('o');
    137                 send_char_com('e');
    138                 disp_open();
    139             }
    140             else
    141             {
    142                 send_char_com('c');
    143                 send_char_com('e');
    144                 disp_close();
    145             }
    146             control=0;
    147         }
    148         if(set_time)
    149         {
    150             if((time[1]<0x60)||(time[2]<0x60)&&(time[3]<0x24))
    151             {
    152                 set_ds1302(time[1],time[2],time[3]);   // s , m ,h 
    153                 //不知为何时间定时器自动停止.  ,数组越界
    154                 set_time=0;
    155             }
    156         }
    157         if(!key_led)
    158         {
    159             control=1;
    160         }
    161         //添加时钟显示代码
    162         get_ds1302();  //2.23ms
    163   }  //不进第一个if  时间为 2ms   进入 13ms  这里指周期
    164 }
    165 
    166 /******************************************************************/
    167 /*                  定时器中断                                    */
    168 /******************************************************************/
    169 void tim(void) interrupt 1 using 1//中断用于温度检测
    170 {
    171     TR0=0;       //关闭定时器
    172     TH0=0x0f;//定时器重装值    定时器有没有中断标志位??,未清零?
    173     TL0=0x00;
    174     flag_get=1;//标志位有效
    175 }
    176 
    177 
    178 
    179 
    180 void UART_SER() interrupt 4   
    181 {
    182     unsigned char Temp;
    183     static unsigned char flag=0;
    184     if(RI)
    185     {
    186         RI=0;
    187         Temp=SBUF;
    188         switch(Temp)
    189         {
    190             case 's':    
    191                 control=1;
    192                 break;
    193             case 't':
    194                 //set_time=1;
    195                 flag=buff_size;
    196                 break;
    197             case 'w':
    198                 TR0=1;
    199                 break;
    200             default:
    201                 break;
    202         }
    203         if(flag)
    204         {        
    205             flag--;
    206             time[flag]=Temp;   //全局变量
    207             if(time[0]=='e')
    208             {
    209                 time[0]=0x11;
    210                 set_time=1;
    211             }
    212         }
    213     }
    214 
    215 }

    18b20.c

     1 #include "reg52.h"
     2 #include "18b20.h"
     3 /******************************************************************/
     4 /*                    定义端口                                    */
     5 /******************************************************************/
     6 sbit DQ=P1^3;//ds18b20 端口
     7 unsigned int temp;
     8 unsigned char flag_get=0 ;
     9 
    10 
    11 /******************************************************************/
    12 /*                    延时函数                                    */
    13 /******************************************************************/
    14 void delay(unsigned int i)//延时函数
    15 {
    16  while(i--);
    17 }
    18 
    19 /******************************************************************/
    20 /*                    初始化                                      */
    21 /******************************************************************/
    22 void Init_DS18B20(void)
    23 {
    24  unsigned char x=0;
    25  DQ = 1;    //DQ复位
    26  delay(8);  //稍做延时
    27  DQ = 0;    //单片机将DQ拉低
    28  delay(80); //精确延时 大于 480us
    29  DQ = 1;    //拉高总线
    30  delay(10);
    31  x=DQ;      //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
    32  delay(5);
    33 }
    34 
    35 /******************************************************************/
    36 /*                    读一个字节                                  */
    37 /******************************************************************/
    38 unsigned char ReadOneChar(void)
    39 {
    40 unsigned char i=0;
    41 unsigned char dat = 0;
    42 for (i=8;i>0;i--)
    43  {
    44   DQ = 0; // 给脉冲信号
    45   dat>>=1;
    46   DQ = 1; // 给脉冲信号
    47   if(DQ)
    48    dat|=0x80;
    49   delay(5);
    50  }
    51  return(dat);
    52 }
    53 
    54 
    55 /******************************************************************/
    56 /*                 写一个字节                                     */
    57 /******************************************************************/
    58 void WriteOneChar(unsigned char dat)
    59 {
    60  unsigned char i=0;
    61  for (i=8; i>0; i--)
    62  {
    63   DQ = 0;
    64   DQ = dat&0x01;
    65   delay(5);
    66   DQ = 1;
    67   dat>>=1;
    68  }
    69 delay(5);
    70 }
    71 
    72 
    73 /******************************************************************/
    74 /*                   读取温度                                     */
    75 /******************************************************************/
    76 unsigned int ReadTemperature(void)
    77 {
    78     unsigned char a=0;
    79     unsigned int b=0;
    80     unsigned int t=0;
    81     Init_DS18B20();
    82     WriteOneChar(0xCC); // 跳过读序号列号的操作
    83     WriteOneChar(0x44); // 启动温度转换
    84     delay(200);
    85     Init_DS18B20();
    86     WriteOneChar(0xCC); //跳过读序号列号的操作 
    87     WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
    88     a=ReadOneChar();   //低位
    89     b=ReadOneChar();   //高位
    90 
    91     b<<=8;
    92     t=a+b;
    93 
    94     return(t);
    95 }

    ds1302.c

      1 #include <reg52.h>
      2 #include "ds1302.h"
      3 
      4 //===以下IO定义请根据您硬件的连接修改===
      5 sbit T_RST=P3^5;//ds1302-5
      6 sbit T_IO=P3^4;//ds1302-6
      7 sbit T_CLK=P3^6;//ds1302-7
      8 sbit ACC0=ACC^0;
      9 sbit ACC7=ACC^7;//累加器A 51单片机原理中有介绍
     10 
     11 unsigned char a,b,clock_ss,clock_sg,clock_fs,clock_fg,clock_ms,clock_mg;
     12 
     13 int hour,mie,sei;
     14 
     15 unsigned char clk_time[3];  //秒,分,时寄存器初始值
     16 code unsigned char ledmap[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};
     17 //数码管段码                            
     18 
     19 /******************DS1302:写入操作(上升沿)*********************/ 
     20 void write_byte(unsigned char da)
     21 {
     22    unsigned char i;
     23    ACC=da;//10000001
     24    for(i=8;i>0;i--)
     25    { 
     26       T_IO=ACC0;
     27             T_CLK=0;     
     28       T_CLK=1;
     29       ACC=ACC>>1;//01000000
     30    }
     31 }
     32 /******************DS1302:读取操作(下降沿)*****************/
     33 unsigned char read_byte(void)
     34 {
     35    unsigned char i;
     36    for(i=0;i<8;i++)//00000001   假设ACC=00000000
     37    {
     38       ACC=ACC>>1;//01000000  
     39             T_CLK = 1;
     40             T_CLK = 0;
     41       ACC7 = T_IO;//10000000
     42    }
     43    return(ACC);
     44 
     45 }
     46 
     47 /******************DS1302:写入数据(先送地址,再写数据)***************************/ 
     48 void write_1302(unsigned char addr,unsigned char da)
     49 {
     50    T_RST=0;    //停止工作
     51    T_CLK=0;                                 
     52    T_RST=1;   //重新工作
     53    write_byte(addr);    //写入地址
     54    
     55    write_byte(da);
     56    T_RST=0;
     57    T_CLK=1;
     58 }
     59 
     60 /******************DS1302:读取数据(先送地址,再读数据)**************************/
     61 unsigned char read_1302(unsigned char addr)
     62 {
     63    unsigned char temp;
     64    T_RST=0;                                   //停止工作
     65    T_CLK=0;  
     66    T_RST=1;                         //重新工作
     67    write_byte(addr);   //写入地址
     68    temp=read_byte();
     69    T_RST=0;
     70    T_CLK=1;     //停止工作
     71    return(temp);
     72 }
     73 
     74 
     75 /***********************延时程序=a*1ms**************************************/
     76 void delay1(unsigned char a)
     77 {
     78    unsigned int i;
     79    while(a-- !=0)
     80    {    // led_disp();
     81         for(i=0;i<12;i++);  //12
     82    }
     83 }
     84 
     85 
     86 /***********************显示程序**********************************************/
     87 
     88 /* DS1302秒,分,时寄存器是BCD码形式:  用16求商和余进行"高4位"和"低4位"分离 */
     89 /****************************************************************************/           
     90 void led_disp()
     91 {   
     92         clock_ms=clk_time[0]/ 16;  
     93         clock_mg=clk_time[0]%16;
     94         
     95         clock_fs=clk_time[1]/ 16;  
     96         clock_fg=clk_time[1]%16;
     97         
     98         mie=clock_fs*10+ clock_fg;   //这个有什么用?
     99         
    100         clock_ss=clk_time[2]/ 16;   
    101         clock_sg=clk_time[2]%16;//BCD*to*10
    102         hour=clock_ss*10+ clock_sg; //用16求商和余进行"高4位"和"低4位"分离
    103     
    104         P2=0;
    105         P0=ledmap[clock_ss];
    106         delay1(1);
    107         P0=0X00;
    108         P2=1;
    109         P0=ledmap[clock_sg];//时个位
    110         delay1(1);
    111         P0=0X00;
    112         P2=2;
    113         P0=ledmap[10];//显示"-"数组里的 0x40
    114         delay1(1);
    115         P0=0X00;
    116         P2=3;
    117         P0=ledmap[clock_fs];//分十位
    118         delay1(1);
    119         P0=0X00;
    120         P2=4;
    121         P0=ledmap[clock_fg];//时个位
    122         delay1(1);P0=0X00;   
    123         P2=5;
    124         P0=ledmap[10];//显示"-"数组里的 0x40
    125         delay1(1);
    126         P0=0X00;
    127         P2=6;
    128         P0=ledmap[clock_ms];//秒十位
    129         delay1(1);
    130         P0=0X00;
    131         P2=7;
    132         P0=ledmap[clock_mg];
    133         delay1(1);
    134         P0=0X00;                      
    135 }
    136 void init_ds1302()
    137 {
    138     write_1302(0x8e,0x80); //WP=1 写保护,加上这个操作之后断电重新上电是正确的时间.
    139 }
    140 void get_ds1302()
    141 {
    142   unsigned char temp=0x81; 
    143      unsigned char i;
    144     for(i=0;i<3;i++)//分别把秒分时数据读出分3次读好一次地址加2" temp+=2;"
    145     {
    146          clk_time[i]=read_1302(temp);
    147          temp+=2;
    148     }
    149     led_disp();    
    150 }
    151 //添加设置时间的代码  ,结合key
    152 void set_ds1302(unsigned m,unsigned char f,unsigned char s)
    153 {
    154     write_1302(0x8e,0x00); //WP=0 写操作
    155     /**/
    156     write_1302(0x80,m);//0x80是写秒数据此处写进"01"秒
    157     write_1302(0x82,f);//0x82是写分数据
    158     write_1302(0x84,s);//0x84是写时数据
    159 
    160     write_1302(0x8e,0x80); //WP=1 写保护  
    161     delay1(255);
    162 }

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

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

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

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

    上位机程序有几个我自认为的亮点. 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>") + 6;
                    int monthIndex = html.IndexOf("<month>") + 7;
                    int dayIndex = html.IndexOf("<day>") + 5;
                    int hourIndex = html.IndexOf("<hour>") + 6;
                    int miniteIndex = html.IndexOf("<minite>") + 8;
                    int secondIndex = html.IndexOf("<second>") + 8;
    
                    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时间的设置,需要进行一下转码,方法如下:

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

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

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

    亮点三,c# hook 

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

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

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

    1 /*
    2             IntPtr hInstance = LoadLibrary("User32");
    3             hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, hInstance, 0);
    4             */
    5          //把引掉的部分更改为下面的
    6             IntPtr hInstance = LoadLibrary("User32");
    7             _keyboardHookProc = new keyboardHookProc(hookProc);
    8             hhook = SetWindowsHookEx(WH_KEYBOARD_LL, _keyboardHookProc, hInstance, 0);

    如果想按下快捷键不对其它的程序产生影响,可以去掉这个方法体 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

  • 相关阅读:
    全面了解Nginx主要应用场景
    手把手教你构建 C 语言编译器
    Docker镜像原理和最佳实践
    Docker网络深度解读
    PostgreSQL 10.0 preview 功能增强
    阿里沈询:分布式事务原理与实践
    CPU、内存、IO虚拟化关键技术及其优化探索
    原理、方法双管齐下,大神带你细解Redis内存管理和优化---场景研读
    ASP.NET 5已终结,迎来ASP.NET Core 1.0和.NET Core 1.0 转
    RabbitMQ学习系列
  • 原文地址:https://www.cnblogs.com/dreamfactory/p/3440368.html
Copyright © 2020-2023  润新知