4.STM32之通信接口《精讲》之USART通信---实验串口发送程序

ops/2024/11/19 17:34:52/

本节将进行实战,基础了解请查看第1,2,3节(Whappy)
开始背!! USART ---》全双工   异步/同步  点对点
C语言基础printf用法,这节将用到printf的重定向,来打印到串口助手上。

先给大家看一下整个过程,然后我再给大家做一个单一的串口发送的程序(不包括接收,将在下一节讲)

串口通信的完整过程概述

在嵌入式开发中,串口通信(UART)是最常用的通信方式之一,常用于调试和数据传输。今天我们先带大家梳理一下整个串口通信的过程和原理。

  1. 通信原理 串口通信是一种异步的串行数据传输方式,数据通过起始位、数据位、校验位和停止位逐位传输。STM32 的串口模块(USART/UART)将这些数据串行发送出去,而接收端则按相同协议解析接收到的数据。

  2. 硬件连接

    • STM32 的 TX 引脚:负责发送数据。
    • 电脑的 RX 引脚:负责接收数据。
    • 共地:STM32 和电脑需要连接 GND 确保信号参考一致。
  3. 软件流程

    • STM32 端: 配置 USART 外设,完成数据发送。
    • 电脑端: 通过串口助手(如 SScom、SecureCRT 等)接收 STM32 发送的数据,并显示在屏幕上。
  4. 配置同步 STM32 和电脑串口助手需配置相同的通信参数(如波特率、数据位、停止位等),才能实现正确的通信。

在 STM32 开发中,串口通信(UART)是常用的通信方式之一。以下是详细的步骤和注意事项,包括如何实现数据发送、接收,以及配置相关的硬件和软件。


一、STM32 串口通信原理

  1. 发送端:STM32 STM32 的串口模块(USART)通过 UART 协议将数据位(包括起始位、数据位、校验位和停止位)串行输出到 TX 引脚。

  2. 接收端:电脑助手 电脑通过串口助手软件(如 SScom、SecureCRT 等)接收 STM32 发送的数据,解码并显示。

  3. 硬件连接

    • TXD(STM32 发送端)连接到电脑串口模块的 RXD(接收端)。
    • GND 需连接在一起以保证信号的公共参考。

二、串口通信基本配置

1. STM32 串口配置

以 STM32CubeMX 和 HAL 库为例:

1.1 硬件配置
  • 时钟源: 启用 USART 的时钟(比如:APB1 或 APB2)。
  • 引脚配置: 将 USART 的 TX/RX 引脚设置为 Alternate Function 模式。
1.2 CubeMX 配置

在 CubeMX 中:

  1. 打开 USARTx 外设,启用 Asynchronous 模式。
  2. 设置波特率(通常 9600、115200 等),并配置:
    • 数据位:8 位
    • 停止位:1 位
    • 校验:无校验
    • 硬件流控:无

2. 串口助手(电脑端)的配置

使用串口助手软件(如 SScom),按以下步骤操作:

  1. 选择正确的 COM 端口: 在设备管理器中查看 STM32 的虚拟串口号(如 COM3)。
  2. 配置波特率等参数: 波特率、数据位、停止位和校验位需与 STM32 的设置一致。
  3. 打开串口后即可接收 STM32 发送的数据。

