介绍
串口(UART通用异步收发器,TTL)通讯是一种设备间的串行全双工通讯方式。由于UART是异步传输,没有传输同步时钟,为了保证数据的正确性,UART采用16倍数据波特率的时钟进行采样。
数据格式
起始位:先发出一个逻辑”0”的信号,表示传输数据的开始。
数据位:可以选择的值有5,6,7,8这四个值,可以传输这么多个值为0或者1的bit位。这个参数最好为8,因为如果此值为其他的值时当你传输的是ASCII值时一般解析肯定会出问题。理由很简单,一个ASCII字符值为8位,如果一帧的数据位为7,那么还有一位就是不确定的值,这样就会出错。
校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性。
停止位:它是一帧数据的结束标志。可以是1bit、1.5bit、2bit的空闲电平。
空闲位:没有数据传输时线路上的电平状态。为逻辑1。
UART传输数据顺序
刚开始传输一个起始位,接着传输数据位,接着传输校验位(可不需要此位),最后传输停止位。这样一帧的数据就传输完了。接下来接着像这样一直传送。
发送数据过程
空闲状态,线路处于高电平;当收到发送指令后,拉低线路的一个数据位的时间T,接着数据按低位到高位依次发送,数据发送完毕后,接着发送奇偶校验位和停止位,一帧数据发送完成。
数据接收过程
空闲状态,线路处于高电平;当检测到线路的下降沿(高电平变为低电平)时说明线路有数据传输,按照约定的波特率从低位到高位接收数据,数据接收完毕后,接着接收并比较奇偶校验位是否正确,如果正确则通知后续设备接收数据或存入缓冲。
硬件连接
UART的硬件连接比较简单,只需要两个设备的TXD和RXD相互反接,再将GND相连即可。
软件实现
USART初始化结构体详解
标准库函数对每个外设都建立了一个初始化结构体,例如USART_InitTypeDef,结构体成员用于设置外设工作参数,并由外设初始化配置函数,比如USART_Init()调用,这些设定参数将会设置外设相应的寄存器。初始化结构体和初始化库函数配合使用是标准库精髓所在。初始化结构体定义在stm32f10x_usart.h文件中,初始化库函数定义在stm32f10x_usart.c。
USART初始化结构体
typedef struct{
uint32_t USART_BaudRate; //波特率
uint16_t USART_WordLength; //字长
uint16_t USART_StopBits; //停止位
uint16_t USART_Parity; //校验位
uint16_t USART_Mode; //USART模式
uint16_t USART_HardwareFlowControl;//硬件流控制 } USART_InitTypeDef;
串口通信实例
学习完串口的相关知识,肯定需要一个例子来实现。下面我们来制作一个简单的串口发送项目。
其中配置串口函数,一般分为中断和非中断两种配置方法,我会分别进行介绍。
非中断实现
非中断配置串口函数,只需要编写Usart1_Configuration函数即可。
void Usart1_Configuration(u32 BAUD){
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
//第一步:初始化时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
//第二步:初始化GPIO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
//第三步:初始化串口参数
USART_InitStructure.USART_BaudRate = BAUD;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
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(USART1, &USART_InitStructure); //初始化串口1
//第四步:使能串口
USART_Cmd(USART1, ENABLE); //使能串口1
USART_ClearFlag(USART1, USART_FLAG_TC); //清空发送完成标志}
中断实现
中断配置串口函数,除了编写Usart1_Configuration函数还需要配置中断。
static void Usart1_NVIC_Configuration(void){
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //从优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器}
void Usart1_Configuration(u32 BAUD){
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
//第一步:初始化时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
//第二步:初始化GPIO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
//第三步:初始化串口参数
USART_InitStructure.USART_BaudRate = BAUD;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
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(USART1, &USART_InitStructure); //初始化串口1
//第四步:开启相关中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启串口空闲中断
//第五步:配置中断优先级
Usart1_NVIC_Configuration();
//第六步:使能串口
USART_Cmd(USART1, ENABLE); //使能串口1
USART_ClearFlag(USART1, USART_FLAG_TC); //清空发送完成标志}
发送数据
void Usart1_SendByte(u8 val){
USART_SendData(USART1, val);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); //等待发送完成}
void Usart1_SendBuf(u8 *buf,u8 len){
while(len--) Usart1_SendByte(*buf++);}
void Usart1_SendString(char *str){
while(*str) Usart1_SendByte(*str++);}
使用
我们使用的时候,只需要先初始化串口1配置函数Usart1_Configuration(选择自己想要设定的波特率);
之后调用发送函数Usart1_SendString(“发送的内容”);
即可。
int main(void){
Usart1_Configuration(115200);
while(1){
…… Usart1_SendString(" usart1 is ok!\r\n");
}}