立创·天空星开发板-GD32F407VE-USART

news2025/1/21 12:15:03

本文以 立创·天空星开发板-GD32F407VET6-青春版 作为学习的板子,记录学习笔记。

立创·天空星开发板-GD32F407VE-USART

    • 基础通信概念
      • 同步通信 & 异步通信
      • 串行通信 & 并行通信
      • 双工 & 单工
      • 通讯速率
        • 码元
    • 串口通信
      • 数据帧
    • 串口封装

基础通信概念

通信协议是网络中(包括互联网)设备之间交换信息时所必须遵守的规则的正式描述。

同步通信 & 异步通信

  • 分类依据:通信过程中发送方和接收方是否使用相同的时钟频率。
  • 同步通信(Synchronous Communication):发送方和接收方使用相同的时钟频率,数据以比特流(数据帧)的形式连续传输。数据帧包括同步字符、数据部分和校验码等。
  • 异步通信(Asynchronous Communication):发送方和接收方使用各自的时钟频率,数据以字符为单位进行传输。每个字符数据前有一个起始位,后有停止位,用于标识字符的开始和结束。

故而,同步通信和异步通信的最大区别在于传输数据时是否需要时钟信号同步。有钟为同,无钟为异。

串行通信 & 并行通信

  • 分类依据:数据在传输线上的传输方式。
  • 串行通信(Serial Communication):数据的各个位在同一根数据线上逐位发送和接收。串行通信传输速度慢,但传输距离远,适合远距离通信。
  • 并行通信(Parallel Communication):数据的各个位同时在多根数据线上发送或接收。并行通信传输速度快,但成本高,适合短距离通信。

故而,串行通信和并行通信的最大区别在于传输数据时数据线的根数。单根为串,多根为并。

双工 & 单工

  • 分类依据:通信双方的信息传输方向。
  • 双工(Duplex)
    • 全双工(Full-Duplex):通信双方可以同时发送和接收数据。
    • 半双工(Half-Duplex):通信双方可以相互发送和接收数据,但不能同时进行。
  • 单工(Simplex):通信是单向的,一方只能发送数据,另一方只能接收数据。

故而,双工和单工的最大区别在于传输方向是否是双向的。双传为双工,单传为单工。

通讯速率

衡量通讯性能的一个非常重要的参数就是通讯速率

  • 比特率:每秒钟传输的二进制位数,单位为(bit/s)
  • 波特率:每秒钟传输了多少个码元
码元

码元是通讯信号调制的概念,通讯中常用时间间隔相同的符号来表示一个二进制数字,这样的信号称为码元。

如果在通讯传输中,用 0V 表示数字 0,5V 表示数字 1,那么一个码元可以表示两种状态 0 和 1,所以一个码元等于一个二进制比特位,此时波特率的大小与比特率一致。

如果在通讯传输中,有 0V、2V、4V 以及 6V 分别表示二进制数 00、01、10、11,那么每个码元可以表示四种状态,即两个二进制比特位,所以码元数是二进制比特位数的一半,这个时候的波特率为比特率的一半。

因为很多常见的通讯中一个码元都是表示两种状态(0和1),所以常常直接以波特率来表示比特率。

串口通信

Universal Asynchronous Receiver Transmitter 即 : 通用异步收发器

串口通信是一种通用的串行的异步通信总线,该总线有两条数据线,可以实现全双工的发送和接收,在嵌入式系统中常用于主机与辅助设备之间的通信。

数据帧

  • 在串口通信中,数据帧是传输数据的单元。
  • 一帧数据包含多个组成部分,以确保数据的正确传输和接收。
    数据帧
    以传递一个字母 k 为例,若数据为采用八位,并使用低位先行的方式进行传输。过程大致如下:
  • 字母 k 的二进制为 01101011
  • 采用低位先行的传输方式的话,其传输顺序应该是 11010110
  • 传输波形大致如下所示:
    串口数据发送波形

串口封装

