串口通信梳理

发布于:2025-02-13 ⋅ 阅读:(59) ⋅ 点赞:(0)

常用的输入输出模式:

输入模式

  • 浮空输入(Floating Input)

    • 原理:引脚的电平状态完全由外部输入信号决定,内部没有上拉或下拉电阻与电源或地相连,引脚处于高阻抗状态。
    • 应用场景:适用于外部信号源本身具有驱动能力,不需要内部上拉或下拉电阻辅助的情况,如按键检测、一些传感器信号输入等。在按键检测中,按键按下和松开时引脚电平变化可直接被检测到。
  • 上拉输入(Pull - up Input)

    • 原理:内部通过上拉电阻将引脚默认电平拉到高电平。当外部输入低电平时,引脚电平被拉低;当无外部信号输入或输入高电平时,引脚保持高电平。
    • 应用场景:常用于外部信号源可能存在不确定性或容易受到干扰的情况,确保在无有效信号输入时引脚处于确定的高电平状态。例如,在按键检测中,按键未按下时引脚为高电平,按下时为低电平,避免引脚电平浮空产生误判。
  • 下拉输入(Pull - down Input)

    • 原理:内部通过下拉电阻将引脚默认电平拉到低电平。当外部输入高电平时,引脚电平被拉高;当无外部信号输入或输入低电平时,引脚保持低电平。
    • 应用场景:与上拉输入类似,用于确保在无有效信号输入时引脚处于确定的低电平状态。例如,在某些传感器应用中,传感器输出低电平为正常状态,使用下拉输入可避免引脚电平受干扰而产生误判。
  • 模拟输入(Analog Input)

    • 原理:引脚直接连接到内部的模拟通道,用于读取模拟信号,此时引脚不经过数字电路处理,可直接将外部模拟信号传输到内部的模数转换器(ADC)进行转换。
    • 应用场景:主要用于模拟信号的采集,如温度传感器、压力传感器等输出的模拟信号,通过模拟输入模式将信号引入到 ADC 进行模数转换,以获取具体的数值。

输出模式

  • 推挽输出(Push - Pull Output)

    • 原理:内部电路由两个 MOS 管组成,一个负责输出高电平,另一个负责输出低电平。当输出高电平时,上 MOS 管导通,下 MOS 管截止;当输出低电平时,下 MOS 管导通,上 MOS 管截止。
    • 应用场景:具有较强的驱动能力,可直接驱动一些小功率的负载,如 LED 灯、继电器等。能够输出稳定的高电平和低电平,适合需要进行电平切换的场合。
  • 开漏输出(Open - Drain Output)

    • 原理:内部只有下拉 MOS 管,没有上拉 MOS 管。当输出低电平时,下拉 MOS 管导通,引脚接地;当输出高电平时,下拉 MOS 管截止,引脚处于高阻态,需要外部接上拉电阻才能输出高电平。
    • 应用场景:常用于实现线与功能、I2C 总线等通信协议。在 I2C 总线中,多个设备的 SDA 和 SCL 线可以通过开漏输出连接在一起,实现多个设备之间的通信。
  • 复用推挽输出(Alternate Function Push - Pull Output)

    • 原理:引脚被配置为复用功能,且工作在推挽输出模式。此时,引脚的控制权由特定的外设(如串口、定时器等)掌握,外设通过该引脚输出数据,输出方式与推挽输出相同。
    • 应用场景:用于外设的信号输出,如串口的发送引脚、SPI 的时钟和数据输出引脚等。通过复用推挽输出,可将外设产生的信号准确地发送出去。
  • 复用开漏输出(Alternate Function Open - Drain Output)

    • 原理:引脚被配置为复用功能,且工作在开漏输出模式。引脚的控制权由特定的外设掌握,输出方式与开漏输出相同。
    • 应用场景:常用于一些需要实现线与功能的外设通信,如 I2C 总线中,SDA 和 SCL 引脚通常配置为复用开漏输出模式,以实现多个设备之间的通信。

串口通信的时候发送端口采用复用推挽输出的原因是:

发送信号需要准确的把高低电平发送出去,复用推挽输出的驱动能力强可以确保将信号在传输的过程中有足够的强度,可以尽量避免一些干扰。其次是控制高低电平比较灵活。

