Summary of STM32 smart car (tracking, following, obstacle avoidance, speed measurement, Bluetooth, wife, 4g, voice recognition)

Table of contents

1. Motor module development

1.1 Let the car move

1.2 Serial port control car direction

1.3 How to carry out PWM speed regulation of the car

1.4 PWM method to realize car steering

2. Tracking car 

2.1 Use of tracking module

2.2 Principle of tracking car

2.3 Core code of tracking car

2.4 Tracking car solves the problem of smooth turning

3. Follow/obstacle avoidance car

3.1 Analysis of infrared barrier moduleEdit

3.2 The principle of following the car

3.3 Follow the car to develop and debug code

3.4 Introduction to ultrasonic module

3.5 Introduction to steering gear module

3.6 Development and debugging code of shaking head obstacle avoidance car

4. Speed ​​measuring car

4.1 Speed ​​measurement module

4.2 Test principle and unit conversion

4.3 Timers and interrupts implement speed testing development and debugging code

4.4 The speed of the car is displayed on the OLED screen

5. Remote control car

5.1 Bluetooth controlled car

5.2 Bluetooth control and speed measurement car

5.3 WiFi controlled speed measuring car

5.4 4g control car

6. Voice control car

6.1 Voice module configuration:

6.2 Voice control car development and debugging code


1. Motor module development

L9110s Overview

Turn on VCC, the GND module power indicator light is on. The following information is from the official source and is based on actual debugging.

IA1 inputs high level, IA1 inputs low level, [OA1 OB1] motor rotates forward;

IA1 inputs low level, IA1 inputs high level, [OA1 OB1] motor reverses;

IA2 inputs high level, IA2 inputs low level, [OA2 OB2] motor rotates forward;

IA2 inputs low level, IA2 inputs high level, [OA2 OB2] motor reverses;

Wiring reference:

B-1A -- PA0

B-1B -- PB1

A-1A -- PA1

A-1B -- PB10 

1.1 Let the car move

Code:

motor.c

#include "motor.h"
void goForward(void)
{
    // 左轮
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);
    // 右轮
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
}
void goBack(void)
{
    // 左轮
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET);
    // 右轮
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
}
void goLeft(void)
{
    // 左轮
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);
    // 右轮
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
}
void goRight(void)
{
    // 左轮
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);
    // 右轮
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
}
void stop(void)
{
    // 左轮
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET);
    // 右轮
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
}

motor.h

#ifndef __MOTOR_H__
#define __MOTOR_H__
#include "main.h"
void goForward(void);
void goBack(void);
void goLeft(void);
void goRight(void);
void stop(void);
#endif

main.c

#include "motor.h"

//main函数的while循环部分:
while (1)
{
    goForward();
    HAL_Delay(1000);
    goBack();
    HAL_Delay(1000);
    goLeft();
    HAL_Delay(1000);
    goRight();
    HAL_Delay(1000);
    stop();
    HAL_Delay(1000);
}
1.2 Serial port control car direction
  • Serial port file programming for code integration - changing the code through phenomena
  • Connect to the Bluetooth module and control the car through Bluetooth
  • Add jog control. If the APP supports sending data continuously when pressed and stopping sending data when released (the custom buttons of the Bluetooth debugging assistant cannot be implemented), the function of the car keeping moving forward after pressing the forward button can be realized.

Code:

usart.c

#include "usart.h"

#include "string.h"
#include "stdio.h"
#include "motor.h"

//串口接收缓存(1字节)
uint8_t buf=0;

//定义最大接收字节数 200,可根据需求调整
#define UART1_REC_LEN 200

// 接收缓冲, 串口接收到的数据放在这个数组里,最大UART1_REC_LEN个字节
uint8_t UART1_RX_Buffer[UART1_REC_LEN];

//  接收状态
//  bit15,      接收完成标志
//  bit14,      接收到0x0d
//  bit13~0,    接收到的有效字节数目
uint16_t UART1_RX_STA=0;

#define SIZE 12

char buffer[SIZE];

