Arduino巡线小车主控部分讲解
·
ARDUINO巡线小车主控部分
概要

一、基本概念
1. 变量类型
(1) 无符号变量
| 类型 | 范围 | 等效类型 |
|---|---|---|
| unsigned char | 0-255 | uint8_t |
| unsigned int | 0-65,535 | uint16_t |
| unsigned long | 0-4,294,967,295 | uint32_t |
| bool | 0(False)/1(True) | - |
(2) 有符号变量
| 类型 | 范围 |
|---|---|
| char | -128~127 |
| int | -32,768~32,767 |
| float | ±3.4e±38 (~7位精度) |
(3) 特殊修饰符
| 修饰符 | 作用 |
|---|---|
static |
函数内:保持局部变量值 全局:限制作用域到当前文件 |
const |
声明只读变量(初始化后不可修改) |
volatile |
禁止编译器优化(用于多线程/中断变量) |
2. 阻塞 vs 非阻塞延时
| 类型 | 特点 | 适用场景 |
|---|---|---|
阻塞(delay()) |
独占CPU 代码执行暂停 |
简单任务 单任务系统 |
| 非阻塞(定时器) | 后台计时 多任务并行 |
复杂系统 实时响应需求 |
3. 宏定义
#define LED_PIN 12 // 无类型简单替换
二、定时器的配置与使用
1.定时器的基本概念(点击蓝色字体跳转)
(1)Arduino的定时器功能
(2)Arduino的定时器配置
2.定时器配置模板(1ms中断)
//定时器2初始化配置 1ms
void timer2_init()
{
// 配置Timer2
noInterrupts(); // 禁用所有中断
TCCR2A = 0; // 清零控制寄存器A
TCCR2B = 0; // 清零控制寄存器B
TCNT2 = 0; // 初始化计数器为0
// 设置比较匹配寄存器 - 每1ms中断一次
OCR2A = 249; // = (16MHz / (64 * 1000Hz)) - 1
TCCR2A |= (1 << WGM21); // 启用CTC模式(比较匹配时清零计数器)
TCCR2B |= (1 << CS22); // 设置64预分频 (CS22=1)
TIMSK2 |= (1 << OCIE2A); // 启用定时器比较匹配中断
interrupts(); // 启用所有中断
}
void setup() {
timer2_init(); //1ms
}
// Timer2比较匹配中断服务函数
ISR(TIMER2_COMPA_vect) {
}
void loop() {
}
3.定时器功能
(1)阻塞与非阻塞函数的区别
单任务场景(无明显差异)
#include <stdbool.h> //声明bool
unsigned char led_slow_down = 0;//led延时函数
unsigned int Motor_delay = 0;//延时计数
bool led_start = 0;//1-点亮 0熄灭
//LED处理函数
void led_proc(void)
{
if(led_slow_down) return;
led_slow_down = 1;
/* 非阻塞延时 */
// digitalWrite(12,led_start);
/* 阻塞延时 */
digitalWrite(12,0);
delay(500);
digitalWrite(12,1);
delay(500);
}
//定时器2初始化配置 1ms
void timer2_init()
{
// 配置Timer2
noInterrupts(); // 禁用所有中断
TCCR2A = 0; // 清零控制寄存器A
TCCR2B = 0; // 清零控制寄存器B
TCNT2 = 0; // 初始化计数器为0
// 设置比较匹配寄存器 - 每1ms中断一次
OCR2A = 249; // = (16MHz / (64 * 1000Hz)) - 1
TCCR2A |= (1 << WGM21); // 启用CTC模式(比较匹配时清零计数器)
TCCR2B |= (1 << CS22); // 设置64预分频 (CS22=1)
TIMSK2 |= (1 << OCIE2A); // 启用定时器比较匹配中断
interrupts(); // 启用所有中断
}
void setup() {
pinMode(12,OUTPUT);
timer2_init(); //1ms
}
// Timer2比较匹配中断服务函数
ISR(TIMER2_COMPA_vect) {
if(++led_slow_down == 10) led_slow_down = 0;//led刷新时间
/* 定时器延时计数(非阻塞) */
if(++Motor_delay >= 500)
{
Motor_delay = 0;//清空计数值
led_start ^= 1;//切换亮灭状态
}
}
void loop() {
led_proc();//刷新LED
}
多任务场景(关键差异)
演示代码:
/* 调用库声明 */
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <stdbool.h> //声明bool
/* Oled配置相关 */
Adafruit_SSD1306 OLED(128,64,&Wire,-1);
/* 变量声明区 */
unsigned char led_slow_down = 0;//led延时函数
unsigned char oled_slow_down = 0;//oled延时函数
unsigned int Motor_delay = 0;//延时计数
bool led_start = 0;//1-点亮 0熄灭
unsigned int i = 0;
//LED处理函数
void led_proc(void)
{
if(led_slow_down) return;
led_slow_down = 1;
/* 非阻塞延时 */
digitalWrite(12,led_start);
/* 阻塞延时 */
// digitalWrite(12,0);
// delay(500);
// digitalWrite(12,1);
// delay(500);
}
/* Oled显示函数 */
void oled_display(void)
{
if(oled_slow_down) return;
oled_slow_down = 1;
OLED.clearDisplay();//清屏
OLED.setTextSize(1);//字号大小
// 第一行:显示左侧距离
OLED.setCursor(0,0);
OLED.print("i: ");
OLED.print(i);
OLED.display();
}
//定时器2初始化配置 1ms
void timer2_init()
{
// 配置Timer2
noInterrupts(); // 禁用所有中断
TCCR2A = 0; // 清零控制寄存器A
TCCR2B = 0; // 清零控制寄存器B
TCNT2 = 0; // 初始化计数器为0
// 设置比较匹配寄存器 - 每1ms中断一次
OCR2A = 249; // = (16MHz / (64 * 1000Hz)) - 1
TCCR2A |= (1 << WGM21); // 启用CTC模式(比较匹配时清零计数器)
TCCR2B |= (1 << CS22); // 设置64预分频 (CS22=1)
TIMSK2 |= (1 << OCIE2A); // 启用定时器比较匹配中断
interrupts(); // 启用所有中断
}
void setup() {
/* LED相关 */
pinMode(12,OUTPUT);
/* Oled相关 */
OLED.begin(SSD1306_SWITCHCAPVCC,0x3c);
OLED.setTextColor(1);
timer2_init(); //1ms
}
// Timer2比较匹配中断服务函数
ISR(TIMER2_COMPA_vect) {
if(++led_slow_down == 10) led_slow_down = 0;//led刷新时间
if(++oled_slow_down == 10) oled_slow_down = 0;//oled刷新时间
i++;
/* 定时器延时计数(非阻塞) */
if(++Motor_delay >= 500)
{
Motor_delay = 0;//清空计数值
led_start ^= 1;//切换亮灭状态
}
}
void loop() {
led_proc();//刷新LED
oled_display();//刷新OLED
}
阻塞延时效果:
现象:LED闪烁期间OLED刷新完全停止
原因:delay()函数独占CPU资源
非阻塞延时效果:
现象:LED闪烁时OLED保持流畅刷新
优势:定时器中断后台计时,不占用主循环资源
小结:在多任务系统中,应减少阻塞延时函数的使用,防止延时任务对其他任务响应速度造成影响。
三、本次考核使用到的模块
1.OLED显示
(1)基本信息
视频教程:Arduino控制oled屏幕,速通-哔哩哔哩
详细信息:机器谱-OLED
(2)OLED显示代码(模块化+定时器2刷新)
/* 调用库声明 */
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
/* Oled配置相关 */
Adafruit_SSD1306 OLED(128,64,&Wire,-1);
/* 变量声明区 */
unsigned char oled_slow_down = 0;//oled延时函数
unsigned char i = 0;//oled显示变量
float j = 1.234;//oled显示变量
/* Oled显示函数 */
void oled_display(void)
{
if(oled_slow_down) return;
oled_slow_down = 1;
OLED.clearDisplay();//清屏
// 第一行
OLED.setCursor(0,0);//x:0 y:0
OLED.print("i: ");//显示字符
OLED.print(i);//显示变量值
// 第二行
OLED.setCursor(0,10);//x:0 y:10
OLED.print("j: ");
OLED.print(j);
OLED.display();//oled刷新函数
}
//定时器2初始化配置 1ms
void timer2_init()
{
// 配置Timer2
noInterrupts(); // 禁用所有中断
TCCR2A = 0; // 清零控制寄存器A
TCCR2B = 0; // 清零控制寄存器B
TCNT2 = 0; // 初始化计数器为0
// 设置比较匹配寄存器 - 每1ms中断一次
OCR2A = 249; // = (16MHz / (64 * 1000Hz)) - 1
TCCR2A |= (1 << WGM21); // 启用CTC模式(比较匹配时清零计数器)
TCCR2B |= (1 << CS22); // 设置64预分频 (CS22=1)
TIMSK2 |= (1 << OCIE2A); // 启用定时器比较匹配中断
interrupts(); // 启用所有中断
}
void setup() {
/* Oled相关 */
OLED.begin(SSD1306_SWITCHCAPVCC,0x3c);//设置驱动型号及I2C地址
OLED.setTextColor(1);//设置文本颜色
OLED.setTextSize(1);//字号大小
/* 定时器2初始化 */
timer2_init(); //1ms
}
// Timer2比较匹配中断服务函数
ISR(TIMER2_COMPA_vect) {
if(++oled_slow_down == 10) oled_slow_down = 0;//oled刷新时间 10ms刷新一次
}
void loop() {
oled_display();//刷新OLED
}
2.电机驱动
(1)基本信息
(2)代码介绍
引脚定义
#define Motor_Right_PIN_A 6 //A相为黑线
#define Motor_Right_PIN_B 5
#define Motor_Left_PIN_A 10 //A相为黑线
#define Motor_Left_PIN_B 9
单极性驱动
analogWrite(Motor_Left_PIN_A , 70); // 左电机正转
analogWrite(Motor_Left_PIN_B , 0);
analogWrite(Motor_Right_PIN_A , 150); // 右电机正转
analogWrite(Motor_Right_PIN_B , 0);
双极性驱动
只建议少量使用,该方式比较伤电机
analogWrite(Motor_Left_PIN_A , 255); //同侧朝速度最大的方向转
analogWrite(Motor_Left_PIN_B , 230);
analogWrite(Motor_Right_PIN_A , 255); // 同侧速度设置相同停转
analogWrite(Motor_Right_PIN_B , 255);
完整示例代码(双极性)
/* 电机相关 */
#define Motor_Right_PIN_A 6 //A相为黑线
#define Motor_Right_PIN_B 5
#define Motor_Left_PIN_A 10 //A相为黑线
#define Motor_Left_PIN_B 9
void setup() {
/* 电机相关 */
pinMode(10,OUTPUT); //将引脚10设置为输出模式
pinMode(9,OUTPUT); //将引脚9设置为输出模式
pinMode(5,OUTPUT); //将引脚5设置为输出模式
pinMode(6,OUTPUT); //将引脚6设置为输出模式
}
void loop() {
analogWrite(Motor_Left_PIN_A , 255); //同侧朝速度最大的方向转
analogWrite(Motor_Left_PIN_B , 230);
analogWrite(Motor_Right_PIN_A , 255); // 同侧速度设置相同停转
analogWrite(Motor_Right_PIN_B , 255);
}
3.蓝牙模块/串口接收
(1)基本信息
蓝牙模块介绍及使用:机器谱-蓝牙模块
Arduino串口接收:Arduino 串口接受字符串操作
(2)串口接收数据并显示到OLED
参考数据帧为:帧头(W)+路况值(-99 - 103);如W99
参考代码:
/* 调用库声明 */
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
/* Oled配置相关 */
Adafruit_SSD1306 OLED(128,64,&Wire,-1);
/* 变量声明区 */
unsigned char oled_slow_down = 0;//oled延时函数
unsigned char i = 0;//oled显示变量
uint8_t uart_slow_down = 0; //串口刷新专用变量
int received_value = 0;//串口接收函数
int direction_car = 0;//小车行驶方向函数
// 串口接收处理函数
//接收数据 帧头(W) 数据(-100 - 103)
void uart_proc(void)
{
if(uart_slow_down) return;
uart_slow_down = 1;
static char raw_buffer[64]; //接收数据存放数组
static uint8_t idx = 0; //接收数据长度
// 非阻塞方式读取串口数据
while (Serial.available() > 0) {
char c = Serial.read();
if(c == 'W')
{
idx = 0;
raw_buffer[idx++] = c;
}
else if(c >= '0' && c <= '9')
{
if(idx < sizeof(raw_buffer) - 1)
raw_buffer[idx++] = c;
}
else if(c == '-' && idx == 1)
{
raw_buffer[idx++] = c;
}
else if(c == '\n')
{
raw_buffer[idx] = '\0';
received_value = atoi(raw_buffer + 1);
if (received_value >= -100 && received_value <=103) //接收完整信号后,进行处理
{
direction_car = received_value;
}
idx = 0;
break;
}
else
{
idx = 0;
}
}
}
/* Oled显示函数 */
void oled_display(void)
{
if(oled_slow_down) return;
oled_slow_down = 1;
OLED.clearDisplay();//清屏
i++;
// 第一行
OLED.setCursor(0,0);//x:0 y:0
OLED.print("i:");//显示字符
OLED.print(received_value);//显示变量值
// 第一行
OLED.setCursor(50,0);//x:0 y:0
OLED.print("j:");//显示字符
OLED.print(direction_car);//显示变量值
OLED.setCursor(0,30);//x:0 y:0
OLED.print("i: ");//显示字符
OLED.print(i);//显示变量值
OLED.display();//oled刷新函数
}
//定时器2初始化配置 1ms
void timer2_init()
{
// 配置Timer2
noInterrupts(); // 禁用所有中断
TCCR2A = 0; // 清零控制寄存器A
TCCR2B = 0; // 清零控制寄存器B
TCNT2 = 0; // 初始化计数器为0
// 设置比较匹配寄存器 - 每1ms中断一次
OCR2A = 249; // = (16MHz / (64 * 1000Hz)) - 1
TCCR2A |= (1 << WGM21); // 启用CTC模式(比较匹配时清零计数器)
TCCR2B |= (1 << CS22); // 设置64预分频 (CS22=1)
TIMSK2 |= (1 << OCIE2A); // 启用定时器比较匹配中断
interrupts(); // 启用所有中断
}
void setup() {
/* Oled相关 */
OLED.begin(SSD1306_SWITCHCAPVCC,0x3c);//设置驱动型号及I2C地址
OLED.setTextColor(1);//设置文本颜色
OLED.setTextSize(1);//字号大小
/* 串口相关 */
Serial.begin(9600);//波特率9600
/* 定时器2初始化 */
timer2_init(); //1ms
}
// Timer2比较匹配中断服务函数
ISR(TIMER2_COMPA_vect) {
if(++oled_slow_down == 50) oled_slow_down = 0;//oled刷新时间 10ms刷新一次
if(++uart_slow_down == 10) uart_slow_down = 0;//串口刷新时间 10ms刷新一次
}
void loop() {
oled_display();//刷新OLED
uart_proc();//串口刷新
}
电脑接收视觉模块串口发送值
Arduino接收视觉模块串口发送值,显示到OLED
蓝牙模块接收手机发送的数据
四、蓝牙遥控小车完整代码
/* 调用库声明 */
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
/* oled配置相关 */
Adafruit_SSD1306 OLED(128,64,&Wire,-1);
/* 超声波配置引脚 */
#define LEFT_ECHOPIN A0
#define LEFT_TRIGPIN A1
/* 电机引脚配置 */
#define Motor_Right_PIN_A 6 //A相为黑线
#define Motor_Right_PIN_B 5
#define Motor_Left_PIN_A 10 //A相为黑线
#define Motor_Left_PIN_B 9
/* 变量声明区 */
uint8_t ultrasonic_slow_down = 0; //超声波刷新专用变量
uint8_t oled_slow_down = 0; //oled刷新专用变量
uint8_t motor_slow_down = 0; //电机刷新专用变量
uint8_t uart_slow_down = 0; //串口刷新专用变量
extern float distance_left = 0;//超声波检测距离变量
String uart_buffer = ""; //串口接收数组
uint8_t obstacle_count = 0;//障碍物检测数量
bool obstacle_flag = 0;//障碍物检测标志位
int received_value = 0;//串口接收函数
int direction_car = 0;//小车行驶方向函数
int car_direction_state = 0;//小车方向状态
bool car_diversion_flag = 0;//小车转向标志位
uint8_t crossroad_num = 0;//经过的十字路口数
bool return_flag = 0;//原路返回标志位
bool inversion_flag = 0;//倒转标志
uint8_t turn_state = 0;//转向状态机
// 串口接收处理函数
void uart_proc(void)
{
if(uart_slow_down) return;
uart_slow_down = 1;
static char raw_buffer[64]; //接收数据存放数组
static uint8_t idx = 0; //接收数据长度
// 非阻塞方式读取串口数据
while (Serial.available() > 0) {
char c = Serial.read();
if(c == 'W')
{
idx = 0;
raw_buffer[idx++] = c;
}
else if(c >= '0' && c <= '9')
{
if(idx < sizeof(raw_buffer) - 1)
raw_buffer[idx++] = c;
}
else if(c == '-' && idx == 1)
{
raw_buffer[idx++] = c;
}
else if(c == '\n')
{
raw_buffer[idx] = '\0';
received_value = atoi(raw_buffer + 1);
if (received_value >= -100 && received_value <=103) //接收完整信号后,进行处理
{
direction_car = received_value;
if(received_value != 101 && turn_state == 3)//转弯任务完成期间
{
turn_state = 0;//重置转向状态机
car_diversion_flag = 0;//
inversion_flag = 1;
}
}
idx = 0;
break;
}
else
{
idx = 0;
}
}
}
bool flag = 0;//十字路口计数标志位
void motor_control(void)
{
if(motor_slow_down) return;
motor_slow_down = 1;
if(return_flag == 0)//正常行驶
{
if(!car_diversion_flag)
{
if(direction_car > 0 && direction_car <= 100)//右转
car_direction_state = 6;
else if(direction_car < 0 && direction_car >= -100)//左转
car_direction_state = 5;
else if(direction_car == 0)//直行
car_direction_state = 1;
else if(direction_car == 101)//无线条情况 停止
{
car_direction_state = 0;
if(crossroad_num == 1 && inversion_flag == 1) //如果经过的十字路口为1,并且未识别到线条,则执行原路返回
{
return_flag = 1;//启动返回
}
}
else if(direction_car == 102) //十字路口判断,识别到后进行停止,确保只进入一次
{
car_direction_state = 4;
crossroad_num++;//添加经过的十字路口数
car_diversion_flag = 1;//打开转向标志
// delay(150);
}
}
}
else if(return_flag == 1)//启动原路返回 ---仅有一小段路需要
{
if(!car_diversion_flag)
{
if(direction_car > 0 && direction_car <= 100)//右转
{
if(crossroad_num != 1)
car_direction_state = 6;
else
car_direction_state = 7;
}
else if(direction_car < 0 && direction_car >= -100)//左转
{
if(crossroad_num != 1)
car_direction_state = 5;
else
car_direction_state = 8;
}
else if(direction_car == 0)//直行
{
if(crossroad_num != 1)
car_direction_state = 1;
else
car_direction_state = 2;
}
else if(direction_car == 101)//无线条情况 停止
{
if(crossroad_num != 1)
car_direction_state = 0;
else
{
car_direction_state = 2;
}
}
else if(direction_car == 102 && flag == 0) //十字路口判断,识别到后进行停止,确保只进入一次
{
// if(crossroad_num == 0)
// {
// crossroad_num = 2;
// }
if(crossroad_num == 1)
{
// crossroad_num--;//添加经过的十字路口数
crossroad_num = 2;
car_diversion_flag = 1;//打开转向标志
inversion_flag = 0;//解除倒转计数限制
car_direction_state = 4;
// flag = 1;
}
}
}
if(direction_car != 102)
{
flag = 0;
}
}
//转向判断状态机
if(car_diversion_flag == 1)//转向标志
{
if(turn_state == 0 && direction_car != 101)//转向前红线
{
car_direction_state = 4;//速度设定为十字路口右转
turn_state = 1;//状态1
}
else if(turn_state == 1 && direction_car == 101)//识别不到红线
{
car_direction_state = 4;//保持右转
turn_state = 2;//状态2
}
else if(turn_state == 2 && direction_car != 101)//重新识别到红线
{
turn_state = 3;//状态3
}
}
switch(car_direction_state) // 根据小车方向指令执行相应动作
{
case 0: // 停止
// 左右电机同时断电
analogWrite(Motor_Left_PIN_A , 0);
analogWrite(Motor_Left_PIN_B , 0);
analogWrite(Motor_Right_PIN_A , 0);
analogWrite(Motor_Right_PIN_B , 0);
break;
case 1: // 前进
// 左右电机同时正转(向前)
analogWrite(Motor_Left_PIN_A , 80); // 左电机正转
analogWrite(Motor_Left_PIN_B , 0);
analogWrite(Motor_Right_PIN_A , 80); // 右电机正转
analogWrite(Motor_Right_PIN_B , 0);
break;
case 2: // 后退
// 左右电机同时反转(向后)
analogWrite(Motor_Left_PIN_A , 0);
analogWrite(Motor_Left_PIN_B , 90); // 左电机反转
analogWrite(Motor_Right_PIN_A , 0);
analogWrite(Motor_Right_PIN_B , 90); // 右电机反转
break;
case 5: // 左转微调
// 左右电机同时反转(向后)
analogWrite(Motor_Left_PIN_A , 70); // 左电机停转
analogWrite(Motor_Left_PIN_B , 0); // 左电机反转
analogWrite(Motor_Right_PIN_A , 130); // 右电机正转
analogWrite(Motor_Right_PIN_B , 0);
break;
case 6: // 右转微调
// 左右电机同时反转(向后)
analogWrite(Motor_Left_PIN_A , 130); // 左电机正转
analogWrite(Motor_Left_PIN_B , 0);
analogWrite(Motor_Right_PIN_A , 70); // 右电机停转
analogWrite(Motor_Right_PIN_B , 0); // 右电机反转
break;
case 3: // 左转
// 左轮反转 + 右轮正转 = 原地左转
analogWrite(Motor_Left_PIN_A , 0); // 左电机停转
analogWrite(Motor_Left_PIN_B , 200); // 左电机反转
analogWrite(Motor_Right_PIN_A , 130); // 右电机正转
analogWrite(Motor_Right_PIN_B , 0);
break;
case 4: // 右转
// 左轮正转 + 右轮反转 = 原地右转
analogWrite(Motor_Left_PIN_A , 255); // 左电机正转 170
analogWrite(Motor_Left_PIN_B , 170);
analogWrite(Motor_Right_PIN_A , 205); // 右电机停转
analogWrite(Motor_Right_PIN_B , 255); // 右电机反转185
break;
case 7: // 返回左偏微调
// 左右电机同时反转(向后)
analogWrite(Motor_Left_PIN_A , 0); // 左电机停转
analogWrite(Motor_Left_PIN_B , 0); // 左电机反转110
analogWrite(Motor_Right_PIN_A , 160); // 右电机正转
analogWrite(Motor_Right_PIN_B , 255); //70
break;
case 8: // 返回右偏微调
// 左右电机同时反转(向后)
analogWrite(Motor_Left_PIN_A , 160); // 左电机正转
analogWrite(Motor_Left_PIN_B , 255); //70
analogWrite(Motor_Right_PIN_A , 0); // 右电机停转
analogWrite(Motor_Right_PIN_B , 0); // 右电机反转110
break;
}
}
/* 超声波函数 */
void ultrasonic_proc(void)
{
if(ultrasonic_slow_down) return;
ultrasonic_slow_down = 1;
// Measure left sensor
digitalWrite(LEFT_TRIGPIN, LOW);
delayMicroseconds(2);
digitalWrite(LEFT_TRIGPIN, HIGH);
delayMicroseconds(10);
digitalWrite(LEFT_TRIGPIN, LOW);
float duration_left = pulseIn(LEFT_ECHOPIN, HIGH, 300); // Timeout after 30ms
distance_left = duration_left / 58.0; // Convert to cm
/* 记录经过障碍的数量 */
if(distance_left > 15 && distance_left < 20 && obstacle_flag == 0)
{
obstacle_flag = 1;
obstacle_count++;
}
else if(distance_left <10 || distance_left > 30)
{
obstacle_flag = 0;
}
}
/* Oled显示函数 */
void oled_display(void)
{
if(oled_slow_down) return;
oled_slow_down = 1;
OLED.clearDisplay();//清屏
OLED.setTextSize(1);//设置字号大小为1
// 第一行:显示左侧超声波模块读数
OLED.setCursor(0,0);
OLED.print("DT:");
OLED.print(distance_left);
OLED.print("cm");
// 第一行:障碍物计数
OLED.setCursor(80,0);
OLED.print("Obs:");
OLED.print(obstacle_count);
// 第二行:显示小车方向
OLED.setCursor(0,10);
OLED.print("State: ");
switch (car_direction_state)
{
case 0: OLED.print("Stop"); break;
case 1: OLED.print("Forward"); break;
case 5: OLED.print("Left Adj"); break;
case 6: OLED.print("Right Adj"); break;
case 3: OLED.print("Hard Left"); break;
case 4: OLED.print("Hard Right"); break;
default: OLED.print("Unknown");
}
//第四行:转弯标志
OLED.setCursor(40,20);
OLED.print("CDF:");
OLED.print(car_diversion_flag);
//第四行:显示视觉数据
OLED.setCursor(0, 40);
OLED.print("V:");
OLED.print(received_value);
//第四行:显示经过的十字路口数量
OLED.setCursor(50, 40);
OLED.print("CNUM:");
OLED.print(crossroad_num);
//第四行:原路返回标志位
OLED.setCursor(0, 50);
OLED.print("R_FLAG:");
OLED.print(return_flag);
OLED.setCursor(50, 50);
OLED.print("FLAG:");
OLED.print(inversion_flag);
//刷新显示屏
OLED.display();
}
/* 上电初始化 */
void setup() {
/* 串口相关 */
Serial.begin(9600);
/* 超声波相关 */
pinMode(LEFT_TRIGPIN, OUTPUT);
pinMode(LEFT_ECHOPIN, INPUT);
/* Oled相关 */
OLED.begin(SSD1306_SWITCHCAPVCC,0x3c);
OLED.setTextColor(1);
/* 电机相关 */
pinMode(10,OUTPUT); //将引脚10设置为输出模式
pinMode(9,OUTPUT); //将引脚9设置为输出模式
pinMode(5,OUTPUT); //将引脚5设置为输出模式
pinMode(6,OUTPUT); //将引脚6设置为输出模式
/* 定时器2相关 */
// 配置Timer2
noInterrupts(); // 禁用所有中断
TCCR2A = 0; // 清零控制寄存器A
TCCR2B = 0; // 清零控制寄存器B
TCNT2 = 0; // 初始化计数器为0
// 设置比较匹配寄存器 - 每1ms中断一次
OCR2A = 249; // = (16MHz / (64 * 1000Hz)) - 1
TCCR2A |= (1 << WGM21); // 启用CTC模式(比较匹配时清零计数器)
TCCR2B |= (1 << CS22); // 设置64预分频 (CS22=1)
TIMSK2 |= (1 << OCIE2A); // 启用定时器比较匹配中断
interrupts(); // 启用所有中断
//根据视觉模块的图像稳定时间,适当调整
delay(1000);
}
// Timer2比较匹配中断服务函数
ISR(TIMER2_COMPA_vect) {
if(++ultrasonic_slow_down == 10) ultrasonic_slow_down = 0; //超声波刷新
if(++oled_slow_down == 50) oled_slow_down = 0; //Oled刷新
if(++motor_slow_down == 10) motor_slow_down = 0; //Motor刷新
if(++uart_slow_down == 10) uart_slow_down = 0; //Motor刷新
}
void loop() {
ultrasonic_proc();
oled_display();
motor_control();
uart_proc();
}
更多推荐
所有评论(0)