#参考江协科技STM32视频#
一、USART简介
USART(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步收发器
- USART是STM32内部集成的硬件外设,可根据数据寄存器的一个字节数据自动生成数据帧时序,从TX引脚发送出去,也可自动接收RX引脚的数据帧时序,拼接为一个字节数据,存放在数据寄存器里
- 自带波特率发生器,最高达4.5Mbits/s
- 可配置数据位长度(8/9)、停止位长度(0.5/1/1.5/2)
- 可选校验位(无校验/奇校验/偶校验)
- 支持同步模式、硬件流控制、DMA、智能卡、IrDA、LIN
STM32F103C8T6 USART资源:USART1、 USART2、 USART3
STM32F103ZET6 USART资源:USART1、USART2、USART3、UART4、UART5
USART1挂载在APB2上,USART2、USART3、UART4、UART5挂载在APB1上。
USART框图
当数据发送到移位寄存器中,TXE标志位置1,便可以继续写入数据了
二、USART基本结构
三、USART特性
数据帧
设置9位字长,一般最后一位就是奇偶校验位
停止位一般设置成1位停止位
四、代码部分
串口初始化:
- 开启USART和GPIO时钟
- GPIO初始化,TX复用输出,RX输入
- 配置USART
- 配置中断(接收)
- 开启USART
常用库函数
//恢复缺省配置、初始化、结构体初始化
void USART_DeInit(USART_TypeDef* USARTx);
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
void USART_StructInit(USART_InitTypeDef* USART_InitStruct);
//时钟输出
void USART_ClockInit(USART_TypeDef* USARTx, USART_ClockInitTypeDef* USART_ClockInitStruct);
void USART_ClockStructInit(USART_ClockInitTypeDef* USART_ClockInitStruct);
//使能USART
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);
void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);
1. 串口发送
Serial.h
#ifndef __SERIAL_H__
#define __SERIAL_H__
#include <stdio.h>
#include <stdarg.h>
void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array, uint16_t Length);
void Serial_SendString(char *String);
void Serial_SendNumber(uint32_t Number, uint8_t Length);
void Serial_Printf(char *format, ...);
#endif
Serial.c
#include "stm32f10x.h" // Device header
#include "Serial.h"
void Serial_Init(void)
{
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);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx;
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_Cmd(USART1,ENABLE);
}
//发送字节
void Serial_SendByte(uint8_t Byte)
{
USART_SendData(USART1,Byte);
while (USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}
//发送数组
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
uint16_t i;
for (i = 0; i < Length; i++)
{
Serial_SendByte(Array[i]);
}
}
//发送字符串
//字符串最后会有结束标志位0,对应空字符
void Serial_SendString(char *String)
{
uint8_t i;
for (i = 0; String[i] != '\0'; i++) //这里'\0'是空字符的转义字符表示形式,和直接写0是一样的
{
Serial_SendByte(String[i]);
}
}
//发送数字
//先定义次方函数
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
uint32_t Result = 1;
while (Y--)
{
Result *=X;
}
return Result;
}
void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
uint8_t i;
for (i = 0; i < Length; i++)
{
Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
}
}
//移植printf函数,重定向到串口
//fputc是printf函数的底层,printf函数打印时就是调用fputc函数一个一个打印的
int fputc(int ch, FILE *f)
{
Serial_SendByte(ch);
return ch;
}
//方法2
//上述串口重定向只给printf定向至串口1,到了串口2就不能用了
//如果多个串口都想用到printf,就可以用sprintf,它可以把格式化字符输出到一个字符串中
//方法3 封装sprintf
//@char *format 用来接收格式化字符串
//@... 用来接收后面可变参数列表
void Serial_Printf(char *format, ...)
{
char String[100]; //定义输出字符串
va_list arg; //定义参数列表变量
va_start(arg, format);
vsprintf(String, format, arg);
va_end(arg);
Serial_SendString(String);
}
main.c
#include "stm32f10x.h" // Device header
#include "delay.h"
#include "OLED.h"
#include "Serial.h"
int main(void)
{
OLED_Init();
Serial_Init();
Serial_SendByte(0x41);
Serial_SendByte('A');
uint8_t MyArray[] = {0x42, 0x43, 0x44, 0x45};
Serial_SendArray(MyArray, 4);
Serial_SendString("HelloWard!\r\n"); // \r\n换行
Serial_SendNumber(12345, 5);
printf("Num1=%d\r\n",111);
//printf方法2:sprintf
char String[100];
sprintf(String, "Num2=%d\r\n",222);
Serial_SendString(String);
//方法3:封装sprintf
Serial_Printf("Num3=%d\r\n",333);
while (1)
{
}
}
2. 串口发送+接收
Serial.h
#ifndef __SERIAL_H__
#define __SERIAL_H__
#include <stdio.h>
#include <stdarg.h>
void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array, uint16_t Length);
void Serial_SendString(char *String);
void Serial_SendNumber(uint32_t Number, uint8_t Length);
void Serial_Printf(char *format, ...);
uint8_t Serial_GetRxFlag(void);
uint8_t Serial_GetRxData(void);
#endif
Serial.c
#include "stm32f10x.h" // Device header
#include "Serial.h"
uint8_t Serial_RxData;
uint8_t Serial_RxFlag;
void Serial_Init(void)
{
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_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
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART1,ENABLE);
}
//发送字节
void Serial_SendByte(uint8_t Byte)
{
USART_SendData(USART1,Byte);
while (USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}
//发送数组
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
uint16_t i;
for (i = 0; i < Length; i++)
{
Serial_SendByte(Array[i]);
}
}
//发送字符串
//字符串最后会有结束标志位0,对应空字符
void Serial_SendString(char *String)
{
uint8_t i;
for (i = 0; String[i] != '\0'; i++) //这里'\0'是空字符的转义字符表示形式,和直接写0是一样的
{
Serial_SendByte(String[i]);
}
}
//发送数字
//先定义次方函数
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
uint32_t Result = 1;
while (Y--)
{
Result *=X;
}
return Result;
}
void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
uint8_t i;
for (i = 0; i < Length; i++)
{
Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
}
}
int fputc(int ch, FILE *f)
{
Serial_SendByte(ch);
return ch;
uint8_t Serial_GetRxFlag(void)
{
if (Serial_RxFlag == 1)
{
Serial_RxFlag = 0;
return 1;
}
return 0;
}
uint8_t Serial_GetRxData(void)
{
return Serial_RxData;
}
void USART1_IRQHandler(void)
{
if (USART_GetFlagStatus(USART1, USART_IT_RXNE) == SET)
{
Serial_RxData = USART_ReceiveData(USART1);
Serial_RxFlag = 1;
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
main.c
#include "stm32f10x.h" // Device header
#include "delay.h"
#include "OLED.h"
#include "Serial.h"
uint8_t RxData;
int main(void)
{
OLED_Init();
OLED_ShowString(1, 1, "RxData:");
Serial_Init();
while (1)
{
if (Serial_GetRxFlag() == 1)
{
RxData = Serial_GetRxData();
Serial_SendByte(RxData);
OLED_ShowHexNum(1, 8, RxData, 2);
}
}
}