【个人笔记】基于单片机的 倒车雷达系统设计 硬件开发(仿真图、原理图、PCB图、实物图、C语言程序代码)
仿真图
电路图
原理图
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 }