三、调试与查看数据

  1. 通过串口助手查看数据 数据通过串口助手的软件窗口实时显示,确保编码格式正确(通常选择 ASCII 或 HEX)。

  2. 硬件问题排查

    • 确认硬件连线正确。
    • 使用示波器或逻辑分析仪查看串口波形,检查电平是否正常。


       

      在 STM32 开发中,串口通信(UART)是常用的通信方式之一。以下是详细的步骤和注意事项,包括如何实现数据发送、接收,以及配置相关的硬件和软件。


      一、STM32 串口通信原理

    • 发送端:STM32 STM32 的串口模块(USART)通过 UART 协议将数据位(包括起始位、数据位、校验位和停止位)串行输出到 TX 引脚。

    • 接收端:电脑助手 电脑通过串口助手软件(如 SScom、SecureCRT 等)接收 STM32 发送的数据,解码并显示。

    • 硬件连接

      • TXD(STM32 发送端)连接到电脑串口模块的 RXD(接收端)。
      • GND 需连接在一起以保证信号的公共参考。

    • 二、串口通信基本配置

      1. STM32 串口配置

      以 STM32CubeMX 和 HAL 库为例:

      1.1 硬件配置
    • 时钟源: 启用 USART 的时钟(比如:APB1 或 APB2)。
    • 引脚配置: 将 USART 的 TX/RX 引脚设置为 Alternate Function 模式。
    • 1.2 CubeMX 配置

      在 CubeMX 中:

    • 打开 USARTx 外设,启用 Asynchronous 模式。
    • 设置波特率(通常 9600、115200 等),并配置:
      • 数据位:8 位
      • 停止位:1 位
      • 校验:无校验
      • 硬件流控:无
    • 生成代码。
    • 1.3 初始化代码

      生成的代码中包含初始化函数,例如:

       

      1.4 数据发送代码

      使用 HAL_UART_Transmit 函数发送数据:

       

      1.5 数据接收代码(轮询模式)

      使用 HAL_UART_Receive 函数接收数据:

       

      2. 串口助手(电脑端)的配置

      使用串口助手软件(如 SScom),按以下步骤操作:

    • 选择正确的 COM 端口: 在设备管理器中查看 STM32 的虚拟串口号(如 COM3)。
    • 配置波特率等参数: 波特率、数据位、停止位和校验位需与 STM32 的设置一致。
    • 打开串口后即可接收 STM32 发送的数据。

    • 三、调试与查看数据

    • 通过串口助手查看数据 数据通过串口助手的软件窗口实时显示,确保编码格式正确(通常选择 ASCII 或 HEX)。

    • 硬件问题排查

      • 确认硬件连线正确。
      • 使用示波器或逻辑分析仪查看串口波形,检查电平是否正常。

    • 四、完整的示例程序

      发送“Hello, UART!”到串口助手

      4.1 主程序
       
      4.2 必备的 STM32 外设初始化代码

      包含 GPIO、时钟等初始化函数(CubeMX 自动生成)。


      五、注意事项

    • 波特率的匹配: STM32 和电脑助手的波特率必须一致。
    • 电平匹配: STM32 的串口为 TTL 电平,若使用 RS232 接口需添加电平转换芯片(如 MAX232)。
    • 调试工具:
      • 可用串口助手接收数据,调试发送内容。
      • 使用 STM32 的 SWD 接口进行代码调试和断点跟踪。

    • 总结

      通过这个简单的串口发送程序,我们可以实现 STM32 向电脑串口助手发送数据的基本功能。下一节我们将详细讲解串口数据的接收方法,包括如何解析收到的数据并进行处理。

接下一来就是,我学习的重点了   用标准库写一个串口发送程序

连接方式

标准库介绍
 

TM32 USART 库函数详解

STM32 的 USART 库函数是通过标准外设库(StdPeriph Library)提供的接口,用于初始化、配置、控制 USART 外设,以及实现串口通信功能。以下对这些函数的作用、使用方法和关键点进行详细说明,并提供示例代码。


1. 函数详细说明