// 接收完成回调函数,收到一个数据后,在这里处理
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	// 判断中断是由哪个串口触发的
	if(huart->Instance == USART1)
	{
		// 判断接收是否完成(UART1_RX_STA bit15 位是否为1)
		if((UART1_RX_STA & 0x8000) == 0)
		{
			// 如果已经收到了 0x0d (回车),
			if(UART1_RX_STA & 0x4000)
			{
				// 则接着判断是否收到 0x0a (换行)
				if(buf == 0x0a)
				{
					// 如果 0x0a 和 0x0d 都收到,则将 bit15 位置为1
					UART1_RX_STA |= 0x8000;

					// 灯控指令
					if(!strcmp(UART1_RX_Buffer, "M1"))
						goForward();
					else if(!strcmp(UART1_RX_Buffer, "M2"))
						goBack();
					else if(!strcmp(UART1_RX_Buffer, "M3"))
						goLeft();
					else if(!strcmp(UART1_RX_Buffer, "M4"))
						goRight();
					else
						stop();
					
					memset(UART1_RX_Buffer, 0, UART1_REC_LEN);
					UART1_RX_STA = 0;
				}
				else
					// 否则认为接收错误,重新开始
					UART1_RX_STA = 0;
			}
			else	// 如果没有收到了 0x0d (回车)
			{
				//则先判断收到的这个字符是否是 0x0d (回车)
				if(buf == 0x0d)
				{
					// 是的话则将 bit14 位置为1
					UART1_RX_STA |= 0x4000;
				}
				else
				{
					// 否则将接收到的数据保存在缓存数组里
					UART1_RX_Buffer[UART1_RX_STA & 0X3FFF] = buf;
					UART1_RX_STA++;
					
					// 如果接收数据大于UART1_REC_LEN(200字节),则重新开始接收
					if(UART1_RX_STA > UART1_REC_LEN - 1)
						UART1_RX_STA = 0;
				}
			}
		}
		// 重新开启中断
		HAL_UART_Receive_IT(&huart1, &buf, 1);
	}
}

int fputc(int ch, FILE *f)
{      
	unsigned char temp[1]={ch};
	HAL_UART_Transmit(&huart1,temp,1,0xffff);  
	return ch;
}
1.3 How to carry out PWM speed regulation of the car

principle :

Full speed ahead is LeftCon1A = 0; LeftCon1B = 1;

Complete stop is LeftCon1A = 0;LeftCon1B = 0;

Then in a unit time, such as 20ms, if there are 15ms of full speed forward and 5ms of complete stop, the speed will be higher than 5ms of full speed forward and 15ms of complete stop, which will gain more power and the corresponding speed will be faster!

Development : Borrowing PWM steering gear control code

Modify the configuration of the four GPIO ports that control the wheels as follows, otherwise the car will not move.

Reason: Each control port of L9110 needs to be high and low before it can move. If the PWM effective level is high, the other GPIO port needs to output low level to drive the wheel.

Code:

main.c

// main函数里
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
while (1)
{
    __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 8);
    __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, 8);
    HAL_Delay(1000);
    __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 10);
    __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, 10);
    HAL_Delay(1000);
    __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, 15);
    __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, 15);
    HAL_Delay(1000);
}
1.4 PWM method to realize car steering

Right turn principle: The speed of the left wheel is greater than that of the right wheel

Principle of left turn: The speed of the right wheel is greater than that of the left wheel

The respective speed adjustment codes for the left and right wheels are implemented:

// main函数里
while (1)
{
    __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,8);
    __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,15);
    HAL_Delay(1000);
    __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,15);
    __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,8);
    HAL_Delay(1000);
}

2. Tracking car 

2.1 Introduction to tracking module
  • The infrared emitting diode of the TCRT5000 sensor continuously emits infrared light
  • When the emitted infrared ray is not reflected back or is reflected back but the intensity is not strong enough
  • The infrared receiving tube is always off. At this time, the output terminal of the module is high level, indicating that the diode is always off.
  • When the object to be detected appears within the detection range, the infrared ray is reflected back with sufficient intensity, and the infrared receiving tube is saturated.
  • At this time, the output terminal of the module is low level, indicating that the diode is lit.
  • The summary is just one sentence, there is no reflection, D0 outputs high level and turns off the light.

