zoukankan      html  css  js  c++  java
  • 电脑控制台灯(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

  • 相关阅读:
    9.11 eventbus
    9.10,,,实现new instanceof apply call 高阶函数,偏函数,柯里化
    9.9 promise实现 写完了传到gitee上面了,这里这个不完整
    9.5cors配置代码
    9.5 jsonp 实现
    9.5 http tcp https总结
    9.3 es6 class一部分 and es5 class 发布订阅
    8.30 cookie session token jwt
    8.30vue响应式原理
    warning: LF will be replaced by CRLF in renard-wx/project.config.json. The file will have its original line endings in your working directory
  • 原文地址:https://www.cnblogs.com/dreamfactory/p/3440368.html
Copyright © 2011-2022 走看看