流程简述:该题简单描述为俩辆车一起围着赛道跑,最后停在终点时俩车距离在20cm左右且速度也要求在一定范围内。
对于该题,我介绍一下我的几种方法:
其中最重要的是巡好线,其次是通信,最后是准确判断好俩车距离。
通过在一定时间内捕获电机的脉冲数进行计算。例如:我的电机减速比为1:45(轮子转动一圈电机转动45圈), 电机单相转一圈输出13个脉冲,车轮直径为65mm,这些参数在购买的产品中都有相关介绍,大家自查即可。好,现在得到以上这些信息后怎么计算路程呢,这里我以单相双边沿触发为例进行计算,首先算出车轮的周长:周长Z=2Pir=Pid=3.14159260.065 (单位m),再计算轮子转动一圈电机输出的脉冲数CNT=13245=1170个脉冲,然后得出每个脉冲可以跑多少m,即M=Z/CNT;最后在一定时间内将捕获得到的脉冲数乘以每个脉冲跑的路程=该段时间内跑的路程,即S=CNT*M,V=S/T。
(1)定时器初始化
void TimA1_Int_Init(uint16_t ccr0, uint16_t psc)
{
// 1.增计数模式初始化
Timer_A_UpModeConfig upConfig;
upConfig.clockSource = TIMER_A_CLOCKSOURCE_SMCLK; //时钟源
upConfig.clockSourceDivider = psc; //时钟分频 范围1-64
upConfig.timerPeriod = ccr0; //自动重装载值(ARR)
upConfig.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE; //禁用 tim溢出中断
upConfig.captureCompareInterruptEnable_CCR0_CCIE = TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE; //启用 ccr0更新中断
upConfig.timerClear = TIMER_A_DO_CLEAR; // Clear value
// 2.初始化定时器A
MAP_Timer_A_configureUpMode(TIMER_A1_BASE, &upConfig);
// 3.选择模式开始计数
MAP_Timer_A_startCounter(TIMER_A1_BASE, TIMER_A_UP_MODE);
// 4.清除比较中断标志位
MAP_Timer_A_clearCaptureCompareInterrupt(TIMER_A1_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_0);
// 5.开启串口端口中断
MAP_Interrupt_enableInterrupt(INT_TA1_0);
}
(2)输入捕获
void TimA2_Cap_Init(void)
{
MAP_GPIO_setAsInputPin(GPIO_PORT_P5, GPIO_PIN6);
/* 定时器配置参数*/
Timer_A_ContinuousModeConfig continuousModeConfig = {
TIMER_A_CLOCKSOURCE_SMCLK, // SMCLK Clock Source
TIMER_A_CLOCKSOURCE_DIVIDER_48, // SMCLK/48 = 1MHz
TIMER_A_TAIE_INTERRUPT_DISABLE, // 关闭定时器溢出中断
TIMER_A_DO_CLEAR // Clear Counter
};
// 3.将定时器初始化为连续计数模式
MAP_Timer_A_configureContinuousMode(TIMER_A2_BASE, &continuousModeConfig);
MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN6, GPIO_PRIMARY_MODULE_FUNCTION);
// 4.配置捕捉模式结构体 */
const Timer_A_CaptureModeConfig captureModeConfig_TA2 = {
TIMER_A_CAPTURECOMPARE_REGISTER_1, //在这里改引脚
TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE, //上升下降沿捕获
TIMER_A_CAPTURE_INPUTSELECT_CCIxA, //CCIxA:外部引脚输入 (CCIxB:与内部ACLK连接(手册)
TIMER_A_CAPTURE_SYNCHRONOUS, //同步捕获
TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE, //开启CCRN捕获中断
TIMER_A_OUTPUTMODE_OUTBITVALUE //输出位值
};
// 5.初始化定时器的捕获模式
MAP_Timer_A_initCapture(TIMER_A2_BASE, &captureModeConfig_TA2);
// 6.选择连续模式计数开始计数
MAP_Timer_A_startCounter(TIMER_A2_BASE, TIMER_A_CONTINUOUS_MODE);
// 7.清除中断标志位
MAP_Timer_A_clearInterruptFlag(TIMER_A2_BASE); //清除定时器溢出中断标志位
MAP_Timer_A_clearCaptureCompareInterrupt(TIMER_A2_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_1); //清除 CCR1 更新中断标志位
MAP_Timer_A_clearCaptureCompareInterrupt(TIMER_A2_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_2); //清除 CCR1 更新中断标志位
// 8.开启定时器端口中断
MAP_Interrupt_enableInterrupt(INT_TA2_N); //开启定时器A2端口中断
MAP_Interrupt_enableMaster();
}
(3)中断计算
每10ms进入一次中断进行路程及时间计算。
void TA1_0_IRQHandler(void)
{
MAP_Timer_A_clearCaptureCompareInterrupt(TIMER_A1_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_0);
n++;
Timer=0.01*n;
s=(encoder_R+encoder_L)/2*m;
v=s*100; // v=s/t t=10ms=0.01s
encoder_L=0;
encoder_R=0;
}
这里我用的是GY56红外激光测距传感器,采用串口通信进行数据采集。
void GY56_Init(void)
{
//1.配置GPIO复用
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P3, GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION);
//2.配置UART结构体
#ifdef EUSCI_A_UART_7_BIT_LEN
//固件库v3_40_01_02
//默认SMCLK 48MHz 比特率 115200
const eUSCI_UART_ConfigV1 uartConfig =
{
EUSCI_A_UART_CLOCKSOURCE_SMCLK, // SMCLK Clock Source
26, // BRDIV = 26
0, // UCxBRF = 0
111, // UCxBRS = 111
EUSCI_A_UART_NO_PARITY, // No Parity
EUSCI_A_UART_LSB_FIRST, // MSB First
EUSCI_A_UART_ONE_STOP_BIT, // One stop bit
EUSCI_A_UART_MODE, // UART mode
EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION, // Oversampling
EUSCI_A_UART_8_BIT_LEN // 8 bit data length
};
eusci_calcBaudDividers((eUSCI_UART_ConfigV1 *)&uartConfig, 115200); //配置波特率
//3.初始化串口
UART_initModule(EUSCI_A2_BASE, &uartConfig);
//4.开启串口模块
UART_enableModule(EUSCI_A2_BASE);
//5.开启串口相关中断
UART_enableInterrupt(EUSCI_A2_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT);
//6.开启串口端口中断
Interrupt_enableInterrupt(INT_EUSCIA2);
//7.开启总中断
Interrupt_enableMaster();
}
void EUSCIA2_IRQHandler(void)
{
uint32_t status = UART_getEnabledInterruptStatus(EUSCI_A2_BASE);
static uint8_t i=0,rebuf[20]={0};
if(status & EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG) //接收中断
{
rebuf[i++]=MAP_UART_receiveData(EUSCI_A2_BASE);;//读取串口数据,同时清接收标志
if (rebuf[0]!=0x5a)//帧头不对
i=0;
if ((i==2)&&(rebuf[1]!=0x5a))//帧头不对
i=0;
if(i>3)//i等于4时,已经接收到数据量字节rebuf[3]
{
if(i!=(rebuf[3]+5))//判断是否接收一帧数据完毕
return;
switch(rebuf[2])//接收完毕后处理
{
case 0x15:
if(!Receive_ok)//当数据处理完成后才接收新的数据
{
memcpy(re_Buf_Data,rebuf,9);//拷贝接收到的数据
Receive_ok=1;//接收完成标志
}
break;
}
i=0;//缓存清0
}
}
}
int Get_distance(void)
{
if(Receive_ok)//串口接收完毕
{
for(sum1=0,i=0;i<(re_Buf_Data[3]+4);i++)
sum1+=re_Buf_Data[i];
if(sum1==re_Buf_Data[i])//校验和判断
{
GY56.distance=re_Buf_Data[4]<<8|re_Buf_Data[5];
GY56.mode=re_Buf_Data[6];
GY56.temp=re_Buf_Data[7];
//printf("%d\r\n",GY56.distance);
}
Receive_ok=0;//处理数据完毕标志
}
return GY56.distance;
}
这里我使用的是HC-05蓝牙 透明传输方式进行通信。
可事先在上位机对俩个蓝牙进行配置,具体配置如下所示:
Tips:先按住蓝牙上的微动开关,然后给蓝牙上电。蓝牙上的红灯慢闪表示进入AT指令模式。
1、打开两个串口调试助手,选好COM口、波特率选38400,数据位为8,停止位为1。
2、恢复两个蓝牙的默认设置(最好选择文本模式发送AT命令):
AT+ORGL/r/n (/r/n代表一个回车,在每一条AT指令之后都要加一个回车)。
3、【(A)主机配置】蓝牙名字配置:AT+NAME=YI(名字任意)
4、【(A)主机配置】蓝牙模式配置:AT+ROLE=1(主机模式)
5、【(A)主机配置】蓝牙密码配置:AT+PSWD=1234(密码任意)
6、【(B)从机配置】蓝牙名字配置:AT+NAME=YI(名字要一致)
7、【(B)从机配置】蓝牙模式配置:AT+ROLE=0(从机模式)
8、【(B)从机配置】蓝牙密码配置:AT+PSWD=1234(密码要一致)
9、蓝牙地址的绑定,通过串口助手查询B蓝牙的地址:AT+ADDR?
10、蓝牙A绑定蓝牙B的地址,给蓝牙A(主蓝牙)发送指令:AT+BIND= (B的地址),注意在绑定地址的时候要把查询到的地址中的冒号换成逗号,例如98d3:51:fd8103,应该换成98d3,51,fd8103。
11、按照相同的方式,查询A的地址,让B绑定A的地址。
12、蓝牙的连接模式配置:AT+CMODE=O(0是指定蓝牙地址连接模式,设置为0才能自动的连接绑定的地址)
13、也可以不绑定地址,一但绑定地址那就只能两个绑定地址的蓝牙连接,其他的设备就不能连接了,所以可以不绑定地址。这样就要改变蓝牙的连接模式: AT+CMODE=1(这样两个蓝牙之间可以连接,手机也可以连接)
14、设置两个蓝牙的波特率:AT+UART=9600,0,0(保证两个蓝牙的波特率相同,在我们初始化之后蓝牙的默认波特率会改变,所以我们要再次设置波特率) 。
void BlueTooth_Init(void)
{
//1.配置GPIO复用
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P2, GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION);
//2.配置UART结构体
#ifdef EUSCI_A_UART_7_BIT_LEN
//固件库v3_40_01_02
//默认SMCLK 48MHz 比特率 115200
const eUSCI_UART_ConfigV1 uartConfig =
{
EUSCI_A_UART_CLOCKSOURCE_SMCLK, // SMCLK Clock Source
26, // BRDIV = 26
0, // UCxBRF = 0
111, // UCxBRS = 111
EUSCI_A_UART_NO_PARITY, // No Parity
EUSCI_A_UART_LSB_FIRST, // MSB First
EUSCI_A_UART_ONE_STOP_BIT, // One stop bit
EUSCI_A_UART_MODE, // UART mode
EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION, // Oversampling
EUSCI_A_UART_8_BIT_LEN // 8 bit data length
};
eusci_calcBaudDividers((eUSCI_UART_ConfigV1 *)&uartConfig, 115200); //配置波特率
//3.初始化串口
UART_initModule(EUSCI_A1_BASE, &uartConfig);
//4.开启串口模块
UART_enableModule(EUSCI_A1_BASE);
//5.开启串口相关中断
UART_enableInterrupt(EUSCI_A1_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT);
//6.开启串口端口中断
Interrupt_enableInterrupt(INT_EUSCIA1);
//7.开启总中断
Interrupt_enableMaster();
}
这里我使用了10个红外传感器。
(1)初始化为输入模式,且默认为高电平
void HongWai_Init(void)
{
gpio_init(GPIO_PORT_P5, GPIO_PIN3,1,1);
gpio_init(GPIO_PORT_P9, GPIO_PIN3,1,1);
gpio_init(GPIO_PORT_P6, GPIO_PIN3,1,1);
gpio_init(GPIO_PORT_P7, GPIO_PIN2,1,1);
gpio_init(GPIO_PORT_P7, GPIO_PIN0,1,1);
gpio_init(GPIO_PORT_P9, GPIO_PIN5,1,1);
gpio_init(GPIO_PORT_P9, GPIO_PIN7,1,1);
gpio_init(GPIO_PORT_P7, GPIO_PIN5,1,1);
gpio_init(GPIO_PORT_P7, GPIO_PIN7,1,1);
gpio_init(GPIO_PORT_P10, GPIO_PIN1,1,1);
}
(2)获取各传感器返回的高低电平
l1=gpio_get(GPIO_PORT_P5, GPIO_PIN3);
l2=gpio_get(GPIO_PORT_P9, GPIO_PIN3);
l3=gpio_get(GPIO_PORT_P6, GPIO_PIN3);
l4=gpio_get(GPIO_PORT_P7, GPIO_PIN2);
l5=gpio_get(GPIO_PORT_P7, GPIO_PIN0);
l6=gpio_get(GPIO_PORT_P9, GPIO_PIN5);
l7=gpio_get(GPIO_PORT_P9, GPIO_PIN7);
l8=gpio_get(GPIO_PORT_P7, GPIO_PIN5);
l9=gpio_get(GPIO_PORT_P7, GPIO_PIN7);
l10=gpio_get(GPIO_PORT_P10, GPIO_PIN1);
(3)循迹 (0.3m/s 、0.5m/s为例)
// Car1: 0.27~0.33m/s ( 4.78m - 14.5~17.7s )
void Xunji30(void)
{
l1=gpio_get(GPIO_PORT_P5, GPIO_PIN3);
l2=gpio_get(GPIO_PORT_P9, GPIO_PIN3);
l3=gpio_get(GPIO_PORT_P6, GPIO_PIN3);
l4=gpio_get(GPIO_PORT_P7, GPIO_PIN2);
l5=gpio_get(GPIO_PORT_P7, GPIO_PIN0);
l6=gpio_get(GPIO_PORT_P9, GPIO_PIN5);
l7=gpio_get(GPIO_PORT_P9, GPIO_PIN7);
l8=gpio_get(GPIO_PORT_P7, GPIO_PIN5);
l9=gpio_get(GPIO_PORT_P7, GPIO_PIN7);
l10=gpio_get(GPIO_PORT_P10, GPIO_PIN1);
if(l1==0 && l2==0 && l3==0 && l4==0 && l5==1 && l6==0 && l7==0 && l8==0 && l9==0 && l10==0)
{
Forward();
target_L=365;
target_R=365;
}
else if(l1==0 && l2==0 && l3==0 && l4==0 && l5==0 && l6==1 && l7==0 && l8==0 && l9==0 && l10==0)
{
Forward();
target_L=365;
target_R=365;
}
else if((l1==1&&l4==1)||(l1==1&&l5==1)||(l2==1&&l5==1)||(l2==1&&l6==1)||(l3==1&&6==1)||(l3==1&&l7==1))
{
Forward();
target_L=365;
target_R=365;
}
//踩左边
else if(l1==0 && l2==0 && l3==0 && l4==1 && l5==0 && l6==0 && l7==0 && l8==0 && l9==0 && l10==0 )
{
Forward();
target_L=355;
target_R=365;
}
else if(l1==0 && l2==0 && l3==1 && l4==0 && l5==0 && l6==0 && l7==0 && l8==0 && l9==0 && l10==0 )
{
Forward();
target_L=345;
target_R=365;
}
else if(l1==0 && l2==1 && l3==0 && l4==0 && l5==0 && l6==0 && l7==0 && l8==0 && l9==0 && l10==0 && Timer>=1.8)
{
Forward();
target_L=335;
target_R=365;
}
else if(l1==1 && l2==0 && l3==0 && l4==0 && l5==0 && l6==0 && l7==0 && l8==0 && l9==0 && l10==0 && Timer>=1.8)
{
Left();
target_L=0;
target_R=300;
}
//踩右边
else if(l1==0 && l2==0 && l3==0 && l4==0 && l5==0 && l6==0 && l7==1 && l8==0 && l9==0 && l10==0 )
{
Forward();
target_L=365;
target_R=355;
}
else if(l1==0 && l2==0 && l3==0 && l4==0 && l5==0 && l6==0 && l7==0 && l8==1 && l9==0 && l10==0 )
{
Forward();
target_L=365;
target_R=345;
}
else if(l1==0 && l2==0 && l3==0 && l4==0 && l5==0 && l6==0 && l7==0 && l8==0 && l9==1 && l10==0 )
{
Forward();
target_L=365;
target_R=335;
}
else if(l1==0 && l2==0 && l3==0 && l4==0 && l5==0 && l6==0 && l7==0 && l8==0 && l9==0 && l10==1 )
{
Right();
target_L=300;
target_R=0;
}
//终点停止
else if(((l2==1&&l3==1&&l4==1)||(l3==1&&l4==1&&l5==1)||(l4==1&&l5==1&&l6==1)||(l5==1&&l6==1&&l7==1)||(l6==1&&l7==1&&l8==1)||(l7==1&&l8==1&&l9==1)) && Timer>=15)
{
UART_transmitData(EUSCI_A1_BASE, 's'); //发送数据
beep_flag++;
TimerA1_Disable();
while(1)
{
Stop();
target_L=0;
target_R=0;
MAP_Timer_A_setCompareValue(TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_1, target_L);
MAP_Timer_A_setCompareValue(TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_2, target_R);
if(beep_flag==1)
{
beep_flag=2;
OLED_ShowNum(47,4,Timer,2,16);
int t=(int)(Timer*10)%10;
OLED_ShowNum(63,4,t,3,16);
int distance1=Get_distance();
OLED_ShowString(30, 6, (uint8_t *)"Distance:", 16);
OLED_ShowNum(100,6,distance1,3,16);
gpio_set(GPIO_PORT_P10, GPIO_PIN4,1);
delay_ms(500);
gpio_set(GPIO_PORT_P10, GPIO_PIN4,0);
}
}
}
MAP_Timer_A_setCompareValue(TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_1, target_L);
MAP_Timer_A_setCompareValue(TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_2, target_R);
}
void Xunji50(void)
{
l1=gpio_get(GPIO_PORT_P5, GPIO_PIN3);
l2=gpio_get(GPIO_PORT_P9, GPIO_PIN3);
l3=gpio_get(GPIO_PORT_P6, GPIO_PIN3);
l4=gpio_get(GPIO_PORT_P7, GPIO_PIN2);
l5=gpio_get(GPIO_PORT_P7, GPIO_PIN0);
l6=gpio_get(GPIO_PORT_P9, GPIO_PIN5);
l7=gpio_get(GPIO_PORT_P9, GPIO_PIN7);
l8=gpio_get(GPIO_PORT_P7, GPIO_PIN5);
l9=gpio_get(GPIO_PORT_P7, GPIO_PIN7);
l10=gpio_get(GPIO_PORT_P10, GPIO_PIN1);
if(l1==0 && l2==0 && l3==0 && l4==0 && l5==1 && l6==0 && l7==0 && l8==0 && l9==0 && l10==0)
{
Forward();
target_L=500;
target_R=510;
}
else if(l1==0 && l2==0 && l3==0 && l4==0 && l5==0 && l6==1 && l7==0 && l8==0 && l9==0 && l10==0)
{
Forward();
target_L=500;
target_R=510;
}
else if(((l1==1&&l4==1)||(l1==1&&l5==1)||(l2==1&&l5==1)||(l2==1&&l6==1)||(l3==1&&6==1)||(l3==1&&l7==1)|| (l3==1&&l2==1)||(l3==1&&l4==1)||(l3==1&&l5==1)||(l4==1&&l5==1)||(l4==1&&l6==1)||(l5==1&&l6==1)||(l5==1&&l7==1)) &&(Timer<=9))
{
Forward();
target_L=500;
target_R=510;
}
//踩左边
else if(l1==0 && l2==0 && l3==0 && l4==1 && l5==0 && l6==0 && l7==0 && l8==0 && l9==0 && l10==0 )
{
Forward();
target_L=500;
target_R=510;
}
else if(l1==0 && l2==0 && l3==1 && l4==0 && l5==0 && l6==0 && l7==0 && l8==0 && l9==0 && l10==0 )
{
Forward();
target_L=495;
target_R=510;
}
else if(l1==0 && l2==1 && l3==0 && l4==0 && l5==0 && l6==0 && l7==0 && l8==0 && l9==0 && l10==0 && Timer>=1)
{
Forward();
target_L=490;
target_R=510;
}
else if(l1==1 && l2==0 && l3==0 && l4==0 && l5==0 && l6==0 && l7==0 && l8==0 && l9==0 && l10==0 && Timer>=1)
{
Left();
target_L=0;
target_R=430;
}
//踩右边
else if(l1==0 && l2==0 && l3==0 && l4==0 && l5==0 && l6==0 && l7==1 && l8==0 && l9==0 && l10==0 )
{
Forward();
target_L=500;
target_R=505;
}
else if(l1==0 && l2==0 && l3==0 && l4==0 && l5==0 && l6==0 && l7==0 && l8==1 && l9==0 && l10==0 )
{
Forward();
target_L=500;
target_R=500;
}
else if(l1==0 && l2==0 && l3==0 && l4==0 && l5==0 && l6==0 && l7==0 && l8==0 && l9==1 && l10==0 )
{
Forward();
target_L=500;
target_R=495;
}
else if(l1==0 && l2==0 && l3==0 && l4==0 && l5==0 && l6==0 && l7==0 && l8==0 && l9==0 && l10==1 )
{
Right();
target_L=430;
target_R=0;
}
//终点停止
else if(((l2==1&&l3==1&&l4==1)||(l3==1&&l4==1&&l5==1)||(l4==1&&l5==1&&l6==1)||(l5==1&&l6==1&&l7==1)||(l6==1&&l7==1&&l8==1)||(l7==1&&l8==1&&l9==1)) && Timer>=12)
{
UART_transmitData(EUSCI_A1_BASE, 's'); //发送数据
beep_flag++;
TimerA1_Disable();
while(1)
{
Stop();
target_L=0;
target_R=0;
MAP_Timer_A_setCompareValue(TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_1, target_L);
MAP_Timer_A_setCompareValue(TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_2, target_R);
if(beep_flag==1)
{
beep_flag=2;
OLED_ShowNum(47,4,Timer,2,16);
int t=(int)(Timer*10)%10;
OLED_ShowNum(63,4,t,3,16);
int distance1=Get_distance();
OLED_ShowString(30, 6, (uint8_t *)"Distance:", 16);
OLED_ShowNum(100,6,distance1,3,16);
gpio_set(GPIO_PORT_P10, GPIO_PIN4,1);
delay_ms(500);
gpio_set(GPIO_PORT_P10, GPIO_PIN4,0);
}
}
}
MAP_Timer_A_setCompareValue(TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_1, target_L);
MAP_Timer_A_setCompareValue(TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_2, target_R);
}
疑难解答或技术交流 联系下方wx即可。