Wiring

  • VCC: Connect to the positive pole of the power supply (3-5V)
  • GND: Connect to the negative pole of the power supply DO: TTL switch signal output 0, 1
  • AO: Analog signal output (different voltages are output at different distances, this pin generally does not need to be connected)
2.2 Principle of tracking car

Since black has strong absorption capacity, when the infrared rays emitted by the tracking module are irradiated to the black line, the infrared rays will be absorbed by the black line, causing the phototransistor on the tracking module to be in a closed state, and at this time, an LED on the module will go out. When no black line is detected, the two LEDs on the module are always on.

The summary is just one sentence, if the black line is sensed, D0 outputs high level and turns off the light.

2.3 Core code of tracking car

Hardware wiring

  • B-1A -- PA0
  • B-1B -- PB1
  • A-1A -- PA1
  • A-1B -- PB10
  • Tracking module (left) -- PB3
  • Tracking module (right) -- PB4

Code example:

#define LeftWheel_Value HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3)
#define RightWheel_Value HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4)

// main函数里
while (1)
{
    if (LeftWheel_Value == GPIO_PIN_RESET && RightWheel_Value == GPIO_PIN_RESET)
        goForward();
    if (LeftWheel_Value == GPIO_PIN_SET && RightWheel_Value == GPIO_PIN_RESET)
        goLeft();
    if (LeftWheel_Value == GPIO_PIN_RESET && RightWheel_Value == GPIO_PIN_SET)
        goRight();
    if (LeftWheel_Value == GPIO_PIN_SET && RightWheel_Value == GPIO_PIN_SET)
        stop();
}
2.4 Tracking car solves the problem of smooth turning

Principle: Both wheels have speed and one wheel is faster than the other

Code:

#define LeftWheel_Value HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3)
#define RightWheel_Value HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4)
// main函数里
while (1)
{
    if(LeftWheel_Value == GPIO_PIN_RESET && RightWheel_Value == GPIO_PIN_RESET)
    {
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,19);
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,19);
    }
    if(LeftWheel_Value == GPIO_PIN_SET && RightWheel_Value == GPIO_PIN_RESET)
    {
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,15);
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,8);
    }
    if(LeftWheel_Value == GPIO_PIN_RESET && RightWheel_Value == GPIO_PIN_SET)
    {
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,8);
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,15);
    }
    if(LeftWheel_Value == GPIO_PIN_SET && RightWheel_Value == GPIO_PIN_SET)
    {
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,0);
        __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2,0);
    }
}

3. Follow/obstacle avoidance car

3.1 Analysis of infrared barrier module

The principle is the same as tracking. The red face of tracking is facing down and the following is facing forward.

3.2 The principle of following the car
  • The following module on the left can return to infrared and output low level, but the following module on the right cannot return and output high level, indicating that the object is on the left and needs to turn left.
  • The following module on the right can return to infrared and output low level. The left following module cannot return and output high level, indicating that the object is on the right and needs to turn right.
3.3 Follow the car to develop and debug code

Hardware wiring

  • B-1A -- PB0
  • B-1B -- PB1
  • A-1A -- PB2
  • A-1B -- PB10
  • Follow module (left) -- PB5
  • Follow module (right) -- PB6

Code example:

#define LeftWheel_Value HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5)
#define RightWheel_Value HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6)
// main函数里
while (1)
{
    if(LeftWheel_Value == GPIO_PIN_RESET && RightWheel_Value == GPIO_PIN_RESET)
        goForward();
    if(LeftWheel_Value == GPIO_PIN_SET && RightWheel_Value == GPIO_PIN_RESET)
        goRight();
    if(LeftWheel_Value == GPIO_PIN_RESET && RightWheel_Value == GPIO_PIN_SET)
        goLeft();
    if(LeftWheel_Value == GPIO_PIN_SET && RightWheel_Value == GPIO_PIN_SET)
        stop();
}
3.4 Introduction to ultrasonic module