串口通信的时候接受端口采用浮空输入的原因是:

浮空输入状态下,引脚的输入阻抗高(阻抗就是阻碍电流的能力,阻抗越高通过电流就越少,消耗的也就越少)几乎不消耗外部信号电流,这样可以避免外部信号源造成的负载影响,保证可以准确的接受外部设备发送过来的微弱信号,此外接受端只需要检测外部信号的高低电平变化,不需要对信号进行处理,浮空输入模式可以之间将外部信号引入到芯片内部,让USART外设进行处理

串口通信:

两个器件相互之间通信要约定好波特率(每秒钟传送码元的个数)

通信的时候要了解数据帧的格式,好对数据进行解析处理

校验:奇校验 偶校验 无校验(就是1的个数,如果个数是奇数采用偶校验,则需要最后一位补1) 一般是无校验

win+X查看端口号然后输入好波特率,确定几位有效数据,有无校验,确定完了基本上就可以完成连接。

单工:就是只能一个方向通信,只能发或者只能收

半双工:就是可以发也可以收,但是不可以同时进行

全双工:两根线,可以同时收发

同步通信就是多了一根时钟线CLK

异步通信就是没有时钟线

并行就是数据同时发送,串行一般是一位一位发送,串行应应用广泛

常用的硬件电路就是

RS232:全双工的 电平标准比较高 逻辑 “1” 为 - 3V 至 - 15V,逻辑 “0” 为 + 3V 至 + 15V tx rx gnd 一般点对点通信

RS485:半双工 电平标准比较低,采用差分电路,不容易受到干扰

也可以使用两对485实现全双工

库函数串口通信的代码结构分析:

// 串口1初始化函数

void USART1_Init(void)
{

//定义好需要使用的结构体变量,分别是 GPIO USART NVIC

 GPIO\_InitTypeDef GPIO\_InitStructure;
USART\_InitTypeDef USART\_InitStructure;
NVIC\_InitTypeDef NVIC\_InitStructure;
// 使能GPIOA和USART1时钟
RCC\_APB2PeriphClockCmd\(RCC\_APB2Periph\_GPIOA \| RCC\_APB2Periph\_USART1, ENABLE\);//开启GPIO和串口的时钟
// 配置USART1 Tx \(PA9\)为复用推挽输出
GPIO\_InitStructure\.GPIO\_Pin \= GPIO\_Pin\_9;
GPIO\_InitStructure\.GPIO\_Mode \= GPIO\_Mode\_AF\_PP;
GPIO\_InitStructure\.GPIO\_Speed \= GPIO\_Speed\_50MHz;
GPIO\_Init\(GPIOA, \&GPIO\_InitStructure\);
// 配置USART1 Rx \(PA10\)为浮空输入
GPIO\_InitStructure\.GPIO\_Pin \= GPIO\_Pin\_10;
GPIO\_InitStructure\.GPIO\_Mode \= GPIO\_Mode\_IN\_FLOATING;
GPIO\_Init\(GPIOA, \&GPIO\_InitStructure\);
// USART1配置
USART\_InitStructure\.USART\_BaudRate \= 115200;//波特率配置
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\);
// 使能USART1接收中断
USART\_ITConfig\(USART1, USART\_IT\_RXNE, ENABLE\);
// 使能USART1
USART\_Cmd\(USART1, ENABLE\);
// 配置NVIC
NVIC\_InitStructure\.NVIC\_IRQChannel \= USART1\_IRQn;
NVIC\_InitStructure\.NVIC\_IRQChannelPreemptionPriority \= 0;//抢占优先级
NVIC\_InitStructure\.NVIC\_IRQChannelSubPriority \= 0;//响应优先级
NVIC\_InitStructure\.NVIC\_IRQChannelCmd \= ENABLE;//使能
NVIC\_Init\(\&NVIC\_InitStructure\);

}

// 串口1中断处理函数
void USART1_IRQHandler(void)
{
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
char ch = USART_ReceiveData(USART1);
// 处理接收到的数据
// 例如,回显接收到的字符
// USART_SendData(USART1, (uint8_t)ch);
USART_ClearITPendingBit(USART1, USART_IT_RXNE);//清楚这个标志 不然一直处于串口中断当中
}
}