ShareIdeas

本博客不再更新,欢迎访问我的github,https://github.com/sunke-github/

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

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

整体设计包含下位机程序和上位机程序.下位机用的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

posted on 2013-11-24 19:36  ShareIdeas  阅读(1397)  评论(0编辑  收藏  举报