Use ultrasonic module, model: HC-SR04

  • How to make it send a Trig wave and give the Trig port a high level of at least 10us
  • How do you know it starts sending an Echo signal? It jumps from low level to high level, which means it starts sending waves.
  • How do you know that the return wave Echo has been received? If it jumps from high level back to low level, it means that the wave has returned.
  • How to calculate the time the Echo pin remains high! When the wave goes out, start the timer. When the wave comes back, we start to stop the timer and calculate how much time has passed.
  • How to calculate distance? Distance = speed (340m/s) * time/2

Timing diagram:

3.5 Introduction to steering gear module

 1. What is a steering gear?

As shown in the figure below, the cheapest servo sg90 usually has three or four wires. The yellow color is the PWM signal control purpose: for opening the lid of the trash can project, full-scale steering of smart cars, camera pan/tilt, robotic arm and other common ones. 0-90°, 0-180°, 0-360°

2. How to control the steering gear

"Inject" the PWM signal into the yellow signal line

The frequency of the PWM wave cannot be too high, about 50HZ, that is, period = 1/frequency = 1/50 = 0.02s, about 20ms

Determine period/frequency:

If the period is 20ms, then PSC=7199, ARR=199

Angle control

0.5ms-------------0 degrees; 2.5% CCRx in the corresponding function is 5

1.0ms------------45 degrees; 5.0% CCRx in the corresponding function is 10

1.5ms------------90 degrees; 7.5% CCRx in the corresponding function is 15

2.0ms-----------135 degrees; 10.0% CCRx in the corresponding function is 20

2.5ms-----------180 degrees; 12.5% ​​CCRx in the corresponding function is 25

3.6 Development and debugging code of shaking head obstacle avoidance car

Hardware wiring

  • sg90 -- PB9

cubeMX configuration

Code

sg90.c

#include "sg90.h"
#include "gpio.h"
#include "tim.h"
void initSG90(void)
{
    HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_4); //启动定时器4
    __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 17); //将舵机置为90度
}
void sgMiddle(void)
{
    __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 17); //将舵机置为90度
}
void sgRight(void)
{
    __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 5); //将舵机置为0度
}
void sgLeft(void)
{
    __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 25); //将舵机置为180度
}

sg90.h

#ifndef __SG90_H__
#define __SG90_H__

void initSG90(void);
void sgMiddle(void);
void sgRight(void);
void sgLeft(void);

#endif

main.c

initSG90();
HAL_Delay(1000);

while (1)
{
    sgLeft();
    HAL_Delay(1000);
    sgMiddle();
    HAL_Delay(1000);
    sgRight();
    HAL_Delay(1000);
    sgMiddle();
    HAL_Delay(1000);
}

Packaged Ultrasonic Sensor

Ultrasonic module wiring:

  • Trig       --    PB7
  • Echo     -- PB8

cubeMX configuration

Code

sr04.c

#include "sr04.h"
#include "gpio.h"
#include "tim.h"

//使用TIM2来做us级延时函数
void TIM2_Delay_us(uint16_t n_us)
{
    /* 使能定时器2计数 */
    __HAL_TIM_ENABLE(&htim2);
    __HAL_TIM_SetCounter(&htim2, 0);
    while(__HAL_TIM_GetCounter(&htim2) < ((1 * n_us)-1) );
    /* 关闭定时器2计数 */
    __HAL_TIM_DISABLE(&htim2);
}

double get_distance(void)
{
    int cnt=0;
    //1. Trig ,给Trig端口至少10us的高电平
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);//拉高
    TIM2_Delay_us(20);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);//拉低

    //2. echo由低电平跳转到高电平,表示开始发送波
    //波发出去的那一下,开始启动定时器
    while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8) == GPIO_PIN_RESET);//等待输入电平拉高
    HAL_TIM_Base_Start(&htim2);
    __HAL_TIM_SetCounter(&htim2,0);

    //3. 由高电平跳转回低电平,表示波回来了
    while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_8) == GPIO_PIN_SET);//等待输入电平变低
    //波回来的那一下,我们开始停止定时器
    HAL_TIM_Base_Stop(&htim2);

    //4. 计算出中间经过多少时间
    cnt = __HAL_TIM_GetCounter(&htim2);

    //5. 距离 = 速度 (340m/s)* 时间/2(计数1次表示1us)
    return (cnt*340/2*0.000001*100); //单位:cm
}

