|
在主函数while(1)里面加上两句代码:
Distance = GetDistance();if(g_mode == MODE_AUTO)
我是在循迹的基础上加的oled(循迹也有点小问题,时不能正常循迹
改了好久都解决不了,请大佬瞅一瞅,看一看。感觉oled占用太多的空间,整个代码效率不高。
超声波我用了定时器2,循迹使用了定时器0,蓝牙串口使用了定时器1,代码:
主函数:
#include <REGX52.H>
#include "config.h"
#include "motor.h"
#include "HCSR04.h"
#include "Track.h"
#include "Delay.H"
#include "Bluetooth.H"
#include <iic.H>
#include <oled.H>
//函数初始化
void System_Init();
void main() {
System_Init();
// 开机动画
OLED_ShowStringWithTypewriter(24, 2, "Smart Car", 16);
Delay(500);
OLED_Clear();
while(1)
{
Distance = GetDistance();//超声波测距
OLED_Refresh();//OLED显示
if(g_mode == MODE_AUTO)
{
// 自动模式:循迹+避障
Track_Logic();
if(GetDistance() < SAFE_DIST)
{
ObstacleAvoidance();
}
}
else
{
// 蓝牙模式
if(g_bt_cmd) // 状态检测
{
Bluetooth_Control(g_bt_cmd);
g_bt_cmd = 0; // 清除指令标志
}
}
Delay(20); // 适当延时
}
}
void System_Init() {
Motor_Init(); // 电机初始化
Timer0_Init(); // PWM定时器0
Timer2_Init(); // 超声波定时器2
UART_Init(); // 串口初始化,定时器1
OLED_init(); // 初始化OLED
OLED_Clear(); // 清屏
OLED_Display_On();
}
超声波:
#include <REGX52.H>
#include "config.h"
#include "HCSR04.h"
#include "intrins.h"
#include "Delay.H"
#include "Motor.h"
bit timeout = 0;
void Timer2_Init()
{
T2CON = 0; // 清零控制寄存器(默认16位自动重装载模式)
T2MOD = 0; // 清零模式寄存器(递增计数)
RCAP2H = 0; // 重装载值高位(初始为0,用于超时计数)
RCAP2L = 0; // 重装载值低位
TH2 = TL2 = 0; // 计数器初值归零
ET2 = 1; // 开启定时器2中断
PT2 = 1; // 设置定时器2为高优先级
EA = 1; // 总中断使能
}
unsigned int GetDistance()
{
unsigned int time_us = 0;
Trig = 1; // 触发信号
Delay20us(); // 20us延时
Trig = 0;
while(!Echo); // 等待回波高电平
TR2 = 1; // 启动定时器2
while(Echo && !timeout); // 等待回波结束或超时
TR2 = 0; // 停止计时
if(timeout) { // 超时处理
timeout = 0;
return 999; // 返回无效值
}
time_us = (TH2 << 8) | TL2; // 获取计数值(注意:需在TR2=0时读取)
TH2 = TL2 = 0; // 定时器复位
return (time_us * 0.017); // 计算距离(cm)
}
//小车避障
void ObstacleAvoidance()
{
// 停止运动
Motor_Control(STOP, STOP, 0, 0);
Delay(200);
// 后退避让
Motor_Control(REV, REV, 70, 70);
Delay(500);
// 右转寻找新路径
Motor_Control(FWD, REV, 80, 80);
Delay(400);
// 恢复循迹
TH2 = TL2 = 0; // 超声波定时器复位
}
/* 定时器2中断处理超时*/
void Timer2_ISR() interrupt 5
{
static unsigned int timeout_cnt = 0;
TF2 = 0; // 必须手动清除中断标志
if(++timeout_cnt > 60000) { // 约350ms超时
timeout_cnt = 0;
timeout = 1;
}
}
蓝牙串口:
#include <REGX52.H>
#include "Bluetooth.H"
#include "Motor.h"
#include "config.h"
#include "Delay.H"
#define BT_BAUD 9600 // 波特率
// 模式枚举
volatile SystemMode g_mode = 0;
// 蓝牙指令缓存
volatile char g_bt_cmd = 0;
//串口初始化
void UART_Init() {
// 定时器1配置
TMOD &= 0x0F; // 保留定时器0配置
TMOD |= 0x20; // 定时器1模式2(8位自动重载)
TH1 = TL1 = 0xFD; // 波特率9600@11.0592MHz
TR1 = 1; // 启动定时器1
// 串口配置
PCON &= 0x7F;
SCON = 0x50; // 模式1,允许接收
ES = 1; // 使能串口中断
EA = 1; // 总中断使能
}
// 串口中断
void UART_ISR() interrupt 4 {
if(RI)
{
g_bt_cmd = SBUF; // 接收蓝牙指令
RI = 0;
// 模式切换指令解析
switch(g_bt_cmd) {
case 'A': // 自动模式指令
g_mode = MODE_AUTO;
IN1 = IN2 = IN3 = IN4 =0;//先注释
break;
case 'B': // 蓝牙模式指令
g_mode = MODE_BT;
IN1 = IN2 = IN3 = IN4 =0;
break;
}
}
}
void Bluetooth_Control(char cmd) {
switch(cmd) {
case '1': // 前进
Motor_Control(FWD, FWD, 70, 70);
Delay(50);
break;
case '2': // 后退
Motor_Control(REV, REV, 70, 70);
Delay(50);
break;
case '3': // 左转
Motor_Control(FWD, REV, 70, 70);
Delay(50);
break;
case '4': // 右转
Motor_Control(REV, FWD, 70, 70);
Delay(50);
break;
case '0': // 停止
Motor_Control(STOP, STOP, 0, 0);
Delay(50);
break;
}
}
oled部分代码:
/* 打字机效果显示函数 */
void OLED_ShowStringWithTypewriter(unsigned char x, unsigned char y, char *str, unsigned char Char_size)
{
while(*str) {
OLED_ShowChar(x, y, *str++, Char_size);
x += 8; // 字符宽度+间距
Delay(70); // 调整延时获得打字速度
if(x > 120) { // 换行处理
x = 0;
y += 2;
}
}
}
/* 显示红外循迹状态(二进制格式) */
void OLED_ShowTrackState(unsigned char x, unsigned char y)
{
char binary[5] = {0};
// 获取低四位并转换为二进制字符串
binary[0] = (Track_State & 0x08) ? '1' : '0';
binary[1] = (Track_State & 0x04) ? '1' : '0';
binary[2] = (Track_State & 0x02) ? '1' : '0';
binary[3] = (Track_State & 0x01) ? '1' : '0';
OLED_ShowString(x, y, binary, 16);
}
/* 主显示更新函数 */
void OLED_Refresh()
{
char dispBuf[16];
// 第一行:显示模式
OLED_Set_Pos(0,0);
switch(g_mode){
case MODE_AUTO: OLED_ShowString(0, 0, "Mode:Auto ", 16); break;
case MODE_BT: OLED_ShowString(0, 0, "Mode:BT ", 16); break;
}
// 第二行:显示距离
sprintf(dispBuf, "Dist:%3dcm", Distance);
OLED_ShowString(0, 2, dispBuf, 16);
// 第三行:显示循迹状态
OLED_ShowString(0, 4, "Track:", 16);
OLED_ShowTrackState(48, 4);
}
|
|