(1)USART 初始化和配置函数
函数作用
void USART_DeInit(USART_TypeDef* USARTx)将指定的 USART 外设寄存器恢复为默认值。用于复位配置。
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct)初始化 USART 外设,包括波特率、数据位、停止位等参数配置。
void USART_StructInit(USART_InitTypeDef* USART_InitStruct)USART_InitTypeDef 结构体初始化为默认值(一般用于快速配置前设置默认参数)。
(2)时钟相关函数
函数作用
void USART_ClockInit(USART_TypeDef* USARTx, USART_ClockInitTypeDef* USART_ClockInitStruct)配置 USART 的同步时钟模式(如 SPI 模式需要)。
void USART_ClockStructInit(USART_ClockInitTypeDef* USART_ClockInitStruct)初始化 USART_ClockInitTypeDef 结构体为默认值。
(3)使能和中断相关函数
函数作用
void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState)使能或禁用指定的 USART 外设。
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState)使能或禁用 USART 的中断(如接收、发送完成中断)。
(4)DMA 功能
函数作用
void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState)使能或禁用 USART 的 DMA 传输请求(支持发送或接收)。
(5)通信模式和高级配置
函数作用
void USART_SetAddress(USART_TypeDef* USARTx, uint8_t USART_Address)配置 USART 的地址(多处理器通信模式下使用)。
void USART_WakeUpConfig(USART_TypeDef* USARTx, uint16_t USART_WakeUp)配置 USART 唤醒模式。
void USART_ReceiverWakeUpCmd(USART_TypeDef* USARTx, FunctionalState NewState)使能或禁用接收器的唤醒功能。
(6)数据收发函数
函数作用
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)向发送数据寄存器写入数据,发送数据。
uint16_t USART_ReceiveData(USART_TypeDef* USARTx)从接收数据寄存器读取数据。
(7)标志位与中断状态管理
函数作用
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG)获取指定的 USART 标志位状态(如发送完成、接收完成)。
void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG)清除指定的 USART 标志位。
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT)获取指定的 USART 中断状态。
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT)清除指定的 USART 中断挂起标志。

接下来我们就要根据上述框图来配置USART的的发送程序,根据程序上述蓝色框图,我们要让单片机发送程序,仅需将我们要发送的程序放到TX管脚即可!(接收部分下节再讲)

具体配置如下

#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>void Serial_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIO_InitStructrue;GPIO_InitStructrue.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructrue.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructrue.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructrue);USART_InitTypeDef USART1_InitStructure;USART1_InitStructure.USART_BaudRate = 9600;USART1_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART1_InitStructure.USART_Mode = USART_Mode_Tx;USART1_InitStructure.USART_Parity = USART_Parity_No ;USART1_InitStructure.USART_StopBits = USART_StopBits_1;USART1_InitStructure.USART_WordLength = USART_WordLength_8b;USART_Init(USART1,&USART1_InitStructure);USART_Cmd(USART1,ENABLE);
}

包含头文件

 

c

复制代码

#include "stm32f10x.h" // STM32F10x 系列的设备头文件 #include <stdio.h> #include <stdarg.h>

  • stm32f10x.h

    • 包含 STM32F10x 系列微控制器的外设寄存器定义和标准外设库支持。
    • 提供对 GPIO、USART 等外设的配置和操作功能。
  • stdio.hstdarg.h

    • 提供标准输入输出函数,如 printf
    • 如果需要处理可变参数,这两个头文件是必要的。

2. 函数 Serial_Init

该函数的作用是初始化串口1(USART1)以及相关的 GPIO 引脚。

2.1 使能时钟
 

c

复制代码

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

  • RCC_APB2PeriphClockCmd
    • 用于使能外设的时钟。
    • RCC_APB2Periph_USART1:使能 USART1 的时钟。
    • RCC_APB2Periph_GPIOA:使能 GPIOA 的时钟(USART1 的 TX 引脚位于 GPIOA9)。
2.2 配置 GPIO
 

c

复制代码

GPIO_InitTypeDef GPIO_InitStructrue; GPIO_InitStructrue.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出模式(用于串口 TX) GPIO_InitStructrue.GPIO_Pin = GPIO_Pin_9; // 配置 GPIOA 的第 9 引脚(USART1 TX) GPIO_InitStructrue.GPIO_Speed = GPIO_Speed_50MHz; // 输出速率为 50MHz GPIO_Init(GPIOA, &GPIO_InitStructrue); // 初始化 GPIOA9

  • 配置 GPIOA 引脚 9 为串口 TX(传输引脚)。
    • GPIO_Mode_AF_PP:复用推挽输出模式,适用于串口功能。
    • GPIO_Pin_9:USART1 的 TX 引脚。
    • GPIO_Speed_50MHz:输出速度设为 50 MHz(用于快速信号传输)。
