這是我上個月做的單片機智能小車,目前可實現紅外避障和藍牙遙控。保證原創,請多多指教。
0.png (9.36 KB, 下載次數: 31)
下載附件
2018-6-2 01:40 上傳
單片機源程序如下:
- #include<reg52.h>
- #include<C52_car.h>
- #include <intrins.h>//包含_nop_指令的頭文件
- #define MAIN_Fosc 11059200UL //宏定義主時鐘HZ
- #define PCF8591_ADDR 0x90 //PCF8591地址
- #define DACOUT_EN 0x40 //DAC輸出使能
- typedef unsigned char uchar;
- typedef unsigned int uint;
- unsigned char pwm_left_val = 0;//左電機占空比值 取值范圍0-80,0最快
- unsigned char pwm_right_val = 0;//右電機占空比值取值范圍0-80 ,0最快
- unsigned char pwm_t = 0;//周期
- unsigned char control=0X01;//車運動控制全局變量,默認開機為停車狀態
- unsigned int time = 0;//傳輸時間
- unsigned long S = 0;//距離
- unsigned char count=0;
- unsigned char SEH_count; //舵機朝向前面
- #define LCD1602_DB P0 //LCD1602數據總線
- uchar Control_mode = 0;
- uchar AD_Value; //存儲AD轉換回的數字量
- sbit LCD1602_RS = P3^5; //RS端
- sbit LCD1602_RW = P3^6; //RW端
- sbit LCD1602_EN = P3^4; //EN端
- sbit DU = P2^6;//
- sbit WE = P2^7;//數碼管位選段選用于關閉數碼管顯示
- void delay(unsigned int z)//毫秒級延時
- {
- unsigned int x,y;
- for(x = z; x > 0; x--)
- for(y = 114; y > 0 ; y--);
- }
- void Delay10us(unsigned char i) //10us延時函數 啟動超聲波模塊時使用
- {
- unsigned char j;
- do{
- j = 10;
- do{
- _nop_();
- }while(--j);
- }while(--i);
- }
- /*====================================
- 函數:void Delay5us()
- 描述:12T 51單片機5微秒延時函數自適應時鐘(11.0592M,12M,22.1184M)
- ====================================*/
- void Delay5us()
- {
- #if MAIN_Fosc == 11059200
- _nop_();
- #elif MAIN_Fosc == 12000000
- _nop_();
- #elif MAIN_Fosc == 22118400
- _nop_(); _nop_(); _nop_();
- #endif
- }
- /*小車前進*/
- void forward()
- {
- left_motor_go; //左電機前進
- right_motor_go; //右電機前進
- }
- /*小車左轉*/
- void left_run()
- {
- left_motor_stops; //左電機停止
- right_motor_go; //右電機前進
- }
- /*小車右轉*/
- void right_run()
- {
- right_motor_stops;//右電機停止
- left_motor_go; //左電機前進
- }
- /*PWM控制使能 小車后退*/
- void backward()
- {
- left_motor_back; //左電機后退
- right_motor_back; //右電機后退
- }
- void stop()
- {
- left_motor_stops; //左電機后退
- right_motor_stops; //右電機后退
- }
- void Init(void)
- {
- EA = 1; //開總中斷
- PT0 = 1;
- IT0 = 0; //邊沿觸發方式
- IT1 = 0; //邊沿觸發方式
- SCON |= 0x50; // SCON: 模式1, 8-bit UART, 使能接收
- T2CON |= 0x34; //設置定時器2為串口波特率發生器并啟動定時器2
- TL2 = RCAP2L = (65536-(FOSC/32/BAUD)); //設置波特率
- TH2 = RCAP2H = (65536-(FOSC/32/BAUD)) >> 8;
- ES= 1; //打開串口中斷
-
- TMOD |= 0x01; //定時器0,工作模式1,16位定時模式
- TH0 = 0;
- TL0 = 0; //T0,16位定時計數用于記錄ECHO高電平時間
- TR0 = 1; //啟動定時器0
- ET0 = 1; //允許定時器0中斷
- TMOD |= 0x10; //定時器1,16位定時模式。
- TH1 = 0xff; //配置定時器0初值,溢出時間為0.1ms
- TL1 = 0xa3;
- TR1 = 1; //啟動定時器1
- ET1 = 1; //允許T1中斷
- }
- void StartModule() //啟動超聲波模塊
- {
- TX=1; //啟動一次模塊
- Delay10us(2);
- TX=0;
- }
- /*計算超聲波所測距離并顯示*/
- void Conut()
- {
- time=TH0*256+TL0;
- TH0 = 0;
- TL0 = 0;
- S=(float)(time*1.085)*0.17; //算出來是MM
- if(S>=7000) //超出測量范圍
- {
- stop();
- beep = 0;
- delay(1000);
- beep = 1;
- }
- }
- /*====================================
- 函數:void SEH_count_0()
- 描述:舵機在左側時指令
- ====================================*/
- void SEH_count_5()
- {
- StartModule(); //啟動模塊測距
- while(!RX); //當RX(ECHO信號回響)為零時等待
- TR0 = 1; //開啟計數
- while(RX) ; //當RX為1計數并等待
- TR0 = 0; //關閉計數
- Conut(); //計算距離
- if(S > 170 && S <850 )//設置隨動距離(單位毫米)
- {
- left_run();
- }
- }
- /*====================================
- 函數:void SEH_count_10()
- 描述:舵機在中間時指令
- ====================================*/
- void SEH_count_10()
- {
- StartModule(); //啟動模塊測距
- while(!RX); //當RX(ECHO信號回響)為零時等待
- TR0 = 1; //開啟計數
- while(RX) ; //當RX為1計數并等待
- TR0 = 0; //關閉計數
- Conut(); //計算距離
- if(S > 170 && S <850 )//設置隨動距離(單位毫米)
- {
- forward();
- }
- }
- /*====================================
- 函數:void SEH_count_20()
- 描述:舵機在右側時指令
- ====================================*/
- void SEH_count_15()
- {
- StartModule(); //啟動模塊測距
- while(!RX); //當RX(ECHO信號回響)為零時等待
- TR0 = 1; //開啟計數
- while(RX) ; //當RX為1計數并等待
- TR0 = 0; //關閉計數
- Conut(); //計算距離
- if(S > 150 && S <850 )//設置隨動距離(單位毫米)
- {
- right_run();
- }
- }
- /*====================================
- 函數:I2C_init()
- 描述:I2C總線初始化
- ====================================*/
- void I2C_init()
- {
- SDA = 1; //數據總線高
- _nop_();
- SCL = 1; //時鐘總線高
- _nop_();
- }
- /*====================================
- 函數:I2C_Start()
- 描述:I2C起始信號
- ====================================*/
- void I2C_Start()
- {
- SCL = 1;
- _nop_();
- SDA = 1;
- Delay5us();
- SDA = 0;
- Delay5us();
- }
- /*====================================
- 函數:I2C_Stop()
- 描述:I2C停止信號
- ====================================*/
- void I2C_Stop()
- {
- SDA = 0;
- _nop_();
- SCL = 1;
- Delay5us();
- SDA = 1;
- Delay5us();
- }
- /*====================================
- 函數:Master_ACK(bit i)
- 參數:i 為0時發送非應答 為1時發送應答
- 描述:I2C主機發送應答
- ====================================*/
- void Master_ACK(bit i)
- {
- SCL = 0; // 拉低時鐘總線允許SDA數據總線上的數據變化
- _nop_(); // 讓總線穩定
- if (i) //如果i = 1 那么拉低數據總線 表示主機應答
- {
- SDA = 0;
- }
- else
- {
- SDA = 1; //發送非應答
- }
- _nop_();//讓總線穩定
- SCL = 1;//拉高時鐘總線 讓從機從SDA線上讀走 主機的應答信號
- _nop_();
- SCL = 0;//拉低時鐘總線, 占用總線繼續通信
- _nop_();
- SDA = 1;//釋放SDA數據總線。
- _nop_();
- }
- /*====================================
- 函數:Test_ACK()
- 返回:0為非應答 1為應答
- 描述:I2C檢測從機應答
- ====================================*/
- bit Test_ACK() // 檢測從機應答
- {
- SCL = 1;//時鐘總線為高電平期間可以讀取從機應答信號
- Delay5us();
- if (SDA)
- {
- SCL = 0;
- I2C_Stop();
- return(0);
- }
- else
- {
- SCL = 0;
- return(1);
- }
- }
- /*====================================
- 函數:I2C_send_byte(uchar byte)
- 參數:byte 要發送的字節
- 描述:I2C發送一個字節
- ====================================*/
- void I2C_send_byte(uchar byte)
- {
- uchar i;
- for(i = 0 ; i < 8 ; i++)
- {
- SCL = 0;
- _nop_();
- if (byte & 0x80) //
- {
- SDA = 1;
- _nop_();
- }
- else
- {
- SDA = 0;
- _nop_();
- }
- SCL = 1;
- _nop_();
- byte <<= 1;
- }
- SCL = 0;
- _nop_();
- SDA = 1;
- _nop_();
- }
- /*====================================
- 函數:I2C_read_byte()
- 返回:讀取的字節
- 描述:I2C讀一個字節
- ====================================*/
- uchar I2C_read_byte()
- {
- uchar i, dat;
- SCL = 0 ;
- _nop_();
- SDA = 1;
- _nop_();
- for(i = 0 ; i < 8 ; i++)
- {
- SCL = 1;
- _nop_();
- dat <<= 1;
- if (SDA)
- {
- dat |= 0x01;
- }
- _nop_();
- SCL = 0;
- _nop_();
- }
- return(dat);
- }
- /*讀AD數據*/
- bit ADC_Read(uchar CON)
- {
- I2C_Start();
- I2C_send_byte(PCF8591_ADDR+0);
- if (!Test_ACK())
- {
- return(0);
- }
- I2C_send_byte(CON);
- Master_ACK(0);
- I2C_Start();
- I2C_send_byte(PCF8591_ADDR+1);
- if (!Test_ACK())
- {
- return(0);
- }
- AD_Value = I2C_read_byte();
- Master_ACK(0);
- I2C_Stop();
- return(1);
- }
- /*=================================================
- *函數名稱:Read_Busy
- *函數功能:判斷1602液晶忙,并等待
- =================================================*/
- void Read_Busy()
- {
- uchar busy;
- LCD1602_DB = 0xff;//復位數據總線
- LCD1602_RS = 0; //拉低RS
- LCD1602_RW = 1; //拉高RW讀
- do
- {
- LCD1602_EN = 1;//使能EN
- busy = LCD1602_DB;//讀回數據
- LCD1602_EN = 0; //拉低使能以便于下一次產生上升沿
- }while(busy & 0x80); //判斷狀態字BIT7位是否為1,為1則表示忙,程序等待
- }
- /*=================================================
- *函數名稱:LCD1602_Write_Cmd
- *函數功能:寫LCD1602命令
- *調用:Read_Busy();
- *輸入:cmd:要寫的命令
- =================================================*/
- void LCD1602_Write_Cmd(uchar cmd)
- {
- Read_Busy(); //判斷忙,忙則等待
- LCD1602_RS = 0;
- LCD1602_RW = 0; //拉低RS、RW操作時序情況1602課件下中文使用說明基本操作時序章節
- LCD1602_DB = cmd;//寫入命令
- LCD1602_EN = 1; //拉高使能端 數據被傳輸到LCD1602內
- LCD1602_EN = 0; //拉低使能以便于下一次產生上升沿
- }
- /*=================================================
- *函數名稱:LCD1602_Write_Dat
- *函數功能:寫LCD1602數據
- *調用:Read_Busy();
- *輸入:dat:需要寫入的數據
- =================================================*/
- void LCD1602_Write_Dat(uchar dat)
- {
- Read_Busy();
- LCD1602_RS = 1;
- LCD1602_RW = 0;
- LCD1602_DB = dat;
- LCD1602_EN = 1;
- LCD1602_EN = 0;
- }
- /*=================================================
- *函數名稱:LCD1602_Dis_Str
- *函數功能:在指定位置顯示字符串
- *調用:LCD1602_Write_Cmd(); LCD1602_Write_Dat();
- *輸入:x:要顯示的橫坐標取值0-40,y:要顯示的行坐標取值0-1(0為第一行,1為第二行)
- *str:需要顯示的字符串
- =================================================*/
- void LCD1602_Dis_Str(uchar x, uchar y, uchar *str)
- {
- if(y) x |= 0x40;
- x |= 0x80;
- LCD1602_Write_Cmd(x);
- while(*str != '\0')
- {
- LCD1602_Write_Dat(*str++);
- }
- }
- /*=================================================
- *函數名稱:Init_LCD1602
- *函數功能:1602初始化
- *調用: LCD1602_Write_Cmd();
- =================================================*/
- void Init_LCD1602()
- {
- LCD1602_Write_Cmd(0x38); // 設置16*2顯示,5*7點陣,8位數據接口
- LCD1602_Write_Cmd(0x0c); //開顯示
- LCD1602_Write_Cmd(0x06); //讀寫一字節后地址指針加1
- LCD1602_Write_Cmd(0x01); //清除顯示
- }
- /*=================================================
- *函數名稱:Dispaly_LCD1602
- *函數功能:1602顯示字符
- *調用: LCD1602_Write_Cmd();
- =================================================*/
- void Dispaly_LCD1602()
- {
- int LCD_CK=0;
- uchar Str_1[] = {"Welcome to use"};
- uchar Str_2[] = {"Pick a pattern"};
- uchar Str_3[] = {"S2 -> automatic"};
- uchar Str_4[] = {"S3 -> bluetooth"};
- Init_LCD1602();//1602初始化
- for(;;) //死循環
- {
- if(LCD_CK == 0)
- {
- LCD1602_Dis_Str(0, 0, &Str_1[0]); //顯示字符串
- LCD1602_Dis_Str(0, 1, &Str_2[0]); //顯示字符串
- delay(10);
- }
- if(LCD_CK == 20000)
- {
- LCD1602_Dis_Str(0, 0, &Str_3[0]); //顯示字符串
- LCD1602_Dis_Str(0, 1, &Str_4[0]); //顯示字符串
- delay(10);
- }/**/
-
- if(key_s2 == 0)// 實時檢測S2按鍵是否被按下
- {
- delay(5); //軟件消抖
- if(key_s2 == 0)//再檢測S2是否被按下
- {
- while(!key_s2);//松手檢測
- delay(50);//50毫秒延時
- Control_mode = 0;
- break; //退出FOR死循環
- }
- }
- if(key_s3 == 0)// 實時檢測S3按鍵是否被按下
- {
- delay(5); //軟件消抖
- if(key_s3 == 0)//再檢測S3是否被按下
- {
- while(!key_s3);//松手檢測
- delay(50);//50毫秒延時
- Control_mode = 1;
- break; //退出FOR死循環
- }
- }
- if(LCD_CK <= 40000) LCD_CK++;
- if(LCD_CK >= 40000) LCD_CK = 0;
- }
- }
- void main()
- {
- DU = 0;
- WE = 0;
- EN2 = EN1 =1;
- SEH_count = 10;
- Dispaly_LCD1602();
- I2C_init();//I2C初始化
- LCD1602_Write_Cmd(0x08); //關閉1602顯示
- Init();//定時器、串口初始化Init();//定時器、串口初始化
- beep = 0;
- delay(200);//延時1秒
- beep = 1;
- while(1)
- {
- if(Control_mode == 1)
- {
- EX0 = 0; //關閉外部中斷1
- EX1 = 0; //關閉外部中斷2
- while(1)
- {
- if(control>0X07)//如果成立,則表示接收的命令不在運行命令內
- {
- stop(); // 停車
- }
- switch(control)
- {
- case 0X02: forward(); break;//前進
- case 0X03: backward(); break;//后退
- case 0X04: left_run(); break;//左轉
- case 0X05: right_run(); break;//右轉
- case 0X01: stop(); break;//停車
- case 0X08: beep = 0; break;//鳴笛
- case 0X09: beep = 1; break;//停止鳴笛
- case 0X0B: SEH_count = 10; break;//SEH_COUNT: 10:0.5+1(0.1*10T)=1.5ms->90°舵機角度
- case 0X0A: Control_mode = 0;break;
- }
- break;
- }
- }
- if(Control_mode == 0)
- {
- EX0 = 1; //打開外部中斷1
- EX1 = 1; //打開外部中斷2
- for (;;)
- {
- SEH_count = 12;
- delay(300);
- ADC_Read(0x03);//體感模塊,當檢測到人體收輸出3.3高電平
- if(AD_Value > 100) SEH_count_10();
- SEH_count = 6;
- delay(300);
- ADC_Read(0x03);//體感模塊,當檢測到人體收輸出3.3高電平
- if(AD_Value > 100) SEH_count_5();//大于3.1V表示感應到了人體,小車行進
- SEH_count = 12;
- delay(300);
- ADC_Read(0x03);//體感模塊,當檢測到人體收輸出3.3高電平
- if(AD_Value > 100) SEH_count_10();
- SEH_count = 18;
- delay(300);
- ADC_Read(0x03);//體感模塊,當檢測到人體收輸出3.3高電平
- if(AD_Value > 150) SEH_count_15();
- if(control == 0X0C)
- {
- Control_mode = 1;
- break;
- }
- }
- }
- }
- }
- void int0() interrupt 0
- {
- EX0 = 0;
- delay(10);
- if(left_led2 == 0)
- {
- backward();
- delay(500);
- key_s3 = 1;
- right_run();
- delay(700);
- forward();
- delay(500);
- stop();
- }
- EX0 = 1;
- }
- //定時器0中斷
- void timer0() interrupt 1
- {
- /* pwm_t++;//周期計時加
- if(pwm_t == 120)
- pwm_t = EN1 = EN2 = 0;
- if(pwm_left_val == pwm_t)//左電機占空比
- EN1 = 1;
- if(pwm_right_val == pwm_t)//右電機占空比
- EN2 = 1;
- */
- }
- void int1() interrupt 2
- {
- EX1 = 0;
- delay(10);
- if(right_led2 == 0)
- {
-
- backward();
- delay(500);
- key_s3 = 1;
- left_run();
- delay(700);
- forward();
- delay(500);
- stop();
- }
- EX1 = 1;
- }
- //定時器1中斷
- void timer1() interrupt 3 //T1中斷用來計數器溢出
- {
- TR1 = 0; //關閉定時器1
- TH1 = 0xff; //重裝初值0.1ms
- TL1 = 0xa3;
- //舵機1
- if(count <= SEH_count) //控制占空比左右
- {
- //如果count的計數小于(5-25)也就是0.5ms-2.5ms則這段小t周期持續高電平。產生方波
- Servo = 1;
- }
- else
- {
- Servo = 0;
- }
- count++;
- if (count >= 200) //T = 20ms則定時器計數變量清0
- {
- count = 0;
- }
- TR1 = 1; //開啟定時器1
- }
- /******************************************************************/
- /* 串口中斷程序*/
- /******************************************************************/
- void UART_SER () interrupt 4
- {
- unsigned char n; //定義臨時變量
- if(RI) //判斷是接收中斷產生
- {
- RI=0; //標志位清零
- n=SBUF; //讀入緩沖區的值
- control=n;
- /* if((n >= 51) && (n <= 150))//左電機調速0~100個檔位 手機端軟件進行調節
- pwm_left_val = 0.8-((n-50)*0.8);
- if((n >= 151) && (n <= 250)) //右電機調速0~100個檔位 手機端軟件進行調節
- pwm_right_val = 0.8-((n-150)*0.8);*/
- if((n >= 51) && (n <= 150))//左電機調速0~100個檔位 手機端軟件進行調節
- pwm_left_val = 1.7-((n-50)*1.7);
- if((n >= 151) && (n <= 250)) //右電機調速0~100個檔位 手機端軟件進行調節
- pwm_right_val = 1.7-((n-150)*1.7);
- }
- }
復制代碼
所有資料51hei提供下載:
Smart_car4 紅外避障&超聲波跟隨.rar
(56.44 KB, 下載次數: 25)
2018-6-1 17:04 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|