STM32一文通(8) 串口通讯
一.原生串口通讯
- 原生的串口通信主要是控制器跟串口的设备或者传感器通信,不需要经过电平转换芯片来转换电平,直接就用TTL电平通信
- 比如: GPS模块、GSM模块、串口转WIFI模块、HC04蓝牙模块
二. 串口与PC通讯
- USB转串口主要用于设备跟电脑通信
- 电平转换芯片一般有CH340、PL2303、CP2102、FT232
- 使用的时候电脑端需要安装电平转换芯片的驱动
三. RS232标准串口通讯
- RS232标准串口主要用于工业设备直接通信
- 电平转换芯片一般有MAX3232,SP3232
四. STM32串口
1. 内部结构
寄存器 | 功能 |
---|---|
TX | 数据发送 |
RX | 数据接收 |
SCLK | 时钟,仅同步通信时使用(不常用) |
nRTS | 发送请求(不常用) |
nCTS | 允许发送 (不常用) |
2. 串口引脚分布
注意:串口一是APB2总线, 其他是APB1总线
3. 串口引脚重定义
参见复用重映射和调试I/O配置寄存器(AFIO_MAPR)
4. 串口寄存器
(1). 串口数据寄存器 USART_DR
USART_DR, 9位有效
USART_DR一个地址对应了两个物理内存。包含一个发送数据寄存器TDR和一个接收数据寄存器RDR。
(2). 串口数据寄存器 USART_CR1 USART_CR2 用来配置串口
(3). 串口波特率寄存器USART_BRR
五. 串口相关结构体
1. 串口初始化结构体 USART_InitTypeDef
typedef struct
{
uint32_t USART_BaudRate; /*!< This member configures the USART communication baud rate.
The baud rate is computed using the following formula:
- IntegerDivider = ((PCLKx) / (16 * (USART_InitStruct->USART_BaudRate)))
- FractionalDivider = ((IntegerDivider - ((u32) IntegerDivider)) * 16) + 0.5 */
uint16_t USART_WordLength; /*!< Specifies the number of data bits transmitted or received in a frame.
This parameter can be a value of @ref USART_Word_Length */
uint16_t USART_StopBits; /*!< Specifies the number of stop bits transmitted.
This parameter can be a value of @ref USART_Stop_Bits */
uint16_t USART_Parity; /*!< Specifies the parity mode.
This parameter can be a value of @ref USART_Parity
@note When parity is enabled, the computed parity is inserted
at the MSB position of the transmitted data (9th bit when
the word length is set to 9 data bits; 8th bit when the
word length is set to 8 data bits). */
uint16_t USART_Mode; /*!< Specifies wether the Receive or Transmit mode is enabled or disabled.
This parameter can be a value of @ref USART_Mode */
uint16_t USART_HardwareFlowControl; /*!< Specifies wether the hardware flow control mode is enabled
or disabled.
This parameter can be a value of @ref USART_Hardware_Flow_Control */
} USART_InitTypeDef;
- USART_BaudRate: 设置波特率,如9600,115200等
- USART_WordLength: 设置数据长度。具体值:USART_WordLength_8b 或 USART_WordLength_9b
- USART_StopBits: 设置停止位大小
- USART_Parity: 奇偶校验
- USART_Mode: 设置收发使能
发送接收都使能
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //发送接收都使能
2.同步时钟初始化结构体 (用的少)
typedef struct
{
uint16_t USART_Clock; /*!< Specifies whether the USART clock is enabled or disabled.
This parameter can be a value of @ref USART_Clock */
uint16_t USART_CPOL; /*!< Specifies the steady state value of the serial clock.
This parameter can be a value of @ref USART_Clock_Polarity */
uint16_t USART_CPHA; /*!< Specifies the clock transition on which the bit capture is made.
This parameter can be a value of @ref USART_Clock_Phase */
uint16_t USART_LastBit; /*!< Specifies whether the clock pulse corresponding to the last transmitted
data bit (MSB) has to be output on the SCLK pin in synchronous mode.
This parameter can be a value of @ref USART_Last_Bit */
} USART_ClockInitTypeDef;
六. 串口相关库函数
1. 串口初始化函数 USART_Init()
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct)
示例:
USART_InitStructure.USART_BaudRate=115200; //设置波特率
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_Cmd(USART2, ENABLE);
2. 中断配置函数 USART_ITConfig()
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState)
例:使能接受完毕中断USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
3. 串口使能函数 USART_Cmd
void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState)
4. 数据发送函数 USART_SendData()
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)
5. 数据接收函数 USART_ReceiveData
uint16_t USART_ReceiveData(USART_TypeDef* USARTx)
6.中断状态位获取函数 USART_GetITStatus
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT)
7. 编程方法
例子:
-
完整的串口发送, 可以printf, 可以发送 8位字 16位半字节 字符串等
-
中断接收功能 , 当有外部数据输入时会产生中断, 中断后将得到的 字 再发送出去,同时点亮RGB
-
可以控制RGB灯的亮灭, PC端输入:0,1,2可以点亮RGB~
psb_usart.h文件(这个文件将5个串口都定义好了, 通过选择编译来确定串口)
#ifndef __BSP_USART_H
#define __BSP_USART_H
#include "stm32f10x.h"
#include <stdio.h>
//用哪个串口就把哪个置1
#define DEBUG_USART1 1
#define DEBUG_USART2 0
#define DEBUG_USART3 0
#define DEBUG_USART4 0
#define DEBUG_USART5 0
#if DEBUG_USART1
// 串口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
#elif DEBUG_USART2
//串口2-USART2
#define DEBUG_USARTx USART2
#define DEBUG_USART_CLK RCC_APB1Periph_USART2
#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
#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_2
#define DEBUG_USART_RX_GPIO_PORT GPIOA
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_3
#define DEBUG_USART_IRQ USART2_IRQn
#define DEBUG_USART_IRQHandler USART2_IRQHandler
#elif DEBUG_USART3
//串口3-USART3
#define DEBUG_USARTx USART3
#define DEBUG_USART_CLK RCC_APB1Periph_USART3
#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOB)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOB
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10
#define DEBUG_USART_RX_GPIO_PORT GPIOB
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11
#define DEBUG_USART_IRQ USART3_IRQn
#define DEBUG_USART_IRQHandler USART3_IRQHandler
#elif DEBUG_USART4
//串口4-UART4
#define DEBUG_USARTx UART4
#define DEBUG_USART_CLK RCC_APB1Periph_UART4
#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOC
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10
#define DEBUG_USART_RX_GPIO_PORT GPIOC
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11
#define DEBUG_USART_IRQ UART4_IRQn
#define DEBUG_USART_IRQHandler UART4_IRQHandler
#elif DEBUG_USART5
//串口5-UART5
#define DEBUG_USARTx UART5
#define DEBUG_USART_CLK RCC_APB1Periph_UART5
#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOC
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_12
#define DEBUG_USART_RX_GPIO_PORT GPIOD
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_2
#define DEBUG_USART_IRQ UART5_IRQn
#define DEBUG_USART_IRQHandler UART5_IRQHandler
#endif
void USART_Config(void);
void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t data);
void Usart_SendHalfWord(USART_TypeDef* pUSARTx, uint16_t data);
void Usart_SendArray(USART_TypeDef* pUSARTx, uint8_t *array,uint8_t num);
void Usart_SendStr(USART_TypeDef* pUSARTx, char *str);
#endif /* __BSP_USART_H */
psb_usart.c
#include "psb_usart.h"
static void NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStruct;//中断初始化结构体
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//先设组
NVIC_InitStruct.NVIC_IRQChannel = DEBUG_USART_IRQ;//中断源
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;//主优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority=7;//从优先级
NVIC_InitStruct.NVIC_IRQChannelCmd= ENABLE; //中断使能
NVIC_Init(&NVIC_InitStruct); //中断初始化
}
void USART_Config(void)
{
//0.变量定义区
GPIO_InitTypeDef GPIO_InitStructure; //创建一个GPIO_InitTypeDef类型的数据
USART_InitTypeDef USART_InitStruct;//串口初始化结构体
//1.配置GPIO
DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_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);
//2.初始化串口
DEBUG_USART_APBxClkCmd(RCC_APB2Periph_USART1,ENABLE);
USART_InitStruct.USART_BaudRate = DEBUG_USART_BAUDRATE; //波特率
USART_InitStruct.USART_WordLength = USART_WordLength_8b;//8位数据为
USART_InitStruct.USART_StopBits = USART_StopBits_1; //停止位1
USART_InitStruct.USART_Parity = USART_Parity_No; //无奇偶校验
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //发送接收都使能
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件流
USART_Init(USART1, &USART_InitStruct);//初始化串口
//3.中断配置
NVIC_Config();
// 使能串口接收中断
USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);
//4. 使能串口
USART_Cmd(DEBUG_USARTx, ENABLE);
}
/*----------------------------------------------------------------------*/
//5. 编写发送函数
//发送一个字节
void Usart_SendByte(USART_TypeDef* USARTx,uint8_t data)
{
USART_SendData(USARTx, data);
while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE)==RESET);
}
//发送两个字节
void Usart_SendHalfWord(USART_TypeDef* USARTx,uint16_t data)
{
uint8_t tempH, tempL;
tempL = data & 0xFF;
tempH = (data>>8) & 0xFF;
Usart_SendByte(USARTx,tempH);
Usart_SendByte(USARTx,tempL);
}
//发送一个数组
void Usart_SendArray(USART_TypeDef* USARTx,uint8_t *array, uint8_t num)
{
uint8_t i;
for(i=0;i<num;i++)
{
Usart_SendByte(USARTx,*array++);
}
while(USART_GetFlagStatus(USARTx, USART_FLAG_TC)==RESET);
}
//发送一个字符串
void Usart_SendStr(USART_TypeDef* pUSARTx, char *str)
{
uint8_t i=0;
do
{
Usart_SendByte(pUSARTx, *(str+i));
i++;
}while(*(str+i) != '\0');
while( USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET );
}
//重定向c库函数printf到串口,重定向后可使用printf函数和putchar函数
int fputc(int ch, FILE *f)
{
/* 发送一个字节数据到串口 */
USART_SendData(DEBUG_USARTx, (uint8_t) ch);
/* 等待发送完毕 */
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
return (ch);
}
/*----------------------------------------------------------------------*/
//6. 编写接收函数
uint16_t Rev_Byte(void)
{
return USART_ReceiveData(DEBUG_USARTx);
}
///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
/* 等待串口输入数据 */
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(DEBUG_USARTx);
}
/*----------------------------------------------------------------------*/
中断部分
#include "stm32f10x_it.h"
#include "psb_usart.h"
#include "led.h"
//省略未修改内容
void DEBUG_USART_IRQHandler(void)
{
uint8_t ucTemp;
if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET)
{
ucTemp = getchar();
USART_SendData(DEBUG_USARTx,ucTemp);
switch(ucTemp)
{
case '0':
LED_R(ON);
LED_G(OFF);
LED_B(OFF);
break;
case '1':
LED_R(OFF);
LED_G(ON);
LED_B(OFF);
break;
case '2':
LED_R(OFF);
LED_G(OFF);
LED_B(ON);
break;
default:
LED_R(OFF);
LED_G(OFF);
LED_B(OFF);
break;
}
}
}
main.c随便写
#include "stm32f10x.h"
#include "led.h"
#include "psb_usart.h"
int main(void)
{
uint8_t a[11]= {0,1,2,3,4,5,6,7,8,9,10};
LED_GPIO_Config();
USART_Config();
LED_B(OFF);
LED_R(OFF);
LED_G(OFF);
//Usart_SendByte(DEBUG_USARTx,0x08);
//Usart_SendHalfWord(DEBUG_USARTx,0xabcd);
//Usart_SendArray(DEBUG_USARTx, a,11);
//Usart_SendStr(DEBUG_USARTx,"滚滚长江东逝水\n");
//printf("浪花淘尽英雄~\n");
printf("PC端输入:0,1,2可以点亮RGB~\n");
}