2.3 配置 USART1
 

c

复制代码

USART_InitTypeDef USART1_InitStructure; USART1_InitStructure.USART_BaudRate = 9600; // 波特率为 9600 USART1_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 无硬件流控 USART1_InitStructure.USART_Mode = USART_Mode_Tx; // 工作模式:仅发送(Tx) USART1_InitStructure.USART_Parity = USART_Parity_No; // 无校验位 USART1_InitStructure.USART_StopBits = USART_StopBits_1; // 停止位:1 USART1_InitStructure.USART_WordLength = USART_WordLength_8b; // 数据位:8 位 USART_Init(USART1, &USART1_InitStructure); // 初始化 USART1

  • 配置串口的通信参数:
    • 波特率:9600 波特。
    • 硬件流控:禁用(常用于硬件握手信号)。
    • 工作模式:仅发送模式(可以扩展为接收和发送)。
    • 校验位:无校验位。
    • 停止位:1 个停止位。
    • 数据位:8 位。
2.4 使能 USART1
 

c

复制代码

USART_Cmd(USART1, ENABLE);

  • 打开 USART1,使能其工作。

总结

这段代码完成了以下工作:

  1. 使能时钟:

    • 为 GPIOA 和 USART1 启用外设时钟。
  2. 配置 GPIO:

    • 将 GPIOA 的第 9 引脚配置为 USART1 的 TX 引脚(推挽输出模式)。
  3. 配置串口参数:

    • 波特率:9600。
    • 数据位:8 位。
    • 停止位:1 位。
    • 无校验位。
    • 无硬件流控。
  4. 使能 USART1:

    • 启用 USART1,使其能够发送数据。

注意事项

  • 接收功能:目前只启用了发送模式。如果需要接收数据,还需配置 RX 引脚(GPIOA10)并将模式改为 USART_Mode_Tx | USART_Mode_Rx
  • 波特率匹配:确保外部接收设备的波特率与 USART1 的设置一致。
  • 中断或 DMA:如果需要更高效的串口通信,可以启用 USART 的中断或 DMA 功能。


     

接下来就是写几个库函数

这段代码的详细解释

函数 Serial_Printf 的作用是通过串口发送一个格式化的字符串。它模仿了标准库中的 printf 函数,用于将格式化后的数据通过串口输出。


函数功能

  • 输入参数:

    • char* format:格式化字符串,用于定义输出格式(如 %d 表示整数,%s 表示字符串)。
    • ...:可变参数,用于提供格式化字符串中占位符对应的实际值。
  • 实现流程:

    1. 将格式化字符串和对应的可变参数组合成一个完整的字符串。
    2. 将生成的字符串通过串口发送。

代码逐步解析

1. 定义缓冲区
 

c

复制代码

char String[100];

  • 定义一个字符数组 String,大小为 100,用于存储格式化后的字符串。
  • 注意:String 的大小应该足够容纳格式化后的字符串。如果格式化结果超出 100 个字符,会导致缓冲区溢出。
  • 可用 snprintf 替代 vsprintf 来限制格式化结果的长度。

2. 定义可变参数列表
 

c

复制代码

va_list arg;

  • va_list 是一个类型,用于存储和访问可变参数。
  • 它由头文件 <stdarg.h> 定义,是处理可变参数的核心工具。

3. 初始化可变参数列表
 

c

复制代码

va_start(arg, format);

  • 功能:
    • 初始化 arg,使其指向第一个可变参数。
    • 参数 format 是固定参数,它告诉 va_start 可变参数从哪里开始。
  • 原理:
    • 在函数调用时,固定参数和可变参数在内存中的位置是连续的。
    • va_start 通过 format 确定固定参数的位置,从而找到第一个可变参数的位置。

4. 格式化字符串
 

c

复制代码