sr04.h

#ifndef __SR04_H__
#define __SR04_H__

double get_distance(void);

#endif

main.c

while (1)
{
    if(dir != MIDDLE){
        sgMiddle();
        dir = MIDDLE;
        HAL_Delay(300);
    }
    disMiddle = get_distance();

    if(disMiddle > 35){
    //前进
    }
    else
    {
        //停止
        //测左边距离
        sgLeft();

        HAL_Delay(300);
        disLeft = get_distance();

        sgMiddle();
        HAL_Delay(300);

        sgRight();
        dir = RIGHT;
        HAL_Delay(300);
        disRight = get_distance();
    }
}

Packaged motor drive

Code:

while (1)
{
    if(dir != MIDDLE){
        sgMiddle();
        dir = MIDDLE;
        HAL_Delay(300);
    }
    disMiddle = get_distance();

    if(disMiddle > 35){
        //前进
        goForward();
    }else if(disMiddle < 10){
        goBack();
    }else
    {
        //停止
        stop();
        //测左边距离
        sgLeft();
        HAL_Delay(300);
        disLeft = get_distance();

        sgMiddle();
        HAL_Delay(300);

        sgRight();
        dir = RIGHT;
        HAL_Delay(300);
        disRight = get_distance();

        if(disLeft < disRight){
            goRight();
            HAL_Delay(150);
            stop();
        }
        if(disRight < disLeft){
            goLeft();
            HAL_Delay(150);
        stop();
        }
    }
    HAL_Delay(50);
}

4. Speed ​​measuring car

4.1 Speed ​​measurement module

  • Usage: Widely used for motor speed detection, pulse counting, position limit, etc.
  • If there is occlusion, the output will be high level; if there is no occlusion, the output will be low level.
  • Wiring: VCC is connected to the positive pole of the power supply 3.3-5V
  • GND is connected to the negative pole of the power supply DO TTL switch signal output
  • AO This module does not work
4.2 Test principle and unit conversion
  • The wheel travels once and passes through a circumference, C = 2x3.14x radius = 3.14 x diameter (6.5cm)
  • The corresponding code wheel also rotates in one circle. The code wheel has 20 grids. Each time it passes through a grid, it will be blocked (high level) or not blocked (low level). Then one pulse will go 3.14 * 6.5 cm /20 = 1.0205CM
  • The timer can be designed to be one second and count the number of pulses. One pulse is 1cm.
  • Assuming there are 80 pulses per second, then it is 80cm/s
4.3 Timers and interrupts implement speed testing development and debugging code

Test data is sent to the host computer through the serial port

Hardware wiring

Speed ​​measurement module:

  • VCC -- 3.3V cannot be connected to 5V, otherwise it will trigger three interrupts once blocked.
  • OUT -- PB14

cubeMX configuration

Code:

unsigned int speedCnt;

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == GPIO_PIN_14)
        if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_14) == GPIO_PIN_RESET)
            speedCnt++;
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    printf("speed: %d\r\n", speedCnt);
    speedCnt = 0;
}

main函数里:
HAL_TIM_Base_Start_IT(&htim2);
4.4 The speed of the car is displayed on the OLED screen

OLED module introduction: Detailed explanation of STM32 OLED screen display

Hardware wiring

  • SCL -- PB6
  • SDA -- PB7

Code example:

oled.c

#include "oled.h"
#include "i2c.h"
#include "oledfont.h"

void Oled_Write_Cmd(uint8_t dataCmd)
{
	
	HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x00, I2C_MEMADD_SIZE_8BIT,
										&dataCmd, 1, 0xff);
}

