STM32红外循迹智能车,TFT液晶显示
STM32红外循迹小车是一种基于STM32微控制器的嵌入式系统项目,它利用红外传感器来检测特定颜色(通常是黑色)的路径,并沿着这条路径自动移动。以下是对STM32红外循迹小车的详细介绍:
一、核心硬件
1. STM32微控制器:常用的型号是STM32F103C8T6,这是一款基于Cortex-M3内核的32位微控制器,具有丰富的外设接口和强大的处理能力。
2. 红外循迹传感器模块:
使用TCRT5000传感器,它包含一个红外发射二极管和一个红外接收管。这些传感器连接到STM32的GPIO输入引脚,用于检测路径的颜色。
3. 电机驱动模块:
电机驱动模块是L298N,它连接到STM32的PWM输出引脚,用于控制电机的速度和方向。
L298驱动产品简介:
电机驱动模块供电电压2V~10V,可同时驱动两个直流电机或者1个4线2相式步进电机,可实现正反转和调速的功能,每路电流能到1.5A持续电流,峰值电流可达2.5A,有热保护并且能够自动恢复。
产品亮点:
1. 采用进口原装专业电机驱动芯片,内置低导通内阻MOS开关管,发热极小,无需散热片,体积小,省电,是您电池供电的理想选择
2. 双路1.5A*2,峰值电流可到2.5A, 内置过热保护电路,不用怕电机堵转烧坏,温度下降后自动恢复。(目前市面上的智能小车电压和电流都在此范围内)
3. 体积小,质量轻,0待机电流,是您模型车载的理想选择
4. 直流电机:作为小车的动力源,连接到L298N电机驱动模块。
直流电机驱动逻辑真值表:
INx接单片机IO或者其他信号源,MOTOR-A和MOTOR-B端接电机
产品参数:
1.双路H桥电机驱动,可以同时驱动两路直流电机或者1个4线两相式步进电机;
2.模块供电电压2V-10V;
3.信号端输入电压1.8-7V;
4.单路工作电流1.5A,峰值电流可达2.5A,低待机电流 (小于 0.1uA);
5.内置防共态导通电路,输入端悬空时,电机不会误动作;
6.内置带迟滞效应的过热保护电路 (TSD),无需担心电机堵转;
TFT-LCD模块简介
TFT-LCD(Thin Film Transistor)液晶显示屏是薄膜晶体管型液晶显示屏,也就是“真彩”(TFT)。TFT液晶为每个像素都设有一个半导体开关,每个像素都可以通过点脉冲直接控制,因而每个节点都相对独立,并可以连续控制,不仅提高了显示屏的反应速度,同时可以精确控制显示色阶,所以TFT液晶的色彩更真。TFT液晶显示屏的特点是亮度好、对比度高、层次感强、颜色鲜艳,但也存在着比较耗电和成本过高的不足。
硬件连接
以STM32F103C8T6和2.4寸TFT-LCD(240×320)为例,硬件连接如下:
- VCC --> 3.3V
- GND --> GND
- CS --> PB11
- Reset --> PB12
- DC --> PB10
- SDI --> PB15
- SCK --> PB13
- LED --> PB9(控制LCD背光,可通过PWM调节亮度)
SPI通讯
TFT-LCD模块通常使用SPI协议进行通讯。SPI协议是一种高速全双工的通信总线,使用3条总线(SCK、MOSI、MISO)及片选线(SS/CS)1。
初始化代码
以下是TFT-LCD的初始化代码示例:
void Lcd_Init(void) {
Lcd_Reset(); // Reset before LCD Init
Lcd_WriteIndex(0x11);
Lcd_WriteData(0x00);
Lcd_WriteIndex(0xCF);
Lcd_WriteData(0X00);
Lcd_WriteData(0XC1);
Lcd_WriteData(0X30);
// 省略部分初始化代码
Lcd_WriteIndex(0x29);
}
该代码初始化了TFT-LCD的各个寄存器,确保屏幕能够正常显示1。
显示函数
TFT-LCD的显示需要依赖几个基础功能函数,如设置显示区域、画点、清屏等:
void Lcd_SetXY(u16 Xpos, u16 Ypos) {
Lcd_WriteIndex(0x2A);
Lcd_WriteData_16Bit(Xpos);
Lcd_WriteIndex(0x2B);
Lcd_WriteData_16Bit(Ypos);
Lcd_WriteIndex(0x2c);
}
void Gui_DrawPoint(u16 x, u16 y, u16 Data) {
Lcd_SetXY(x, y);
Lcd_WriteData_16Bit(Data);
}
void Lcd_Clear(u16 Color) {
unsigned int i;
Lcd_SetRegion(0, 0, X_MAX_PIXEL - 1, Y_MAX_PIXEL - 1);
LCD_CS_CLR;
LCD_RS_SET;
for (i = 0; i < X_MAX_PIXEL * Y_MAX_PIXEL; i++) {
SPIv_WriteData(Color >> 8);
SPIv_WriteData(Color);
}
LCD_CS_SET;
}
这些函数用于设置显示区域、绘制点和清屏1
二、硬件连接
1. STM32与红外循迹传感器的连接:将红外循迹传感器的输出引脚连接到STM32的GPIO输入引脚,以便读取传感器的状态。
2. STM32与电机驱动模块的连接:将STM32的PWM输出引脚连接到电机驱动模块的输入引脚,用于控制电机的速度和方向。同时,将电机的电源线和地线分别连接到电机驱动模块的电源输入端和地线端。
三、软件编程
1. 初始化配置:
* 配置GPIO引脚为输入模式或输出模式,以连接红外循迹传感器和电机驱动模块。
* 启用外部中断(如果需要使用)。
* 配置定时器以产生PWM信号,控制电机的速度。
2. 循迹逻辑:
* 根据红外传感器的输入,判断小车当前所在的位置。
* 根据位置信息,控制电机的转向和速度,使小车沿着黑线移动。
* 常用的控制策略包括:当检测到黑线在中间时,小车直行;当检测到黑线在左侧时,小车右转;当检测到黑线在右侧时,小车左转;当未检测到黑线时,小车停车。
3. 主循环:在主函数中,初始化硬件后进入循环,不断检测传感器状态并调整小车方向。
四、注意事项
1. 传感器校准:确保红外传感器正确校准,以准确检测黑线。
2. 电源稳定性:确保电源稳定,避免电压波动影响传感器和电机的稳定性。
3. 代码优化:根据实际应用需求,优化循迹算法和PWM控制逻辑。
代码
#include "delay.h"
#include "sys.h"
#include "lcd.h"
#include "touch.h"
#include "gui.h"
#include "test.h"
#include "stm32f10x.h"
#define ON 0
#define OFF 1
//STM32F103
//
/****************************************************************************************************
//=======================================液晶屏数据线接线==========================================//
//CS 接PB12 //片选信号
//CLK 接PB13 //SPI时钟信号
//SDI(DIN) 接PB15 //SPI总线数据信号
//=======================================液晶屏控制线接线==========================================//
//RS(D/C) 接PB1 //寄存器/数据选择信号(RS=0数据总线发送的是指令;RS=1数据总线发送的是像素数据)
/
//==================================如何精简到只需要3个IO=======================================//
//1.CS信号可以精简,不作SPI复用片选可将CS接地常低,节省1个IO
//2.LED背光控制信号可以接高电平3.3V背光常亮,节省1个IO
//3.RST复位信号可以接到单片机的复位端,利用系统上电复位,节省1个IO
//==================================如何切换横竖屏显示=======================================//
//打开lcd.h头文件,修改宏#define USE_HORIZONTAL 值为0使用竖屏模式.1,使用横屏模式
//===========================如何切换模拟SPI总线驱动和硬件SPI总线驱动=========================//
//打开lcd.h头文件,修改宏#define USE_HARDWARE_SPI 值为0使用模拟SPI总线.1,使用硬件SPI总线
**************************************************************************************************/
u16 LeftEye = 0;
u16 RightEye = 0;
/*************** 小车配置用到的I/O口 *******************/
void GPIO_Config(void)
{
/**************电机驱动管教*******************/
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE); // 使能PA端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //选择电机A1对应的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA端口
GPIO_SetBits(GPIOA, GPIO_Pin_0 ); // 电机A1
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //选择电机A2对应的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA端口
GPIO_SetBits(GPIOA, GPIO_Pin_1 ); // 电机A2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //选择电机B1对应的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA端口
GPIO_SetBits(GPIOA, GPIO_Pin_2 ); // 电机B1
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //选择电机B2对应的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA端口
GPIO_SetBits(GPIOA, GPIO_Pin_3 ); // 电机B2
/**************红外循迹*******************/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //选择红外循迹左边对应的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA端口
GPIO_SetBits(GPIOA, GPIO_Pin_5 );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //选择红外循迹右边对应的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA端口
GPIO_SetBits(GPIOA, GPIO_Pin_6 );
/**************LED*******************/
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE); // 使能PC端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; //选择LED灯对应的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化PC端口
GPIO_SetBits(GPIOC, GPIO_Pin_13 ); // 关闭所有LED
}
void XunjiCheck(void)//红外循迹传感器查询
{
LeftEye = (GPIO_ReadInputData(GPIOA)&0x20)>>5;
RightEye = (GPIO_ReadInputData(GPIOA)&0x40)>>6;
}
void MotorStop(void) //小车停止
{
GPIO_ResetBits(GPIOA,GPIO_Pin_0);
GPIO_ResetBits(GPIOA,GPIO_Pin_1);
GPIO_ResetBits(GPIOA,GPIO_Pin_2);
GPIO_ResetBits(GPIOA,GPIO_Pin_3);
}
void MotorRun(void) //小车启动
{
GPIO_SetBits(GPIOA,GPIO_Pin_0);
GPIO_ResetBits(GPIOA,GPIO_Pin_1);
GPIO_SetBits(GPIOA,GPIO_Pin_2);
GPIO_ResetBits(GPIOA,GPIO_Pin_3);
}
void MotorTurnLeft(void) //小车左转
{
GPIO_ResetBits(GPIOA,GPIO_Pin_0);
GPIO_ResetBits(GPIOA,GPIO_Pin_1);
GPIO_SetBits(GPIOA,GPIO_Pin_2);
GPIO_ResetBits(GPIOA,GPIO_Pin_3);
}
void MotorTurnRight(void) //小车右转
{
GPIO_SetBits(GPIOA,GPIO_Pin_0);
GPIO_ResetBits(GPIOA,GPIO_Pin_1);
GPIO_ResetBits(GPIOA,GPIO_Pin_2);
GPIO_ResetBits(GPIOA,GPIO_Pin_3);
}
void LED1(char led) //LED灯
{
if(led==1)
{
GPIO_SetBits(GPIOC,GPIO_Pin_13);
}
else
{
GPIO_ResetBits(GPIOC,GPIO_Pin_13);
}
}
void Delay(u32 nCount)
{
for(; nCount != 0; nCount--);
}
int main(void)
{
SystemInit();//初始化RCC 设置系统主频为72MHZ
delay_init(72); //延时初始化
LCD_Init(); //液晶屏初始化
LCD_Clear(BLACK); //清屏
POINT_COLOR=WHITE;
LCD_DrawRectangle(0,0,128-1,128-1); //画矩形
Show_Str(32,5,BLUE,YELLOW,"系统监控",16,0);
Show_Str(5,25,RED,YELLOW,"温度 ℃",24,1);
LCD_ShowNum2412(5+48,25,RED,YELLOW,":32",24,1);
Show_Str(5,50,YELLOW,YELLOW,"湿度 %",24,1);
LCD_ShowNum2412(5+48,50,YELLOW,YELLOW,":20",24,1);
Show_Str(5,75,WHITE,YELLOW,"电压 V",24,1);
LCD_ShowNum2412(5+48,75,WHITE,YELLOW,":3.2",24,1);
Show_Str(5,100,GREEN,YELLOW,"电流 A",24,1);
LCD_ShowNum2412(5+48,100,GREEN,YELLOW,":0.2",24,1);
/*小车初始化*/
GPIO_Config();
while(1)
{
//LED1( ON ); // 亮
//Delay(0x200000);
//LED1( OFF ); // 灭
//Delay(0x200000);
//MotorRun();
XunjiCheck();
if((LeftEye == 0)&&(RightEye == 0)) //看到白色为0,看到黑色为1
{
MotorRun();
}
else if((LeftEye == 1)&&(RightEye == 0)) //左边看到黑线
{
MotorTurnRight();
Delay(20);
}
else if((RightEye == 1)&&(LeftEye == 0))
{
MotorTurnLeft();
Delay(20);
}
else
{
MotorStop();
}
};
}