B8组 (康夏涛,符友,罗积昌) 两轮平衡小车
做车嘛,电机是主要的吧,所以第一部开调电机的程序了,我用的电机是n20减速电机,查了一下资料,要用到驱动,刚好之前买了个L298N步进电机的驱动模板,试了一下,驱动模板一边接电机,另一边接单片机两个io口,赋一个高电平一个低电平,电机和单片机没有共地,电机可以工作,发现转速有一点慢,应该接更高伏的电。一开始我是想用PWM信号的方法进行调速,调好程序后确实有效果,不过后来我想用三个轮子做一个车就好了,后面装一个万向轮,就可以省了用步进电机转弯,我的想法是靠前面减速电机的速度差进行转弯,最后决定就用两个速度,一个非常慢,一个是最快速度。首先用到四个独立按键进行控制小车前后左右的效果,因为还没有搭架子,直接接两个电机看效果,调好程序后,简直完美。
今天上午调了一上午的平衡程序,发现好多问题,电机这块的程序就好多bug,然后就越调越乱
,最后完全没了思路,所以准备把车全部搭出来再程序写程序。
把各种模块都拿出来,需要的电阻,电容,烙铁,跳线,摆一排,感觉我们三是要大干一场了
。
(搭第二层中)

这里打孔又是最麻烦的,因为不在实验室,没有钻孔机了,我们用锤子螺丝慢慢打出来的
(红外线循迹)

(资料是在网上找的)
(原理图)

红外发射二极管跟普通的LED二极管一样,只是LED发射的是肉眼看得到的可见光,而红外发射二极管发射的是人眼看不见的红外线,红外发射二极管的正向压降大约1.2V,发射的功率以及发射的距离跟流经的电流成正比,嘴大平均工作电流不要大于100mA,这里选用的是220欧姆的限流电阻,流经红外发射二极管电流为(5V-1.2V)/220欧姆=17.2mA。
停止
红外接收二极管跟光敏电阻类似,可以根据这一点在其电路上加一个10K欧姆的电阻,当有红外线照射时电阻很小,则在上图中与红外接收二极管负极相连的P2.0/P2.1/P2.2输出口输出为“0”,当没有红外线照射时,输出为“+5V”。
可以根据这一点进行红外巡线,巡线原理如下:当红外发光二极管照射到白色地板时,反射红外线,被与之对应的红外接收二极管接收,输出为逻辑“0”。反之当红外发光二极管照射到黑线时,红外线被黑色物体吸收,则与之对应的红外接受二极管无红外线照射,输出为逻辑“1”。
我的想法是将其分为“左”“中”“右”3路,那么分别会有8中情况,情况如下
程序以后供上
左路
中路
右路
电机动作
0
0
0
停止
0
0
1
右转
0
1
0
前进
0
1
1
右转
1
0
0
左转
1
0
1
停止
1
1
0
左转
1
1
1
(电源)
从图中可以看出我接了两个电源接口,一个5V usb接口,一个接9V 电池,因为电池不怎么好,所以调程序时准备用移动电源。
(整体)
一下午搭的,是不是帅到想哭![]()
(顺便分享一点经验,就是用排针引出VCC或GND时多接几个排针,像我们只接了四个排针,回来发现少了时再引出来特别麻烦的。)
然后简单的写了个lcd的程序,哈哈,感觉特别特别特别帅
(附上所用单片机IO口)
接下来的日子就只要是把一个一个的模块程序写出来,然后慢慢调吧
![]()
![]()
不好意思几天没有更新了,这几天事情多,进展比较慢
首先说一下小车控制方面,小车一开始是打算用蓝牙控制的,因为运气太差,淘宝到一个坏的蓝牙模板,害我们调半天搞不懂
,后来就准备用无线,我们首先是用315无线发射和接收模块,没有资料,百度说要自己编码,找几个例程和天书一样,当时就蒙了,然后试了各种方法,还是放弃了,于是我发现了一种带遥控器的无线模板
固定码,接收到信号就输出高电平,一下就简单了。
(信号问题)
这个无线模板主要问题是信号弱,我们首先想到的就是加天线,一开始我们是自己用绝缘线做的,根本没起到什么作用,百度一查,原来天线中间是空心的,然后我们果断拆了路由器的一根天线装上,效果一下就来了,距离可以到一两米了。

