【学习笔记】stm32单片机USART串口

最近学了 stm32 的串口通信。
串口在之前学 51 的时候用过，不过差不多忘干净了（悲）
那么开始复习串口通信。

（一）什么是 USART

串口是一种应用十分广泛的通讯接口，串口成本低、容易使用、通信线路简单，可实现两个设备的互相通信。
单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信，极大地扩展了单片机的应用范围，增强了单片机系统的硬件实力。
其通信方式为异步全双工，异步是指通信双方间没有时钟线相连，需要预先设置好波特率（传输频率）；全双工是指通信双方都可以发送和接收信号，互不干扰。
USART 串口通信有两条线，一条是 TXD，用于发送信号；一条是 RXD，用于接收信号。双方的 TXD 与对方的 RXD 交叉相连。（图片莫名奇妙传不上来，算了）
USART 发送的一个完整的信息包括：起始位、数据位、校验位、停止位，其中，数据位跟校验位总共有 8 或者 9 位位，校验位只有一位，我们可以通过改变停止位的长度来改变发送频率，不过一般选择 8 位无校验，或者 9 位校验，停止位长度 1 位就可以了。

（二）代码配置

stm32 的库函数中有专门的 USART 函数，所以配置过程可比 51 的简单多了。
代码如下：
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure);

USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate=9600; USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;
USART_InitStructure.USART_Parity=USART_Parity_No;
USART_InitStructure.USART_StopBits=USART_StopBits_1;
USART_InitStructure.USART_WordLength=USART_WordLength_8b; USART_Init(USART1,&USART_InitStructure);

USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0; NVIC_Init(&NVIC_InitStructure);

USART_Cmd(USART1,ENABLE);
我们只要开启时钟初始化引脚后用 USART_Init 初始化 USART（波特率 9600，8 位不校验），然后再用 USART_ITConfig 开启中断，最后配置 NVIC 并启动串口就可以了。

（三）发送与接收信号

发送信号很简单我们只要用 USART_SendData 函数就可以了：
void Serial_SendByte(uint8_t Data)
{
USART_SendData(USART1,Data);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
}

而在这个的基础上，我们还可以封装出发送字符串、发送数字的函数，比如下面这个发送字符串的函数：
void Serial_SendString(uint8_t*Data)
{
int j = 0;
for(j=0;Data[j]!='\0';j++)
{
Serial_SendByte(Data[j]);
}
}

而接收数据则需要用中断，代码如下：
void USART1_IRQHandler()
{
while(USART_GetITStatus(USART1,USART_IT_RXNE)==RESET);
SerialRXFlag=1;
SerialRXData=USART_ReceiveData(USART1);
}

（四）串口收发数据包

其实就是让串口收发某种特定格式的内容，比如数据包包头为 0xFF，包尾为 0xFE，代码大致如下：
void Serial_Sendpacket()
{
Serial_SendByte(0xFF);
Serial_SendArray(SerialTXPacket,4);
Serial_SendByte(0xFE);
}

void USART1_IRQHandler()
{
static int pRXPacket = 0;
static uint8_t RxState = 0;
while(USART_GetITStatus(USART1,USART_IT_RXNE)==RESET);
uint8_t RXData = 0;
RXData = USART_ReceiveData(USART1);
switch (RxState)
{
case 0:
if (RXData == 0xFF)
{
RxState = 1;
pRXPacket = 0;
}
break;
case 1:
SerialRXPacket[pRXPacket] = RXData;
pRXPacket++;
if (pRXPacket >= 4)
{
RxState = 2;
}
break;
case 2:
if (RXData == 0xFE)
{
RxState = 0;
SerialRXFlag=1;
}
break;
}
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}

USART 的内容大概就这么多，说不上多复杂，因为函数库已经把我们本来需要配置的一堆东西都做了。