本文主要讲述如何使用LCD. 具体过程解释可查看代码注释.
程序代码:
1602LCD
1//1602液晶显示程序, TX-1B实验板上的1602LCD的R/W读写端接地, 即始终只写, 不读数据
2//使用1602LCD显示DS18B20转换的温度值
3#include <reg52.H>
4#include <intrins.H>
5#include <math.H>
6
7#define uchar unsigned char
8#define uint unsigned int
9sbit dula = P2^6;
10sbit wela = P2^7;
11
12sbit RS = P3^5; //数据/命令选择端(H/L)
13sbit LCDEN = P3^4; //使能端
14
15void delayUs()
16{
17 _nop_();
18}
19
20void delayMs(uint a)
21{
22 uint i, j;
23 for(i = a; i > 0; i--)
24 for(j = 100; j > 0; j--);
25}
26
27//第一行开始地址为0x80, 第二行开始地址为0xc0;
28//写命令:RS=0, RW=0;
29void writeComm(uchar comm)
30{
31 RS = 0;
32 P0 = comm;
33 LCDEN = 1;
34 delayUs();
35 LCDEN = 0;
36 delayMs(1);
37}
38
39//写数据:RS=1, RW=0;
40void writeData(uchar dat)
41{
42 RS = 1;
43 P0 = dat;
44 LCDEN = 1;
45 delayUs();
46 LCDEN = 0;
47 delayMs(1);
48}
49
50//初始化
51//显示模式, 固定指令为00111000=0x38, 16*2显示, 5*7点阵,8位数据接口
52//显示开/关及光标设置
53//指令1: 00001DCB : D:开显示/关显示(H/L); C:显示光标/不显示(H/L), B:光标闪烁/不闪烁(H/L)
54//指令2: 000001NS :
55//N=1, 当读/写一个字符后地址指针加1, 且光标也加1; N=0则相反
56//S=1, 当写一个字符, 整屏显示左移(N=1)或右移(N=0), 但光标不移动; S=0, 整屏不移动
57void init()
58{
59 //先关闭数码管, 使两个锁存器锁存, 因开了数码管, USB电压驱动不够, 将无法使LCD正常工作
60 dula = wela = 0;
61 writeComm(0x38); //显示模式
62 writeComm(0x0c); //开显示, 关光标
63 writeComm(0x06); //写字符后地址加1, 光标加1
64 writeComm(0x01); //清屏
65}
66
67void writeString(uchar * str, uchar length)
68{
69 uchar i;
70 for(i = 0; i < length; i++)
71 {
72 writeData(str[i]);
73 }
74}
75
76/**//*****************************DS18B20*******************************/
77sbit ds = P2^2;
78//初始化DS18B20
79//让DS18B20一段相对长时间低电平, 然后一段相对非常短时间高电平, 即可启动
80void dsInit()
81{
82 //对于11.0592MHz时钟, unsigned int型的i, 作一个i++操作的时间大于为8us
83 unsigned int i;
84 ds = 0;
85 i = 100; //拉低约800us, 符合协议要求的480us以上
86 while(i>0) i--;
87 ds = 1; //产生一个上升沿, 进入等待应答状态
88 i = 4;
89 while(i>0) i--;
90}
91
92void dsWait()
93{
94 unsigned int i;
95 while(ds);
96 while(~ds); //检测到应答脉冲
97 i = 4;
98 while(i > 0) i--;
99}
100
101//向DS18B20读取一位数据
102//读一位, 让DS18B20一小周期低电平, 然后两小周期高电平,
103//之后DS18B20则会输出持续一段时间的一位数据
104bit readBit()
105{
106 unsigned int i;
107 bit b;
108 ds = 0;
109 i++; //延时约8us, 符合协议要求至少保持1us
110 ds = 1;
111 i++; i++; //延时约16us, 符合协议要求的至少延时15us以上
112 b = ds;
113 i = 8;
114 while(i>0) i--; //延时约64us, 符合读时隙不低于60us要求
115 return b;
116}
117
118//读取一字节数据, 通过调用readBit()来实现
119unsigned char readByte()
120{
121 unsigned int i;
122 unsigned char j, dat;
123 dat = 0;
124 for(i=0; i<8; i++)
125 {
126 j = readBit();
127 //最先读出的是最低位数据
128 dat = (j << 7) | (dat >> 1);
129 }
130 return dat;
131}
132
133//向DS18B20写入一字节数据
134void writeByte(unsigned char dat)
135{
136 unsigned int i;
137 unsigned char j;
138 bit b;
139 for(j = 0; j < 8; j++)
140 {
141 b = dat & 0x01;
142 dat >>= 1;
143 //写"1", 将DQ拉低15us后, 在15us~60us内将DQ拉高, 即完成写1
144 if(b)
145 {
146 ds = 0;
147 i++; i++; //拉低约16us, 符号要求15~60us内
148 ds = 1;
149 i = 8; while(i>0) i--; //延时约64us, 符合写时隙不低于60us要求
150 }
151 else //写"0", 将DQ拉低60us~120us
152 {
153 ds = 0;
154 i = 8; while(i>0) i--; //拉低约64us, 符号要求
155 ds = 1;
156 i++; i++; //整个写0时隙过程已经超过60us, 这里就不用像写1那样, 再延时64us了
157 }
158 }
159}
160
161//向DS18B20发送温度转换命令
162void sendChangeCmd()
163{
164 dsInit(); //初始化DS18B20, 无论什么命令, 首先都要发起初始化
165 dsWait(); //等待DS18B20应答
166 delayMs(1); //延时1ms, 因为DS18B20会拉低DQ 60~240us作为应答信号
167 writeByte(0xcc); //写入跳过序列号命令字 Skip Rom
168 writeByte(0x44); //写入温度转换命令字 Convert T
169}
170
171//向DS18B20发送读取数据命令
172void sendReadCmd()
173{
174 dsInit();
175 dsWait();
176 delayMs(1);
177 writeByte(0xcc); //写入跳过序列号命令字 Skip Rom
178 writeByte(0xbe); //写入读取数据令字 Read Scratchpad
179}
180
181//获取当前温度值
182int getTmpValue()
183{
184 unsigned int tmpvalue;
185 int value; //存放温度数值
186 float t;
187 unsigned char low, high;
188 sendReadCmd();
189 //连续读取两个字节数据
190 low = readByte();
191 high = readByte();
192 //将高低两个字节合成一个整形变量
193 //计算机中对于负数是利用补码来表示的
194 //若是负值, 读取出来的数值是用补码表示的, 可直接赋值给int型的value
195 tmpvalue = high;
196 tmpvalue <<= 8;
197 tmpvalue |= low;
198 value = tmpvalue;
199
200 //使用DS18B20的默认分辨率12位, 精确度为0.0625度, 即读回数据的最低位代表0.0625度
201 t = value * 0.0625;
202 //将它放大100倍, 使显示时可显示小数点后两位, 并对小数点后第三进行4舍5入
203 //如t=11.0625, 进行计数后, 得到value = 1106, 即11.06 度
204 //如t=-11.0625, 进行计数后, 得到value = -1106, 即-11.06 度
205 value = t * 100 + (value > 0 ? 0.5 : -0.5); //大于0加0.5, 小于0减0.5
206 return value;
207}
208
209void display(int v)
210{
211 unsigned char count;
212 unsigned char datas[] = {0, 0, 0, 0, 0};
213 unsigned int tmp = abs(v);
214 datas[0] = tmp / 10000;
215 datas[1] = tmp % 10000 / 1000;
216 datas[2] = tmp % 1000 / 100;
217 datas[3] = tmp % 100 / 10;
218 datas[4] = tmp % 10;
219 writeComm(0xc0+3);
220 if(v < 0)
221 {
222 writeString("- ", 2);
223 }
224 else
225 {
226 writeString("+ ", 2);
227 }
228 if(datas[0] != 0)
229 {
230 writeData('0'+datas[0]);
231 }
232 for(count = 1; count != 5; count++)
233 {
234 writeData('0'+datas[count]);
235 if(count == 2)
236 {
237 writeData('.');
238 }
239 }
240}
241/**//*****************************DS18B20*******************************/
242
243void main()
244{
245 uchar table[] = "Now Temperature:";
246 sendChangeCmd();
247 init();
248 writeComm(0x80);
249 writeString(table, 16);
250 while(1)
251 {
252 delayMs(1000); //温度转换时间需要750ms以上
253 writeComm(0xc0);
254 display(getTmpValue());
255 sendChangeCmd();
256 }
257}
1//1602液晶显示程序, TX-1B实验板上的1602LCD的R/W读写端接地, 即始终只写, 不读数据
2//使用1602LCD显示DS18B20转换的温度值
3#include <reg52.H>
4#include <intrins.H>
5#include <math.H>
6
7#define uchar unsigned char
8#define uint unsigned int
9sbit dula = P2^6;
10sbit wela = P2^7;
11
12sbit RS = P3^5; //数据/命令选择端(H/L)
13sbit LCDEN = P3^4; //使能端
14
15void delayUs()
16{
17 _nop_();
18}
19
20void delayMs(uint a)
21{
22 uint i, j;
23 for(i = a; i > 0; i--)
24 for(j = 100; j > 0; j--);
25}
26
27//第一行开始地址为0x80, 第二行开始地址为0xc0;
28//写命令:RS=0, RW=0;
29void writeComm(uchar comm)
30{
31 RS = 0;
32 P0 = comm;
33 LCDEN = 1;
34 delayUs();
35 LCDEN = 0;
36 delayMs(1);
37}
38
39//写数据:RS=1, RW=0;
40void writeData(uchar dat)
41{
42 RS = 1;
43 P0 = dat;
44 LCDEN = 1;
45 delayUs();
46 LCDEN = 0;
47 delayMs(1);
48}
49
50//初始化
51//显示模式, 固定指令为00111000=0x38, 16*2显示, 5*7点阵,8位数据接口
52//显示开/关及光标设置
53//指令1: 00001DCB : D:开显示/关显示(H/L); C:显示光标/不显示(H/L), B:光标闪烁/不闪烁(H/L)
54//指令2: 000001NS :
55//N=1, 当读/写一个字符后地址指针加1, 且光标也加1; N=0则相反
56//S=1, 当写一个字符, 整屏显示左移(N=1)或右移(N=0), 但光标不移动; S=0, 整屏不移动
57void init()
58{
59 //先关闭数码管, 使两个锁存器锁存, 因开了数码管, USB电压驱动不够, 将无法使LCD正常工作
60 dula = wela = 0;
61 writeComm(0x38); //显示模式
62 writeComm(0x0c); //开显示, 关光标
63 writeComm(0x06); //写字符后地址加1, 光标加1
64 writeComm(0x01); //清屏
65}
66
67void writeString(uchar * str, uchar length)
68{
69 uchar i;
70 for(i = 0; i < length; i++)
71 {
72 writeData(str[i]);
73 }
74}
75
76/**//*****************************DS18B20*******************************/
77sbit ds = P2^2;
78//初始化DS18B20
79//让DS18B20一段相对长时间低电平, 然后一段相对非常短时间高电平, 即可启动
80void dsInit()
81{
82 //对于11.0592MHz时钟, unsigned int型的i, 作一个i++操作的时间大于为8us
83 unsigned int i;
84 ds = 0;
85 i = 100; //拉低约800us, 符合协议要求的480us以上
86 while(i>0) i--;
87 ds = 1; //产生一个上升沿, 进入等待应答状态
88 i = 4;
89 while(i>0) i--;
90}
91
92void dsWait()
93{
94 unsigned int i;
95 while(ds);
96 while(~ds); //检测到应答脉冲
97 i = 4;
98 while(i > 0) i--;
99}
100
101//向DS18B20读取一位数据
102//读一位, 让DS18B20一小周期低电平, 然后两小周期高电平,
103//之后DS18B20则会输出持续一段时间的一位数据
104bit readBit()
105{
106 unsigned int i;
107 bit b;
108 ds = 0;
109 i++; //延时约8us, 符合协议要求至少保持1us
110 ds = 1;
111 i++; i++; //延时约16us, 符合协议要求的至少延时15us以上
112 b = ds;
113 i = 8;
114 while(i>0) i--; //延时约64us, 符合读时隙不低于60us要求
115 return b;
116}
117
118//读取一字节数据, 通过调用readBit()来实现
119unsigned char readByte()
120{
121 unsigned int i;
122 unsigned char j, dat;
123 dat = 0;
124 for(i=0; i<8; i++)
125 {
126 j = readBit();
127 //最先读出的是最低位数据
128 dat = (j << 7) | (dat >> 1);
129 }
130 return dat;
131}
132
133//向DS18B20写入一字节数据
134void writeByte(unsigned char dat)
135{
136 unsigned int i;
137 unsigned char j;
138 bit b;
139 for(j = 0; j < 8; j++)
140 {
141 b = dat & 0x01;
142 dat >>= 1;
143 //写"1", 将DQ拉低15us后, 在15us~60us内将DQ拉高, 即完成写1
144 if(b)
145 {
146 ds = 0;
147 i++; i++; //拉低约16us, 符号要求15~60us内
148 ds = 1;
149 i = 8; while(i>0) i--; //延时约64us, 符合写时隙不低于60us要求
150 }
151 else //写"0", 将DQ拉低60us~120us
152 {
153 ds = 0;
154 i = 8; while(i>0) i--; //拉低约64us, 符号要求
155 ds = 1;
156 i++; i++; //整个写0时隙过程已经超过60us, 这里就不用像写1那样, 再延时64us了
157 }
158 }
159}
160
161//向DS18B20发送温度转换命令
162void sendChangeCmd()
163{
164 dsInit(); //初始化DS18B20, 无论什么命令, 首先都要发起初始化
165 dsWait(); //等待DS18B20应答
166 delayMs(1); //延时1ms, 因为DS18B20会拉低DQ 60~240us作为应答信号
167 writeByte(0xcc); //写入跳过序列号命令字 Skip Rom
168 writeByte(0x44); //写入温度转换命令字 Convert T
169}
170
171//向DS18B20发送读取数据命令
172void sendReadCmd()
173{
174 dsInit();
175 dsWait();
176 delayMs(1);
177 writeByte(0xcc); //写入跳过序列号命令字 Skip Rom
178 writeByte(0xbe); //写入读取数据令字 Read Scratchpad
179}
180
181//获取当前温度值
182int getTmpValue()
183{
184 unsigned int tmpvalue;
185 int value; //存放温度数值
186 float t;
187 unsigned char low, high;
188 sendReadCmd();
189 //连续读取两个字节数据
190 low = readByte();
191 high = readByte();
192 //将高低两个字节合成一个整形变量
193 //计算机中对于负数是利用补码来表示的
194 //若是负值, 读取出来的数值是用补码表示的, 可直接赋值给int型的value
195 tmpvalue = high;
196 tmpvalue <<= 8;
197 tmpvalue |= low;
198 value = tmpvalue;
199
200 //使用DS18B20的默认分辨率12位, 精确度为0.0625度, 即读回数据的最低位代表0.0625度
201 t = value * 0.0625;
202 //将它放大100倍, 使显示时可显示小数点后两位, 并对小数点后第三进行4舍5入
203 //如t=11.0625, 进行计数后, 得到value = 1106, 即11.06 度
204 //如t=-11.0625, 进行计数后, 得到value = -1106, 即-11.06 度
205 value = t * 100 + (value > 0 ? 0.5 : -0.5); //大于0加0.5, 小于0减0.5
206 return value;
207}
208
209void display(int v)
210{
211 unsigned char count;
212 unsigned char datas[] = {0, 0, 0, 0, 0};
213 unsigned int tmp = abs(v);
214 datas[0] = tmp / 10000;
215 datas[1] = tmp % 10000 / 1000;
216 datas[2] = tmp % 1000 / 100;
217 datas[3] = tmp % 100 / 10;
218 datas[4] = tmp % 10;
219 writeComm(0xc0+3);
220 if(v < 0)
221 {
222 writeString("- ", 2);
223 }
224 else
225 {
226 writeString("+ ", 2);
227 }
228 if(datas[0] != 0)
229 {
230 writeData('0'+datas[0]);
231 }
232 for(count = 1; count != 5; count++)
233 {
234 writeData('0'+datas[count]);
235 if(count == 2)
236 {
237 writeData('.');
238 }
239 }
240}
241/**//*****************************DS18B20*******************************/
242
243void main()
244{
245 uchar table[] = "Now Temperature:";
246 sendChangeCmd();
247 init();
248 writeComm(0x80);
249 writeString(table, 16);
250 while(1)
251 {
252 delayMs(1000); //温度转换时间需要750ms以上
253 writeComm(0xc0);
254 display(getTmpValue());
255 sendChangeCmd();
256 }
257}
效果图1:
效果图2: