蓝牙模块的理解:
蓝牙可以理解为一个无线的串口,手机和单片机之间可以通过蓝牙来发送数据,控制单片机IO口,进而来控制小车,总体的逻辑是,手机发送数据给蓝牙,蓝牙将这个数据再发送给单片机。另外蓝牙的代码跟我们学的串口通信差不多。
usart2.c
#include "usart2.h"
void uart2_init( u32 bound )
{
/* GPIO端口设置 */
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
RCC_APB1PeriphClockCmd( RCC_APB1Periph_USART3, ENABLE ); /* 使能USART3,GPIOA时钟 */
/* PB10 TXD3 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init( GPIOB, &GPIO_InitStructure );
/* PB11 RXD3 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init( GPIOB, &GPIO_InitStructure );
/* USART 初始化设置 */
USART_InitStructure.USART_BaudRate = bound; /* 串口波特率 */
USART_InitStructure.USART_WordLength = USART_WordLength_8b; /* 字长为8位数据格式 */
USART_InitStructure.USART_StopBits = USART_StopBits_1; /* 一个停止位 */
USART_InitStructure.USART_Parity = USART_Parity_No; /* 无奇偶校验位 */
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; /* 无硬件数据流控制 */
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; /* 收发模式 */
USART_Init( USART3, &USART_InitStructure ); /* 初始化串口1 */
USART_Cmd( USART3, ENABLE ); /* 使能串口 2 */
}
这里就是我的蓝牙模块的初始化代码,我用的是串口3,对应的RXD引脚是PB11,TXD引脚是PB10,详情看上面的代码。
蓝牙App的制作开发
相信很多小伙伴做这个项目更多是喜欢自己做一个遥控器,实现“自己生产化”,所以我就没有使用配套资料给我的app,自己做了一个。可以给大家参考下我自己制作的一个app
怎么制作这个app呢,我这个有链接,小伙伴可以自己去观看
电机驱动模块:
stm32因为输出的电流电压比较小,所以我们 需要使用L298N模块来驱动电机,我这里使用的是直流电机。我大概说说怎么使用,L298N有4个IN端口,4个OUT端口,OUT是接电机的,OUT1 2是接一个电机的正负极,另外 OUT3 4接另外一个电机。IN端口接单片机IO端口。,输入不同的值可以让电机正反转,同时可以使用PWM模式来控制电机的转速。
具体的视频,我推荐一下链接,博主用的是51来讲解的,原理差不多,很容易懂:
PWM设置占空比
这个板块针对的是一些小伙伴不怎么会使用stm32设置占空比的问题,我不过多讲述,我提供一个博主的视频,对大家有很大的帮助:
PWM.c
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
//使能定时器TIM4时钟,注意TIM4时钟为APB1
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
//使能PWM输出GPIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//定时器TIM4的PWM输出通道1,TIM4_CH1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;//定时器TIM4的PWM输出通道2,TIM4_CH2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;//定时器TIM4的PWM输出通道3,TIM4_CH3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;//定时器TIM4的PWM输出通道4,TIM4_CH4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
TIM_TimeBaseStructure.TIM_Period = 100 - 1;//arr;//自动重装值
TIM_TimeBaseStructure.TIM_Prescaler =36 - 1;//psc; //时钟预分频数
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//TIM向上计数模式
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //初始化TIM4
//初始化TIM4_CH1的PWM模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//??PWM??1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//??????
TIM_OCInitStructure.TIM_Pulse = 0; //
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//??????
TIM_OC1Init(TIM4, &TIM_OCInitStructure);//???TIM4_CH1
//初始化TIM4_CH2的PWM模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
//TIM4_CH2初始化,OC2
TIM_OC2Init(TIM4, &TIM_OCInitStructure);
//初始化TIM4_CH3的PWM模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC3Init(TIM4, &TIM_OCInitStructure);
//初始化TIM4_CH4的PWM模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC4Init(TIM4, &TIM_OCInitStructure);
//使能4个通道的预装载寄存器
TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);//OC1
TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);//OC2
TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable);//OC3
TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable);//OC4
TIM_ARRPreloadConfig(TIM4, ENABLE); //使能重装寄存器
TIM_Cmd(TIM4, ENABLE);//使能定时器TIM4,准备工作
}
数码管显示车速:
!!!!注意我使用的是共阳极数码管
LED.c
#include "stm32f10x.h" // Device header
#include "LED.h"
void LED_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2|GPIO_Pin_0 |GPIO_Pin_3 |GPIO_Pin_4 |GPIO_Pin_5 |GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//灯暗
GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2|GPIO_Pin_0 |GPIO_Pin_3 |GPIO_Pin_4 |GPIO_Pin_5 |GPIO_Pin_6|GPIO_Pin_7);
}
void s0(void){
// 设置所有引脚为低电平
GPIO_ResetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_3);
// 设置第7引脚为高电平
GPIO_SetBits(GPIOA, GPIO_Pin_7| GPIO_Pin_6 );
}
void s1(void){
// 设置所有引脚为高电平,除了第0引脚和第2引脚
GPIO_SetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7);
// 设置第0引脚和第2引脚为低电平
GPIO_ResetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2);
}
void s2(void){
// 设置所有引脚为高电平,除了第0引脚和第2引脚
GPIO_SetBits(GPIOA, GPIO_Pin_2 | GPIO_Pin_5 | GPIO_Pin_7);
// 设置第0引脚和第2引脚为低电平
GPIO_ResetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_3| GPIO_Pin_4| GPIO_Pin_6| GPIO_Pin_0);
}
void s3(void){
// 设置所有引脚为高电平,除了第0引脚和第2引脚
GPIO_SetBits(GPIOA, GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7);
// 设置第0引脚和第2引脚为低电平
GPIO_ResetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_3| GPIO_Pin_2| GPIO_Pin_6| GPIO_Pin_0);
}
void s4(void){
// 设置所有引脚为高电平,除了第0引脚和第2引脚
GPIO_SetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_3 | GPIO_Pin_7| GPIO_Pin_4);
// 设置第0引脚和第2引脚为低电平
GPIO_ResetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2| GPIO_Pin_5| GPIO_Pin_6);
}
void s5(void){
// 设置所有引脚为高电平,除了第0引脚和第2引脚
GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_7| GPIO_Pin_4);
// 设置第0引脚和第2引脚为低电平
GPIO_ResetBits(GPIOA, GPIO_Pin_2| GPIO_Pin_5| GPIO_Pin_6|GPIO_Pin_0 |GPIO_Pin_3);
}
void s6(void){
// 设置所有引脚为高电平,除了第0引脚和第2引脚
GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_7 );
// 设置第0引脚和第2引脚为低电平
GPIO_ResetBits(GPIOA, GPIO_Pin_2| GPIO_Pin_5| GPIO_Pin_6|GPIO_Pin_0 |GPIO_Pin_3| GPIO_Pin_4);
}
void s7(void){
// 设置所有引脚为高电平,除了第0引脚和第2引脚
GPIO_SetBits(GPIOA, GPIO_Pin_3| GPIO_Pin_5| GPIO_Pin_6|GPIO_Pin_4 |GPIO_Pin_7 );
// 设置第0引脚和第2引脚为低电平
GPIO_ResetBits(GPIOA, GPIO_Pin_2| GPIO_Pin_1|GPIO_Pin_0);
}
void sz8(void){
// 设置所有引脚为高电平,除了第0引脚和第2引脚
GPIO_SetBits(GPIOA, GPIO_Pin_7 );
// 设置第0引脚和第2引脚为低电平
GPIO_ResetBits(GPIOA, GPIO_Pin_3| GPIO_Pin_5| GPIO_Pin_6|GPIO_Pin_4 |GPIO_Pin_2| GPIO_Pin_1|GPIO_Pin_0);
}
void s9(void){
// 设置所有引脚为高电平,除了第0引脚和第2引脚
GPIO_SetBits(GPIOA, GPIO_Pin_7|GPIO_Pin_4 );
// 设置第0引脚和第2引脚为低电平
GPIO_ResetBits(GPIOA, GPIO_Pin_3| GPIO_Pin_5| GPIO_Pin_6|GPIO_Pin_2| GPIO_Pin_1|GPIO_Pin_0);
}
按键模块:
我需要对这里进行解释说明,我的板子上面有一个按钮,按下去,才可以正常使用车的功能,所以这里有一个按键模块
KEY.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
void Key_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
uint8_t Key_GetNum(void)
{
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15) == 0)//检测按键有没有按下
{
Delay_ms(20);
while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15) == 0);
Delay_ms(20);
return 1;
}
return 0;
}
小车运动模块
这里我需要解释一下,有些朋友可能会疑惑,只有电机,车怎么左右转起来的,其实这里有个秘诀,如果要左转的话,我只需要让左边的轮子不动或者向后转动,让右边的轮子转动起来就可以,简单概括就是右边的轮子要比左边的轮子运动快就可以实现了,然后我的一个轮子是自由轮子,具体看图:
上面那个是自由轮子
主函数模块:
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "robot.h"
#include "Key.h"
#include "LED.h"
uint8_t i;
uint16_t flag_key=0;
uint8_t state;
void speed_con(int t){
if(state=='s'){makerobo_Spin_Left(t);}
else if(state=='f'){makerobo_run(t);}
else if(state=='t'){makerobo_Spin_Right(t);}
else if(state=='l'){makerobo_Left(t);}
else if(state=='p'){makerobo_brake();}
else if(state=='r'){makerobo_Right(t);}
}
int main(void)
{
int data;
LED_Init();
robot_Init(); // 机器人初始化
Key_Init(); // 按键初始化
uart2_init(9600);
while (1)
{
if(Key_GetNum() == 1)
{
flag_key=!flag_key;
}
if(flag_key==1){
if(USART_GetFlagStatus(USART3,USART_FLAG_RXNE)==1)
{
data=USART_ReceiveData(USART3);
switch(data){//检测运动状态按键是否按下
case 10: //case多少是根据我设计的那个app决定的所以前面的视频需要先看一下
makerobo_Spin_Left(100);
s9();
state='s';//state是记录车子当前运动的状态,方便后面我给他设置挡位时候,数码管可以显示出来
break;
case 11:
makerobo_run(100);
s9();
state='f';
break;
case 12:
makerobo_Spin_Right(100);
s9();
state='t';
break;
case 13:
makerobo_Left(100);
s9();
state='l';
break;
case 14:
makerobo_brake();
s9();
state='p';
break;
case 15:
makerobo_Right(100);
s9();
state='r';
break;
case 16:
makerobo_back(100);
s9();
state='b';
break;
}
if(data==1|data==2|data==3|data==4|data==5|data==6|data==7|data==8|data==9){ //检测挡位按键是否按下
speed_con(data*10);
if(data==1) s1(); //占空比10%,记为1档
if(data==2) s2();
if(data==3) s3();
if(data==4) s4();
if(data==5) s5();
if(data==6) s6();
if(data==7) s7();
if(data==8) sz8();
if(data==9) s9();
}
}
}
}
}
开发板原理图:
各位朋友,请给我点点免费的赞 谢谢支持啦
标签:Pin,TIM,void,引脚,蓝牙,数码管,InitStructure,stm32f103c8t6,GPIO From: https://blog.csdn.net/jdjeng/article/details/140913331