首页 > 其他分享 >USART串口协议 和va_list,va_start,va_end,vsprintf

USART串口协议 和va_list,va_start,va_end,vsprintf

时间:2024-07-14 15:58:18浏览次数:9  
标签:va end USART list 参数 串口 数据

串口接口

通信的目的:将一个设备的数据传送到另一个设备扩展硬件系统
通讯协议: 制定通信的规则,通信双方按照协议规则进行数据收发。

在这里插入图片描述

注意: 差分信号一般传输速度和距离都会非常高。
多设备相当于老师在教师给所有同学讲课,点对点相当于老师找你到办公室谈话。

串口是一种应用十分广泛的通讯接口,串口成分低,容易使用、通讯线路简单,可实现两个设备的项目通讯。

单片机的串口可以使单片机与单片机、单片机与电脑(非常适合调试程序,USART串口协议的一大优势),单片机与各式各样的串口相互通讯,极大地扩展了单片机的应用范围,增强了单片机系统的硬件实力。

TX: Transmit(发送)
RX: Receive(接收)

硬件电路

简单双向串口通讯有两根通信线(发送端TX,接收端RX)
TX与RX要交叉连接
当只需单向的数据传输时,可以只接一根通信线
当电平标准不一致时,需要加电平转换芯片。
在这里插入图片描述

电平标准

电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电平与数据的对应关系,串口常用的电平标准有如下三种:

1.TTL 电平: +3.3V或者+5V 表示1,0V表示0
2. RS232电平: -3V—— -15V 表示1,+3—— +15V 表示0
3. RS485电平 : 两线压差+2——+6V表示1,-2—— -6 V表示0(差分信号)

异步通讯: 是一种数据传输方式,其中数据的发送和接受不需要双发时钟同步。也就是说,发送方和接收方可以在不同步的时钟频率下独立操作,并且数据传输时不预先协调的时刻进行的。

串口参数及时序

波特率:串口通讯的速度
起始位:标志一个数据帧的开始,固定为低电平
数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行
校验位: 用于数据验证,根据数据位计算得来。
停止位:用于数据帧间隔, 固定为高电平
在这里插入图片描述
在这里插入图片描述
USART (Universal Synchronous/ Asynchronous Receiver/Transmitter) 通用同步/异步收发器

USART是STM32内部集成的硬件外设,可根据数据寄存器的一个字节数据自动生成数据帧时序,从TX引脚发送出去,也可自动接受RX引脚的数据帧时序,拼接为一个字节数据,存放在数据寄存器里。

自带波特率发生器,最高达4.5Mbit/s

可配置数据位长度(8/9),停止位长度(0.5/1/1.5/2)

可选校验位(无校验/奇校验/偶校验)
支持同步模式、硬件流控制,DMA、智能卡、IrDA,LIN

STM32F103C8T6 USART 资源: USART1, USART2, USART3.
USART框图

在这里插入图片描述

USART基本结构

在这里插入图片描述

数据帧

在这里插入图片描述

数据帧 配置停止位

在这里插入图片描述

USART电路输入数据策略

USART电路比较复杂,输入的采样频率和波特率一致, 输入要对噪声有一点判断能力

起始位侦测

在这里插入图片描述
以波特率的16倍进行采样
忽略了前面没3个里面没有至少有2个0。不算检测验到起始位
开始重新补充下降沿。如果通过了数据采样,接受状态就由空闲变为起始位。之后接受数据位,都在第8、9、10次,进行采样。

数据采样

在这里插入图片描述
你看在8、9、10 位进行数据采样。
NE 是噪声标志位

波特率发生器

1.发送器和接收器的波特率由波特率寄存器BRR里的DIV确定
2. 计算公式: 波特率 = fpclk/(16div)
假如要配置波特率为9600 由于USART的频率为72MHz,
那么计算公式就是 9600 = 72000,000/(16
div)
div = 72MHz / 9600 / 16 = 468.75
将10进制转化为2进制

在这里插入图片描述

将USART硬件

在这里插入图片描述
CH340G_VCC是选择供电引脚
在这里插入图片描述
但是将跳线帽拔掉,依然可以给CH340供电

代码的编写

想知道怎么配置外设的GPIO的模式,可以到参考手册的外设GPIO配置找

数据模式

1.HEX模式/十六进制/二进制模式 : 以原始数据的形式显示。
2.文本模式/字符模式:以原始数据编码的形式显示。
在这里插入图片描述
在这里插入图片描述

如何使用printf ,并将printf重定向到串口。
第一种方式

在这里插入图片描述
使用use MIcro LIB

将#include<stdio.h> 放在Serial.h 中。
int fputc(int ch,FILE *f)
{
Serial_SendByte(ch);
return ch;

}

第二种方式
char String[100];
sprintf(String,"Num=%d\r\n",666);/// 不涉及重定向
Serial_SendString(String);
第三种方式

添加头文件 #include<stdarg.h>
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);
}

(1). va_list 是C语言的一个宏定义,用于表示一个变长参数列表的指针,可以通过宏va_start,va_arg 和 va_end 对变长参数列表进行访问和操作。在函数中需要接受不定数量的参数时,可以使用va_list来处理这些参数。

(2). va_start 是一个宏定义,用于在使用可变参数函数获取可变参数的起始地址。它的作用是初始化一个va_list类型的变量,使其指向可变参数列表的第一个参数。va_start宏需要两个参数,分别是一个va_list类型的变量和可变参数的在最后一个固定参数的地址.

(3).va_arg: 是一个宏,用于获取可变参数列表中的下一个参数值

va_arg(ap, type)

其中,ap 是 va_list 类型的可变参数列表指针,type 是要获取的参数的类型。va_arg 宏返回指定类型的参数值,并将可变参数列表指针 ap 向后移动到下一个参数。注意,调用 va_arg 宏之前必须先调用 va_start 宏初始化可变参数列表指针。
(4). va_end:是一个宏,用于结束使用 va_start 和 va_arg 宏定义的可变参数列表。它的作用是清理 va_list 类型变量,以便该变量可以被再次使用。

(5). vsnprintf 是一个函数,用于将格式化的字符串输出到指定的缓存区中,其参数列表。与printf类似,vsnprintf可以根据格式化字符串中的占位符,将后续的参数转化为对应的字符串并输出到缓存区中,但是与printf 不同的是,vsnprintf可以指定的最大长度,以避免缓存区溢出的问题。

(6).vsprintf 是 C 标准库中的一个函数,用于将格式化的数据写入一个字符串。与 sprintf 不同,vsprintf 允许你传递一个 va_list 类型的参数列表,而不是可变数量的参数。它通常用于编写需要处理可变参数的函数.

int vsprintf(char *str, const char *format, va_list ap);

#include <stdio.h>
#include <stdarg.h>

void my_printf(const char *format, ...) {
    char buffer[1024];   // 创建一个缓冲区来存储结果字符串
    va_list args;        // 声明一个 va_list 类型的变量
    va_start(args, format); // 初始化 va_list 变量
    vsprintf(buffer, format, args); // 使用 vsprintf 将格式化的数据写入缓冲区
    va_end(args);        // 清理 va_list 变量
    printf("%s", buffer); // 打印结果字符串
}

int main() {
    my_printf("Hello %s! You have %d new messages.\n", "Alice", 5);
    return 0;
}

(1).参数处理方式:

sprintf 直接接受可变数量的参数。
vsprintf 接受一个 va_list 类型的参数列表。
(2).使用场景:

sprintf 适合直接使用固定数量的参数进行格式化。
vsprintf 适合编写需要处理可变参数的函数,例如自定义的打印函数。
(3).代码复杂度:

sprintf 使用起来比较简单,直接传入格式化字符串和参数即可。
vsprintf 需要使用 va_list、va_start、va_end 等宏来处理参数列表。

如何打印汉字

–no-multibyte-chars
在这里插入图片描述

另一种方式

选为GB2312
在这里插入图片描述
在串口助手选择:GBK

串口读取

有查询和中断两种方式进入

查询的代码
while(1)
	{
		if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==SET)
		{
			RXData = USART_ReceiveData(USART1);
			//读DR
			
			OLED_ShowHexNum(1,1,RXData,2);
			
		}
}
USART串口数据包

当发送连续的数据包的时候,串口可能错位。这时候就可以数据进行分割。
在这里插入图片描述

这里使用了固定包长,可变包长 ,含包头包尾

如果数据和包头包尾重复,可能引起误判,
第一种 限制载荷数据的范围
第二种 无法避免载荷数据和包头包尾重复,尽量使用固定长度的数据包

如果载荷会出现和包头包尾重复的情况,尽量使用固定包长。

文本数据包

在这里插入图片描述

HEX数据包接收

状态机

标签:va,end,USART,list,参数,串口,数据
From: https://blog.csdn.net/wedream23/article/details/140334100

相关文章

  • 【tomcat】Tomcat如何扩展Java线程池原理
    池化技术在后端中,对于经常使用池化就是来提升系统性能,比如数据库连接池、线程池连接池等,本质都是利用空间换时间的来提升性能,用来避免资源的频繁创建和销毁,以此提高资源的复用率,所以合理设置系统所需的线程池大小非常重要,一般都需要结合线程启动监控系统来观察,查看设置的是......
  • Java中Lambda表达式的应用
    Java中Lambda表达式的应用大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!Lambda表达式的基础语法Lambda表达式是Java8引入的一个重要特性,它提供了一种更简洁、更函数式的方式来编写匿名函数。Lambda表达式主要由参数列表、箭头符号(->)和方法体组成。例......
  • 深入解析Java中的泛型
    深入解析Java中的泛型大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!泛型的基本概念与语法在Java中,泛型(Generics)是一种强大的特性,它允许我们在编写代码时使用参数化类型。泛型提供了编译时类型安全检查,使得程序更加健壮和可维护。packagecn.juwatech.......
  • Java中的异常处理最佳实践
    Java中的异常处理最佳实践大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!异常处理的基本原则在Java编程中,异常处理是保证程序健壮性和可靠性的重要手段之一。良好的异常处理实践可以提升代码的可读性和维护性,下面我们来深入探讨Java中的异常处理最佳实......
  • Java中的设计模式详解
    Java中的设计模式详解大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!单例模式在实际开发中,经常会遇到需要保证一个类只有一个实例的情况。单例模式通过私有化构造方法和静态方法来确保只有一个实例被创建。以下是一个示例:packagecn.juwatech.designpa......
  • Java中的序列化与反序列化
    Java中的序列化与反序列化大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!序列化与反序列化概述在Java中,序列化是将对象转换为字节流的过程,可以将对象持久化保存到文件、数据库或网络传输中。反序列化则是将字节流恢复为对象的过程。Java中的序列化与反......
  • Java中的内存模型详解
    Java中的内存模型详解大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!Java内存模型概述Java内存模型(JavaMemoryModel,JMM)定义了Java程序中多线程并发访问共享变量的规范,确保多线程间的内存可见性、原子性和有序性。理解Java内存模型对于编写并发安全的......
  • Java中的Fork/Join框架详解
    Java中的Fork/Join框架详解大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在Java中,Fork/Join框架是一种用于并行处理任务的强大工具,特别适用于那些可以递归地分解成更小任务的场景。Fork/Join框架基于“工作窃取”算法,允许空闲的线程从那些繁忙的线程那......
  • Java中的CompletableFuture详解
    Java中的CompletableFuture详解大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在现代Java编程中,异步编程变得越来越重要。Java8引入了CompletableFuture,它极大地简化了异步编程的复杂性。CompletableFuture不仅支持异步操作,还提供了丰富的API来处理异步......
  • Java中的ReentrantLock详解
    Java中的ReentrantLock详解大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在Java编程中,多线程同步是一个常见的需求。为了保证多个线程对共享资源的安全访问,Java提供了多种锁机制,其中ReentrantLock是一个重要的工具。本文将详细介绍ReentrantLock的使用,......