void Oled_Write_Data(uint8_t dataData)
{
	HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x40, I2C_MEMADD_SIZE_8BIT,
										&dataData, 1, 0xff);
}

void Oled_Init(void){
	Oled_Write_Cmd(0xAE);//--display off
	Oled_Write_Cmd(0x00);//---set low column address
	Oled_Write_Cmd(0x10);//---set high column address
	Oled_Write_Cmd(0x40);//--set start line address  
	Oled_Write_Cmd(0xB0);//--set page address
	Oled_Write_Cmd(0x81); // contract control
	Oled_Write_Cmd(0xFF);//--128   
	Oled_Write_Cmd(0xA1);//set segment remap 
	Oled_Write_Cmd(0xA6);//--normal / reverse
	Oled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)
	Oled_Write_Cmd(0x3F);//--1/32 duty
	Oled_Write_Cmd(0xC8);//Com scan direction
	Oled_Write_Cmd(0xD3);//-set display offset
	Oled_Write_Cmd(0x00);//
	
	Oled_Write_Cmd(0xD5);//set osc division
	Oled_Write_Cmd(0x80);//
	
	Oled_Write_Cmd(0xD8);//set area color mode off
	Oled_Write_Cmd(0x05);//
	
	Oled_Write_Cmd(0xD9);//Set Pre-Charge Period
	Oled_Write_Cmd(0xF1);//
	
	Oled_Write_Cmd(0xDA);//set com pin configuartion
	Oled_Write_Cmd(0x12);//
	
	Oled_Write_Cmd(0xDB);//set Vcomh
	Oled_Write_Cmd(0x30);//
	
	Oled_Write_Cmd(0x8D);//set charge pump enable
	Oled_Write_Cmd(0x14);//
	
	Oled_Write_Cmd(0xAF);//--turn on oled panel		
}

void Oled_Screen_Clear(void){
	char i,n;
	Oled_Write_Cmd (0x20);                    //set memory addressing mode
	Oled_Write_Cmd (0x02);                    //page addressing mode

	for(i=0;i<8;i++){
		Oled_Write_Cmd(0xb0+i);               
		Oled_Write_Cmd(0x00);                 
		Oled_Write_Cmd(0x10);                 
		for(n=0;n<128;n++)Oled_Write_Data(0x00); 			
	}	
}

void Oled_Show_Char(char row,char col,char oledChar){ //row*2-2
	unsigned int  i;
	Oled_Write_Cmd(0xb0+(row*2-2));                           //page 0
	Oled_Write_Cmd(0x00+(col&0x0f));                          //low
	Oled_Write_Cmd(0x10+(col>>4));                            //high	
	for(i=((oledChar-32)*16);i<((oledChar-32)*16+8);i++){
		Oled_Write_Data(F8X16[i]);                            //写数据oledTable1
	}

	Oled_Write_Cmd(0xb0+(row*2-1));                           //page 1
	Oled_Write_Cmd(0x00+(col&0x0f));                          //low
	Oled_Write_Cmd(0x10+(col>>4));                            //high
	for(i=((oledChar-32)*16+8);i<((oledChar-32)*16+8+8);i++){
		Oled_Write_Data(F8X16[i]);                            //写数据oledTable1
	}		
}


/******************************************************************************/
// 函数名称:Oled_Show_Char 
// 输入参数:oledChar 
// 输出参数:无 
// 函数功能:OLED显示单个字符
/******************************************************************************/
void Oled_Show_Str(char row,char col,char *str){
	while(*str!=0){
		Oled_Show_Char(row,col,*str);
		str++;
		col += 8;	
	}		
}

main.c

extern uint8_t buf;
unsigned int speedCnt = 0;
char speedMes[24];  //主程序发送速度数据的字符串缓冲区

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if (GPIO_Pin == GPIO_PIN_14)
		if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_14) == GPIO_PIN_RESET)
			speedCnt++;
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	printf("speed: %d\r\n", speedCnt);
	sprintf(speedMes,"speed:%2d cm/s",speedCnt);//串口数据的字符串拼装,speed是格子,每个格子1cm
	Oled_Show_Str(2,2,speedMes);
	speedCnt = 0;
}

