STM32F407——串口通信
前言
本文将对串口通信的分类和基于 stm32 的串口配置进行介绍,以及如何使用串口调试助手进行串口收发功能的调试,旨在帮助还不会使用 stm32 单片机串口资源进行通信的家人们快速学会如何使用串口来进行通信。 (纯干货、快速上手、零基础也能会!!!)
一、串口通信的概念及分类
1、串口及串口通信概念
(1)串口,即串行接口,是一种可以将接收来自CPU的并行数据字符转换为连续的串行数据流发送出去,同时可将接收的串行数据流转换为并行的数据字符供给CPU的器件。
(2)串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。它很简单并且能够实现远距离通信。
2、串口分类
常用的有串口有三种: (1)RS232标准的串口 这一类的串口采用的是 RS232 电平标准,其中高电平为 +15V ,低电平为 -15V ,这类串口抗干扰性强,但是对我这种平平无奇大学生来说用不上。就是下面这玩意:
(2)USB转串口 这类串口十分常用,主要用来调试串口(下面会将如何用)。在 STM32F407 中也有一个 USB 串口,如下图所示: 板载 CH340 USB 转 TTL 芯片,可以说是个串口调试的工具。 (3)原生的串口 这一类主要用于控制器跟串口的设备或者传感器通信,不需要经过电平转换芯片来转换电平,直接就用 TTL 电平(高电平 3.3V 或 5V,低电平 0V)通信。大家平常用的蓝牙、传感器等很多都是采用这个。
二、串口配置与调试
1、配置步骤
以 STM32F407 的串口3为例,跟大家讲下如何配置一个串口,使其能进行数据收发。 (1)串口初始化 在这一步中,需要: ① 对该串口使用到的 IO 口进行初始化和使能相应的时钟树,并对端口进行复用映射; ② 中断配置 (主要是一个优先级); ③ 串口初始化配置(奇偶校验、收发配置等); ④ 串口使能; 按上述步骤编写函数,代码如下:
void USART3_Init(u32 bound)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource10,GPIO_AF_USART3);
GPIO_PinAFConfig(GPIOB,GPIO_PinSource11,GPIO_AF_USART3);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOB,&GPIO_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_InitStructure.USART_BaudRate = bound;
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_ITConfig(USART3, USART_IT_RXNE, ENABLE);
USART_Cmd(USART3, ENABLE);
TIM7_Int_Init(100-1,8400-1);
USART3_RX_STA=0;
TIM_Cmd(TIM7,DISABLE);
}
(2)编写发送与接收函数 这个其实不用编写,库里就有了,接收与发送分别是:
uint16_t USART_ReceiveData(USART_TypeDef* USARTx)
{
assert_param(IS_USART_ALL_PERIPH(USARTx));
return (uint16_t)(USARTx->DR & (uint16_t)0x01FF);
}
void USART_SendData(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);
}
这个大家知道一下这两个的功能和如何调用函数即可。如果要接收串口3的信息,这样调用:Receive = USART_ReceiveData(USART3);如果要通过串口3发送消息,则:USART_SendData(USART3,data)。等下在中断函数和串口打印函数中会用到。 (3)编写中断服务函数
void USART3_IRQHandler(void)
{
#if SYSTEM_SUPPORT_OS
OSIntEnter();
#endif
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
{
Res =USART_ReceiveData(USART3);
if((USART3_RX_STA&0x8000)==0)
{
if(USART3_RX_STA&0x4000)
{
if(Res!=0x0a)USART3_RX_STA=0;
else USART3_RX_STA|=0x8000;
}
else
{
if(Res==0x0d)USART3_RX_STA|=0x4000;
else
{
USART3_RX_BUF[USART3_RX_STA&0X3FFF]=Res ;
USART3_RX_STA++;
if(USART3_RX_STA>(USART3_MAX_RECV_LEN-1))USART3_RX_STA=0;
}
}
}
}
}
中断函数是在发生中断时间后,主程序自动进入中断函数运行,运行结束后在退出中断函数,返回到进入中断函数之前的运行状态。我愿把他成为一个时光静止器,执行到这个函数时,外界暂停,此刻整个世界只有自己,我们可以利用这段时间尽情地做我们想做的事,对我们所接收的信息进行分析处理等等。 (4)编写串口打印函数 这一函数与 C 语言中的 printf 其实是类似的,可将接收到的信息打印到电脑上,主要用于调试,函数如下:
void u3_printf(char* fmt,...)
{
u16 i,j;
va_list ap;
va_start(ap,fmt);
vsprintf((char*)USART3_TX_BUF,fmt,ap);
va_end(ap);
i=strlen((const char*)USART3_TX_BUF);
for(j=0;j<i;j++)
{
while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==RESET);
USART_SendData(USART3,USART3_TX_BUF[j]);
}
}
完成这几步后,一个串口就算配置好了,那如何检测配好的串口是否能进行正常的信息收发呢?请继续往下看。
2、串口收发功能测试
要测试的话,咱们需要自费5块钱左右买来一个 USB 转 TTL 模块(我20岁,现在能全款买下一个 USB 转 TTL 模块,大家应该也可以)。然后按照模块 5V 端口接单片机 5V 电源,模块 GND 端口接单片机 GND,模块 TX 端口接单片机 RX 端,模块 RX 端口接单片机 TX 端(发接收,收接发,不能接错,否则通信不起来)这样的连接方式将该模块连接到单片机上串口用到的引脚,然后插入电脑,打开串口调试助手(个人推荐正点原子的 XCOM),打开后的界面如下所示: 接下来,我们要在串口选择栏选择对应串口,设置对应波特率,如果你在配置的时候设置的是115200,那这里就选择115200,一定不能出错,否则会造成输出乱码或者无法输出。然后奇偶校验这些咱们就按默认来,不需要设置,因为在配置中也没设置奇偶校验,然后点击打开串口,此时该栏的黑点会变成红点。如图所示: 之后我们就可以进行收发测试了,收发测试需要在中断函数或者主函数中加上这一行代码:
u3_printf("收到的消息:%c/r/n",Res);
我们发个字符 ‘1’ 试试: 发 ‘1’ 收 ‘1’ ,说明我们串口收发没问题,这样我们就可以放心大胆地在接收中断中做文章了。 如果要改成串口4的话,只需要改个引脚,把 3 改成 4 就行了。移植代码如下:
#include "uart4.h"
#include "delay.h"
#include "stdarg.h"
#include "stdio.h"
#include "string.h"
u8 UART4_RX_BUF[UART4_MAX_RECV_LEN];
u8 UART4_TX_BUF[UART4_MAX_SEND_LEN];
vu16 UART4_RX_STA=0;
void uart4_init(u32 bound){
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4,ENABLE);
GPIO_PinAFConfig(GPIOC,GPIO_PinSource11,GPIO_AF_UART4);
GPIO_PinAFConfig(GPIOC,GPIO_PinSource10,GPIO_AF_UART4);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOC,&GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = bound;
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(UART4, &USART_InitStructure);
USART_Cmd(UART4, ENABLE);
USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void UART4_IRQHandler(void)
{
u8 Res;
if(USART_GetITStatus(UART4, USART_IT_RXNE) != RESET)
{
Res =USART_ReceiveData(UART4);
if((UART4_RX_STA&0x8000)==0)
{
if(UART4_RX_STA&0x4000)
{
if(Res!=0x0a)UART4_RX_STA=0;
else UART4_RX_STA|=0x8000;
}
else
{
if(Res==0x0d)UART4_RX_STA|=0x4000;
else
{
UART4_RX_BUF[UART4_RX_STA&0X3FFF]=Res ;
UART4_RX_STA++;
if(UART4_RX_STA>(UART4_MAX_RECV_LEN-1))UART4_RX_STA=0;
}
}
}
}
}
void u4_printf(char* fmt,...)
{
u16 i,j;
va_list ap;
va_start(ap,fmt);
vsprintf((char*)UART4_TX_BUF,fmt,ap);
va_end(ap);
i=strlen((const char*)UART4_TX_BUF);
for(j=0;j<i;j++)
{
while(USART_GetFlagStatus(UART4,USART_FLAG_TC)==RESET);
USART_SendData(UART4,(uint8_t)UART4_TX_BUF[j]);
}
}
结语
本文主要讲了串口的配置步骤和注意事项以及串口的调试。 关于 STM32F407 的串口串口通信我就讲这么多,个人认为纯干货,拿来开发(不是很难的)也够用了。一样的,欢迎各位批评指正,联系微信:Cyy15880234628
|