常见通信接口
串口定义
串口定义:
通用串行异步收发器
- 通用:UART的应用非常广泛,应用领域:工控行业,电力系统等
- 串行:处理器和外设之间只需连接一根信号线,处理器和外设数据传输是一个bit位一个bit位的传输
切记:UART数据传输从低位开始传输
通用串行异步收发器
![](https://i-blog.csdnimg.cn/direct/d1d642ba12cf45c58f1cbcb7bf2e6b6c.png)
收发器:发送数据和接收数据的硬件单元
- 如果CPU给外设发送数据:CPU是发送器,外设是接收器
- 如果外设给CPU发送数据:外设是发送器,CPU是接收器
UART数据传输的协议
串口特性
电器特性:串口标准规定了电平的高低阈值和电平范围
TTL电平:硬件平台使用的TTL电平
- 高电平:3.3v或者5v
- 低电平:0v
EIA电平:串口线上的电平标准
- 高电平:-3~-15v
- 低电平:3v~15v
举例:外设发送逻辑低电平
串口线上是0(3.3v),但CPU读取到3.3v认为是1,数据传输错误
需要进行电平转换:电脑(TTL->EIA)--- 串口线 --- CPU(EIA->TTL)
机械特性
连接器类型
- 串口座
- USB转串口
-
接插件-三个插针(TX/RX/GND)
协议中的概念
- 空闲位:处理器和外设不进行数据传输时,数据线上持续发送空闲位,空闲位的有效位数为一个bit位, 高电平有效
- 起始位:如果处理器和外设开始传输数据,首先传输起始位,有效位数为一个bit位,低电平有效
- 数据位:表示处理器和外设传输数据的有效位数,数据位的有效位数:5/6/7/8,一般选择8位(表示传输的数据有效位数为8个bit位)注意:处理器和外设数据位保持一致
- 奇偶校验位:用于检测双方数据传输是否发送了错误,有效位数为一个bit位,如果不校验,则无需发送校验位,注意:双方的校验方式保持一致
- 停止位:如果处理器和外设要结束数据的传输,只需发送停止位即可,有效位数为:1/2有效电平是高电平,注意:处理器和外设停止位保持一致
- 波特率:表示双方数据传输的速率,常用的两个波特率:115200bps/9600bps(bps = bit per second = 每秒传输多少位),注意:双方的配置也要一致
UART的三种工作方式
- 单工:数据传输永远朝一个方向
- 半双工:数据传输可以双向进行,但是同一时刻只能朝一个方向
- 全双工:数据传输可以同时双向进行,一般都是工作在全双工模式下
切记结论:UART实际硬件连接至少三根线:TX(发送),RX(接收),GND(共地)
硬件连接
简化硬件
UART控制器
发送数据流程:
- 由于CPU核发送数据的速度,也就是向数据寄存器DR中写入数据的速度远远快于发送移位寄存器将数据一位一位的发送到TX引脚上的速度,所以首先判断TC位是否为1,如果为1表示发送数据寄存器为空则CPU方可发送数据,否则采用轮询方式等待,直到发送数据寄存器为空也就是TC为1时才能发送下一个数据
- 如果TC为1,则CPU核软件上以指针或者采用库函数将数据放到数据寄存器DR中
- 发送数据寄存器的数据硬件上自动拷贝到发送移位器中
- 发送移位器根据给定的波特率将数据一位一位的按照UART协议发送到TX引脚上
接收数据流程:
- 接收移位器首先根据给定的波特率将数据一位一位的按照UART协议从RX引脚上获取数据
- 接收移位寄存器中的数据硬件上自动拷贝到数据寄存器DR中
- 由于CPU核从数据寄存器DR中读取数据的速度远远快于接收移位器从RX引脚上一位一位接收数据的速度,所以当RXNE为1时,CPU核方可从数据寄存器DR中获取数据,否则CPU核轮询等待,直到数据寄存器DR中有数据也就是RXNE为1时CPU才能读取数据
- 如果RXNE为1,则CPU核软件上以指针或者采用库函数从数据寄存器DR中读取数据
测试代码
uart.c
//USART.c
#include "uart.h"
void UART_Init(void){
//打开GPIOA和USRTA的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
//配置PA9为推挽复用输出,TX
GPIO_InitTypeDef GPIO_Config;
GPIO_Config.GPIO_Pin = GPIO_Pin_9;
GPIO_Config.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Config.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_Config);
//配置PA10为浮空输入,RX
GPIO_Config.GPIO_Pin = GPIO_Pin_10;
GPIO_Config.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_Config);
//配置串口工作参数
USART_InitTypeDef USART_Config;
USART_Config.USART_BaudRate = 115200;
USART_Config.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Config.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Config.USART_Parity = USART_Parity_No;
USART_Config.USART_StopBits = USART_StopBits_1;
USART_Config.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1,&USART_Config);
//使能串口1
USART_Cmd(USART1,ENABLE);
}
//发送一个字符
void UART_Putc(char c){
//界定DR寄存器中是否有数据
//返回值RESET继续等待,SET不要等待,可以向DR中放入数据
while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);
//将字符串放到串口1的DR寄存器中
USART_SendData(USART1, c);
}
void UART_Puts(char* pstr){
//u8 pstr_len = sizeof(pstr)/sizeof(pstr[0]);
//for(int i =0; i<pstr_len;i++)
// UART_Putc(pstr[i]);
while(*pstr){
UART_Putc(*pstr);
pstr++;
}
}
//读取一个字符
char UART_Getc(void){
//判断接收数据寄存器DR是否还有有效数据
while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE) == RESET);
//从串口1中读取数据
return (char)USART_ReceiveData(USART1);
}
//读取一个字符串
void UART_Gets(char* buf,u32 len){
int i = 0;
for(i = 0;i<(len-1);i++){
//每读取到一个字符就放到buf里
buf[i] = UART_Getc();
//如果读取到\n字符,就不继续读取了
if(buf[i] == '\n'){
break;
}
}
buf[i-1] = '\0';
}
调用main.c
// @file : main.c
#include "stm32f10x.h"
#include "uart.h"
#include "systick.h"
#define BUF_LEN 128
static char buf[BUF_LEN];
int main(void){
UART_Init();
Systick_init();
while(1){
// 下位机->上位机:请输入消息
UART_Puts("please put string");
// 上位机发送消息给下位机
UART_Gets(buf,BUF_LEN);
//回显
UART_Puts("\n");
UART_Puts("your input:");
UART_Puts(buf);
UART_Puts("\n");
}
}
效果展示
串口调试工具
在调试工具中进行设置,端口,波特率,数据长度,停止位,和上位机设置匹配
选择端口
选择端口号,配置波特率,打开串口
在串口调试助手中向STM32发送welcome to beijing