5. Remote control car

5.1 Bluetooth controlled car
  • Using Bluetooth module, serial port transparent transmission
  • Bluetooth module, also called Bluetooth serial port module

Serial port transparent transmission technology:

  • Transparent transmission means that during the data transmission process, the set of data does not undergo any form of change through wireless means, as if the transmission process is transparent, while ensuring the quality of the transmission and arriving at the final reception intact. in hands.
  • Ethernet, Bluetooth, Zigbee, GPRS and other modules play the same way. For embedded programmers, there is no need to care about the internal data of the communication module and the working principle of the protocol stack. They only need to obtain the data through serial port programming.

Code:

Integrate the front serial port control car code and connect to the Bluetooth module

if (!strcmp(UART1_RX_Buffer, "M1"))
{
    goForward();
    HAL_Delay(10);
}
else if (!strcmp(UART1_RX_Buffer, "M2"))
{
    goBack();
    HAL_Delay(10);
}
else if (!strcmp(UART1_RX_Buffer, "M3"))
{
    goLeft();
    HAL_Delay(10);
}
else if (!strcmp(UART1_RX_Buffer, "M4"))
{
    goRight();
    HAL_Delay(10);
}
else
    stop();
5.2 Bluetooth control and speed measurement car

Principle: Use the Bluetooth module and speed measurement module mentioned above to integrate the two codes

5.3 WiFi controlled speed measuring car

  • Wifi module-ESP-01s
  • Communication modules such as Bluetooth, ESP-01s, Zigbee, NB-Iot, etc. are all designed based on AT commands.

Introduction to AT commands:

  • The AT command set is sent from the terminal equipment (Terminal Equipment, TE) or data terminal equipment (Data Terminal Equipment, DTE) to the terminal adapter (Terminal Adapter, TA) or data circuit terminal equipment (Data Circuit Terminal Equipment, DCE).
  • It has a definition for the size of the transmitted data packet: that is, for the transmission of AT commands, in addition to the two AT characters, a maximum length of 1056 characters (including the last null character) can be received.
  • Each AT command line can only contain one AT command; for the URC instruction or response actively reported by the terminal device to the PC, it is also required to have at most one in one line, and multiple instructions or responses in one reported line are not allowed. AT commands end with carriage return, and responses or reports end with carriage return and line change.

Hardware wiring

  • Plug esp8266 into serial port 1

Instructions:

Wifi module-ESP-01s_esp01s baud rate-CSDN Blog

5.4 4g control car

Principle: Using EC03-DNC4G communication module

Module introduction:

  • Development method based on serial port AT commands
  • There are two working modes. The default is transparent transmission mode. You can enter AT command mode through other methods.
  • Be careful not to make mistakes when inserting the card. The red position in the picture below is the SIM card status light. It is normal if it is on.

The code does not need to be modified, it is directly integrated based on the Bluetooth car. The 4g module only needs to do transparent transmission to the external network.

6. Voice control car

6.1 Voice module configuration :

Using SU-03T/LD3320

For a detailed introduction, please see the blog I wrote before: Use of SU-03T voice module_Luo Xiaobai’s godfather’s blog-CSDN blog

  

6.2 Voice control car development and debugging code

Hardware wiring:

 Tracking car: 

  • Tracking module (left) -- PB3
  • Tracking module (right) -- PB4

 Follow the car: 

  • Follow module (left) -- PA8
  • Follow module (right) -- PA9

 Obstacle avoidance car: 

  • sg90:PB9
  • Trig:PA10
  • Echo:PA11

 OLED module: 

  • SCL -- PB6
  • SDA -- PB7

 Voice module: 

  • A25 -- PA15 (follow)
  • A26 -- PA13 (obstacle avoidance)
  • A27 -- PA14 (tracking)

cubeMX configuration  

Code example:

#include "main.h"
#include "i2c.h"
#include "tim.h"
#include "gpio.h"

#include "sg90.h"
#include "sr04.h"
#include "motor.h"
#include "oled.h"

