!!!鸣谢轩哥上课笔记!!!
一,USART基本原理
(1)基本概念
- UART 和 USART ?_uart同步模式 在什么场景下使用-CSDN博客
-
由于异步通信不需要时钟来进行数据同步,但是通信双方必须提前约定好字符格式与通信速率
-
字符格式:需要通信双方在协议层规定好传输的数据包(字符帧)的格式,字符帧由起始位、数据位、校验位、停止位组成。这样通信双方就可以利用起始位和停止位实现同步。
-
通信速率:如果设置好了通信的字符格式,还需要通信双方约定好通信速率,也就是单位时间内传输的有效二进制数的个数,所以也被称为波特率(bps baud pre second)。一般串口通信常用的波特率为9600bps、38400bps、57600bps、115200bps
问题一:数据包中一定要有起始位吗
答:是,在异步通信中,没有单独的时钟信号来同步发送器和接收器。起始位提供了一个信号,告诉接收器数据传输的开始,这样接收器就可以开始同步接收后续的数据位。
问题二:数据包中一定要有停止位吗
答:否,在USART通信时,数据包一般是需要停止位的,但是停止位并不是必须的。但是在大多数情况下,为了确保通信的稳定性和可靠性,推荐使用停止位。
问题三,数据包中一定要有校验位吗
答:否,是否使用校验位需要看具体要求;例如当噪声较大需要提高通信可靠性时通常就需要校验位,当考虑到额外开销或性能提升时,就可以不需要校验位
问题四,波特率9600是什么意思
答:即1s内传输9600个bit位
(2)USART的使用流程
- 打开KEIL5工程,然后把ST公司提供的标准外设库的关于USART的源文件添加到工程中
- 参考并分析ST公司提供的代码例程以及提供的关于USART源文件的开头注释,进行理解
二,MCU 和 计算机如何进行通信
(1)硬件接线原理
- 需要CH340芯片将USB通信协议转成TTL电平协议
- 当数据通过USB先到达CH340芯片进行转换,从TXD输出;当数据从MCU发送时通过RXD先会经过CH340进行转换,从USB输出出去
- 通过1-3, 2-4短接,使得MCU的发送端与计算机的接收端相接,MCU的接收端和计算机的发送端相接
(2)代码实现(一次中断只能接收和转发一个字节)
/*
*******************************************************************************
* @file main.c
* @author
* @version V1.0
* @date 2024/09/27
* @brief 主要学习MCU内部的UART串口外设的应用,串口属于异步通信,采用全双工的
通信模式,具有TX发送端和RX接收端
需要配置UART串口外设的波特率和字符帧格式(1bit停止位、8bit数据位)
如果MCU打算使用UART1和PC端通信 则需要把USART1的接口1-3短接 2-4短接
******************************************************************************
*/
#include "stm32f4xx.h" //必须包含
/* Private typedef 用于记录用户自定义的一些数据类型的别名-------------------*/
/* Private define 用于记录用户自定义的类型,比如结构体、共用体、枚举-------*/
/* Private macro 用于记录用户自定义的宏定义-------------------------------*/
/* Private variables 用于记录用户自定义的全局变量-----------------------------*/
/* Private function prototypes 用于记录用户自定义的函数声明-------------------*/
/* Private functions 用于记录用户自定义的函数原型-----------------------------*/
/**
* @brief 延时微秒
* @param
@nus :待延时的微秒 注意:不能超过798915us
* @retval None
*/
void delay_us(uint32_t nus)
{
SysTick->CTRL = 0; // 关闭定时器
SysTick->LOAD = nus * 21 - 1; // 设置重载值 nus * 21 - 1
SysTick->VAL = 0; // 清除当前值
SysTick->CTRL = 1; // 打开定时器并且使用参考时钟 168MHZ/8 = 21MHZ
while ((SysTick->CTRL & 0x00010000)==0);// 等待计数值递减到0
SysTick->CTRL = 0; // 关闭定时器
}
/**
* @brief 延时毫秒
* @param
@nms :待延时的毫秒
* @retval None
*/
void delay_ms(uint32_t nms)
{
while(nms--)
{
SysTick->CTRL = 0; // 关闭定时器
SysTick->LOAD = 21*1000 - 1; // 设置重载值 nus * 21 - 1
SysTick->VAL = 0; // 清除当前值
SysTick->CTRL = 1; // 打开定时器并且使用参考时钟 168MHZ/8 = 21MHZ
while ((SysTick->CTRL & 0x00010000)==0);// 等待计数值递减到0
SysTick->CTRL = 0; // 关闭定时器
}
}
/**
* @brief Configures the USART1 Peripheral.
* @param None
* @retval None
* @note USART1串口的IO口是PA9和PA10
*/
void USART1_Config(void)
{
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
//打开GPIOA的时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
//打开USART1的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
//选择GPIO引脚的复用功能
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9 , GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
//配置GPIO的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//配置UART1的参数 最常用的格式: 1bit停止位 8bit数据位 No校验位 9600bps
USART_InitStructure.USART_BaudRate = 9600; //波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位
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(USART1, &USART_InitStructure);
//配置USART的中断
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//选择UART1的中断源 接收到数据则触发中断请求
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
//打开USART1串口
USART_Cmd(USART1, ENABLE);
}
/**
* @brief 程序的入口
* @param None
* @retval None
*/
int main(void)
{
//硬件的初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置优先级分组 2bit抢占(0~3) 2bit响应(0~3)
USART1_Config();
while(1)
{
}
}
/**
* @brief This function handles USRAT1 interrupt request.
* @param None
* @retval None
*/
void USART1_IRQHandler(void)
{
uint8_t data = 0;
//判断是否接收到数据
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
//把串口收到的字节存储到变量data中
data = USART_ReceiveData(USART1);
USART_SendData(USART1,data); //把接收的数据转发给PC端
}
}
/********************** (C) COPYRIGHT Your Name [email protected]***END OF FILE****/
步骤总结:
- 打开GPIO时钟
- 打开串口时钟
- 配置IO口参数,设置IO口为复用模式
- 选择IO口的复用功能
- 配置串口参数(选择波特率,配置数据位、校验位、停止位的位数,关闭流控,打开全双工)
- 配置串口中断(选择中断通道,设置抢占优先级,设置响应优先级,打开中断通道)
- 选择串口的中断源(接收到数据则触发中断请求)
- 打开串口
- 编写串口中断服务函数
三,MCU 和 BLE 如何进行通信
(1)硬件接线原理
- 当MCU与BLE进行通信时,需要3-5,4-6短接,这样蓝牙和MCU就能相互传输数据
- 传感器的TX和RX需要与MCU的UART1的RX和TX进行交叉连接,就是说传感器TX需要连接在MCU的RX,传感器RX需要连接在MCU的TX
(2)BLE的基本概念
- 所用的BLE工作频率为2.4GHz
- 所用的BLE模式是从模式,即被动等待配对连接
(3)修改参数(具体看BLE数据手册)
想要使用手机连接蓝牙模块,则需要配置蓝牙模块的参数,对于蓝牙模块的参数,需要使用蓝牙模块的厂商提供的AT指令集实现。
(4.1)代码实现1(配置蓝牙信息)
/*
*******************************************************************************
* @file main.c
* @author
* @version V1.0
* @date 2024/09/29
* @brief 使用UART2来修改蓝牙模块的参数 蓝牙模块默认采用9600bps进行通信,UART2
采用的引脚是PA2和PA3
如果MCU打算使用UART1和PC端通信 则需要把USART1的接口1-3短接 2-4短接
如果MCU打算使用UART2和BLE端通信 则需要把USART2的接口1-3短接 2-4短接
******************************************************************************
*/
#include "stm32f4xx.h" //必须包含
/* Private typedef 用于记录用户自定义的一些数据类型的别名-------------------*/
/* Private define 用于记录用户自定义的类型,比如结构体、共用体、枚举-------*/
/* Private macro 用于记录用户自定义的宏定义-------------------------------*/
/* Private variables 用于记录用户自定义的全局变量-----------------------------*/
/* Private function prototypes 用于记录用户自定义的函数声明-------------------*/
/* Private functions 用于记录用户自定义的函数原型-----------------------------*/
/**
* @brief 延时微秒
* @param
@nus :待延时的微秒 注意:不能超过798915us
* @retval None
*/
void delay_us(uint32_t nus)
{
SysTick->CTRL = 0; // 关闭定时器
SysTick->LOAD = nus * 21 - 1; // 设置重载值 nus * 21 - 1
SysTick->VAL = 0; // 清除当前值
SysTick->CTRL = 1; // 打开定时器并且使用参考时钟 168MHZ/8 = 21MHZ
while ((SysTick->CTRL & 0x00010000)==0);// 等待计数值递减到0
SysTick->CTRL = 0; // 关闭定时器
}
/**
* @brief 延时毫秒
* @param
@nms :待延时的毫秒
* @retval None
*/
void delay_ms(uint32_t nms)
{
while(nms--)
{
SysTick->CTRL = 0; // 关闭定时器
SysTick->LOAD = 21*1000 - 1; // 设置重载值 nus * 21 - 1
SysTick->VAL = 0; // 清除当前值
SysTick->CTRL = 1; // 打开定时器并且使用参考时钟 168MHZ/8 = 21MHZ
while ((SysTick->CTRL & 0x00010000)==0);// 等待计数值递减到0
SysTick->CTRL = 0; // 关闭定时器
}
}
/**
* @brief Configures the USART1 Peripheral.
* @param None
* @retval None
* @note USART1串口的IO口是PA9和PA10
*/
void USART1_Config(u32 baud)
{
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
//打开GPIOA的时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
//打开USART1的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
//选择GPIO引脚的复用功能
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9 , GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
//配置GPIO的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//配置UART1的参数 最常用的格式: 1bit停止位 8bit数据位 No校验位 9600bps
USART_InitStructure.USART_BaudRate = baud; //波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位
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(USART1, &USART_InitStructure);
//配置USART的中断
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//选择UART1的中断源 接收到数据则触发中断请求
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
//打开USART1串口
USART_Cmd(USART1, ENABLE);
}
/**
* @brief Configures the USART2 Peripheral.
* @param None
* @retval None
* @note USART2串口的IO口是PA2和PA3
*/
void USART2_Config(u32 baud)
{
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
//打开GPIOA的时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
//打开USART2的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
//选择GPIO引脚的复用功能
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);
//配置GPIO的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//配置UART2的参数 最常用的格式: 1bit停止位 8bit数据位 No校验位 9600bps
USART_InitStructure.USART_BaudRate = baud; //波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位
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);
//配置USART的中断
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//选择UART2的中断源 接收到数据则触发中断请求
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
//打开USART2串口
USART_Cmd(USART2, ENABLE);
}
/**
* @brief UART2发送字符串
* @param
str :指的是待发送的字符串
* @retval None
*/
void UART2_SendString(char *str)
{
while(*str != '\0')
{
USART_SendData(USART2,*str++); //把字符串发给BLE
while( USART_GetFlagStatus(USART2,USART_FLAG_TXE) == RESET); //等待上一次字节发送完成
}
}
/**
* @brief 程序的入口
* @param None
* @retval None
*/
int main(void)
{
//硬件的初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置优先级分组 2bit抢占(0~3) 2bit响应(0~3)
USART1_Config(9600); // 和PC端通信
USART2_Config(9600); // 和BLE 通信
//给蓝牙模块发送测试指令 "AT\r\n"
UART2_SendString("AT\r\n");
//给蓝牙模块发送修改名称 "AT+NAMEGZ2404\r\n"
UART2_SendString("AT+NAMEGZ2404\r\n");
//给蓝牙模块发送重启指令
UART2_SendString("AT+RESET\r\n");
while(1)
{
}
}
/**
* @brief This function handles USRAT1 interrupt request.
* @param None
* @retval None
*/
void USART1_IRQHandler(void)
{
uint8_t data = 0;
//判断是否接收到数据
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
//把串口收到的字节存储到变量data中
data = USART_ReceiveData(USART1);
USART_SendData(USART1,data); //把接收的数据转发给PC端
}
}
/**
* @brief This function handles USRAT2 interrupt request.
* @param None
* @retval None
*/
void USART2_IRQHandler(void)
{
uint8_t data = 0;
//判断是否接收到数据
if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
{
//把串口收到的字节存储到变量data中
data = USART_ReceiveData(USART2);
USART_SendData(USART1,data); //把接收的数据转发给PC端
}
}
/********************** (C) COPYRIGHT Your Name [email protected]***END OF FILE****/
(4.2)代码实现2(实现手机发送字符串,通过蓝牙的透传模式,显示在显示屏)
???透传模式 ???
当手机连接了蓝牙后,蓝牙会进入透传模式(该模式下无法修改蓝牙参数),透传模式只能进行数据的转发
/*
*******************************************************************************
* @file main.c
* @author
* @version V1.0
* @date 2024/09/29
* @brief 使用UART2来修改蓝牙模块的参数 蓝牙模块默认采用9600bps进行通信,UART2
采用的引脚是PA2和PA3
如果MCU打算使用UART1和PC端通信 则需要把USART1的接口1-3短接 2-4短接
如果MCU打算使用UART2和BLE端通信 则需要把USART2的接口1-3短接 2-4短接
******************************************************************************
*/
#include "stm32f4xx.h" //必须包含
#include "string.h"
/* Private typedef 用于记录用户自定义的一些数据类型的别名-------------------*/
/* Private define 用于记录用户自定义的类型,比如结构体、共用体、枚举-------*/
/* Private macro 用于记录用户自定义的宏定义-------------------------------*/
/* Private variables 用于记录用户自定义的全局变量-----------------------------*/
uint8_t u2_rxbuf[512] = {0}; //作为UART2的接收缓冲区
uint32_t u2_rxcnt = 0; //作为UART2的接收计数器
/* Private function prototypes 用于记录用户自定义的函数声明-------------------*/
/* Private functions 用于记录用户自定义的函数原型-----------------------------*/
/**
* @brief 延时微秒
* @param
@nus :待延时的微秒 注意:不能超过798915us
* @retval None
*/
void delay_us(uint32_t nus)
{
SysTick->CTRL = 0; // 关闭定时器
SysTick->LOAD = nus * 21 - 1; // 设置重载值 nus * 21 - 1
SysTick->VAL = 0; // 清除当前值
SysTick->CTRL = 1; // 打开定时器并且使用参考时钟 168MHZ/8 = 21MHZ
while ((SysTick->CTRL & 0x00010000)==0);// 等待计数值递减到0
SysTick->CTRL = 0; // 关闭定时器
}
/**
* @brief 延时毫秒
* @param
@nms :待延时的毫秒
* @retval None
*/
void delay_ms(uint32_t nms)
{
while(nms--)
{
SysTick->CTRL = 0; // 关闭定时器
SysTick->LOAD = 21*1000 - 1; // 设置重载值 nus * 21 - 1
SysTick->VAL = 0; // 清除当前值
SysTick->CTRL = 1; // 打开定时器并且使用参考时钟 168MHZ/8 = 21MHZ
while ((SysTick->CTRL & 0x00010000)==0);// 等待计数值递减到0
SysTick->CTRL = 0; // 关闭定时器
}
}
/**
* @brief Configures the USART1 Peripheral.
* @param None
* @retval None
* @note USART1串口的IO口是PA9和PA10
*/
void USART1_Config(u32 baud)
{
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
//打开GPIOA的时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
//打开USART1的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
//选择GPIO引脚的复用功能
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9 , GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
//配置GPIO的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//配置UART1的参数 最常用的格式: 1bit停止位 8bit数据位 No校验位 9600bps
USART_InitStructure.USART_BaudRate = baud; //波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位
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(USART1, &USART_InitStructure);
//配置USART的中断
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//选择UART1的中断源 接收到数据则触发中断请求
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
//打开USART1串口
USART_Cmd(USART1, ENABLE);
}
/**
* @brief Configures the USART2 Peripheral.
* @param None
* @retval None
* @note USART2串口的IO口是PA2和PA3
*/
void USART2_Config(u32 baud)
{
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
//打开GPIOA的时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
//打开USART2的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
//选择GPIO引脚的复用功能
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);
//配置GPIO的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//配置UART2的参数 最常用的格式: 1bit停止位 8bit数据位 No校验位 9600bps
USART_InitStructure.USART_BaudRate = baud; //波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位
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);
//配置USART的中断
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//选择UART2的中断源 接收到数据则触发中断请求
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
//打开USART2串口
USART_Cmd(USART2, ENABLE);
}
/**
* @brief UART2发送字符串
* @param
str :指的是待发送的字符串
* @retval None
*/
void UART2_SendString(char *str)
{
while(*str != '\0')
{
USART_SendData(USART2,*str++); //把字符串发给BLE
while( USART_GetFlagStatus(USART2,USART_FLAG_TXE) == RESET); //等待上一次字节发送完成
}
}
/**
* @brief LED的初始化
* @param None
* @retval None
*/
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//打开外设的时钟 LED --- PF9
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
//配置引脚的参数
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
//初始化GPIO端口
GPIO_Init(GPIOF, &GPIO_InitStructure);
GPIO_SetBits(GPIOF,GPIO_Pin_9); //输出高电平
}
void SG90_PWMConfig(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
//打开外设的时钟 PC6
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
//打开定时器的时钟 TIM3_CH1
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
//配置引脚的参数
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
GPIO_Init(GPIOC, &GPIO_InitStructure);
//需要选择GPIO引脚要复用的功能
GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_TIM3);
//配置定时器的时基 舵机就要20ms的时基
TIM_TimeBaseStructure.TIM_Prescaler = 840-1; // 84MHZ / 840 = 100000HZ --> 10us计数1次
TIM_TimeBaseStructure.TIM_Period = 2000-1; // 20ms * 1000 / 10us = 2000次
TIM_TimeBaseStructure.TIM_ClockDivision = 0; // 不分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM3选择递增计数
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
//配置定时器的通道
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //PWM模式1 CNT < CCR 通道有效
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //开启输出比较
TIM_OCInitStructure.TIM_Pulse = 50; //比较值的初值 CCR寄存器的初值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性为高电平 高电平有效
TIM_OC1Init(TIM3, &TIM_OCInitStructure); //对TIM14的CH1进行初始化
//使能预装载寄存器
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
//使能自动重装载
TIM_ARRPreloadConfig(TIM3, ENABLE);
//打开定时器
TIM_Cmd(TIM3, ENABLE);
}
/**
* @brief 程序的入口
* @param None
* @retval None
*/
int main(void)
{
//硬件的初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置优先级分组 2bit抢占(0~3) 2bit响应(0~3)
USART1_Config(9600); // 和PC端通信
USART2_Config(9600); // 和BLE 通信
LED_Init();
SG90_PWMConfig();
//给蓝牙模块发送测试指令 "AT\r\n"
//UART2_SendString("AT\r\n");
//给蓝牙模块发送修改名称 "AT+NAMEGZ2404\r\n"
//UART2_SendString("AT+NAMEGZ2404\r\n");
//给蓝牙模块发送重启指令
//UART2_SendString("AT+RESET\r\n");
while(1)
{
//判断UART2是否接收到数据 假设接收到 "led_on",则让LED点亮
if( u2_rxcnt > 0 && strstr((char *)u2_rxbuf,"led_on"))
{
GPIO_ResetBits(GPIOF,GPIO_Pin_9); //输出低电平
u2_rxcnt = 0; //计数器复位
memset((char *)u2_rxbuf,0,512); //清空数组
}
//判断UART2是否接收到数据 假设接收到 "led_off",则让LED熄灭
if( u2_rxcnt > 0 && strstr((char *)u2_rxbuf,"led_off"))
{
GPIO_SetBits(GPIOF,GPIO_Pin_9); //输出高电平
u2_rxcnt = 0; //计数器复位
memset((char *)u2_rxbuf,0,512); //清空数组
}
if( u2_rxcnt > 0 && strstr((char *)u2_rxbuf,"begin"))
{
//指定动作:0 - 180
for(int i = 50; i < 250 ; i++)
{
TIM_SetCompare1(TIM3,i);
delay_ms(1);
}
u2_rxcnt = 0; //计数器复位
memset((char *)u2_rxbuf,0,512); //清空数组
}
if( u2_rxcnt > 0 && strstr((char *)u2_rxbuf,"stop"))
{
//指定动作: 180 - 0
for(int i = 250; i >= 50; i--)
{
TIM_SetCompare1(TIM3,i);
delay_ms(1);
}
u2_rxcnt = 0; //计数器复位
memset((char *)u2_rxbuf,0,512); //清空数组
}
}
}
/**
* @brief This function handles USRAT1 interrupt request.
* @param None
* @retval None
*/
void USART1_IRQHandler(void)
{
uint8_t data = 0;
//判断是否接收到数据
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
//把串口收到的字节存储到变量data中
data = USART_ReceiveData(USART1);
USART_SendData(USART1,data); //把接收的数据转发给PC端
}
}
/**
* @brief This function handles USRAT2 interrupt request.
* @param None
* @retval None
*/
void USART2_IRQHandler(void)
{
//判断是否接收到数据
if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
{
//把串口收到的字节存储到变量data中
u2_rxbuf[u2_rxcnt++] = USART_ReceiveData(USART2);
if( u2_rxcnt >= 512 )
{
u2_rxcnt = 0;
}
USART_SendData(USART1,u2_rxbuf[u2_rxcnt-1]); //把接收的数据转发给PC端
}
}
/********************** (C) COPYRIGHT Your Name [email protected]***END OF FILE****/
核心代码:
定义一个全局数组用于保存串口中断接收的数据,通过strstr函数来比较约定好的字符串,实现手机蓝牙控制外设的功能
//判断UART2是否接收到数据 假设接收到 "led_on",则让LED点亮
if( u2_rxcnt > 0 && strstr((char *)u2_rxbuf,"led_on"))
{
GPIO_ResetBits(GPIOF,GPIO_Pin_9); //输出低电平
u2_rxcnt = 0; //计数器复位
memset((char *)u2_rxbuf,0,512); //清空数组
}
/**
* @brief 串口中断服务函数,用于接收来自蓝牙的数据,保存并转发到显示屏上
* @param None
* @retval None
*/
void USART2_IRQHandler(void)
{
//判断是否接收到数据
if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
{
//把串口收到的字节存储到变量data中
u2_rxbuf[u2_rxcnt++] = USART_ReceiveData(USART2);
if( u2_rxcnt >= 512 )
{
u2_rxcnt = 0;
}
USART_SendData(USART1,u2_rxbuf[u2_rxcnt-1]); //把接收的数据转发给PC端
}
}
总结:
- 打开串口、GPIO时钟
- 配置IO引脚为复用模式
- 配置串口参数(配置波特率,配置格式,关闭流控,打开全双工)
- 配置串口中断(配置中断通道,配置抢占优先级,配置响应优先级)
- 选择串口中断源
- 编写串口中断服务函数
- 当蓝牙往MCU发送数据时,会触发串口中断服务函数
- 当MCU向蓝牙发送数据时,不会触发串口中断服务函数
四,MCU 和 ESP8266 如何进行通信
(1)基本概念
- STA :让WIFI连接路由器,实现外网通信
- AP :让WIFI作为路由器,实现组网通信
- STA + AP :WIFI既可以作为路由器实现组网通信;也可以连接路由器,实现外网通信
(2)代码实现(实现联网功能)
/*
*******************************************************************************
* @file main.c
* @author
* @version V1.0
* @date 2024/09/29
* @brief 使用UART3来修改WIFI模块的参数,模块默认采用115200bps进行通信,UART3
采用的引脚是PB10和PB11
如果MCU打算使用UART1和PC端通信 则需要把USART1的接口1-3短接 2-4短接
如果MCU打算使用UART2和BLE端通信 则需要把USART2的接口1-3短接 2-4短接
如果MCU打算使用UART3和WIFI通信 则需要把USART3的接口1-3短接 2-4短接
******************************************************************************
*/
#include "stm32f4xx.h" //必须包含
#include "string.h"
/* Private typedef 用于记录用户自定义的一些数据类型的别名-------------------*/
/* Private define 用于记录用户自定义的类型,比如结构体、共用体、枚举-------*/
/* Private macro 用于记录用户自定义的宏定义-------------------------------*/
/* Private variables 用于记录用户自定义的全局变量-----------------------------*/
uint8_t u3_rxbuf[512] = {0}; //作为UART3的接收缓冲区
uint32_t u3_rxcnt = 0; //作为UART3的接收计数器
/* Private function prototypes 用于记录用户自定义的函数声明-------------------*/
/* Private functions 用于记录用户自定义的函数原型-----------------------------*/
/**
* @brief 延时微秒
* @param
@nus :待延时的微秒 注意:不能超过798915us
* @retval None
*/
void delay_us(uint32_t nus)
{
SysTick->CTRL = 0; // 关闭定时器
SysTick->LOAD = nus * 21 - 1; // 设置重载值 nus * 21 - 1
SysTick->VAL = 0; // 清除当前值
SysTick->CTRL = 1; // 打开定时器并且使用参考时钟 168MHZ/8 = 21MHZ
while ((SysTick->CTRL & 0x00010000)==0);// 等待计数值递减到0
SysTick->CTRL = 0; // 关闭定时器
}
/**
* @brief 延时毫秒
* @param
@nms :待延时的毫秒
* @retval None
*/
void delay_ms(uint32_t nms)
{
while(nms--)
{
SysTick->CTRL = 0; // 关闭定时器
SysTick->LOAD = 21*1000 - 1; // 设置重载值 nus * 21 - 1
SysTick->VAL = 0; // 清除当前值
SysTick->CTRL = 1; // 打开定时器并且使用参考时钟 168MHZ/8 = 21MHZ
while ((SysTick->CTRL & 0x00010000)==0);// 等待计数值递减到0
SysTick->CTRL = 0; // 关闭定时器
}
}
/**
* @brief Configures the USART1 Peripheral.
* @param None
* @retval None
* @note USART1串口的IO口是PA9和PA10
*/
void USART1_Config(u32 baud)
{
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
//打开GPIOA的时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
//打开USART1的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
//选择GPIO引脚的复用功能
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9 , GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
//配置GPIO的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//配置UART1的参数 最常用的格式: 1bit停止位 8bit数据位 No校验位 9600bps
USART_InitStructure.USART_BaudRate = baud; //波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位
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(USART1, &USART_InitStructure);
//配置USART的中断
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//选择UART1的中断源 接收到数据则触发中断请求
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
//打开USART1串口
USART_Cmd(USART1, ENABLE);
}
/**
* @brief Configures the USART2 Peripheral.
* @param None
* @retval None
* @note USART2串口的IO口是PA2和PA3
*/
void USART2_Config(u32 baud)
{
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
//打开GPIOA的时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
//打开USART2的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
//选择GPIO引脚的复用功能
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);
//配置GPIO的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//配置UART2的参数 最常用的格式: 1bit停止位 8bit数据位 No校验位 9600bps
USART_InitStructure.USART_BaudRate = baud; //波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位
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);
//配置USART的中断
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//选择UART2的中断源 接收到数据则触发中断请求
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
//打开USART2串口
USART_Cmd(USART2, ENABLE);
}
/**
* @brief Configures the USART3 Peripheral.
* @param None
* @retval None
* @note USART3串口的IO口是PB10和PB11
*/
void USART3_Config(u32 baud)
{
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
//打开GPIOB的时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
//打开USART3的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
//选择GPIO引脚的复用功能
GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_USART3);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_USART3);
//配置GPIO的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//配置UART3的参数 最常用的格式: 1bit停止位 8bit数据位 No校验位 9600bps
USART_InitStructure.USART_BaudRate = baud; //波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位
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);
//配置USART的中断
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//选择UART3的中断源 接收到数据则触发中断请求
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
//打开USART3串口
USART_Cmd(USART3, ENABLE);
}
/**
* @brief UART1发送字符串
* @param
str :指的是待发送的字符串
* @retval None
*/
void UART1_SendString(char *str)
{
while(*str != '\0')
{
USART_SendData(USART1,*str++); //把字符串发给BLE
while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET); //等待上一次字节发送完成
}
}
/**
* @brief UART2发送字符串
* @param
str :指的是待发送的字符串
* @retval None
*/
void UART2_SendString(char *str)
{
while(*str != '\0')
{
USART_SendData(USART2,*str++); //把字符串发给BLE
while( USART_GetFlagStatus(USART2,USART_FLAG_TXE) == RESET); //等待上一次字节发送完成
}
}
/**
* @brief UART3发送字符串
* @param
str :指的是待发送的字符串
* @retval None
*/
void UART3_SendString(char *str)
{
while(*str != '\0')
{
USART_SendData(USART3,*str++); //把字符串发给WIFI
while( USART_GetFlagStatus(USART3,USART_FLAG_TXE) == RESET); //等待上一次字节发送完成
}
}
/**
* @brief 程序的入口
* @param None
* @retval None
*/
int main(void)
{
//硬件的初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置优先级分组 2bit抢占(0~3) 2bit响应(0~3)
USART1_Config(9600); // 和PC端通信
USART2_Config(9600); // 和BLE 通信
USART3_Config(115200); // 和WIFI通信
//向WIFI模块发送测试指令 "AT\r\n"
UART3_SendString("AT\r\n");
delay_ms(500);
UART1_SendString((char *)u3_rxbuf); //输出内容
memset((char *)u3_rxbuf,0,512); //清空数组
u3_rxcnt = 0; //下标归零
//向WIFI模块发送设置模式指令 "AT+CWMODE_DEF=3\r\n"
UART3_SendString("AT+CWMODE_DEF=3\r\n");
delay_ms(500);
UART1_SendString((char *)u3_rxbuf); //输出内容
memset((char *)u3_rxbuf,0,512); //清空数组
u3_rxcnt = 0; //下标归零
//向WIFI模块发送连接热点指令 "AT+CWJAP_DEF=\" \",\" \"\r\n"
UART3_SendString("AT+CWJAP_DEF=\"gz2404\",\"12345678\"\r\n");
delay_ms(7000);
UART1_SendString((char *)u3_rxbuf); //输出内容
memset((char *)u3_rxbuf,0,512); //清空数组
u3_rxcnt = 0; //下标归零
//向WIFI模块发送建立TCP连接指令 "AT+CIPSTART=\"TCP\",\"www.baidu.com\",80\r\n"
UART3_SendString("AT+CIPSTART=\"TCP\",\"www.baidu.com\",80\r\n");
delay_ms(5000);
UART1_SendString((char *)u3_rxbuf); //输出内容
memset((char *)u3_rxbuf,0,512); //清空数组
u3_rxcnt = 0; //下标归零
//向WIFI模块发送设置透传指令 "AT+CIPMODE=1\r\n"
UART3_SendString("AT+CIPMODE=1\r\n");
delay_ms(1000);
UART1_SendString((char *)u3_rxbuf); //输出内容
memset((char *)u3_rxbuf,0,512); //清空数组
u3_rxcnt = 0;
//向WIFI模块发送设置透传指令 "AT+CIPSEND\r\n"
UART3_SendString("AT+CIPSEND\r\n");
delay_ms(5000);
UART1_SendString((char *)u3_rxbuf); //输出内容
memset((char *)u3_rxbuf,0,512); //清空数组
u3_rxcnt = 0;
while(1)
{
}
}
/**
* @brief This function handles USRAT1 interrupt request.
* @param None
* @retval None
*/
void USART1_IRQHandler(void)
{
uint8_t data = 0;
//判断是否接收到数据
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
//把串口收到的字节存储到变量data中
data = USART_ReceiveData(USART1);
USART_SendData(USART1,data); //把接收的数据转发给PC端
}
}
/**
* @brief This function handles USRAT2 interrupt request.
* @param None
* @retval None
*/
void USART2_IRQHandler(void)
{
uint8_t data = 0;
//判断是否接收到数据
if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
{
//把串口收到的字节存储到变量data中
data = USART_ReceiveData(USART2);
USART_SendData(USART1,data); //把接收的数据转发给PC端
}
}
/**
* @brief This function handles USRAT3 interrupt request.
* @param None
* @retval None
*/
void USART3_IRQHandler(void)
{
//判断是否接收到数据
if (USART_GetITStatus(USART3, USART_IT_RXNE) == SET)
{
//把串口收到的字节存储到缓冲区中
u3_rxbuf[u3_rxcnt++] = USART_ReceiveData(USART3);
}
}
/********************** (C) COPYRIGHT Your Name [email protected]***END OF FILE****/
核心代码:
发送AT指令联网时需要进行延时等待,提高代码健壮性
/**
* @brief UART3发送字符串
* @param
str :指的是待发送的字符串
* @retval None
*/
void UART3_SendString(char *str)
{
while(*str != '\0')
{
USART_SendData(USART3,*str++); //把字符串发给WIFI
while( USART_GetFlagStatus(USART3,USART_FLAG_TXE) == RESET); //等待上一次字节发送完成
}
}
/**
* @brief 程序的入口
* @param None
* @retval None
*/
int main(void)
{
//硬件的初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置优先级分组 2bit抢占(0~3) 2bit响应(0~3)
USART1_Config(9600); // 和PC端通信
USART2_Config(9600); // 和BLE 通信
USART3_Config(115200); // 和WIFI通信
//向WIFI模块发送测试指令 "AT\r\n"
UART3_SendString("AT\r\n");
delay_ms(500);
UART1_SendString((char *)u3_rxbuf); //输出内容
memset((char *)u3_rxbuf,0,512); //清空数组
u3_rxcnt = 0; //下标归零
//向WIFI模块发送设置模式指令 "AT+CWMODE_DEF=3\r\n"
UART3_SendString("AT+CWMODE_DEF=3\r\n");
delay_ms(500);
UART1_SendString((char *)u3_rxbuf); //输出内容
memset((char *)u3_rxbuf,0,512); //清空数组
u3_rxcnt = 0; //下标归零
//向WIFI模块发送连接热点指令 "AT+CWJAP_DEF=\" \",\" \"\r\n"
UART3_SendString("AT+CWJAP_DEF=\"gz2404\",\"12345678\"\r\n");
delay_ms(7000);
UART1_SendString((char *)u3_rxbuf); //输出内容
memset((char *)u3_rxbuf,0,512); //清空数组
u3_rxcnt = 0; //下标归零
//向WIFI模块发送建立TCP连接指令 "AT+CIPSTART=\"TCP\",\"www.baidu.com\",80\r\n"
UART3_SendString("AT+CIPSTART=\"TCP\",\"www.baidu.com\",80\r\n");
delay_ms(5000);
UART1_SendString((char *)u3_rxbuf); //输出内容
memset((char *)u3_rxbuf,0,512); //清空数组
u3_rxcnt = 0; //下标归零
//向WIFI模块发送设置透传指令 "AT+CIPMODE=1\r\n"
UART3_SendString("AT+CIPMODE=1\r\n");
delay_ms(1000);
UART1_SendString((char *)u3_rxbuf); //输出内容
memset((char *)u3_rxbuf,0,512); //清空数组
u3_rxcnt = 0;
//向WIFI模块发送设置透传指令 "AT+CIPSEND\r\n"
UART3_SendString("AT+CIPSEND\r\n");
delay_ms(5000);
UART1_SendString((char *)u3_rxbuf); //输出内容
memset((char *)u3_rxbuf,0,512); //清空数组
u3_rxcnt = 0;
while(1)
{
}
}
/**
* @brief This function handles USRAT3 interrupt request.
* @param None
* @retval None
*/
void USART3_IRQHandler(void)
{
//判断是否接收到数据
if (USART_GetITStatus(USART3, USART_IT_RXNE) == SET)
{
//把串口收到的字节存储到缓冲区中
u3_rxbuf[u3_rxcnt++] = USART_ReceiveData(USART3);
}
}