天空星开发板的 PA9 和 PA10 对应的是 USART0 的 TX 和 RX 功能。
运用库函数,封装代码如下:

  • ExtendedUSART.h
#ifndef __EXTENDED_USART_H__
#define __EXTENDED_USART_H__

#include "gd32f4xx.h"
#include <stdio.h>

// 发送配置
#define USART_TX_RCU        RCU_GPIOA
#define USART_TX_PORT       GPIOA
#define USART_TX_PIN        GPIO_PIN_9
#define USART_TX_ALT        GPIO_AF_7
// 接收配置
#define USART_RX_RCU        RCU_GPIOA
#define USART_RX_PORT       GPIOA
#define USART_RX_PIN        GPIO_PIN_10
#define USART_RX_ALT        GPIO_AF_7
// 中断配置
#define USART_RCU           RCU_USART0
#define USART_NUM           USART0
#define USART_IRQ           USART0_IRQn
#define USART_IRQ_Handler   USART0_IRQHandler

/*!
    \brief    初始化串口 0
    \param[in]  b  : [uint8_t] 一个字节的数据
    \param[out] none
    \retval     none
*/
void USART0_config();

/*!
    \brief    往串口 0 发送1个字节数据
    \param[in]  b  : [uint8_t] 一个字节的数据
    \param[out] none
    \retval     none
*/
void USART0_send_byte(uint8_t b);

/*!
    \brief    往串口 0 发送多个字节数据
    \param[in]  dat  : [uint8_t*] 字节数据首元素地址
    \param[in]  len  : [uint32_t] 字节数据的长度
    \param[out] none
    \retval     none
*/
void USART0_send_data(uint8_t* dat, uint32_t len);

/*!
    \brief    往串口 0 发送发送字符串 (结尾标记\0)
    \param[in]  dat  : [char*] 字符串首字符地址
    \param[out] none
    \retval     none
*/
void USART0_send_string(char *dat);

#endif
  • ExtendedUSART.c
#include "ExtendedUSART.h"


// 串口接收缓冲区大小
#define USART_RECEIVE_LENGTH  1024
// 串口接收数据缓冲区
static uint8_t g_recv_buff[USART_RECEIVE_LENGTH];
// 接收到字符的长度
static uint32_t g_recv_length = 0;


/*!
    \brief    初始化串口 0
    \param[in]  b  : [uint8_t] 一个字节的数据
    \param[out] none
    \retval     none
*/
void USART0_config() {
    // GPIO 配置: TXD, PA9
    rcu_periph_clock_enable(USART_TX_RCU);
    gpio_mode_set(USART_TX_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, USART_TX_PIN);
    gpio_af_set(USART_TX_PORT, USART_TX_ALT, USART_TX_PIN);
    // GPIO 配置: TXD, PA10
    rcu_periph_clock_enable(USART_RX_RCU);
    gpio_mode_set(USART_RX_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, USART_RX_PIN);
    gpio_af_set(USART_RX_PORT, USART_RX_ALT, USART_RX_PIN);

    // 启用串口时钟
    rcu_periph_clock_enable(USART_RCU);
    // 复位串口
    usart_deinit(USART_NUM);

    usart_baudrate_set(USART_NUM, 115200);	            // 波特率
    usart_parity_config(USART_NUM, USART_PM_NONE);      // 校验位, 无校验(USART_PM_NONE), 偶校验(USART_PM_EVEN), 奇校验(USART_PM_ODD)
    usart_word_length_set(USART_NUM, USART_WL_8BIT);    // 数据位数
    usart_stop_bit_set(USART_NUM, USART_STB_1BIT);      // 停止位
    usart_data_first_config(USART_NUM, USART_MSBF_LSB); // 先发送高位还是低位

    // 发送功能配置
    usart_transmit_config(USART_NUM, USART_TRANSMIT_ENABLE);
	
    // 接收功能配置
    usart_receive_config(USART_NUM, USART_RECEIVE_ENABLE);
    // 接收中断配置
    nvic_irq_enable(USART_IRQ, 2, 2);
    // 串口中断能
    usart_interrupt_enable(USART_NUM, USART_INT_RBNE);
    usart_interrupt_enable(USART_NUM, USART_INT_IDLE);
	
    // 串口使能
    usart_enable(USART_NUM);
}

