stm32—串口(USART)通讯
一、通讯概述:
一个通讯协议大体从4点了解:
1、数据传送方式(串行、并行)
串行: 数据按位顺序传输,速度慢,占用资源少。如: FSMC
并行: 数据各个位同时传输,速度快,占用资源多;如:USART、SPI、ICC
2、数据通讯方式(单工、半双工、全双工)
单工 : 在任意时刻只能进行一个方向的通讯,即是一个固定的发送设备,另一个固定的接收设备。
半双工: 两个设备之间可以收发数据,但不能在同一时刻。
全双工: 在同一时刻,两台设备之间可以收发数据。
3、数据同步方向(异步、同步)
异步特点 :
由于异步通讯是没有时钟SCLK约束的;使得双方接收和发送数据不同步(接收方根本不知道你什么时候发了数据过来,更不知数据是从哪一位有效);所以你发送一个字符数据时,必须先发送一个起始位(告诉对方开始发数据了),然后才有数据字符和奇偶校验(可选),最后发送结束后告诉对方(发送停止位)
由此可见;异步USART通讯不带时钟约束,双方必须设定好波特率、数据格式来达到双方数据收发稳定:
1、波特率
2、数据格式(起始位、有效数据位、奇偶校验位、停止位)
同步 特点:
1、数据传输是以数据块传输(多个字符组成数据流);
2、在一个数据块内数据是没间隔的;
3、因为一次传输的数据块包含数据比较多,所以接收时钟和发送时钟严格同步,通常要有同步时钟SCLK;
4、通讯上方时钟是连在一起的,提供同步时钟。
5、通讯双方接收与发送是同步的(时刻相同)
4、数据通讯速度(比特率、波特率)
二、基于固件库如何配置串口通讯
1、配置时钟:GPUO口的时钟、串口时钟、引脚复用时钟
2、配置GPIO结构体
3、配置串口结构体
4、串口发送
以USART1(PA9位TX,PA10位RX)为例:
1、配置时钟:GPIO口的时钟、串口时钟、引脚复用时钟
void Usart_Init(void)
{
//使能GPIO口的时钟、串口时钟、引脚复用时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
}
2、配置GPIO结构体
void Usart_Init(void)
{ //定义GPIOA的结构体
GPIO_InitTypeDef gpio_initStruct;
//配置GPIOA9 TX 复用功能推挽输出模式GPIO_Mode_AF_PP
gpio_initStruct.GPIO_Mode = GPIO_Mode_AF_PP;
gpio_initStruct.GPIO_Pin = GPIO_Pin_9;
gpio_initStruct.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOA, &gpio_initStruct);
//配置GPIOA10 RX 浮空输入模式GPIO_Mode_IN_FLOATING
gpio_initStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
gpio_initStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_Init(GPIOA, &gpio_initStruct);
}
3、配置串口结构体
异步串口结构:
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;
1、USART_BaudRate : 波特率(配置波特率)
2、USART_WordLength : 字节 (配置控制数据位的字节:八、九位)
3、USART_StopBits : 停止位(配置停止位:0.5、1、5、2)
4、USART_Parity : 校验位(配置校验位、无、奇、偶)
5、USART_Mode : 模式(配置工作模式收/发)
6、USART_HardwareFlowControl : 硬件流控制
同步时钟的USART串口结构:
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_Clock : 同步时钟 (配置是否打开)
2、USART_CPOL : 极性(配至串口空闲位高电平、低电平)
3、USART_CPHA : 相位(配置选择边沿)
4、USART_LastBit : 最后一个时钟(配置使能还是关闭)
配置串口结构体如下:
void Usart_Init(void)
{//定义串口结构体
USART_InitTypeDef usart_initStruct;
//配置串口结构体
usart_initStruct.USART_BaudRate =115200;
usart_initStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
usart_initStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
usart_initStruct.USART_Parity = USART_Parity_No;
usart_initStruct.USART_StopBits = USART_StopBits_1;
usart_initStruct.USART_WordLength = USART_WordLength_8b;
//初始化串口结构体
USART_Init(USART1, &usart_initStruct);
//使能串口
USART_Cmd(USART1, ENABLE);
}
4、串口函数
//初始化串口
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
//串口使能函数
void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);
//中断配置函数
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);
//串口发送函数
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
//串口接收函数
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
//获取相应的串口标志位
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
//中断状态获取
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);
USART_FLAG | 描述 |
---|---|
USART_FLAG_CTS | CTS标志位 |
USART_FLAG_LBD | LIN中断标志位 |
USART_FLAG_TXE | 发送数据寄存器空标志位 |
USART_FLAG_TC | 发送完成标志位 |
USART_FLAG_RXNE | 接收数据寄存器非空标志位 |
USART_FLAG_IDLE | 空闲总线标志位 |
USART_FLAG_ORE | 溢出错误标志位 |
USART_FLAG_NE | 噪声错误标志位 |
USART_FLAG_FE | 帧错误标志位 |
USART_FLAG_PE | 奇偶错误标志位 |
串口发送一个字符代码:
USART_SendData(USART1,'o');
//USART_GetFlagStatus用来判断是否发送完成标志
while (USART_GetFlagStatus( USART1, USART_FLAG_TXE) == RESET );
封装一个发送字符的函数:
void USART_SendByte(USART_TypeDef* USARTx, uint16_t Data)
{
USART_SendData(USARTx,Data);
while (USART_GetFlagStatus( USART1, USART_FLAG_TXE) == RESET );
}
封装一个发送字符串的函数:
void USART_SendStr(USART_TypeDef* USARTx,char *str)
{
uint16_t i = 0;
do
{
USART_SendByte(USARTx,*(str+i));
i++;
}while(*(str+i) != '\0');
while (USART_GetFlagStatus( USART1, USART_FLAG_TC ) == RESET );
}
三、串口中断接收配置
void Usart_Init(void)
{
//定义串口中断结构体
NVIC_InitTypeDef nvic_usartStruct;
//初始化中断优先组2
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//初始化外部中断源
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
//中断结构体定义
nvic_usartStruct.NVIC_IRQChannel = USART1_IRQn;
nvic_usartStruct.NVIC_IRQChannelCmd = ENABLE;
nvic_usartStruct.NVIC_IRQChannelPreemptionPriority = 1;
nvic_usartStruct.NVIC_IRQChannelSubPriority = 1;
//初始化中断结构体
NVIC_Init(&nvic_usartStruct);
}
最终串口收发配置程序:
void Usart_Init(void)
{
//定义引脚结构体
GPIO_InitTypeDef gpio_initStruct;
//定义串口结构体
USART_InitTypeDef usart_initStruct;
//定义串口中断结构体
NVIC_InitTypeDef nvic_usartStruct;
//使能GPIO口的时钟、串口时钟、引脚复用时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//配置GPIOA9 TX 复用功能推挽输出模式GPIO_Mode_AF_PP
gpio_initStruct.GPIO_Mode = GPIO_Mode_AF_PP;
gpio_initStruct.GPIO_Pin = GPIO_Pin_9;
gpio_initStruct.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOA, &gpio_initStruct);
//配置GPIOA10 RX 浮空输入模式GPIO_Mode_IN_FLOATING
gpio_initStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
gpio_initStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_Init(GPIOA, &gpio_initStruct);
//配置串口结构体
usart_initStruct.USART_BaudRate =115200;
usart_initStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
usart_initStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
usart_initStruct.USART_Parity = USART_Parity_No;
usart_initStruct.USART_StopBits = USART_StopBits_1;
usart_initStruct.USART_WordLength = USART_WordLength_8b;
//初始化串口结构体
USART_Init(USART1, &usart_initStruct);
//使能串口
USART_Cmd(USART1, ENABLE);
//初始化中断优先级组2
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//初始化外部中断源
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
//中断结构体配置
nvic_usartStruct.NVIC_IRQChannel = USART1_IRQn;
nvic_usartStruct.NVIC_IRQChannelCmd = ENABLE;
nvic_usartStruct.NVIC_IRQChannelPreemptionPriority = 1;
nvic_usartStruct.NVIC_IRQChannelSubPriority = 1;
//初始化中断结构体
NVIC_Init(&nvic_usartStruct);
}
四、中断处理函数编写
void USART1_IRQHandler(void)
{
char date;
//判断串口标志位是否产生中断,开始接收数据
if ( USART_GetITStatus(USART1, USART_IT_RXNE) != RESET )
{ //获取串口信息
date = USART_ReceiveData(USART1);
if(date == 'O')
{
GPIO_ResetBits(GPIOC, GPIO_Pin_13);
USART_SendStr(USART1,"led is open");
}
}
}