今天我们把电机的程序程序重新写了一遍,用到PWM信号调速,方便平衡小车的自平衡
程序如下:
#include <reg51.h>
//IO口
sbit dian1=P2^0;
sbit dian2=P2^1;
sbit dian3=P2^2;
sbit dian4=P2^3;
sbit k1=P2^6;
sbit k2=P2^7;
sbit k3=P3^4;
sbit k4=P3^5;
//变量
unsigned char i,n,nk,nd,fx;
//n,nk,nd 速度标识
//fx(1正 2反 3左 4右) 方向标识
//声明函数
void zz(); //电机正方向
void ff(); //电机反方向
void fz(); //电机左转
void zf(); //电机右转
void sudu(); //根据速度标识选择速度值
void dian(); //检测按键
void delay(unsigned int z); //延时函数
//主函数
void main()
{
while(1)
{
dian();
sudu();
if(fx==1) //根据方向标识选择方向
zz();
if(fx==2)
ff();
if(fx==3)
fz();
if(fx==4)
zf();
}
}
//函数
void dian() //检测按键,用无线模块控制,接收到信号时输出高电平
{
if(k1==1) //前进
{
n++;
if(n==5)
n=4;
fx=1;
}
if(k2==1) //左转
{
n++;
if(n==5)
n=4;
fx=3;
}
if(k3==1) //减速、后退
{
n++;
if(n==5)
n=4;
fx=2;
}
if(k4==1) //右转
{
n++;
if(n==5)
n=4;
fx=4;
}
if((k1!=1)&&(k2!=1)&&(k3!=1)&&(k4!=1))//没有无线信号时电机停止转动
{
n=0;
}
}
void zz() //正方向
{
for(i=0;i<nd;i++)
{
dian1=1;
dian2=1;
dian3=1;
dian4=1;
delay(5);
}
for(i=0;i<nk;i++)
{
dian1=0;
dian2=1;
dian3=0;
dian4=1;
delay(5);
}
}
void ff() //反方向
{
for(i=0;i<nd;i++)
{
dian1=1;
dian2=1;
dian3=1;
dian4=1;
delay(5);
}
for(i=0;i<nk;i++)
{
dian1=1;
dian2=0;
dian3=1;
dian4=0;
delay(5);
}
}
void fz() //一正一反,左转
{
for(i=0;i<nd;i++)
{
dian1=0;
dian2=0;
dian3=1;
dian4=1;
delay(5);
}
for(i=0;i<nk;i++)
{
dian1=1;
dian2=0;
dian3=0;
dian4=1;
delay(5);
}
}
void zf() //一反一正,右转
{
for(i=0;i<nd;i++)
{
dian1=1;
dian2=1;
dian3=0;
dian4=0;
delay(5);
}
for(i=0;i<nk;i++)
{
dian1=0;
dian2=1;
dian3=1;
dian4=0;
delay(5);
}
}
void sudu()//根据n的值赋nk,nd来调节IO口输出的PWM信号
{
switch(n)
{
case 0:
nk=0;
nd=4;
break;
case 1:
nk=1;
nd=3;
break;
case 2:
nk=2;
nd=2;
break;
case 3:
nk=3;
nd=1;
break;
case 4:
nk=4;
nd=0;
break;
}
}
void delay(unsigned int z) //延时函数 (1ms)
{
unsigned int x;
for(;z>0;z--)
for(x=110;x>0;x--);
}
![]()
陀螺仪方面已经完成了,是根据陀螺仪资料里的例程改写的,在1602上显示x,y,z轴加速度和角速度
因为是模块化编程,就只上一部分程序了
(陀螺仪头文件)
#ifndef __TLY_H__ #define __TLY_H__ #include <reg51.h> #include "kxt.h" sbit SCL=P3^7; //IIC时钟引脚定义 sbit SDA=P3^6; //IIC数据引脚定义 #define SMPLRT_DIV 0x19 //陀螺仪采样率,典型值:0x07(125Hz) #define CONFIG 0x1A //低通滤波频率,典型值:0x06(5Hz) #define GYRO_CONFIG 0x1B //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s) #define ACCEL_CONFIG 0x1C //加速计自检、测量范围及高通滤波频率,典型值:0x01(不自检,2G,5Hz) #define ACCEL_XOUT_H 0x3B #define ACCEL_XOUT_L 0x3C #define ACCEL_YOUT_H 0x3D #define ACCEL_YOUT_L 0x3E #define ACCEL_ZOUT_H 0x3F #define ACCEL_ZOUT_L 0x40 #define TEMP_OUT_H 0x41 #define TEMP_OUT_L 0x42 #define GYRO_XOUT_H 0x43 #define GYRO_XOUT_L 0x44 #define GYRO_YOUT_H 0x45 #define GYRO_YOUT_L 0x46 #define GYRO_ZOUT_H 0x47 #define GYRO_ZOUT_L 0x48 #define PWR_MGMT_1 0x6B //电源管理,典型值:0x00(正常启用) #define WHO_AM_I 0x75 //IIC地址寄存器(默认数值0x68,只读) #define SlaveAddress 0xD0 //IIC写入时的地址字节数据,+1为读取 void InitMPU6050(); //初始化MPU6050 void I2C_Start(); void I2C_Stop(); void I2C_SendACK(bit ack); bit I2C_RecvACK(); void I2C_SendByte(unsigned char dat); unsigned char I2C_RecvByte(); void I2C_ReadPage(); void I2C_WritePage(); unsigned char Single_ReadI2C(unsigned char REG_Address);/读取I2C数据 void Single_WriteI2C(unsigned char REG_Address,unsigned char REG_data);//向I2C写入数据 #endif
(陀螺仪I2C通信)
#include "tly.h"
void Delay10us()
{
unsigned char a,b;
for(b=1;b>0;b--)
for(a=2;a>0;a--);
}
void I2C_Start()
{
SDA = 1; //拉高数据线
SCL = 1; //拉高时钟线
Delay10us(); //延时
SDA = 0; //产生下降沿
Delay10us(); //延时
SCL = 0; //拉低时钟线
}
void I2C_Stop()
{
SDA = 0; //拉低数据线
SCL = 1; //拉高时钟线
Delay10us(); //延时
SDA = 1; //产生上升沿
Delay10us(); //延时
}
//I2C发送应答信号
void I2C_SendACK(bit ack)
{
SDA = ack; //写应答信号
SCL = 1; //拉高时钟线
Delay10us(); //延时
SCL = 0; //拉低时钟线
Delay10us(); //延时
}
//I2C接收应答信号
bit I2C_RecvACK()
{
SCL = 1; //拉高时钟线
Delay10us(); //延时
CY = SDA; //读应答信号
SCL = 0; //拉低时钟线
Delay10us(); //延时
return CY;
}
//向I2C总线发送一个字节数据
void I2C_SendByte(uc dat)
{
uc i;
for (i=0; i<8; i++) //8位计数器
{
dat <<= 1; //移出数据的最高位
SDA = CY; //送数据口
SCL = 1; //拉高时钟线
Delay10us(); //延时
SCL = 0; //拉低时钟线
Delay10us(); //延时
}
I2C_RecvACK();
}
//从I2C总线接收一个字节数据
unsigned char I2C_RecvByte()
{
uc i;
uc dat = 0;
SDA = 1; //使能内部上拉,准备读取数据,
for (i=0; i<8; i++) //8位计数器
{
dat <<= 1;
SCL = 1; //拉高时钟线
Delay10us(); //延时
dat |= SDA; //读数据
SCL = 0; //拉低时钟线
Delay10us(); //延时
}
return dat;
}
//向I2C设备写入一个字节数据
void Single_WriteI2C(uc REG_Address,uc REG_data)
{
I2C_Start(); //起始信号
I2C_SendByte(SlaveAddress); //发送设备地址+写信号
I2C_SendByte(REG_Address); //内部寄存器地址,
I2C_SendByte(REG_data); //内部寄存器数据,
I2C_Stop(); //发送停止信号
}
//初始化MPU6050
void InitMPU6050()
{
Single_WriteI2C(PWR_MGMT_1, 0x00); //解除休眠状态
Single_WriteI2C(SMPLRT_DIV, 0x07);
Single_WriteI2C(CONFIG, 0x06);
Single_WriteI2C(GYRO_CONFIG, 0x18);
Single_WriteI2C(ACCEL_CONFIG, 0x01);
}
(主函数部分)
void main() { delay(500); //上电延时 LCDI(); //液晶初始化 InitMPU6050(); //初始化MPU6050 delay(150); while(1) { Display10BitData(GetData(ACCEL_XOUT_H),2,0); //显示X轴加速度 Display10BitData(GetData(ACCEL_YOUT_H),7,0); //显示Y轴加速度 Display10BitData(GetData(ACCEL_ZOUT_H),12,0); //显示Z轴加速度 Display10BitData(GetData(GYRO_XOUT_H),2,1); //显示X轴角速度 Display10BitData(GetData(GYRO_YOUT_H),7,1); //显示Y轴角速度 Display10BitData(GetData(GYRO_ZOUT_H),12,1); //显示Z轴角速度 delay(500); } }
回复
| 有奖活动 | |
|---|---|
| 硬核工程师专属补给计划——填盲盒 | |
| “我踩过的那些坑”主题活动——第002期 | |
| 【EEPW电子工程师创研计划】技术变现通道已开启~ | |
| 发原创文章 【每月瓜分千元赏金 凭实力攒钱买好礼~】 | |
| 【EEPW在线】E起听工程师的声音! | |
| 高校联络员开始招募啦!有惊喜!! | |
| 【工程师专属福利】每天30秒,积分轻松拿!EEPW宠粉打卡计划启动! | |
| 送您一块开发板,2025年“我要开发板活动”又开始了! | |
我要赚赏金