vsprintf(String, format, arg);

  • 功能:
    • 根据 format 和可变参数 arg,将格式化后的结果存入 String
    • vsprintf 是标准库中的函数,作用类似于 sprintf,但支持可变参数。
  • 参数解释:
    • String:用于存储格式化结果的缓冲区。
    • format:格式化字符串,定义输出格式。
    • arg:可变参数列表,包含需要插入到格式化字符串中的值。
  • 示例:
     

    c

    复制代码

    char buffer[100]; va_list args; va_start(args, "Value: %d\n"); vsprintf(buffer, "Value: %d\n", args); // 如果传入的可变参数是 42,则 buffer 的内容是 "Value: 42\n"。


5. 清理可变参数列表
 

c

复制代码

va_end(arg);

  • 功能:
    • 清理 va_list,释放相关资源。
    • va_startva_end 之间,arg 的内容是有效的。调用 va_end 后,它不能再被访问。

6. 发送字符串
 

c

复制代码

Serial_SendString(String);

  • 功能:
    • 调用 Serial_SendString 函数,将格式化后的字符串通过串口发送出去。
    • Serial_SendString 会逐字符发送缓冲区 String 的内容,直到遇到字符串的结束符 \0

示例运行过程

假设调用如下代码:

 

c

复制代码

Serial_Printf("Temperature: %d°C, Humidity: %.2f%%\n", 25, 65.23);

运行过程如下:

  1. format 的内容是 "Temperature: %d°C, Humidity: %.2f%%\n"
  2. 可变参数列表 arg 包含两个值:2565.23
  3. vsprintfformatarg 合并,生成的字符串为:
     

    swift

    复制代码

    "Temperature: 25°C, Humidity: 65.23%\n"

  4. Serial_SendString 将上述字符串逐字节发送到串口。

注意事项

  1. 缓冲区大小限制:

    • 如果格式化后的字符串超过了 String[100] 的容量,可能会导致缓冲区溢出。
    • 可以使用 vsnprintf 替代 vsprintf,限制格式化结果的长度。例如:
       

      c

      复制代码

      vsnprintf(String, sizeof(String), format, arg);

  2. 性能:

    • 该实现直接调用 Serial_SendString 将整个字符串发送,性能较高。
    • 如果字符串过长,发送时间可能会较久。
  3. 线程安全性:

    • 该实现没有考虑多线程环境。如果多个线程同时调用 Serial_Printf,可能会出现数据混乱。
    • 可以通过互斥锁或其他同步机制解决。

总结

  • 作用:Serial_Printf 是一个自定义的格式化输出函数,支持通过串口发送格式化字符串。
  • 实现原理:
    • 使用可变参数列表(va_list)。
    • 利用标准库函数 vsprintf 格式化字符串。
    • 调用 Serial_SendString 通过串口发送。
  • 优点:
    • 灵活性强,支持多种数据格式的输出。
    • 易于扩展,类似于标准库中的 printf
  • 改进建议:
    • 使用 vsnprintf 提升安全性,防止缓冲区溢出。
    • 添加线程同步以支持多线程环境。

这种可变函数特别重要,在以后自己想要打印别的函数

可变参数函数(Variadic Functions)是一种函数设计模式,它允许函数接收数量可变的参数。C语言中,通过 <stdarg.h> 提供的工具(如 va_listva_startva_argva_end),可以实现这种功能。


作用

可变参数函数的主要作用是为函数调用提供灵活性,适应输入参数数量和类型不固定的场景。以下是一些典型应用:

  1. 格式化输出:

    • 函数如 printf 可以接收不同数量和类型的参数,灵活地处理格式化字符串和对应的数据。
       

      c

      复制代码

      printf("Hello, %s! You have %d messages.\n", "User", 5);

  2. 日志记录:

    • 日志函数 log(const char* format, ...) 可以根据不同的输入生成对应的日志消息。
       

      c

      复制代码

      log("Error code: %d, Message: %s\n", 404, "Not Found");

  3. 多参数计算:

    • 例如实现一个简单的求和函数 sum(int count, ...)
       

      c

      复制代码

      int sum(int count, ...) { int total = 0; va_list args; va_start(args, count); for (int i = 0; i < count; i++) { total += va_arg(args, int); } va_end(args); return total; } sum(3, 1, 2, 3); // 返回 6

  4. 通用处理接口:

    • 允许定义一个函数处理多种类型的数据,减少代码重复。例如在嵌入式系统中,可变参数函数用于调试信息的格式化输出。

