Question requirements
1. Complete the assembly of the car;
2. The car has a tracking function;
3. The car has a remote control function;
4. It can display the battery voltage and the speed of the left and right wheels.
Question analysis
From the question, we can know that the car can be roughly divided into four parts: main control, display, Bluetooth, and tracking.
The main control I chose is CW32F030C8T6. The chip comes from Wuhan Xinyuan Semiconductor Co., Ltd. This chip is based on the ARM Cortex-M0+ core, with a maximum main frequency of 64MHZ, 64K bytes of FLASH, 8K bytes of RAM, and LQFP48 packaging. It is a cost-effective domestic MCU. Now CW32 has a developer support plan, with a lot of welfare subsidies, such as cash subsidies for projects. WeChat search: "CW32 Ecological Community" public account can apply for Wuhan Xinyuan Semiconductor's CW32 chips, core boards and development boards for free. Search for the "CW32 Ecological Community" public account and follow it to enter. Click "Development Support" in the lower left corner, click "Sample Application", and the "Start Answering" pop-up pops up. Click and fill in the application information.
For the display part, I choose OLED 0.96OLED, which has a small screen size, high resolution, and can work at a low voltage of 3.3V. It is widely used in various electronic products.
For the Bluetooth remote control, I choose the HC-05 master-slave integrated Bluetooth module.
The tracking adopts the module designed by zgnb based on 74hc165.
The overall design scheme block diagram

and schematic diagram design description
First, the power input is reduced to 5V through DCDC LM1584, and then the 5V is reduced to 3.3V through 1117 to power different modules in the circuit.

The battery voltage detection circuit, through ADC acquisition, displays the battery voltage in real time

. The motor drive adopts TB6612, TB6612 dual motor drive board, each channel outputs a continuous drive current of up to 1A, and the starting peak current reaches 2A/3A; 4 motor control modes: forward/reverse/brake/stop; PWM supports frequencies up to 100kHz;

0.96OLED, motor encoding, button circuit, buzzer circuit, LED light circuit, MPU6050, tracking module are as follows: MPU6050 is used to stabilize the action posture of the car.

Overall schematic diagram

PCB design description
The power line, ground line and printed wire should be arranged properly on the PCB, and should be as short and straight as possible to reduce the loop area formed between the signal line and the return line. The power line should be larger.
Overall PCB

software description
Tracking module code
/**************************************************************************** *Function name: HC165_Disable() *Function: Disable tracking board *Parameter: None *Return: None***************************************************************************/void HC165_Disable(void){ HC165_PEN_H;}
int Get_HC165_Data(void){ int HC165_Data = 0; int i=0; HC165_LD_L; HC165_LD_H; //while(--i) for(i = 23 ; i >= 0 ; i -- ) { if(HC165_Read_SER == 0 ) { HC165_Data |= 1<
Initialize the system task configuration program:
/* USER CODE END GET_IDLE_TASK_MEMORY *//** * @brief FreeRTOS initialization * @param None * @retval None */void MX_FREERTOS_Init(void) { /* USER CODE BEGIN Init */
/* USER CODE END Init */ /* Create the mutex(es) */ /* definition and creation of myMutex01 */ osMutexDef(myMutex01); myMutex01Handle = osMutexCreate(osMutex(myMutex01));
/* USER CODE BEGIN RTOS_MUTEX */ /* add mutexes, ... */ /* USER CODE END RTOS_MUTEX */
/* USER CODE BEGIN RTOS_SEMAPHORES */ /* add semaphores, ... */ * USER CODE END RTOS_SEMAPHORES */
/* USER CODE BEGIN RTOS_TIMERS */ /* start timers, add new ones, ... */ /* USER CODE END RTOS_TIMERS */
/* Create the queue(s) */ /* definition and creation of myQueue01 */ osMessageQDef(myQueue01, 1, void *); myQueue01Handle = osMessageCreate(os MessageQ(myQueue01), NULL);
/* USER CODE BEGIN RTOS_QUEUES */ /* add queues, ... */ /* USER CODE END RTOS_QUEUES */
/* Create the thread(s) */ /* definition and creation of task_system */ osThreadDef(task_system, LS_task_system, osPriorityNormal, 0, 256); task_systemHandle = osThreadCreate(osThread(task_system), NULL);
/* definition and creation of task_usart */ osThreadDef(task_usart, LS_task_usart, osPriorityRealtime, 0, 128); task_usartHandle = osThreadCreate(osThread(task_usart), NULL);
/* definition and creation of task_user */ osThreadDef(task_user, LS_task_user, osPriorityIdle , 0, 1024); task_userHandle = osThreadCreate(osThread(task_user), NULL);
/* USER CODE BEGIN RTOS_THREADS */ /* add threads, ... */ /* USER CODE END RTOS_THREADS */
}
System user task processing function :
void LS_task_system(void const * argument){
for(;;) { MPU_Get_Gyroscope(&gx,&gy,&gz); gz = gz + 148; trask = Get_HC165_Data(); //24-bit data trask8_data = trask&0xff; //Extract 8-bit tracking data trask16_data = (trask >> 8); //Extract 16-bit tracking data trask16_data = trask16_data>> 8 |((trask16_data<<8) & 0xff00); trask16_data = trask16_data & 0x1ff8; position16 = car_Track_Find16_Position_Lift(trask16_data); position8 = car_Track_Find_Position_Lift(trask8_data); if(trask8_data != 0) // There is a black line { old_position8 = position8; // Keep the last position value } else // No black line { // Use the last value and enlarge it by 2 times position8 = old_position8; }
if(abs(position8)<=1) Espeed = z; else Espeed = -w;
if(trask16_data != 0) // black line{ old_position16 = position16; // keep the last position value} else // no Black line { // Use the last value and enlarge it by 2 times position16 = old_position16 * 2; }
err_pwm_Kp = (-trask_Pid.p) * position16 ; // Calculate the p value err_pwm_Kd = gz/65 * (-trask_Pid.d); // Calculate D value lift_PWM_OUT = base_Speed_PWM + err_pwm_Kp + err_pwm_Kd + Espeed; right_PWM_OUT = base_Speed_PWM - err_pwm_Kp - err_pwm_Kd + Espeed; if(track_Control_EN != 0) { HAL_TIM_Base_Start(&htim4); if(htim4.Instance->CNT > 980) { time ++; } sec = time/1000.00; //Invert limiting // if(lift_PWM_OUT < -4000 ) lift_PWM_OUT = -4000; // if(right_PWM_OUT < -4000) right_PWM_OUT = -4000; Set_Motor_PWM(lift_PWM_OUT,right_PWM_OUT) ; } else { HAL_TIM_Base_Stop(&htim4); time = 0; htim4.Instance->CNT = 0; } osDelay (1); }}
Car diagram

