stm32通信接口

综述一下

名称 引脚 方向 时钟 电平 设备
USART TX/RX 全双工 异步 TTL电平 点对点
I2C SDA/SCL 半双工 同步 TTL电平 多设备
SPI SCLK/MOSI/MISO/CS 全双工 同步 TTL电平 多设备
CAN CAN_H/CAN_L 半双工 异步 差分电平 多设备
USB D+/D- 半双工 异步 差分电平 点对点

简单解释一下

全双工与半双工的区别在于通信的方向性。
全双工通信允许同时进行数据的发送和接收,而半双工通信则只能在同一时间内进行数据的发送或接收,不能同时进行。

同步与异步的区别在于通信的时钟信号。
同步通信需要一个共享的时钟信号来协调数据的传输,而异步通信则不需要共享时钟,需要通信双方约定采样频率,还需要添加一些采样位置对齐的帧。

TTL电平是相对于GND的电平差,所以TTL其实还需要GND,而差分电平是两个信号线的差.

串口通信结构

设备2

设备1

电源

发送数据

接收数据

vcc

GND

TX

RX

vcc

GND

TX

RX

1. USART(通用同步异步收发传输器)

USART是一种常用的串行通信接口,支持同步和异步两种通信模式。相较于U A R T
多了时钟输出。

UART(通用异步收发传输器)

是USART的一种异步通信模式,常用于串口通信。它通过TX(发送)和RX(接收)引脚进行数据传输,支持全双工通信。

USART基本结构

接收控制器

发送控制器

PCLK2/1

波特率发生器

发送数据寄存器TDR

发送位移寄存器

接收数据寄存器RDR

接收位移寄存器

GPIO1

TX

RX

GPIO2

linux 查看串口

  lsusb   #查看USB设备
    dmesg | grep ch341  #查看内核日志中与tty相关的信息
    [63809.198053] usb 2-1: ch341-uart converter now attached to ttyUSB0 # 查看其映射在ttyusb0上
  
    ls /dev/tty*
    
权限问题无法访问串口
 ls -l /dev/ttyUSB0 
crw-rw---- 1 root dialout 188, 0  3月 20 18:51 /dev/ttyUSB0

这里查看ttyUSB0属于dialout组 所以要将user加入dialout组才可以使用串口调试

简单来个例子

先上代码
简单初始化一下

void UART_Init (void) {
    // UART 初始化代码
    __HAL_RCC_USART1_CLK_ENABLE (); // 使能 USART1 时钟
    __HAL_RCC_GPIOA_CLK_ENABLE (); // 使能 GPIOA 时钟

    //初始化GPIO引脚
    GPIO_InitTypeDef GPIO_Init = { 0 };
    GPIO_Init.Mode = GPIO_MODE_AF_PP; // 复用推挽输出
    GPIO_Init.Pin = GPIO_PIN_9;
    GPIO_Init.Pull = GPIO_NOPULL;
    GPIO_Init.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init (GPIOA, &GPIO_Init); // 初始化 GPIOA9

    usart.Instance = USART1; // 选择 USART1
    usart.Init.BaudRate = 115200; // 设置波特率
    usart.Init.WordLength = USART_WORDLENGTH_8B; // 8位数据位
    usart.Init.StopBits = USART_STOPBITS_1; // 1位停止位
    usart.Init.Parity = USART_PARITY_NONE; // 无奇偶校验
    usart.Init.Mode = USART_MODE_TX; // 使能发送和接收
    usart.Init.CLKPolarity = USART_POLARITY_LOW; // 时钟极性低
    usart.Init.CLKPhase = USART_PHASE_1EDGE; // 时钟相位第一边沿
    usart.Init.CLKLastBit = USART_LASTBIT_DISABLE; // 不输出最后一位时钟

    HAL_USART_Init (&usart); // 初始化 USART1
}
void Send_Byte (uint8_t byte) {
    HAL_USART_Transmit (&usart, &byte, 1, HAL_MAX_DELAY); // 发送一个字节
    while (HAL_USART_GetState (&usart) != HAL_USART_STATE_READY); // 等待发送完成
}

主函数简单一个发送测试一下


int main (void) {

  HAL_Init ();
  OLED_Init ();
  MX_GPIO_Init ();

  UART_Init ();
  Send_Byte (0x41);

  while (1) {

  }
}

在这里插入图片描述

  1. 封装一个发送数组函数
void Send_Array (uint8_t * array, uint16_t size) {
    uint16_t i;
    for (i = 0; i < size; i++) {
        Send_Byte (array[i]); // 逐字节发送数组
    }
}
 uint8_t str[] = "Hello, UART!";

这里可能有疑问为什么uint可以使用字符串。字符串其实就是一个字符数组,字符在C语言中是以ASCII码的形式存储的,所以可以使用uint8_t类型来表示字符串中的每个字符。

 Send_Array (str, sizeof (str) - 1); // 发送字符串,减去1是为了不发送末尾的'\0'

在这里插入图片描述

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