好处

1. 提高灵活性
  • 可变参数函数适用于输入参数数量或类型不确定的情况,可以根据需求动态调整输入参数,避免定义多个类似的函数。
  • 例如,printf 函数通过解析格式化字符串自动匹配参数,无需为不同的输出需求定义多个函数。
2. 简化代码
  • 可以用一个通用函数代替多个特定函数,减少代码重复,提高代码可维护性。
  • 示例:
     

    c

    复制代码

    void print_hello(int times) { for (int i = 0; i < times; i++) { printf("Hello\n"); } }

3. 扩展性强
  • 新的需求只需修改格式化字符串或参数传递方式,而不需要修改函数本身。
  • 示例:
    • 增加新参数的日志记录需求,只需调整调用方式,而无需重写函数逻辑。
4. 支持通用接口
  • 在接口设计中,可变参数函数能够统一处理不同类型和数量的输入,提供一致的接口。
  • 例如,设计一个数据打包函数 pack(int count, ...),可以根据数据类型和数量自动生成字节流。

局限性

尽管可变参数函数提供了许多优势,但它也有一些潜在的局限性和风险:

1. 缺乏类型检查
  • 编译器无法对可变参数的类型和数量进行验证,容易引发运行时错误。
     

    c

    复制代码

    printf("%d", "string"); // 类型不匹配,可能导致未定义行为

2. 难以理解和调试
  • 可变参数函数的实现较为复杂,维护时需要仔细检查 va_list 的使用,特别是错误传参或遗漏 va_end 时,可能导致不可预测的行为。
3. 性能开销
  • 可变参数的处理需要额外的时间开销,特别是在函数被频繁调用的情况下,性能可能受到一定影响。
4. 不适用于所有场景
  • 如果参数类型和数量可以提前确定,使用普通函数往往更安全和高效。

应用场景总结

可变参数函数适合以下场景:

  1. 参数数量和类型不固定。
  2. 需要统一接口处理不同类型的数据。
  3. 提供通用的输出格式(如日志记录、调试信息、格式化输出等)。

使用建议

  1. 安全使用:
    • 使用 vsnprintf 替代 vsprintf 以避免缓冲区溢出。
    • 明确函数的用途,严格控制输入格式。
  2. 合理场景:
    • 对于参数确定的情况,优先选择普通函数。
    • 在接口设计中,尽量提供一个明确的标志(如参数数量或格式字符串)以描述参数内容。
  3. 注重文档和注释:
    • 为可变参数函数编写清晰的文档,描述参数的用法和格式。

总结

可变参数函数的主要好处是灵活、简化和通用,但它也需要小心处理,特别是在参数类型和数量动态变化的场景下。通过合理使用,可以极大提高代码的可扩展性和复用性,同时降低维护成本。


整个发送代码如下!
 

