突发奇想,于是便写了一个小程序用于控制台灯,这几天功能也在不断的完善中,目前基本已经完成.下面进行功能的简述的代码的分析.
整体设计包含下位机程序和上位机程序.下位机用的c语言,上位机用的c#
整个系统功能包括:定时采集室温在电脑右下角显示,可联网校准电子时钟,可以电脑端快捷键控制台灯.视频中展示的顺序为
1,自动获取温度,图标动态显示室温 2,手动获取温度 3,按钮控制台灯 4 ,快捷键控制台灯 5,联网校准电子时钟 6最后展示
在任何界面只要按下快捷键便可以打开台灯(windows hook).
下面进行整个系统代码和原理的介绍.
下位机,
硬件上 ,包括 51单片机,ds1302,18b20,uln2003,pl2303 .硬件连接图如下:
下位机程序分析:
1 /************************************************************************/
2 // 本程序作者 HennSun ,转载请表明出处.
3 //
4 /************************************************************************/
5 #include
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
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("
int monthIndex = html.IndexOf("
int dayIndex = html.IndexOf("
int hourIndex = html.IndexOf("
int miniteIndex = html.IndexOf("
int secondIndex = html.IndexOf("
string year = html.Substring(yearIndex, html.IndexOf("") - yearIndex);
string month = html.Substring(monthIndex, html.IndexOf("") - monthIndex); ;
string day = html.Substring(dayIndex, html.IndexOf("") - dayIndex);
string hour = html.Substring(hourIndex, html.IndexOf("") - hourIndex);
string minite = html.Substring(miniteIndex, html.IndexOf("") - miniteIndex);
string second = html.Substring(secondIndex, html.IndexOf("") - 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 ///
2 /// 这里进行编码转化 ,ds1302 每一位是16进制数据.如果你想设置成12点, 需要发送 0x12 .
3 ///
4 ///
5 ///
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;
*/
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』