目录标题
- 控制流程
- 硬件设计
- 软件设计
- 工程目录:
- 实验效果:
- 参考资料
先导知识
- STM32入门笔记(02):AFIO复用端口与重映射 、NVIC中断优先级管理、外部中断、串口通信及串口实验(SPL库函数版)
控制流程
手机APP ——蓝牙通信——> 蓝牙TBO4模块 ——UART2串口通信 ——> MCU STM32F407
硬件设计
硬件准备:
- 1.STM32F407VET6
- 2.无线蓝牙串口透传BT04从机
BL(蓝牙) | MCU (F407) |
Rx | PD5 (USART2_TX) |
Tx | PD6 (USART2_RX) |
软件工具:
- 1.FlyMcu 程序串口烧录
- 2.XCOM V2.0 串口调试助手
- 3.蓝牙APP(用于测试遥控)
A | B | C | D | E | F | G | H |
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
前 | 右前 | 右 | 右后 | 后 | 左后 | 左 | 左前 |
软件设计
工程目录:
usartx.h文件
#ifndef __USRATX_H
#define __USRATX_H
#include "stdio.h"
#include "sys.h"
#include "system.h"
void uart2_init(u32 bound);
int USART2_IRQHandler(void);
void usart2_send(u8 data);
#endif
usartx.c文件
#include "usartx.h"
/**************************************************************************
函数功能:串口2初始化
入口参数:无
返回 值:无
**************************************************************************/
void uart2_init(u32 bound)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); //使能GPIO时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); //使能USART时钟
GPIO_PinAFConfig(GPIOD,GPIO_PinSource5,GPIO_AF_USART2);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource6 ,GPIO_AF_USART2);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF; //输出模式
GPIO_InitStructure.GPIO_OType=GPIO_OType_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //高速50MHZ
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOD, &GPIO_InitStructure); //初始化
//UsartNVIC配置
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
//抢占优先级
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;
//子优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
//IRQ通道使能
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
//根据指定的参数初始化VIC寄存器
NVIC_Init(&NVIC_InitStructure);
//初始化设置
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(USART2, &USART_InitStructure); //初始化串口2
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); //开启串口接受中断
USART_Cmd(USART2, ENABLE); //使能串口2
}
/**************************************************************************
函数功能:串口2接收中断
入口参数:无
返回 值:无
**************************************************************************/
int USART2_IRQHandler(void)
{
int Usart_Receive;
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //判断是否接收到数据
{
static u8 Flag_PID,i,j,Receive[50],Last_Usart_Receive;
static float Data;
Usart_Receive=USART2->DR; //读取数据
printf("Usart_Receive=%d \r\n",Usart_Receive);
if(Usart_Receive==0x41&&Last_Usart_Receive==0x41&&APP_ON_Flag==0)// 0x41:0100 0001
//开机10秒之后,按下APP的前进键进入APP控制模式
//APP控制标志位置1,其它标志位置0
PS2_ON_Flag=0,Remote_ON_Flag=0,APP_ON_Flag=1,CAN_ON_Flag=0,Usart_ON_Flag=0;
Last_Usart_Receive=Usart_Receive;
if(Usart_Receive==0x4B) //0x4B:0100 1011 -- 75
Turn_Flag=1; //进入APP转向控制界面
// printf("Turn_Flag=1 进入APP转向控制界面 \r\n");
else if(Usart_Receive==0x49||Usart_Receive==0x4A) //0x49:0100 1001 --73; 0x4A:0100 1010 --74
Turn_Flag=0; //进入APP方向控制界面
// printf("Turn_Flag=0 进入APP方向控制界面 \r\n");
//
if(Turn_Flag==0)
{
//APP摇杆控制界面命令
if(Usart_Receive>=0x41&&Usart_Receive<=0x48) // 0x41:0100 0001--65 ; 0x48:0100 1000 --72
{
Flag_Direction = Usart_Receive-0x40; // 例如:(0x42)为01000010 - (0x40)为01000000 = 0010 = 2,也就是66-64=2
}
else if(Usart_Receive<=8) // Usart_Receive为0(即0x00=0000 0000); 2(即0x02=0000 0010) …… 7(即0x07=0000 0111);8(即0x08=0000 1000) -- 0~8
{
Flag_Direction=Usart_Receive;//0、1、2、3、4、5、6、7、8 接收手机app端的方向控制指令
}
else Flag_Direction=0;
printf("进入APP方向控制界面 Flag_Direction=%d \r\n",Flag_Direction);
}
// 以下代码内容可选择性参考
else if(Turn_Flag==1)
{
//APP转向控制界面命令
if (Usart_Receive==0x43) Flag_Left=0,Flag_Right=1; //右自转
else if(Usart_Receive==0x47) Flag_Left=1,Flag_Right=0; //左自转
else Flag_Left=0,Flag_Right=0;
if (Usart_Receive==0x41||Usart_Receive==0x45) Flag_Direction=Usart_Receive-0x40;
else Flag_Direction=0;
}
if(Usart_Receive==0x58) RC_Velocity=RC_Velocity+100; //加速按键,+100mm/s
if(Usart_Receive==0x59) RC_Velocity=RC_Velocity-100; //减速按键,-100mm/s
//以下是与APP调试界面通讯
if(Usart_Receive==0x7B) Flag_PID=1; //APP参数指令起始位
if(Usart_Receive==0x7D) Flag_PID=2; //APP参数指令停止位
if(Flag_PID==1) //采集数据
{
Receive[i]=Usart_Receive;
i++;
}
if(Flag_PID==2) //分析数据
{
if(Receive[3]==0x50) PID_Send=1;
else if(Receive[1]!=0x23)
{
for(j=i;j>=4;j--)
{
Data+=(Receive[j-1]-48)*pow(10,i-j);
}
switch(Receive[1])
{
case 0x30: RC_Velocity=Data;break;
case 0x31: Velocity_KP=Data;break;
case 0x32: Velocity_KI=Data;break;
case 0x33: break;
case 0x34: break;
case 0x35: break;
case 0x36: break;
case 0x37: break;
case 0x38: break;
}
}
//相关标志位清零
Flag_PID=0;
i=0;
j=0;
Data=0;
memset(Receive, 0, sizeof(u8)*50); //数组清零
}
if(RC_Velocity<0) RC_Velocity=0;
}
return 0;
}
/**************************************************************************
函数功能:串口2发送数据
入口参数:要发送的数据
返回 值:无
**************************************************************************/
void usart2_send(u8 data)
{
USART2->DR = data;
while((USART2->SR&0x40)==0);
}
system.h 文件
#ifndef __SYSTEM_H
#define __SYSTEM_H
#include "stm32f4xx.h"
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "usartx.h"
// extern 申明变量定义在别的文件中 system.c
//PS2手柄、蓝牙APP、航模手柄、CAN通信、串口1通信控制标志位。这5个标志位默认都为0
extern u8 PS2_ON_Flag, APP_ON_Flag, Remote_ON_Flag, CAN_ON_Flag, Usart_ON_Flag;
extern u8 Flag_Left, Flag_Right, Flag_Direction, Turn_Flag; //蓝牙遥控相关的标志位
extern u8 PID_Send; //向蓝牙APP发送参数的标志位
extern float RC_Velocity; //遥控小车的默认速度,单位:mm/s
extern float Move_X, Move_Y, Move_Z; //小车三轴目标运动速度,单位:m/s
extern float Velocity_KP,Velocity_KI;//速度控制PID参数
extern void systemInit(void);
//C库函数的相关头文件
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "stdarg.h"
#endif
system.c文件
#include "system.h"
u8 PS2_ON_Flag=0, APP_ON_Flag=0, Remote_ON_Flag=0, CAN_ON_Flag=0, Usart_ON_Flag=0; //PS2手柄、蓝牙APP、航模手柄、CAN通信、串口1通信控制标志位。这5个标志位默认都为0,代表串口3控制模式
u8 Flag_Left, Flag_Right, Flag_Direction=0, Turn_Flag; //蓝牙遥控相关的标志位
u8 PID_Send; //向蓝牙APP发送参数的标志位
float RC_Velocity=500; //遥控小车的默认速度,单位:mm/s
float Move_X, Move_Y, Move_Z; //小车三轴目标运动速度,单位:m/s
float Velocity_KP=700,Velocity_KI=700; //速度控制PID参数
void systemInit(void)
{
//延时函数初始化168MHz时钟
delay_init(168);
//初始化串口1 波特率设置为115200
uart_init(115200);
//串口2初始化,通信波特率9600,用于与蓝牙APP端通信
uart2_init(9600);
}
main.c文件
#include "system.h"
int main(void)
{
systemInit();//初始化
while(1){}
}
实验效果:
串口调试助手显示接收到的指令。
资料下载:
- STM32F407VET6+串口通信蓝牙+SPL固件库函数版(0402)