前言
本次跟随小车作为2024年电赛做准备的练习项目,主要用于TI芯片包括1306和3507的学习。将其移植到Keil进行开发,有点类似于Keil+STM32Cube的开发模式。此次练习移植了1306及3507代码,并画了相对应的小车系统板,由于接触时间比较短且接近电赛,只实现1306小车稳定运行,3507仅作简单测试。除此之外,学会采用灰度iic循迹,大大减少了io口的使用,收获颇丰。
一、跟随小车解题思路
以1306/3507作为主控,主车配备按键可供选择模式,双车配备蓝牙模块hc-05,主车配备主机,跟随小车配备从机,由全程由主车向跟随小车发送指令。双车同时以速度环为内环,测距和循迹为外环并环,单片机调用相应的函数来驱动MG310小型电机,通过pid算法让小车稳定运行。
1、MSPM0G3507/MSPM0L1306
嘉立创官方为了助力电赛,特地推广了一款TI的开发板——MSP0系列,其中覆盖开发环境的搭建,同时配套各种外设的开发教程以及各类传感器等模块的开发教程,附加源码示例,可直接按文档移植即可。
【立创·地猛星MSPM0G3507】电赛开发板 - 飞书云文档 (feishu.cn)
2、蓝牙通信
蓝牙主从配置的具体方法可以自行查阅,这里不再详述。当主车启动时,它会向副车发送一个数据包。副车在接收到数据包后,启动电机,开始与主车同步运动。当主车的灰度传感器检测到停止线时,主车会立即停下并发送停止信号给副车。副车在收到停止信号后也会立即停止。
3、灰度iic循迹
通过I2C通信,从一个八路传感器中获取数据,每个传感器的状态(0或1)会被打包成一个8位二进制数,存储在一个char类型的变量中,方便后续的数据处理和决策。
IIC通信: IIC(I2C)是一种用于短距离通信的串行通信协议,通常用于微控制器和外围设备(如传感器)之间的数据传输。通过I2C总线,主设备(如微控制器)可以与多个从设备(如传感器)通信。
iic通信代码如下:
#include "ti_msp_dl_config.h"
#include "Myiic.h"
char IIC_Device[10];
void SDA_OUT(void)
{
DL_GPIO_initDigitalOutput(Myiic_iic_SDA_IOMUX);
DL_GPIO_setPins(Myiic_PORT, Myiic_iic_SDA_PIN);
DL_GPIO_enableOutput(Myiic_PORT, Myiic_iic_SDA_PIN);
}
void SDA_IN(void)
{
DL_GPIO_initDigitalInputFeatures(Myiic_iic_SDA_IOMUX,DL_GPIO_INVERSION_DISABLE, DL_GPIO_RESISTOR_PULL_UP,DL_GPIO_HYSTERESIS_DISABLE, DL_GPIO_WAKEUP_DISABLE);
}
void I2C_W_SCL (uint8_t BitValue)
{
if(BitValue == 0)
{
DL_GPIO_clearPins(Myiic_PORT,Myiic_iic_SCL_PIN);
}
else
{
DL_GPIO_setPins(Myiic_PORT,Myiic_iic_SCL_PIN);
}
delay_us(10);
}
void I2C_W_SDA(uint8_t BitValue)
{
SDA_OUT();
if(BitValue == 0)
{
DL_GPIO_clearPins(Myiic_PORT,Myiic_iic_SDA_PIN);
}
else
{
DL_GPIO_setPins(Myiic_PORT,Myiic_iic_SDA_PIN);
}
delay_us(10);
}
uint8_t I2C_R_SDA(void)
{
uint8_t BitValue;
SDA_IN();
BitValue = DL_GPIO_readPins(Myiic_PORT,Myiic_iic_SDA_PIN) == 0 ? 0 : 1;
delay_us(10);
return BitValue;
}
void I2C_Init(void)
{
DL_GPIO_setPins(Myiic_PORT, Myiic_iic_SDA_PIN | Myiic_iic_SCL_PIN);//ÉèÖÃPA8ºÍPA9Òý½Å³õʼ»¯ºóĬÈÏΪ¸ßµçƽ£¨ÊÍ·Å×ÜÏß״̬£©
}
void I2C_Start(void)
{
SDA_OUT();
I2C_W_SDA(1);
I2C_W_SCL(1);
I2C_W_SDA(0);
I2C_W_SCL(0);
}
void I2C_Stop(void)
{
SDA_OUT();
I2C_W_SDA(0);
I2C_W_SCL(1);
I2C_W_SDA(1);
}
void I2C_SendByte(uint8_t Byte)
{
uint8_t i;
SDA_OUT();
for(i = 0;i<8;i++)
{
I2C_W_SDA(Byte & (0x80 >> i));
I2C_W_SCL(1);
I2C_W_SCL(0);
}
}
uint8_t I2C_ReceiveByte(void)
{
uint8_t i,Byte = 0x00;
SDA_OUT();
I2C_W_SDA(1);
for(i = 0;i<8;i++)
{
SDA_IN();
I2C_W_SCL(1);
if(I2C_R_SDA() == 1) Byte |= (0x80>>i);
I2C_W_SCL(0);
}
return Byte;
}
void I2C_SendAck(uint8_t AckBit)
{
SDA_OUT();
I2C_W_SDA(AckBit);
I2C_W_SCL(1);
I2C_W_SCL(0);
}
uint8_t I2C_ReceiveAck(void)
{
uint8_t AckBit;
SDA_OUT();
I2C_W_SDA(1);
I2C_W_SCL(1);
SDA_IN();
AckBit = I2C_R_SDA();
I2C_W_SCL(0);
return AckBit;
}
此外,我还写了个寻址代码,可供参考
void Get_iic_device()
{
char number = 0;
for(int i=0;i<127;i++){
I2C_Start();
I2C_SendByte(i<<1);
if(I2C_ReceiveAck()==0){
IIC_Device[number] = i;
number ++;
}
I2C_Stop();
}
}
4、超声波测距
利用声音测距,声音在空气中的速度是340m/s(15℃)
当声音传播时,若遇到障碍物时,就会被反弹回来,通过计时反弹回来的时间就可以计算出从发射端到障碍物的距离
外部MCU给模块Trig脚一个大于10uS的高电平脉冲;模块会给出一个与距离等比的高电平脉冲信号,可根据脉宽时间“T”算出:距离=T*C/2 (C为声速)
以下是超声波测距部分代码
float Hcsr04GetLength(void)
{
volatile float length = 0;
t = 0;
volatile float sum = 0;
volatile unsigned int i = 0;
Close_Timer();
while(i !=1)
{
SR04_TRIG(0);
delay_1us(10);
SR04_TRIG(1);
delay_1us(20);
SR04_TRIG(0);
while(SR04_ECHO() == 0);
Open_Timer();
i++;
while(SR04_ECHO() > 0);
Close_Timer();
t = (float)Get_TIMER_Count();
length = (float)t / 58.0f; // cm
sum += length;
}
length = sum;
distance = length;
return length;
}
PID闭环串并环控制
小车以速度环为内环,灰度和超声波测距为外环,完成基本跟车循迹