串口通讯介绍
串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此大部分电子设备都支持该通讯方式, 电子工程师在调试设备时也经常使用该通讯方式输出调试信息。
在计算机科学里,大部分复杂的问题都可以通过分层来简化。如芯片被分为内核层和片上外设;STM32标准库则是在寄存器与用户代码之间的软件层。 对于通讯协议,我们也以分层的方式来理解,最基本的是把它分为物理层和协议层。物理层规定通讯系统中具有机械、电子功能部分的特性, 确保原始数据在物理媒体的传输。协议层主要规定通讯逻辑,统一收发双方的数据打包、解包标准。 简单来说物理层规定我们用嘴巴还是用肢体来交流,协议层则规定我们用中文还是英文来交流。
我们知道常见的电子电路中常使用TTL的电平标准,理想状态下,使用5V表示二进制逻辑1,使用0V表示逻辑0; 而为了增加串口通讯的远距离传输及抗干扰能力,它使用-15V表示逻辑1,+15V表示逻辑0。 使用RS232与TTL电平校准表示同一个信号时的对比。
GPIO和USART宏定义
/**
* 串口宏定义,不同的串口挂载的总线和IO不一样,移植时需要修改这几个宏
*/
// 串口1-USART1
#define DEBUG_USARTx USART1
#define DEBUG_USART_CLK RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOA
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9
#define DEBUG_USART_RX_GPIO_PORT GPIOA
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10
#define DEBUG_USART_IRQ USART1_IRQn
#define DEBUG_USART_IRQHandler USART1_IRQHandler
嵌套向量中断控制器NVIC配置
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 嵌套向量中断控制器组选择 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* 配置USART为中断源 */
NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
/* 抢断优先级为1 */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* 子优先级为1 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/* 使能中断 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
/* 初始化配置NVIC */
NVIC_Init(&NVIC_InitStructure);
}
USART初始化配置
void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// 打开串口GPIO的时钟
DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
// 打开串口外设的时钟
DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
// 将USART Tx的GPIO配置为推挽复用模式
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
// 将USART Rx的GPIO配置为浮空输入模式
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
// 配置串口的工作参数
// 配置波特率
USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
// 配置 针数据字长
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(DEBUG_USARTx, &USART_InitStructure);
// 串口中断优先级配置
NVIC_Configuration();
// 使能串口接收中断
USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);
// 使能串口
USART_Cmd(DEBUG_USARTx, ENABLE);
}
字符发送
/***************** 发送一个字符 **********************/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
/* 发送一个字节数据到USART */
USART_SendData(pUSARTx,ch);
/* 等待发送数据寄存器为空 */
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
/***************** 发送字符串 **********************/
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
unsigned int k=0;
do {
Usart_SendByte( pUSARTx, *(str + k) );
k++;
} while (*(str + k)!='\0');
/* 等待发送完成 */
while (USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET) {
}
}
USART中断服务函数
void DEBUG_USART_IRQHandler(void)
{
uint8_t ucTemp;
if (USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET) {
ucTemp = USART_ReceiveData( DEBUG_USARTx );
USART_SendData(DEBUG_USARTx,ucTemp);
}
}
函数介绍
1.bsp_usartx.c
/* 包含头文件 ----------------------------------------------------------------*/
#include "bsp/usart/bsp_usartx.h"
/**
* 函数功能: 配置NVIC,设定USART接收中断优先级.
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 嵌套向量中断控制器组选择 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
/* 配置USART为中断源 */
NVIC_InitStructure.NVIC_IRQChannel = USARTx_IRQn;
/* 抢断优先级为0 */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
/* 子优先级为1 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/* 使能中断 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
/* 初始化配置NVIC */
NVIC_Init(&NVIC_InitStructure);
}
/**
* 函数功能: 串口参数配置.
*/
void USARTx_Init(void)
{
/* 定义IO硬件初始化结构体变量 */
GPIO_InitTypeDef GPIO_InitStructure;
/* 定义USART初始化结构体变量 */
USART_InitTypeDef USART_InitStructure;
/* 配置NVIC,设定USART接收中断优先级 */
NVIC_Configuration();
/* 使能USART时钟 */
USARTx_ClockCmd(USARTx_CLK,ENABLE);
/* 使能USART功能GPIO时钟 */
USARTx_GPIO_ClockCmd(USARTx_TX_CLK | USARTx_RX_CLK | RCC_APB2Periph_AFIO,ENABLE);
/* 调试USART功能GPIO初始化 */
/* 设定USART发送对应IO编号 */
GPIO_InitStructure.GPIO_Pin = USARTx_TX_PIN;
/* 设定USART发送对应IO模式:复用推挽输出 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
/* 设定USART发送对应IO最大操作速度 :GPIO_Speed_50MHz */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/* 初始化USART发送对应IO */
GPIO_Init(USARTx_TX_PORT, &GPIO_InitStructure);
/* 设定USART接收对应IO编号 */
GPIO_InitStructure.GPIO_Pin = USARTx_RX_PIN;
/* 设定USART发送对应IO模式:浮空输入 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
/* 其他没有重新赋值的成员使用与串口发送相同配置 */
/* 初始化USART接收对应IO */
GPIO_Init(USARTx_RX_PORT, &GPIO_InitStructure);
/* USART工作环境配置 */
/* USART波特率:115200 */
USART_InitStructure.USART_BaudRate = USARTx_BAUDRATE;
/* USART字长(有效位):8位 */
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
/* USART停止位:1位 */
USART_InitStructure.USART_StopBits = USART_StopBits_1;
/* USART校验位:无 */
USART_InitStructure.USART_Parity = USART_Parity_No ;
/* USART硬件数据流控制(硬件信号控制传输停止):无 */
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
/* USART工作模式使能:允许接收和发送 */
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
/* 初始化USART */
USART_Init(USARTx, &USART_InitStructure);
/* 使能接收中断 */
USART_ITConfig(USARTx, USART_IT_RXNE, ENABLE);
/* 使能USART */
USART_Cmd(USARTx, ENABLE);
/* 清除发送完成标志 */
USART_ClearFlag(USARTx, USART_FLAG_TC|USART_FLAG_TXE|USART_FLAG_RXNE);
}
/**
* 函数功能: 串口发送一个字节数据
* 输入参数: ch:待发送字符
*/
void Usart_SendByte(uint8_t ch)
{
/* 发送一个字节数据到USART1 */
USART_SendData(USARTx,ch);
/* 等待发送完毕 */
while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
}
/**
* 函数功能: 串口发送指定长度的字符串
* 输入参数: str:待发送字符串缓冲器
* strlen:指定字符串长度
*/
void Usart_SendStr_length(uint8_t *str,uint32_t strlen)
{
unsigned int k=0;
do
{
Usart_SendByte(*(str + k));
k++;
} while(k < strlen);
}
/**
* 函数功能: 串口发送字符串,直到遇到字符串结束符
* 输入参数: str:待发送字符串缓冲器
*/
void Usart_SendString(uint8_t *str)
{
unsigned int k=0;
do
{
Usart_SendByte(*(str + k));
k++;
} while(*(str + k)!='\0');
}
/**
* 函数功能: 重定向c库函数printf到USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fputc(int ch, FILE *f)
{
/* 发送一个字节数据到调试串口 */
USART_SendData(USARTx, (uint8_t) ch);
/* 等待串口数据发送完毕 */
while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
return (ch);
}
/**
* 函数功能: 重定向c库函数getchar,scanf到USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fgetc(FILE *f)
{
/* 等待串口输入数据 */
while (USART_GetFlagStatus(USARTx, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(USARTx);
}
2.bsp_usartx.h
#ifndef __BSP_USARTX_H__
#define __BSP_USARTX_H__
/* 包含头文件 ----------------------------------------------------------------*/
#include <stm32f10x.h>
/* 类型定义 ------------------------------------------------------------------*/
/* 宏定义 --------------------------------------------------------------------*/
#define USARTx_BAUDRATE 115200
#define USARTx_ClockCmd RCC_APB2PeriphClockCmd
#define USARTx_CLK RCC_APB2Periph_USART1
#define USARTx_GPIO_ClockCmd RCC_APB2PeriphClockCmd
#define USARTx_TX_PORT GPIOA
#define USARTx_TX_PIN GPIO_Pin_9
#define USARTx_TX_CLK RCC_APB2Periph_GPIOA
#define USARTx_RX_PORT GPIOA
#define USARTx_RX_PIN GPIO_Pin_10
#define USARTx_RX_CLK RCC_APB2Periph_GPIOA
#define USARTx_IRQHANDLER USART1_IRQHandler
#define USARTx_IRQn USART1_IRQn
#define USARTx USART1
/* 扩展变量 ------------------------------------------------------------------*/
/* 函数声明 ------------------------------------------------------------------*/
void USARTx_Init(void);
void Usart_SendByte(uint8_t ch);
void Usart_SendStr_length(uint8_t *str,uint32_t strlen);
void Usart_SendString(uint8_t *str);
#endif // __BSP_USARTX_H__
3.main.c
/* 包含头文件 ----------------------------------------------------------------*/
#include "stm32f10x.h"
#include "bsp/led/bsp_led.h"
#include "bsp/key/bsp_key.h"
#include "bsp/delay/delay.h"
#include "bsp/systick/bsp_SysTick.h"
#include "bsp/GeneralTIM/bsp_GeneralTIM.h"
#include "bsp/wdg/bsp_iwdg.h"
/* 函数体 --------------------------------------------------------------------*/
//static uint16_t timecount;
__IO uint16_t timer_count=0;
#include "bsp/usart/bsp_usartx.h"
uint8_t Rxflag=0;
uint8_t ucTemp;
/**
* 函数功能: 主函数.
*/
int main(void)
{
uint8_t ucaRxBuf[256];
uint16_t usRxCount;
/* USART 配置模式为 115200 8-N-1,中断接收 */
USARTx_Init();
/* 简单的通信协议,遇到回车换行符认为1个命令帧 */
usRxCount = 0;
while (1)
{
/**
* 接收COM1口的数据,分析并处理
* 可以将此段代码封装为一个函数,在主程序其它流程调用
*/
if(Rxflag)
{
if (usRxCount < sizeof(ucaRxBuf))
{
ucaRxBuf[usRxCount++] = ucTemp;
}
else
{
usRxCount = 0;
}
/* 遇到换行字符,认为接收到一个命令 */
if (ucTemp == 0x0A) /* 换行字符 */
{
Usart_SendStr_length(ucaRxBuf,usRxCount);
usRxCount = 0;
}
Rxflag=0;
}
Usart_SendString("越努力越幸运!\n");
Usart_SendString("加油!\n");
Delay(1000);
}
void USARTx_IRQHANDLER(void)
{
if(USART_GetITStatus(USARTx, USART_IT_RXNE) != RESET)
{
Rxflag=1;
ucTemp = USART_ReceiveData(USARTx);
}
}