需要实现的项目内容
1.材料清单
材料 | 数量 |
电机 | 2 |
万向轮 | 1 |
轮胎 | 2 |
循迹模块 | 2 |
超声波、舵机 | 1 |
STM32F103学习板或者最小系统 | 1 |
L298N | 1 |
12V可充电锂电池 | 1 |
蓝牙模块HC-06 | 1 |
1.2图片
2.L298N电机驱动(重点)
2.1L298N原理
如上图所示: 输出A和输出B接到电机。12V供电接到锂电池正极,5V接到单片机正极(注意单片机上的5V丝印层字样),GND单片机和锂电池共用。拔掉通道A使能和通道B使能,各接到单片机PC6和PC7口(PWM控制电机速度,用的是TIM3,开启复用模式,详细看PWM输出实验详细示例),IN1和IN2为一组( IN1是PA0; //左电机正转, IN2 = PA1; //左电机反转),接到单片机P2对应OutA(输出A); IN3和IN4为一组(IN3 是PA2; //右电机正转 ,IN4 是PC3; //右电机反转),对应OutB(输出B)。注意自己的L298N的IN1IN2IN3IN4驱动电子的方向。ENA和ENB是用来控制小车速度的,给高电平有效。
正反转逻辑(0为低电平,1为高电平)
IN1 | IN2 | IN3 | IN4 | 电机 |
1 | 0 | 0 | 1 | 向前 |
0 | 1 | 1 | 0 | 向后 |
0 | 0 | 0 | 1 | 左转 |
1 | 0 | 0 | 0 | 向后 |
1 | 1 | 1 | 1 | 停止 |
0 | 0 | 0 | 0 | 停止 |
PWM,STM32的I/O口PC6和PC7,TIM_SetCompare1(TIM3,PWM1)中PWM1控制小车转速即占空比。
2.2代码:
PWM.C
#include "To.h"
void PWM_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
GPIO_InitTypeDef GPIO_InitStruct;
/***************时钟使能*******************/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
/***************TIM使能*******************/
TIM_TimeBaseInitStruct.TIM_Period= 100-1;//重装载值
TIM_TimeBaseInitStruct.TIM_Prescaler = 720-1;//预分频数
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
/***************PWM使能*******************/
TIM_OCStructInit(&TIM_OCInitStruct);//给结构体成员赋初始值
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;//PWM1模式
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;//设置极性
TIM_OCInitStruct.TIM_Pulse = 50;//占空比
TIM_OCInitStruct.TIM_OutputState= TIM_OutputState_Enable;//使能/失能
TIM_OC2Init(TIM3,&TIM_OCInitStruct);
TIM_OC1Init(TIM3,&TIM_OCInitStruct);
TIM_Cmd(TIM3,ENABLE);
}
TO.h 总头文件
#ifndef _TO_H
#define _TO_H
#include "stm32f10x.h"
//管脚初始化
void GPIOx_cofing(void);
//delay
void delay_init(void);
void delay_ms(u16 nms);
void delay_us(u32 nus);
void delay_s(int s);
//PWM
void PWM_Init(void);
//控制电机
void qj(int PWM1,int PWM2);
void zz(int PWM1,int PWM2);
void yz(int PWM1,int PWM2);
void ht(int PWM1,int PWM2);
void tz(int PWM1,int PWM2);
//循迹
void XJ(void);
//蓝牙通信
void usart_Initconfig(void);
void USART_SendByte(USART_TypeDef* USARTx, uint16_t Data);
uint8_t USART_ReceiveByte(USART_TypeDef* USARTx);
extern uint16_t temp;
//遥控
void YKXC(void);
#endif
3.车轮的控制和初始化代码
motor.c
#include "To.h"
//车轮方向控制
void qj(int PWM1,int PWM2)//前进
{
TIM_SetCompare1(TIM3,PWM1);
GPIO_SetBits(GPIOA,GPIO_Pin_0);
GPIO_ResetBits(GPIOA,GPIO_Pin_1);
TIM_SetCompare2(TIM3,PWM2);
GPIO_SetBits(GPIOA,GPIO_Pin_2);
GPIO_ResetBits(GPIOA,GPIO_Pin_3);
}
void zz(int PWM1,int PWM2)//左转
{
TIM_SetCompare1(TIM3,PWM1);
GPIO_SetBits(GPIOA,GPIO_Pin_0);
GPIO_ResetBits(GPIOA,GPIO_Pin_1);
TIM_SetCompare2(TIM3,PWM2);
GPIO_SetBits(GPIOA,GPIO_Pin_2);
GPIO_ResetBits(GPIOA,GPIO_Pin_3);
}
void yz(int PWM1,int PWM2)//右转
{
TIM_SetCompare1(TIM3,PWM1);
GPIO_SetBits(GPIOA,GPIO_Pin_0);
GPIO_ResetBits(GPIOA,GPIO_Pin_1);
TIM_SetCompare2(TIM3,PWM2);
GPIO_SetBits(GPIOA,GPIO_Pin_2);
GPIO_ResetBits(GPIOA,GPIO_Pin_3);
}
void ht(int PWM1,int PWM2)//后退
{
TIM_SetCompare1(TIM3,PWM1);
GPIO_ResetBits(GPIOA,GPIO_Pin_0);
GPIO_SetBits(GPIOA,GPIO_Pin_1);
TIM_SetCompare2(TIM3,PWM2);
GPIO_ResetBits(GPIOA,GPIO_Pin_2);
GPIO_SetBits(GPIOA,GPIO_Pin_3);
}
void tz(int PWM1,int PWM2)//停止
{
TIM_SetCompare1(TIM3,PWM1);
GPIO_ResetBits(GPIOA,GPIO_Pin_0);
GPIO_ResetBits(GPIOA,GPIO_Pin_1);
TIM_SetCompare2(TIM3,PWM2);
GPIO_ResetBits(GPIOA,GPIO_Pin_2);
GPIO_ResetBits(GPIOA,GPIO_Pin_3);
}
4.管脚初始化代码
GPIOX.c I/O口初始化代码
#include "To.h"
void GPIOx_cofing(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC,ENABLE);
//小车车轮接口
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
//LED
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStruct);
//小车循迹接口
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0| GPIO_Pin_1|GPIO_Pin_10| GPIO_Pin_11;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
//pwm输出/串口
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_9; //GPIO_Pin_9 //TX
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; //GPIO_Pin_10
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStruct);
}
5.循迹
5.1循迹模块的选择
循迹模块有模拟量和数字量的,初学者建议选择数字量,但循迹不丝滑,它的循迹原理就是接收到信号来转向。
5.2循迹代码
#include "To.h"
void XJ(void)
{
if( GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0&& GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)==0)
{
qj(23,23);
}
else if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==1&&GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)==0)
{
zz(13,25);
}
else if( GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0&&GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)==1)
{
yz(25,13);
}
else if( GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==1&&GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)==1)
{
tz(0,0);
}
}
6.蓝牙通信
6.1蓝牙的接线方法
请看VCR
HC-05蓝牙模块--------手机与STM32通信(代码编写)(上位机配置)保姆级教程
我这里用RCC_APB2Periph_USART1,波特率9600,PA9是TX,PA9接到蓝牙模块的RX,PA10是RX,PA10接到蓝牙模块的TX,单片机和蓝牙模块的这两个口反接。
#include "To.h"
uint16_t temp;
void usart_Initconfig(void)
{
USART_InitTypeDef USART_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1,ENABLE);
USART_InitStruct.USART_BaudRate = 9600;//波特率
USART_InitStruct.USART_WordLength = USART_WordLength_8b;//数据位
USART_InitStruct.USART_StopBits = USART_StopBits_1;//停止位长度
USART_InitStruct.USART_Parity = USART_Parity_No;//校验位;无
USART_InitStruct.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;//发送/接收
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控
USART_Init(USART1,&USART_InitStruct);
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//使能usart1的中断
USART_Cmd(USART1, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority =0 ;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelCmd =ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
void USART1_IRQHandler()
{
//判断是否接收到数据
if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
temp=USART_ReceiveByte(USART1);
//USART_SendByte(USART1,temp);
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}
}
void USART_SendByte(USART_TypeDef* USARTx, uint16_t Data)
{
assert_param(IS_USART_ALL_PERIPH(USARTx));
assert_param(IS_USART_DATA(Data));
USARTx->DR = (Data & (uint16_t)0x01FF);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE)==0);
}
uint8_t USART_ReceiveByte(USART_TypeDef* USARTx)
{
while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE)==0);//为0表示没有收到数据;为1表示收到数据
return (uint8_t)USART_ReceiveData(USART1);
}
6.2蓝牙控制代码
#include "To.h"
void YKXC(void)
{
if(temp == 'w') //控制w十六进制为“0x77”,temp == 0x77 也可以
{
qj(25,26);
}
else if(temp == 'a')
{
zz(22,30);
}
else if(temp == 'd')
{
yz(30,22);
}
else if(temp == 's')
{
ht(25,25);
}
else if(temp == 't')
{
tz(0,0);
}
else if(temp == 'x')
{
XJ();
}
}
7.舵机
7.1舵机的接法
信号线(黄色)、正极(红色)、负极(棕色)
信号线连接到P3^4,用定时器0,0.1ms中断一次,0.1*6(中断次数)=1ms(指向右边);0.1*15(中断次数)=1.5ms(舵机指向中间);0.1*20(中断次数)=2ms(舵机指向左边)
180度舵机控制参数 | |||
角度 | 脉冲周期 | 脉冲高电平时间 | 占空比 |
0 | 20ms | 0.5ms | 2.50% |
45 | 20ms | 1ms | 5.00% |
90 | 20ms | 1.5ms | 7.50% |
145 | 20ms | 2ms | 10.00% |
180 | 20ms | 2.5ms | 12.50% |
7.2例子代码:暂无
8.超声波
8.1超声波接线:
超声波和舵机是接在一起的,一般网上买都有连接材料,超声波可以随便连接I/O口,我这里接的是EchoPin = P3^6;//超声波模块Echo 接收端;TrigPin = P3^5;//超声波模块Trig 控制端。