#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>void Serial_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIO_InitStructrue;GPIO_InitStructrue.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructrue.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructrue.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructrue);USART_InitTypeDef USART1_InitStructure;USART1_InitStructure.USART_BaudRate = 9600;USART1_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART1_InitStructure.USART_Mode = USART_Mode_Tx;USART1_InitStructure.USART_Parity = USART_Parity_No ;USART1_InitStructure.USART_StopBits = USART_StopBits_1;USART1_InitStructure.USART_WordLength = USART_WordLength_8b;USART_Init(USART1,&USART1_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, uint8_t Lenght)
{uint16_t i;for(i=0; i<Lenght; i++){Serial_SendByte(Array[i]);}
}void Serial_SendString(char* String)
{uint8_t i;for(i=0; String[i] != '\0'; i++){Serial_SendByte(String[i]);}
}uint32_t Result(uint32_t X, uint32_t Y)
{uint8_t result = 1;while(Y--){result = result * X;}return result;
}void Serial_SendNum(uint32_t Num, uint16_t Lenght)
{uint16_t i;uint32_t ww;for(i=Lenght; i>0; i--){ww = Result(10,i-1);Serial_SendByte((Num/ww )% 10 + '0');}}int fputc(int ch, FILE* f)
{Serial_SendByte(ch);return ch;
}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);
}重定向C库函数printf()到串口,重定向后可使用printf();
//int fputc(int ch,FILE *f)
//{
//	USART_SendData(USART1,(uint8_t)ch);
//	while(!(USART_GetFlagStatus(USART1,USART_FLAG_TC)));
//	return ch;
//}

下一节是接收程序代码!请看下节!!!!!!!!


http://www.ppmy.cn/ops/135034.html

相关文章

Electron教程2-第一个应用

玩转Electron2 前提条件从开源程序electron-tabs入手运行效果图 解读主进程窗口渲染进程自定义标签问题 前提条件 Electron教程1-初学入门 从开源程序electron-tabs入手 下载源码 解压 进入目录 cnpm i npm run demo 运行效果图 解读 app.js 入口文件 electron-tabs.ht…

TypeORM在Node.js中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 TypeORM在Node.js中的应用 TypeORM在Node.js中的应用 TypeORM在Node.js中的应用 引言 TypeORM 概述 定义与特点 发展历程 TypeO…

学习笔记026——Redis基本操作命令

Redis是一个开源的、基于内存的键值对&#xff08;Key-Value&#xff09;数据库。 它以其高性能、丰富的数据类型支持以及多种高级特性&#xff0c;在多个领域得到了广泛的应用。 文章目录 1、连接redis2、ping命令3、切换数据库4、get/set&#xff08;读写键值命令&#xff09…

Android 开发构建问题

1.Android studio gradle 同步慢 在Android Studio中打开新的项目 同步新项目可能会出现 gradle zip包下载慢的问题&#xff0c;我们可以尝试替换源 可以把 services.gradle.org/distributions 可能需要半小时以上替换为 mirrors.cloud.tencent.com/gradle/ 这样下载速度明…

并查集 poj 2524,1611,1703,2236,2492,1988 练习集【蓝桥杯备赛】

目录 前言 并查集优势 Ubiquitous Religions poj 2524 问题描述 问题分析 代码 The Suspects poj 1611 问题描述 问题分析 代码 Wireless Network poj 2236 问题描述 问题分析 代码 分类 带权并查集合 权值树构建步骤 Find them, Catch them poj 1703 问题描述 问题分…

RPA真的是人工智能吗?

1. RPA与AI的定义与区别 1.1 RPA的定义与特点 机器人流程自动化&#xff08;Robotic Process Automation&#xff0c;简称RPA&#xff09;是一种软件技术&#xff0c;它通过模拟人类用户的操作行为来自动执行重复性、基于规则的任务。RPA的核心特点包括&#xff1a; 非侵入性…

Vue.js 前端框架入门

简介 Vue.js 是一个构建用户界面的渐进式JavaScript框架。本文将带你了解Vue项目的目录结构&#xff0c;启动顺序&#xff0c;并逐步指导你安装必要的环境&#xff0c;以及如何开发一个基础的Vue项目。 需要的环境 Node.js&#xff1a;Vue.js 项目依赖于Node.js&#xff0c;…

HarmonyOS知识点

HarmonyOS应用模型Stage&FA 、ArkTS、ArkUI Stage模型&#xff1a; Module - UIAbility - Page - component 装饰器Entry、Component、CustomDialog、State、关键字struct、函数build() 系统组件&#xff08;Text Column Row Scroll&#xff09;、自定义组件 、组件复用、…