/*!
    \brief    往串口 0 发送1个字节数据
    \param[in]  b  : [uint8_t] 一个字节的数据
    \param[out] none
    \retval     none
*/
void USART0_send_byte(uint8_t b) {
    //通过USART发送
    usart_data_transmit(USART0, b);
    //判断缓冲区是否已经空了
    while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
}

/*!
    \brief    往串口 0 发送多个字节数据
    \param[in]  dat  : [uint8_t*] 字节数据首元素地址
    \param[in]  len  : [uint32_t] 字节数据的长度
    \param[out] none
    \retval     none
*/
void USART0_send_data(uint8_t* dat, uint32_t len) {
    while(dat && len--) {
        USART0_send_byte(*dat);
        dat++;
    }
}

/*!
    \brief    往串口 0 发送发送字符串 (结尾标记\0)
    \param[in]  dat  : [char*] 字符串首字符地址
    \param[out] none
    \retval     none
*/
void USART0_send_string(char *dat) {
    //满足: 1.data指针不为空  2.发送的数据不是\0结束标记
    while(dat && *dat) {
        USART0_send_byte((uint8_t)(*dat));
        dat++;
    }
}

int fputc(int ch, FILE *f) {
    USART0_send_byte((uint8_t)ch);
    return ch;
}

// 声明弱函数, 用于接收来自串口 0 的数据并回显
// 外部可以通过声明同名强函数来覆盖该函数的默认行为
__attribute__((weak)) void USART0_on_received(uint8_t* dat, uint32_t len) {
	USART0_send_data(dat,len);
}

// 串口接收数据的中断处理函数
void USART_IRQ_Handler(void) {
    if ((usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)) == SET) {
        usart_interrupt_flag_clear(USART0, USART_INT_FLAG_RBNE);
        uint16_t value = usart_data_receive(USART0);

        g_recv_buff[g_recv_length] = value;
        g_recv_length++;
    }
    if (usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE) == SET) {
        //读取缓冲区,清空缓冲区
        usart_data_receive(USART0);
        g_recv_buff[g_recv_length] = '\0';

        // g_recv_buff 为接收的数据, g_recv_length 为接收的长度
        USART0_on_received(g_recv_buff, g_recv_length);

        g_recv_length = 0;
    }
}
  • main.c
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"

#include "ExtendedUSART.h"

void USART0_on_received(uint8_t* dat, uint32_t len) {
	printf("Received: %s\r\n", dat);
}

int main(void) {
    systick_config();
    USART0_config();
	
    uint8_t cnt = 0;
    while(1) {
        USART0_send_byte(cnt++);
        USART0_send_byte(0x0D); // \r
        USART0_send_byte(0x0A); // \n
        USART0_send_string("This is string!\r\n");
        printf("cnt = %d\r\n", cnt);
        if(cnt > 99) {
        	cnt = 0;
        }
        delay_1ms(1000);
    }
}

额外说明

  1. 如果希望通过 printf 函数将数据打印到串口助手上显示,需要重写 stdio.h 中的 fputc 函数。
  2. 如果希望调用方无论是否定义回调函数都能使得回调函数默认可用,可以采用定义弱函数的方式来实现。也就是我这边提供的 ExtendedUSART.c 文件中的 USART0_on_received 函数的定义方式,即便是在 main.c 中没有定义,照样能回显数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1801383.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

美颜相机「BeautyCam」v12.0.80 祛广告解索会员版(美妆相机功能,展现女神魅力)

