SmartCar 项目
概述
本文章是整理基于TM4C123G开发板的智能小车的项目笔记,它会包括整个项目的开发流程及相关技术知识等,但它没有任何工程学上的目标,只是一种学习或者说一种动手设计的乐趣。
功能目标
首先我们定义我们初步要达到的功能目标:
- 支持自动左右转向,当遇到障碍物时可以转向或者倒
- 支持加速和减速,自动模式或者手动模式
- 支持红外线遥控,可以手动遥控左右转向、倒退/前进以及加减速
高级功能:
- 增加WIFI模块,可以通过远程控制
- 增加摄像头模块,可以进行视频采集和监控
使用的硬件模组
TM4C123G 微控制器开发版

红外对管距离传感器 3个
分别位于车体的前部、左部和右部
红外线接收器和遥控器
L298N电机驱动模块
L298N电机驱动
摄像头和WIFI模组
L298N电机驱动
L298N电机驱动
带有前后直流电机的模型小车
前部电机控制方向,后部电机负责前进和倒退
初步功能实现后:
L298N电机驱动
软件平台
使用 Keil uVersion IDE.
代码结构
main函数主结构
首先我们实现程序的主结构,它包含如下步骤:
激活grader和设置系统时钟
设置系统时钟的方法是配置PLL,TM4C123G使用16M的主振荡器,具体配置PLL的方法在上一章中已经介绍。我们这里只需要直接调用接口:
1 | TexaS_INIT(SW_PIN_PE210, LED_PIN_PB543210); |
它会设置系统时钟为 80M Hz.
初始化IO端口和定时器及中断
首先初始化 TM4C123G 板上自带的RGB LED端口为数字输出端口,它分别对应pin口为PF1(R)、PF2(B)、PF3(G),具体的函数定义在后面加入,这里只需要明白它做了什么。
1 | RGB_LED_Init(); |
初始化和直流电机相关的端口
设置PD0,PD1,PD2,PD3为数字输出端口,并设置其初始值为0;设置PE5为数字输出端口,并设初始值为1。上述5个端口都使用8mA驱动,具体如何用于控制电机后面会进行描述。
1 | Motor_Port_Init() |
前置电机定时器Timer0和中断初始化
我们在这里初始化Timer0A定时器,优先级为2,它的 IRQ 编号为19,ISR为Timer0A_Handler。
1 | Motro_Front_Init() |
后置电机定时器 Systick 和中断初始化
我们设置 SysTick 定时器,优先级为2,ISR 为SysTick_Handler,SysTick中断不需要中断确认(ack)。
1 | Motro_Back_Init(); |
我们在使用定时器的目的是使用 PWM 来驱动电机,使其可以加速或者减速, 定时器可以帮助我们生成不同占空比的PWM,对于后置电机占空比由 BACK_L和 BACK_H 变量控制,这两个变量交替作为SysTick的初始计数器值。PD0和PD1端口与LN298模块相连,在SysTick_Handler中会向PDO和PD1输出 0 或者 1,如下所示:
1 | void SysTick_Handler(void){ |
其中reversal用来控制电机反向旋转;NVIC_ST_RELOAD_R寄存器存有 SysTick 的计数器初始值。
初始化 IRremote 模块
该模块负责红外遥控,主要包括NEC协议的解析等。
1 | IRremote_init(); |
初始化和红外线距离传感器相关的端口及中断
我们设置PA4,PA5,PA6为数字输入端口,并设置为双边缘触发中断,优先级为1,IRQ为 0,它们分别对应前方、左方和右方的传感器。连接到响应端口,当有信号到来时,会触发中断,进而执行 GPIOPortA_Handler ISR。在 ISR 中首先进行中断确认,然后会获取3个端口的数据值,根据数据值来判断当前小车前、左和右方是否有障碍物,会根据具体情况进行后退、转向或者加速等。在IR_sensor_Init中会时设置延迟定时器TIMER1A,但不能启动定时器,该定时器在GPIOPortA_Handler中启动,并根据具体参数设置延迟时间。在延迟期间,GPIOPortA_Handler不再处理来自传感器的数据而是直接返回。
1 | IR_sensor_Init(); |
全局中断使能
调用如下接口:
1 | EnableInterrupts(); |
其具体实现通过汇编代码表示为:
1 | EnableInterrupts CPSID I ; set I = 1 |
进入主循环:
1 | while (1) { |
主循环主要是监听红外遥控命令来作出反应。
其他子函数
后置电机停止 Motor_Back_Stop 函数
该函数通过禁止 SysTick 定时器和设置 PD0 和 PD1 端口为 0:
1 | void Motor_Back_Stop(){ |
后置电机运行
重新使能 SysTick 并设置 PD0 和 PD1:
1 | void Motor_Back_Run(){ |
后置电机减速
通过调节 Bask_L 和 Back_H 全局变量来实现,我们只能这两个变量会与 SysTick 定时器合作完成 PWM 控制。
1 | void Motor_Back_SlowDown(int n){ |
后置电机加速
1 | void Motor_Back_SpeedUp(int n){ |
后置电机反向旋转
1 | void Motor_Back_Reversal(){ |
左右转弯
左右转弯通过 PWM 控制前置电机完成,它要重新使能Timer0A定时器,因为在停止转向函数中该定时器会被禁止。
1 | void Turn_Left(){ |
停止转向
1 | void Turn_Stop(){ |