#define MIDDLE 0
#define LEFT 1
#define RIGHT 2

#define BZ 1
#define XJ 2
#define GS 3

#define LeftWheel_Value_XJ HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_3)
#define RightWheel_Value_XJ HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4)

#define LeftWheel_Value_GS HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8)
#define RightWheel_Value_GS HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_9)

#define A25 HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15)
#define A26 HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_13)
#define A27 HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_14)

void SystemClock_Config(void);

char dir;

void xunjiMode()
{
	if(LeftWheel_Value_XJ == GPIO_PIN_RESET && RightWheel_Value_XJ == GPIO_PIN_RESET)
		goForward();
	if(LeftWheel_Value_XJ == GPIO_PIN_SET && RightWheel_Value_XJ == GPIO_PIN_RESET)
		goLeft();
	if(LeftWheel_Value_XJ == GPIO_PIN_RESET && RightWheel_Value_XJ == GPIO_PIN_SET)
		goRight();
	if(LeftWheel_Value_XJ == GPIO_PIN_SET && RightWheel_Value_XJ == GPIO_PIN_SET)
		stop();
}

void gensuiMode()
{
	if(LeftWheel_Value_GS == GPIO_PIN_RESET && RightWheel_Value_GS == GPIO_PIN_RESET)
		goForward();
	if(LeftWheel_Value_GS == GPIO_PIN_SET && RightWheel_Value_GS == GPIO_PIN_RESET)
		goRight();
	if(LeftWheel_Value_GS == GPIO_PIN_RESET && RightWheel_Value_GS == GPIO_PIN_SET)
		goLeft();
	if(LeftWheel_Value_GS == GPIO_PIN_SET && RightWheel_Value_GS == GPIO_PIN_SET)
		stop();
}

void bizhangMode()
{
	double disMiddle;
	double disLeft;
	double disRight;

	if(dir != MIDDLE){
		sgMiddle();
		dir = MIDDLE;
		HAL_Delay(300);
	}
	disMiddle = get_distance();
	
	if(disMiddle > 35){
		//前进
		goForward();
	}else if(disMiddle < 10){
		goBack();
		
	}else
	{
		//停止
		stop();
		//测左边距离
		sgLeft();
		HAL_Delay(300);
		disLeft = get_distance();
		
		sgMiddle();
		HAL_Delay(300);
		
		sgRight();
		dir = RIGHT;
		HAL_Delay(300);
		disRight = get_distance();
		
		if(disLeft < disRight){
			goRight();
			HAL_Delay(150);
			stop();
		}
		if(disRight < disLeft){
			goLeft();
			HAL_Delay(150);
			stop();
		}
	}
	HAL_Delay(50);
}

int main(void)
{
    int mark = 0;

    HAL_Init();


    SystemClock_Config();


    MX_GPIO_Init();
    MX_TIM4_Init();
    MX_TIM2_Init();
    MX_I2C1_Init();

	initSG90();
	HAL_Delay(1000);
	dir = MIDDLE;
	Oled_Init();
	Oled_Screen_Clear();
	Oled_Show_Str(2,2,"-----Ready----");

  while (1)
  {

		//满足寻迹模式的条件
		if(A25 == 1 && A26 == 1 && A27 == 0){
			if(mark != XJ){
				Oled_Screen_Clear();
				Oled_Show_Str(2,2,"-----XunJi----");
			}
			mark = XJ;
			xunjiMode();
		}
		//满足跟随模式的条件
		if(A25 == 0 && A26 == 1 && A27 == 1){
			if(mark != GS){
				Oled_Screen_Clear();
				Oled_Show_Str(2,2,"-----GenSui----");
			}
			mark = GS;
			gensuiMode();
		}
		//满足避障模式的条件
		if(A25 == 1 && A26 == 0 && A27 == 1){
			if(mark != BZ){
				Oled_Screen_Clear();
				Oled_Show_Str(2,2,"-----BiZhang----");
			}
			mark = BZ;
			bizhangMode();
		}
  }
}


Guess you like

Origin blog.csdn.net/m0_74712453/article/details/134113174