题目要求
1、完成小车组装;
2、小车具有循迹功能;
3、小车具有遥控功能;
4、可显示电池电压及左右轮分别的转速。
题目分析
由题可知小车大致可分为主控、显示、蓝牙、循迹四个部分
主控我选用的是CW32F030C8T6,芯片来源于武汉芯源半导体有限公司,这款芯片基于ARM公司Cortex-M0+内核,最高主频64MHZ,64K字节FLASH,8K字节RAM,采用LQFP48封装,是一款高性价比的国产MCU。现在CW32有开发者扶持计划,有很多福利资助,像做项目之类的都会给现金资助。 微信搜索:“CW32生态社区”公众号可以免费申领武汉芯源半导体的CW32芯片、核心板以及开发板。 搜索“CW32生态社区”公众号,关注后进入。点击左下角“开发扶持”,点击“样品申请”,弹出“开始答题”,点击后填写申请信息即可。
显示部分我选用OLED 0.96OLED,该屏幕尺寸小,分辨率高,低压3.3V就可工作被广泛应用在各种电子产品在中。
蓝牙遥控我选用HC-05主从机一体蓝牙模块
循迹采用zgnb大佬基于74hc165设计的模块
总体设计方案框图
原理图设计说明
首先是电源输入通过DCDC LM1584降至5V,再通过1117将5V降至3.3V,以便给电路中的不同模块供电
电池电压检测电路,同过ADC采集,实时显示电池电压
电机驱动采用TB6612,TB6612双电机驱动板,每通道输出最高1A的连续驱动电流,启动峰值电流达2A/3A;4种电机控制模式:正转/反转/制动/停止;PWM支持频率高达100kHz;
0.96OLED,电机编码,按键电路,蜂鸣器电路、LED灯电路、MPU6050、循迹模块如下:其中MPU6050用来稳定小车的动作姿态
整体原理图
PCB设计说明
电源线、地线及印制导线在PCB上的排列要恰当,尽量做到短而直,以减小信号线与回线之间所形成的环路面积。电源线走大一些。
总体PCB
软件说明
寻迹模块代码
/******************************************************************************
*函数名称:HC165_Disable()
*功能: 失能循迹板
*参数: 无
*返回: 无
*******************************************************************************/
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<<i;
}
HC165_CLK_L;
HC165_CLK_H;
}
return HC165_Data;
}
初始化系统任务配置程序:
/* 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(osMessageQ(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 */
}
系统用户任务处理函数:
void LS_task_system(void const * argument)
{
for(;;)
{
MPU_Get_Gyroscope(&gx,&gy,&gz);
gz = gz + 148;
trask = Get_HC165_Data();//二十四位数据
trask8_data = trask&0xff;//提取八位循迹数据
trask16_data = (trask >> 8);//提取十六位循迹数据
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) // 有黑线
{
old_position8 = position8; // 保留上次位置值
}
else // 无黑线
{ // 用上次的值,放大2倍
position8 = old_position8;
}
if(abs(position8)<=1) Espeed = z;
else Espeed = -w;
if(trask16_data != 0) // 有黑线
{
old_position16 = position16; // 保留上次位置值
}
else // 无黑线
{ // 用上次的值,放大2倍
position16 = old_position16 * 2;
}
err_pwm_Kp = (-trask_Pid.p) * position16 ; // 计算 p 值
err_pwm_Kd = gz/65 * (-trask_Pid.d); // 计算 D 值
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;
//反转限幅
// 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);
}
}
小车图
CW开发板申请流程如下: