资讯动态

STM32新手首项目:简单实用的入门之作

发布时间:2026/10/26 10:22:59 来源:尧图企业网站定制
这是我学习STM32之后做的第一个小项目基于STM32的循迹小车这个项目比较简单适合作为新手做的第一个项目。那么话不多说直接进入正题。一、所需材料1.1四路循迹模块1.2L298N电机驱动模块1.3STM32F103C8T6最小系统板1.4循迹小车套件二、模块介绍2.1循迹模块2.1.1工作原理四路循迹一般用4 个 TCRT5000 红外灰度传感器横向并排安装在小车底部沿着赛道垂直方向排布用来识别黑色引导线黑线吸光、白纸反光单片机读取四路信号判断小车相对黑线的偏移再控制电机左右差速把车拉回线上。2.1.2接线部分四路循迹模块STM32C103C8T6VCC5VGNDGNDX1A10X2A11X3A12X4A152.2电机驱动模块2.2.1工作原理内部是两路独立 H 桥单片机 IO 只输出小信号控制 H 桥里功率管通断给电机提供大电流实现正转、反转、刹车、PWM 调速。ENAIN1IN2电机 A 状态0××禁止停止110正转101反转100刹车短接制动快速停111刹车电机B同理2.2.2接线部分L298NSTM32ENAB7ENBB6IN1B15IN2B14IN3B13IN4B12GND共地OUT1\OUT2左电机OUT3\OUT4右电机三、代码部分3.1GPIO初始化建议在正式写代码之前先将引脚宏定义写上方便后续修改代码以及更换引脚注意ENA、ENB的模式一定要配置为复用推挽输出。#include stm32f10x.h // Device header #define L298N_B_ENA GPIO_Pin_7 #define L298N_B_IN1 GPIO_Pin_15 #define L298N_B_IN2 GPIO_Pin_14 #define L298N_B_IN3 GPIO_Pin_13 #define L298N_B_IN4 GPIO_Pin_12 #define L298N_B_ENB GPIO_Pin_6 #define L298N_GPIO GPIOB void GPIO_Configuration(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Pin L298N_A_IN1 | L298N_A_IN2 | L298N_A_IN3 | L298N_A_IN4; GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(L298N_GPIO,GPIO_InitStruct); GPIO_InitStruct.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Pin L298N_A_ENA | L298N_A_ENB; GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(L298N_GPIO,GPIO_InitStruct); }3.2PWM初始化void PWM_Init(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruture; TIM_TimeBaseInitStruture.TIM_ClockDivision TIM_CKD_DIV1; TIM_TimeBaseInitStruture.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseInitStruture.TIM_Period 999; //ARR TIM_TimeBaseInitStruture.TIM_Prescaler 0; //PSC TIM_TimeBaseInitStruture.TIM_RepetitionCounter 0; TIM_TimeBaseInit(TIM4,TIM_TimeBaseInitStruture); //PWM模式配置 TIM_OCInitTypeDef TIM_OCInitInitStruture; TIM_OCStructInit(TIM_OCInitInitStruture); TIM_OCInitInitStruture.TIM_OCMode TIM_OCMode_PWM1; TIM_OCInitInitStruture.TIM_OCPolarity TIM_OCPolarity_High; TIM_OCInitInitStruture.TIM_OutputState TIM_OutputState_Enable; TIM_OCInitInitStruture.TIM_Pulse 0; //CCR //配置通道1ENB TIM_OC1Init(TIM4,TIM_OCInitInitStruture); TIM_OC1PreloadConfig(TIM4,TIM_OCPreload_Enable); //配置通道2ENA TIM_OC2Init(TIM4,TIM_OCInitInitStruture); TIM_OC2PreloadConfig(TIM4,TIM_OCPreload_Enable); TIM_Cmd(TIM4,ENABLE); }3.3电机驱动部分//设置左电机的速度与转向 void L298N_Left(int Speed,uint8_t Fangxiang) { //速度限制 if(Speed 999) Speed 999; if(Speed 0) Speed 0; //正转 if(Fangxiang 1) { GPIO_SetBits(L298N_GPIO,L298N_A_IN1); GPIO_ResetBits(L298N_GPIO,L298N_A_IN2); } //反转 else if(Fangxiang 2) { GPIO_SetBits(L298N_GPIO,L298N_A_IN2); GPIO_ResetBits(L298N_GPIO,L298N_A_IN1); } //停止 else if(Fangxiang 0) { GPIO_ResetBits(L298N_GPIO,L298N_A_IN1); GPIO_ResetBits(L298N_GPIO,L298N_A_IN2); } TIM_SetCompare2(TIM4,Speed); } ////设置左电机的速度与转向 void L298N_Right(int Speed,uint8_t Fangxiang) { if(Speed 999) Speed 999; if(Speed 0) Speed 0; //正转 if(Fangxiang 1) { GPIO_SetBits(L298N_GPIO,L298N_A_IN3); GPIO_ResetBits(L298N_GPIO,L298N_A_IN4); } //反转 else if(Fangxiang 2) { GPIO_SetBits(L298N_GPIO,L298N_A_IN4); GPIO_ResetBits(L298N_GPIO,L298N_A_IN3); } //停止 else if(Fangxiang 0) { GPIO_ResetBits(L298N_GPIO,L298N_A_IN3); GPIO_ResetBits(L298N_GPIO,L298N_A_IN4); } TIM_SetCompare1(TIM4,Speed); }3.4循迹模块初始化#include stm32f10x.h // Device header #include XunJi.h #include PWM.h #include Delay.h #define X1 GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_10) #define X2 GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_11) #define X3 GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12) #define X4 GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15) void XunJi_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode GPIO_Mode_IPU; GPIO_InitStruct.GPIO_Pin GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_15; GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA,GPIO_InitStruct); }3.5循迹功能的实现要注意循迹模块的传感器是不是按顺序排列我的循迹模块从左到右的排序是X2、X1、X3、X4void XunJi_Task(void) { //正常直线行驶 if(X1 0 X3 0) { L298N_Left(900,1); L298N_Right(900,1); } //稍微偏左 if(X1 1 X3 0) { L298N_Left(0,0); L298N_Right(800,1); } if(X1 0 X3 1) { L298N_Left(800,1); L298N_Right(0,0); } //偏左很多 if(X1 1 X2 1 X3 1 X4 0) { L298N_Left(0,0); L298N_Right(999,1); } if(X1 1 X2 0 X3 1 X4 1) { L298N_Left(999,1); L298N_Right(0,0); } //转直角个人感觉停顿一下比较好看 if(X3 0 X4 0) { Delay_ms(200); L298N_Left(0,0); L298N_Right(0,0); Delay_ms(200); do { L298N_Left(999,2); L298N_Right(999,1); }while(X1 0); } if(X1 0 X2 0) { Delay_ms(200); L298N_Left(0,0); L298N_Right(0,0); Delay_ms(200); do { L298N_Left(999,1); L298N_Right(999,2); }while(X3 0); } }3.6主函数#include stm32f10x.h // Device header #include Delay.h #include OLED.h #include PWM.h #include XunJi.h int main(void) { GPIO_Configuration(); PWM_Init(); XunJi_Init(); while (1) { XunJi_Task(); } }四、总结本篇介绍的是基于STM32F103C8T6最小系统板通过标准库控制L298N电机驱动模块以及四路循迹模块实现的循迹小车这个项目相对简单可以快速了解电机是如何驱动的为智能小车等其他项目奠定基础。在实际应用中可以根据具体要求再做一些拓展例如利用编码器和OLED显示屏显示当前的速度以及行驶的距离等。通过这个项目的实践可以掌握 STM32 单片机 GPIO、ADC、定时器 PWM 的原理与配置理解复用推挽输出的用途。理解灰度循迹原理学会红外传感器信号采集、阈值判断。熟悉 L298N H 桥驱动明白电机正反转、PWM 调速、差速转向的实现。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