软件介绍 美颜相机&#xff0c;一款由知名移动互联网企业Meitu Inc.开发的移动设备照片编辑与美化应用&#xff0c;起初主要针对娱乐消费市场&#xff0c;随后集成了商业营销功能。目前&#xff0c;它已跻身全球最受欢迎的手机摄影应用程序之列。在中国&#xff0c;美颜相机和…

Web前端指南

前言 前端开发员主要负责网站的设计、外观和感觉。他们设计引人入胜的在线用户体验,激发用户兴趣,鼓励用户重复访问。他们与设计师密切合作,使网站美观、实用、快捷。 如果您喜欢创造性思维、打造更好的体验并对视觉设计感兴趣,这将是您的理想职业道路。 探讨前端、后端以…

Llama模型家族之拒绝抽样(Rejection Sampling)(五)蒙特卡罗算法在拒绝抽样中:均匀分布与样本接受标准

LlaMA 3 系列博客 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;一&#xff09; 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;二&#xff09; 基于 LlaMA 3 LangGraph 在windows本地部署大模型 &#xff08;三&#xff09; 基于 LlaMA…

gulimall-search P125 springboot整合elasticsearch版本冲突

一、问题 spring-boot.version 2.2.4.RELEASE,在gulimall-search pom.xml中添加elasticsearch.version 7.4.2后&#xff0c;发现出现如下问题&#xff1a;elasticsearch版本是springboot引入的6.8.6&#xff0c;没有变为7.4.2。 二、原因 在gulimall-search 的pom文件中&#…

HTML,CSS,JavaScript实例——3D骰子,跨纬度蠕虫,动态登录表单。

文章目录 一、3D筛子1.HTML2.CSS 二、跨纬度蠕虫1.HTML2.CSS3.JS 三、动态登录表单1.HTML2.CSS 一、3D筛子 1.HTML <!--ring div starts here--> <div class"ring"><i style"--clr:#00ff0a;"></i><i style"--clr:#ff0057…

UI学习笔记(一)

UI学习 一&#xff1a;UIView基础frame属性隐藏视图对象&#xff1a;UIView的层级关系 二&#xff1a;UIWindow对象三&#xff1a;UIViewController基础UIViewController使用 四&#xff1a;定时器与视图移动五&#xff1a;UISwitch控件六&#xff1a;滑动条和进度条七&#xf…

前端三大主流框架

目录 1.概述 2.React 2.1.作用 2.2.诞生背景 2.3.版本历史 2.4.优缺点 2.5.应用场景 2.6.示例 2.7.未来展望 3.Vue 3.1.作用 3.2.诞生背景 3.3.版本历史 3.4.优缺点 3.5.应用场景 3.7.示例 3.8.未来展望 4.Angular 4.1.作用 4.2.诞生背景 4.3.版本历史 4…

从诺曼底登陆八十周年说起

昨天&#xff08;2024年6月6日&#xff09;是诺曼底登陆&#xff08;Normandy Campaign&#xff09;八十周年纪念日。媒体上有很多对相关纪念活动的报道。 诺曼底登陆战役&#xff0c;是第二次世界大战也是世界战争史上规模最大的登陆战役。敦刻尔克大撤退后&#xff0c;西欧大…

2. pytorch环境安装

概述 ​ 本文提供基于Anaconda环境Windows11操作系统的Pytorch深度学习环境的配置。深度学习环境分为GPU和CPU两大部分。使用GPU进行环境配置&#xff0c;需要保证电脑配有独立显卡&#xff0c;并且显卡驱动安装正常&#xff0c;详情见前文。 1. 创建新的虚拟环境用来配置Pyt…

Suse Linux ssh配置免密后仍需要输入密码

【问题描述】 Suse Linux已经配置了ssh免密&#xff0c;但无法ssh到目标服务器。 对自身的ssh登陆也需要输入密码。 系统–Suse 15 SP5 【重现步骤】 1.使用ssh-keygen -t rsa生产key文件 2.使用ssh-copy-id拷贝public key到目标机器(或者自身) 3.配置成功后ssh 目标时仍需要输…

const详解

