基於單片機的倒車雷達系統設計
仿真圖

電路圖
原理圖

PCB圖

實物圖

C程序
1 #include <reg52.h>
2 #include <intrins.h>
3
4 #define uchar unsigned char // 以后unsigned char就可以用uchar代替
5 #define uint unsigned int // 以后unsigned int 就可以用uint 代替
6
7 sfr ISP_DATA = 0xe2; // 數據寄存器
8 sfr ISP_ADDRH = 0xe3; // 地址寄存器高八位
9 sfr ISP_ADDRL = 0xe4; // 地址寄存器低八位
10 sfr ISP_CMD = 0xe5; // 命令寄存器
11 sfr ISP_TRIG = 0xe6; // 命令觸發寄存器
12 sfr ISP_CONTR = 0xe7; // 命令寄存器
13
14 sbit LcdRs_P = P1^1; // 1602液晶的RS管腳
15 sbit LcdRw_P = P1^2; // 1602液晶的RW管腳
16 sbit LcdEn_P = P1^3; // 1602液晶的EN管腳
17
18 sbit Trig1_P = P3^2; // 超聲波模塊1的Trig管腳
19 sbit Echo1_P = P3^3; // 超聲波模塊1的Echo管腳
20
21 sbit KeySet_P = P2^2; // 設置按鍵的管腳
22 sbit KeyDown_P = P2^1; // 減按鍵的管腳
23 sbit KeyUp_P = P2^0; // 加按鍵的管腳
24
25 sbit Buzzer_P = P2^3; // 蜂鳴器的管腳
26 sbit Led1_P = P3^4; // 傳感器1報警燈
27
28 uint gAlarm; // 報警距離變量
29
30
31
32 /*********************************************************/
33 // 單片機內部EEPROM不使能
34 /*********************************************************/
35 void ISP_Disable()
36 {
37 ISP_CONTR = 0;
38 ISP_ADDRH = 0;
39 ISP_ADDRL = 0;
40 }
41
42
43 /*********************************************************/
44 // 從單片機內部EEPROM讀一個字節,從0x2000地址開始
45 /*********************************************************/
46 unsigned char EEPROM_Read(unsigned int add)
47 {
48 ISP_DATA = 0x00;
49 ISP_CONTR = 0x83;
50 ISP_CMD = 0x01;
51 ISP_ADDRH = (unsigned char)(add>>8);
52 ISP_ADDRL = (unsigned char)(add&0xff);
53 // 對STC89C51系列來說,每次要寫入0x46,再寫入0xB9,ISP/IAP才會生效
54 ISP_TRIG = 0x46;
55 ISP_TRIG = 0xB9;
56 _nop_();
57 ISP_Disable();
58 return (ISP_DATA);
59 }
60
61
62 /*********************************************************/
63 // 往單片機內部EEPROM寫一個字節,從0x2000地址開始
64 /*********************************************************/
65 void EEPROM_Write(unsigned int add,unsigned char ch)
66 {
67 ISP_CONTR = 0x83;
68 ISP_CMD = 0x02;
69 ISP_ADDRH = (unsigned char)(add>>8);
70 ISP_ADDRL = (unsigned char)(add&0xff);
71 ISP_DATA = ch;
72 ISP_TRIG = 0x46;
73 ISP_TRIG = 0xB9;
74 _nop_();
75 ISP_Disable();
76 }
77
78
79 /*********************************************************/
80 // 擦除單片機內部EEPROM的一個扇區
81 // 寫8個扇區中隨便一個的地址,便擦除該扇區,寫入前要先擦除
82 /*********************************************************/
83 void Sector_Erase(unsigned int add)
84 {
85 ISP_CONTR = 0x83;
86 ISP_CMD = 0x03;
87 ISP_ADDRH = (unsigned char)(add>>8);
88 ISP_ADDRL = (unsigned char)(add&0xff);
89 ISP_TRIG = 0x46;
90 ISP_TRIG = 0xB9;
91 _nop_();
92 ISP_Disable();
93 }
94
95
96
97 /*********************************************************/
98 // 毫秒級的延時函數,time是要延時的毫秒數
99 /*********************************************************/
100 void DelayMs(uint time)
101 {
102 uint i,j;
103 for(i=0;i<time;i++)
104 for(j=0;j<112;j++);
105 }
106
107
108 /*********************************************************/
109 // 1602液晶寫命令函數,cmd就是要寫入的命令
110 /*********************************************************/
111 void LcdWriteCmd(uchar cmd)
112 {
113 LcdRs_P = 0;
114 LcdRw_P = 0;
115 LcdEn_P = 0;
116 P0=cmd;
117 DelayMs(2);
118 LcdEn_P = 1;
119 DelayMs(2);
120 LcdEn_P = 0;
121 }
122
123
124 /*********************************************************/
125 // 1602液晶寫數據函數,dat就是要寫入的數據
126 /*********************************************************/
127 void LcdWriteData(uchar dat)
128 {
129 LcdRs_P = 1;
130 LcdRw_P = 0;
131 LcdEn_P = 0;
132 P0=dat;
133 DelayMs(2);
134 LcdEn_P = 1;
135 DelayMs(2);
136 LcdEn_P = 0;
137 }
138
139
140 /*********************************************************/
141 // 液晶光標定位函數
142 /*********************************************************/
143 void LcdGotoXY(uchar line,uchar column)
144 {
145 // 第一行
146 if(line==0)
147 LcdWriteCmd(0x80+column);
148 // 第二行
149 if(line==1)
150 LcdWriteCmd(0x80+0x40+column);
151 }
152
153
154
155 /*********************************************************/
156 // 液晶輸出字符串函數
157 /*********************************************************/
158 void LcdPrintStr(uchar *str)
159 {
160 while(*str!='\0')
161 LcdWriteData(*str++);
162 }
163
164
165 /*********************************************************/
166 // 液晶輸出數字
167 /*********************************************************/
168 void LcdPrintNum(uint num)
169 {
170 LcdWriteData(num/100+0x30); // 百位
171 LcdWriteData(num%100/10+0x30); // 十位
172 LcdWriteData(num%10+0x30); // 個位
173 }
174
175
176 /*********************************************************/
177 // 1602液晶功能初始化
178 /*********************************************************/
179 void LcdInit()
180 {
181 LcdWriteCmd(0x38); // 16*2顯示,5*7點陣,8位數據口
182 LcdWriteCmd(0x0C); // 開顯示,不顯示光標
183 LcdWriteCmd(0x06); // 地址加1,當寫入數據后光標右移
184 LcdWriteCmd(0x01); // 清屏
185 }
186
187
188
189 /*********************************************************/
190 // 1602液晶顯示內容初始化
191 /*********************************************************/
192 void LcdShowInit()
193 {
194 LcdGotoXY(0,0); // 定位到第0行第0列
195 LcdPrintStr("D: cm "); // 第0行顯示"D: "
196 }
197
198
199 /*********************************************************/
200 // 計算傳感器1測量到的距離
201 /*********************************************************/
202
203 uint GetDistance1(void)
204 {
205 uint ss; // 用於記錄測得的距離
206
207 TH0=0;
208 TL0=0;
209
210 Trig1_P=1; // 給超聲波模塊1一個開始脈沖
211 DelayMs(1);
212 Trig1_P=0;
213
214 while(!Echo1_P); // 等待超聲波模塊1的返回脈沖
215 TR0=1; // 啟動定時器,開始計時
216 while(Echo1_P); // 等待超聲波模塊1的返回脈沖結束
217 TR0=0; // 停止定時器,停止計時
218
219 ss=((TH0*256+TL0)*0.034)/2; // 距離cm=(時間us * 速度cm/us)/2
220 return ss;
221 }
222
223 /*********************************************************/
224 // 按鍵掃描
225 /*********************************************************/
226 void KeyScanf()
227 {
228 if(KeySet_P==0) // 判斷是否有按鍵按下
229 {
230 LcdGotoXY(0,0); // 光標定位
231 LcdPrintStr(" Alarm Set "); // 第0行顯示“ Alarm Set ”
232 LcdGotoXY(1,0); // 光標定位
233 LcdPrintStr(" alarm= cm "); // 第1行顯示“ alarm= cm ”
234 LcdGotoXY(1,8); // 光標定位
235 LcdPrintNum(gAlarm); // 顯示當前的報警值
236
237 DelayMs(10); // 消除按鍵按下的抖動
238 while(!KeySet_P); // 等待按鍵釋放
239 DelayMs(10); // 消除按鍵松開的抖動
240
241 while(1)
242 {
243 /* 報警值減的處理 */
244 if(KeyDown_P==0)
245 {
246 if(gAlarm>2) // 報警值大於2才能減1
247 gAlarm--; // 報警值減1
248 LcdGotoXY(1,8); // 光標定位
249 LcdPrintNum(gAlarm); // 刷新修改后的報警值
250 DelayMs(300); // 延時
251 }
252
253 /* 報警值加的處理 */
254 if(KeyUp_P==0)
255 {
256 if(gAlarm<400) // 報警值小於400才能加1
257 gAlarm++; // 報警值加1
258 LcdGotoXY(1,8); // 光標定位
259 LcdPrintNum(gAlarm); // 刷新修改后的報警值
260 DelayMs(300); // 延時
261 }
262
263 /* 退出報警值設置 */
264 if(KeySet_P==0)
265 {
266 break; // 退出while循環
267 }
268 }
269
270 LcdShowInit(); // 液晶恢復測量到測量界面
271 DelayMs(10); // 消除按鍵按下的抖動
272 while(!KeySet_P); // 等待按鍵釋放
273 DelayMs(10); // 消除按鍵松開的抖動
274
275 Sector_Erase(0x2000); // 保存報警距離
276 EEPROM_Write(0x2000,gAlarm/100);
277 EEPROM_Write(0x2001,gAlarm%100);
278 }
279 }
280
281
282 /*********************************************************/
283 // 傳感器1報警判斷
284 /*********************************************************/
285 void AlarmJudge1(uint ss)
286 {
287
288 if(ss<gAlarm) // LED燈判斷
289 {
290 Led1_P=0;
291 Buzzer_P=1;
292 DelayMs(10);
293 Buzzer_P=0;
294 DelayMs(10);
295 }
296 else
297 {
298 Led1_P=1;
299 Buzzer_P=0;
300 }
301
302
303 }
304
305 /*********************************************************/
306 // 報警值初始化
307 /*********************************************************/
308 void AlarmInit()
309 {
310 gAlarm=EEPROM_Read(0x2000)*100+EEPROM_Read(0x2001); // 從EEPROM讀取報警值
311
312 if((gAlarm==0)||(gAlarm>400)) // 如果讀取到的報警值異常(等於0或大於400則認為異常)
313 {
314 gAlarm=15; // 重新賦值報警值為15
315 }
316 }
317
318
319 /*********************************************************/
320 // 主函數
321 /*********************************************************/
322 void main()
323 {
324 uchar i; // 循環變量
325 uint dist; // 保存測量結果
326
327 LcdInit(); // 液晶功能初始化
328 LcdShowInit(); // 液晶顯示內容初始化
329 AlarmInit(); // 報警值初始化
330
331 TMOD = 0x01; // 選擇定時器0,並且確定是工作方式1(為了超聲波模塊測量距離計時用的)
332
333 Trig1_P=0; // 初始化觸發引腳為低電平
334
335 while(1)
336 {
337 /*傳感器1*/
338 dist=GetDistance1(); // 讀取超聲波模塊1測量到的距離
339 LcdGotoXY(0,7); // 光標定位
340 LcdPrintNum(dist); // 顯示傳感器1測量到的距離
341 AlarmJudge1(dist); // 判斷傳感器1的測量距離是否需要報警
342
343 /*延時並掃描按鍵*/
344 for(i=0;i<15;i++)
345 {
346 KeyScanf();
347 DelayMs(10);
348 }
349
350
351 }
352 }