关键字const用来定义常量&#xff0c;如果一个变量被const修饰&#xff0c;那么它的值就不能再被改变。 但是&#xff0c;可以通过取地址进行修改。 将const 在指针前进行修饰&#xff0c;那么就修饰指针所指向的变量。 但是指针变量可以被修改。 将const 在指针后进行修饰&am…

外挂知识库的基本知识与内容

外挂知识库 1.什么是rag&#xff1f; RAG,即LLM在回答问题或生成文本时&#xff0c;会先从大量文档中检索出相关的信息&#xff0c;然后基于这些信息生成回答或文本&#xff0c;从而提高预测质量。 2.外挂知识库的实现思路 只用几十万量级的数据对大模型进行微调并不能很好…

使用Python创建Word文档

使用Python创建Word文档 安装python-docx库创建Word文档代码效果 在这篇文章中&#xff0c;我们将介绍如何使用 Python创建一个Word文档。首先&#xff0c;我们需要安装python-docx库&#xff0c;然后通过一段简单的代码示例展示如何创建和编辑Word文档。 安装python-docx库 …

2024 年适用于 Mac 的 5 大免费录屏软件

要成为Mac的优秀屏幕录像机&#xff0c;捕获视频的高清质量和易于操作的界面是两个主要重要因素。此外&#xff0c;Mac上的付费屏幕录像机不仅可以输出高质量的屏幕捕获视频。您也可以在免费的视频捕获软件中获得类似的桌面录制服务。因此&#xff0c;如果您不需要以专业的方式…

企业应如何选择安全合规的内外网文件摆渡系统?

网络隔离是一种安全措施&#xff0c;旨在将网络划分为不同的部分&#xff0c;以减少安全风险并保护敏感信息。常见的隔离方式像物理隔离、逻辑隔离、防火墙隔离、虚拟隔离、DMZ区隔离等&#xff0c;将网络隔离成内网和外网。内外网文件摆渡通常指在内部网络&#xff08;内网&am…

yarn保姆级安装和使用

目录 前言 一、yarn简介 主要特性 使用场景 二、yarn的安装 yarn的下载 配置环境变量 三、yarn的常用命令 四、yarn的常用配置项 五、npm与yarn的区别 前言 本文旨在介绍如何安装和使用Yarn&#xff0c;以及它的一些常见用法。我们将从Yarn的基本概念开始&#xff0c;…

[C#]使用OpenCvSharp图像滤波中值滤波均值滤波高通滤波双边滤波锐化滤波自定义滤波

在使用OpenCvSharp进行图像滤波处理时&#xff0c;各种滤波方法都有其特定的用途和效果。以下是对中值滤波、均值滤波、高通滤波、双边滤波、锐化滤波和自定义滤波的详细解释和归纳&#xff1a; 中值滤波&#xff08;MedianBlur&#xff09; 原理与作用&#xff1a;中值滤波是…

学习Canvas过程中2D的方法、注释及感悟一(通俗易懂)

1.了解Canvas&#xff1a; Canvas是前端一个很重要的知识点&#xff0c;<canvas>标签用于创建画布绘制图形&#xff0c;通过JavaScript进行操作。它为开发者提供一个动态绘制图形的区域&#xff0c;用于创建图标、游戏动画、图像处理等。 对于能够熟练使用Canvas的开发者…

Python报错:IndentationError: unexpected indent问题的解决办法及原因

解决Python报错&#xff1a;IndentationError: unexpected indent问题的解决办法及原因 Python是一种注重可读性的编程语言&#xff0c;它使用缩进来定义代码块。如果你遇到了IndentationError: unexpected indent的错误&#xff0c;这意味着Python解释器在代码中遇到了意外的缩…

qq号码采集软件

寅甲QQ号码采集软件, 一款采集QQ号、QQ邮件地址&#xff0c;采集QQ群成员、QQ好友的软件。可以按关键词采集&#xff0c;如可以按地区、年龄、血型、生日、职业等采集。采集速度非常快且操作很简单。