裸机:串口通信

news2024/11/14 22:04:09

串口通信的基本原理

单工通信和双工通信
(1)单工就是单方向,双工就是双方同时收发,同时只能但方向但是方向可以改变叫半双工
(2)如果只能A发B收则单工,A发B收或者B发A收(两个方向不能同时)叫半双工,A发B收同时B发A收叫全双工。

三根通信线:Rx Tx GND
(1)任何通信都要有信息传输载体,或者是有线的或者是无线的。
(2)串口通信是有线通信,是通过串口线来通信的。
(3)串口通信线最少需要2根(GND和信号线),可以实现单工通信,也可以使用3根通信线(Tx、Rx、GND)来实现全双工。
(4)一般开发板都会引出SoC上串口引脚直接输出的TTL电平的串口(X210开发板没有),插座用插针式插座,每个串口引出的都有3个线(Tx、Rx、GND),可以用这些插座直接连接外部的TTL电平的串口设备。

收发双方事先规定好通信参数(波特率、数据位、奇偶校验位、停止位等)
(1)串口通信属于基层基本性的通信规约,它自己本身不会去协商通信参数,需要通信前通信双方事先约定好通信参数(一般4个最重要的)
(2)串口通信的任何一个关键参数设置错误,都会导致通信失败。譬如波特率调错了,发送方发送没问题,接收方也能接收,但是接收到全是乱码···

S5PV210的串口控制器工作原理框图

《S5PV210_UM_REV1.1》853页

在这里插入图片描述
(1)S5PV210的数据手册中串口控制器在section8.1
(2)串口的官方名称叫:universal asynchronous reciver and transmitter,通用异步收发器
英文缩写是uart,中文简称串口。

在这里插入图片描述
将来计算串口控制器的源时钟时是以APB总线来计算的。
整个串口控制器包含transmitter和receiver两部分,两部分功能彼此独立,transmitter负责210向外部发送信息,receiver负责从外部接收信息到210内部。

Transmitter(发送器)
组成:由发送缓冲区和发送移位器两部分构成。
工作流程优化描述:
信息编码:首先,待发送的信息被高效编码为ASCII码(或根据需求选择其他适合的编码方式)形式的二进制流。
缓冲区写入:随后,这一串二进制流被组织成帧,每帧通常包含8位(或其他预定义长度),并自动写入发送缓冲区。此过程无缝衔接,确保数据流的连续性。
自动发送:一旦数据被安全存入缓冲区,发送移位器即自动介入,无需CPU额外干预。它逐位地从缓冲区中读取数据帧,并通过精心设计的移位机制将每位数据依次发送到Tx(发送)通信线上。这一过程极大减轻了CPU的负担,提高了数据传输的效率和稳定性。

Receiver(接收器)
组成:由接收缓冲区和接收移位器两部分组成。
工作流程优化描述:
数据接收:当外部设备通过串口Rx(接收)通信线发送数据时,这些数据首先被接收移位器捕获。移位器迅速而准确地处理每一位进入的数据,通过内部移位操作将它们整理成有序的二进制位序列。
缓冲存储:整理好的二进制位序列被自动存储到接收缓冲区中,直到一帧完整的数据被接收完毕。此过程确保了数据的完整性和准确性。
中断通知:一旦一帧数据被完全接收并存储在缓冲区中,接收器会立即生成一个中断信号给CPU。这一设计允许CPU在需要时才介入处理数据,从而实现了资源的有效分配和系统的低功耗运行。CPU在接收到中断后,将响应该信号,从接收缓冲区中读取数据帧,进行后续处理。

串口控制器中有一个波特率发生器,作用是产生串口发送/接收的节拍时钟。波特率发生器其实就是个时钟分频器,它的工作需要源时钟(APB总线来),然后内部将源时钟进行分频(软件设置寄存器来配置)得到目标时钟,然后再用这个目标时钟产生波特率(硬件自动的)。

基本知识

自动流控(AFC:Auto flow control)是一种在数据传输过程中用于控制数据流速和确保数据完整性的机制。它主要用于串口通信中,特别是在发送方速率可能超过接收方处理能力的情况下,通过自动调整数据传输的速率来防止数据丢失。

FIFO模式及其作用
(1)典型的串口设计,发送/接收缓冲区只有1字节,每次发送/接收只能处理1帧数据。这样在单片机中没什么问题,但是到复杂SoC中(一般有操作系统的)就会有问题,会导致效率低下,因为CPU需要不断切换上下文。
(2)解决方案就是想办法扩展串口控制器的发送/接收缓冲区,譬如将发送/接收缓冲器设置为64字节,CPU一次过来直接给发送缓冲区64字节的待发送数据,然后transmitter慢慢发,发完再找CPU再要64字节。但是串口控制器本来的发送/接收缓冲区是固定的1字节长度的,所以做了个变相的扩展,就是FIFO。
(3)FIFO就是first in first out,先进先出。fifo其实是一种数据结构,这里这个大的缓冲区叫FIFO是因为这个缓冲区的工作方式类似于FIFO这种数据结构。

DMA模式及其作用
(1)DMA direct memory access,直接内存访问。DMA本来是DSP中的一种技术,DMA技术的核心就是在交换数据时不需要CPU参与,模块可以自己完成。
(2)DMA模式要解决的问题和上面FIFO模式是同一个问题,就是串口发送/接收要频繁的折腾CPU造成CPU反复切换上下文导致系统效率低下。
(3)传统的串口工作方式(无FIFO无DMA)效率是最低的,适合低端单片机;高端单片机上CPU事物繁忙所以都需要串口能够自己完成大量数据发送/接收。这时候就需要FIFO或者DMA模式。FIFO模式是一种轻量级的解决方案,DMA模式适合大量数据迸发式的发送/接收时。

IrDA模式及其用法
(1)IrDA其实就是红外,红外就是红外线通信(电视机、空调遥控器就是红外通信的)。
(2)红外通信的原理是发送方固定间隔时间向接收方发送红外信号(表示1或0)或者不发送红外信号(表示0或者1),接收方每隔固定时间去判断有无红外线信号来接收1和0.
(3)分析可知,红外通信和串口通信非常像,都是每隔固定时间发送1或者0(判断1或0的物理方式不同)给接收方来通信。因此210就利用串口通信来实现了红外发送和接收。
(4)210的某个串口支持IrDA模式,开启红外模式后,我们只需要向串口写数据,这些数据就会以红外光的方式向外发射出去(当然是需要一些外部硬件支持的),然后接收方接收这些红外数据即可解码得到我们的发送信息。

串行通信与中断的关系

(1)串口通信分为发送/接收2部分。发送方一般不需要(也可以使用)中断即可完成发送,接收方必须(一般来说必须,也可以轮询方式接收)使用中断来接收。
(2)发送方可以选择使用中断,也可以选择不使用中断。使用中断的工作情景是:发送方先设置好中断并绑定一个中断处理程序,然后发送方丢一帧数据给transmitter,transmitter发送耗费一段时间来发送这一帧数据,这段时间内发送方CPU可以去做别的事情,等transmitter发送完成后会产生一个TXD中断,该中断会导致事先绑定的中断处理程序执行,在中断处理程序中CPU会切换回来继续给transmitter放一帧数据,然后CPU切换离开;不使用中断的工作情景是:发送方事先禁止TXD中断(当然也不需要给相应的中断处理程序了),发送方CPU给一帧数据到transmitter,然后transmitter耗费一段时间来发送这帧数据,这段时间CPU在这等着(CPU没有切换去做别的事情),待发送方发送完成后CPU再给它一帧数据继续发送直到所有数据发完。CPU是怎么知道transmitter已经发送完了?原来是有个状态寄存器,状态寄存器中有一个位叫发送缓冲区空标志,transmitter发送完成(发送缓冲区空了)就会给这个标志位置位,CPU就是通过不断查询这个标志位为1还是0来指导发送是否已经完成的。
(3)因为串口通信是异步的,异步的意思就是说发送方占主导权。也就是说发送方随时想发就能发,但是接收方只有时刻等待才不会丢失数据。所以这个差异就导致发送方可以不用中断,而接收方不得不使用中断模式。

210串行通信接口的时钟设计

(1)串口通信为什么需要时钟?因为串口通信需要一个固定的波特率,所以transmitter和receiver都需要一个时钟信号。
(2)时钟信号从哪里来?源时钟信号是外部APB总线(PCLK_PSYS,66MHz)提供给串口模块的(这就是为什么我们说串口是挂在APB总线上的),然后进到串口控制器内部后给波特率发生器(实质上是一个分频器),在波特率发生器中进行分频,分频后得到一个低频时钟,这个时钟就是给transmitter和receiver使用的。
(3)串口通信中时钟的设置主要看寄存器设置。重点的有:寄存器源设置(为串口控制器选择源时钟,一般选择为PCLK_PSYS,也可以是SCLK_UART),还有波特率发生器的2个寄存器。
(4)波特率发生器有2个重要寄存器:UBRDIVn和UDIVSLOTn,其中UBRDIVn是主要的设置波特率的寄存器,UDIVSLOTn是用来辅助设置的,目的是为了校准波特率的。

代码实现

始化串口的Tx和Rx引脚所对应的GPIO(查原理图可知Rx和Rx分别对应GPA0_1和GPA0_0)
在这里插入图片描述
主要的几个寄存器
(1)ULCON0(ULCON0, R/W, Address = 0xE290_0000) = 0x3 // 0校验位、8数据位、1停止位
(2)UCON0(R/W, Address = 0xE290_0004) = 0x5 // 发送和接收都是polling mode
(3)UMCON0(UMCON0, R/W, Address = 0xE290_000C) = 0x0 // 禁止modem、afc
(4)UFCON0(UFCON0, R/W, Address = 0xE290_0008) = 0x0 // 禁止FIFO模式
(5)UBRDIV0(UBRDIV0, R/W, Address = 0xE290_0028)和UDIVSLOT0(UDIVSLOT0, R/W, Address = 0xE290_002C)和波特率有关,要根据公式去算的

#define GPA0CON		0xE0200000
#define UCON0 		0xE2900004
#define ULCON0 		0xE2900000
#define UMCON0 		0xE290000C
#define UFCON0 		0xE2900008
#define UBRDIV0 	0xE2900028
#define UDIVSLOT0	0xE290002C
#define UTRSTAT0	0xE2900010
#define UTXH0		0xE2900020	
#define URXH0		0xE2900024	

GPA0CON:
用于配置端口A的第0组引脚的功能(如输入、输出、特殊功能等)。
UCON0:
UART控制寄存器0的地址。这个寄存器用于控制UART0的基本操作,如设置UART的模式(如中断模式、轮询模式)、设置波特率生成器、使能UART接收/发送等。
ULCON0:
UART线路控制寄存器0的地址。这个寄存器用于设置UART的线路控制特性,如数据位长度、停止位数量、奇偶校验位等。
UMCON0:
UART调制控制寄存器0的地址。这个寄存器可能用于控制UART的流控制(如软件流控制RTS/CTS)或其他调制相关的功能。
UFCON0:
UART FIFO控制寄存器0的地址。FIFO(先进先出)是一种用于缓冲数据的队列结构,这个寄存器用于控制UART的FIFO缓冲区,如使能/禁用FIFO、设置FIFO触发级别等。
UBRDIV0:
UART波特率除数寄存器0的地址。这个寄存器用于设置UART的波特率除数,通过调整这个值,可以调整UART通信的波特率。
UDIVSLOT0:
UART除法槽寄存器0的地址。这个寄存器可能用于更精细地调整UART的波特率,特别是在需要非常精确的波特率设置时。
UTRSTAT0:
UART传输/接收状态寄存器0的地址。这个寄存器提供了UART传输和接收操作的状态信息,如是否有数据可读、发送缓冲区是否空等。
UTXH0:
UART发送缓冲区寄存器0的地址。这个寄存器用于存放要发送的数据,当UART发送器准备好时,它会从这个寄存器中读取数据并发送出去。
URXH0:
UART接收缓冲区寄存器0的地址。这个寄存器用于存放接收到的数据,当UART接收器接收到数据时,它会将数据存放在这个寄存器中,供CPU读取。

波特率的计算

DIV_VAL = (PCLK / (bps x 16)) −1
在这里插入图片描述余数决定UDIVSLOTn
0.816 = 12.8 选 0xDFDD
0.18
16 =2.88 选0x0888在这里插入图片描述

//初始化
void uart_init(void)
{
	// 初始化 Tx Rx 对应的引脚
	rGPA0CON &= ~(0xff<<0);			//把寄存器的bit0~7全部清零
	rGPA0CON |= 0x00000022;			// 0b0010, Rx Tx
	
	// 关键寄存器配置
	rULCON0 = 0x3;// 0校验位、8数据位、1停止位
	rUCON0 = 0x5;// 发送和接收都是polling mode
	rUMCON0 = 0;// 禁止modem、afc
	rUFCON0 = 0;// 禁止FIFO模式
	

	// 波特率公式	DIV_VAL = (PCLK / (bps x 16))-1
	// PCLK_PSYS=66MHz		余数0.8 
    // DIV_VAL = (66000000/(115200*16)-1) = 34.80
	//rUBRDIV0 = 34;	
	//rUDIVSLOT0 = 0xdfdd;//0.8*16 = 12.8 选 0xDFDD
	
	// PCLK_PSYS=66.7MHz		余数0.18 
	// DIV_VAL = (66700000/(115200*16)-1) = 35.18
	rUBRDIV0 = 35;
	//例子 (num of 1's in UDIVSLOTn)/16 = 0.7 -》UDIVSLOTn= 余数*19=6按照表格找值
	rUDIVSLOT0 = 0x0888;		// 0.18*16 =2.88 选0x0888
}

波特率的计算和设置
(1)第一步,用PCLK_PSYS和目标波特率去计算DIV_VAL: DIV_VAL = (PCLK / (bps x 16)) -1
(2)第二步,UBRDIV0寄存器中写入DIV_VAL的整数部分
(3)第三步,用小数部分*16得到1个个数,查表得uBDIVSLOT0寄存器的设置值

串口发送和接收函数的编写
(1)写发送函数,主要发送前要用while循环等待发送缓冲区为空才能发送。

//发送一个字节
void uart_putc(char c)
{
    //因为串口控制器发送1个字节的速度远低于CPU的速度,所以CPU发送1个字节前必须
    //确认串口控制器当前缓冲区是空的(意思就是串口已经发完了上一个字节
    //如果缓冲区非空则位为0,此时应该循环,直到bit1位为1
    while (!(rUTRSTAT0 & (1<<1)));//硬件判断是否发送结束 bit1 
	rUTXH0 = c;  //串口发送一个字符,其实就是把一个字节丢到发送给冲区中去

}

下载程序验证成功

在这里插入图片描述
在这里插入图片描述

uart stdio的移植

什么是stdio
(1)#include <stdio.h>
(2)stdio:standard input output,标准输入输出
(3)标准输入输出就是操作系统定义的默认的输入和输出通道。一般在PC机的情况下,标准输入指的是键盘,标准输出指的是屏幕。
(4)printf函数和scanf函数可以和底层输入/输出函数绑定,然后这两个函数就可以和stdio绑定起来。也就是说我们直接调用printf函数输出,内容就会被从标准输出输出出去。
(5)在我们这里,标准输出当然不是屏幕了,而是串口。标准输出也不是键盘,而是串口。

printf函数的工作原理
(1)printf函数工作时内部实际调用了2个关键函数:一个是vsprintf函数(主要功能是格式化打印信息,最终得到纯字符串格式的打印信息等待输出),另一个就是真正的输出函数putc(操控标准输出的硬件,将信息发送出去)

移植printf函数的三种思路
(1)我们希望在我们的开发板上使用printf函数进行(串口)输出,使用scanf函数进行(串口)输入,就像在PC机上用键盘和屏幕进行输入输出一样。因此需要移植printf函数/scanf函数
(2)我们说的移植而不是编写,我们不希望自己完全从新编写而是想尽量借用也有的代码(叫移植)
(3)一般移植printf函数可以有3个途径获取printf的实现源码:最原始最原本的来源就是linux内核中的printk。难度较大、关键是麻烦;稍微简单些的方法是从uboot中移植printf;更简单的方法就是直接使用别人移植好的。
(3)我们课程中使用第三种方法,别人移植好的printf函数来自于友善之臂的Tiny210的裸机教程中提供的。

主要是将修改Makefile,将别人的代码添加进来

CC		= arm-linux-gcc
LD 		= arm-linux-ld
OBJCOPY	= arm-linux-objcopy
OBJDUMP	= arm-linux-objdump
AR		= arm-linux-ar

INCDIR	:= $(shell pwd)
# C预处理器的flag,flag就是编译器可选的选项
CPPFLAGS	:= -nostdlib -nostdinc -I$(INCDIR)/include
# C编译器的flag
CFLAGS		:= -Wall -O2 -fno-builtin

#导出这些变量到全局,其实就是给子文件夹下面的Makefile使用
export CC LD OBJCOPY OBJDUMP AR CPPFLAGS CFLAGS


objs := start.o led.o clock.o uart.o main.o
objs += lib/libc.a

uart.bin: $(objs)
	$(LD) -Tlink.lds -o uart.elf $^
	$(OBJCOPY) -O binary uart.elf uart.bin
	$(OBJDUMP) -D uart.elf > uart_elf.dis
	gcc mkv210_image.c -o mkx210
	./mkx210 uart.bin 210.bin

lib/libc.a:
	cd lib;	make;	cd ..
	
%.o : %.S
	$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c

%.o : %.c
	$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c

clean:
	rm *.o *.elf *.bin *.dis mkx210 -f
	cd lib; make clean; cd ..

	
	

在这里插入图片描述

学习记录,侵权联系删除。
来源:朱老师物联网大课堂

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

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

相关文章

【C++】类与对象篇一

【C】类与对象篇一 一 .面向过程和面向对象初步认识二 .类的详解1.类的引入2.类的定义3.类的访问限定符及封装&#xff08;面试题&#xff09;4.类的作用域5.类的实例化6.类对象模型 三 . 结构体内存对齐规则&#xff08;面试题&#xff09;四 . this指针1.this指针的特性2.thi…

WOFOST的web应用

目录 运行可视化 参考链接 https://github.com/irripro/WOFOST_streamlit/tree/main 运行 运行主程序.py之后&#xff0c;得到一串命令 将该命令放到命令台中运行 然后会转到WOFOST的web端上 可视化 目前好像只支持欧洲区域的模拟运行

C++篇:C向C++迈进(上)

引言 C语言作为编程基石&#xff0c;其高效与直接性深受开发者喜爱。然而&#xff0c;随着软件复杂度的增加&#xff0c;C以其面向对象及高级特性成为了新的选择。我们接下来将学习C&#xff0c;从C语言迈向C。 什么是C C 是一种高级语言&#xff0c;由 Bjarne Stroustrup 于…

Docker 的简介

Docker 的简介 为什么会有 Docker环境一致性问题提高资源利用率和可移植性快速部署和伸缩简化管理和维护版本控制和回滚 Docker 的历史dotCloud 时代&#xff08;2010年前&#xff09;Docker 诞生&#xff08;2010-2013&#xff09;快速发展与开源&#xff08;2013-2014&#x…

mysql 日期字段自动填写日期 及自动更新日期

INSERT 时 自动给日期字段 添加 当前日期时间&#xff1a; 在默认里选中&#xff1a; CURRENT_TIMESTAMP UPDATE 时 自动给日期字段 更新 当前日期时间&#xff1a; 勾选&#xff1a;根据当前时间戳更新

通过VIN车架号查询车辆登记日期

我们先来介绍下什么是vin码&#xff0c;以及vin码的构成结构解析&#xff0c;汽车VIN码&#xff0c;也叫车辆识别号码&#xff0c;通俗可以理解为汽车的身份证号码。 接口介绍 通过17位vin码&#xff0c;获取到车辆的发动机号&#xff0c;初登日期&#xff0c;车辆型号等信息。…

CI/CD之Jenkins用于Linux系统的部署方式汇总

目录 一、前言 二、CI/CD的定义与核心原则 CI/CD在现代软件开发中的重要性 CI/CD与Jenkins的关系 三、Jenkins部署方式汇总 1. 独立服务器部署 &#xff08;1&#xff09;离线安装 &#xff08;2&#xff09;在线安装 2. Docker容器部署 3. Kubernetes集群部署 4. 云…

聚焦自闭儿童:关注与理解

在探讨一个三岁自闭症孩子不会说话的情况时&#xff0c;我们首先需要理解自闭症这一复杂神经发育障碍的本质&#xff0c;以及它如何影响儿童的社交互动、沟通能力和行为模式。自闭症不仅仅是一个简单的“不会说话”的问题&#xff0c;而是一系列症状的综合体现&#xff0c;这些…

机器学习:随机森林决策树学习算法及代码实现

1、概念 随机森林&#xff08;Random Forest&#xff09;是一种集成学习方法&#xff0c;它通过构建多个决策树来进行分类或回归预测。随机森林的核心原理是“集思广益”&#xff0c;即通过组合多个弱学习器&#xff08;决策树&#xff09;的预测结果来提高整体模型的准确性和健…

基于Java的小区物业管理系统APP的设计与实现(论文+源码)_kaic

摘 要 小区物业管理系统是现代社会中非常热门的软件&#xff0c;伴随着社区规模的不断扩大和住户的不断增多&#xff0c;本系统的主要目的是辞别帐本以及传统的单一数据管理系统&#xff0c;快捷的保存用户各种数据信息。本系统针对Java系统展开&#xff0c;使用Java、SpringB…

tomcat服务器相关搭建

文章目录 web应用服务器tomcatTomcat功能及介绍配置tomcat服务器生成tomcat启动文件 nginx反向代理session共享服务器 web应用服务器tomcat Tomcat功能及介绍 Tomcat 服务器是一个免费的开放源代码的Web 应用服务器&#xff0c;属于轻量级应用服务器&#xff0c;在中小型系统和…

香橙派AIPro开发板安装PyQt5 aarch64

香橙派AIPro开发板安装PyQt5 参考 开发板信息 官网开发板信息 软件环境信息 1、安装依赖环境 sudo apt-get install cmake gcc g pip3 install --upgrade pip pip3 install wheel setuptools sudo apt-update sudo apt-get install qt5-default sudo apt-get install qtd…

为什么互联网上要设立防火墙?WAF又是什么?

防火墙&#xff08;英语&#xff1a;Firewall&#xff09;技术是通过有机结合各类用于安全管理与筛选的软件和硬件设备&#xff0c;帮助计算机网络于其内、外网之间构建一道相对隔绝的保护屏障&#xff0c;以保护用户资料与信息安全性的一种技术。 防火墙技术的功能主要在于及…

python库(21):

1 TextBlob简介 TextBlob 是一个基于 Python 的文本处理库&#xff0c;能够让基础的自然语言处理任务变得异常简单。 它提供了一个简单直观的 API&#xff0c;让你能够轻松执行词性标注、名词短语提取、情感分析、文本分类和关键词提取等功能。 值得一提的是&#xff0c;Tex…

计算机网络计算题【408】——里昂视频

计算机网络【408】计算题 计算机网络概述【17题】【18题】甘特图【19题】甘特图【20题】【21题】 通信基础【14】求最大传输速率使用两个公式【27】【28】【29】差分曼彻斯特【30】[21]重点 p14 通信基础T31 流量控制与可靠传输机制T21 选择重传协议[GBN]:SR [22][24]***⭐【25…

linux系统使用 docker 来部署web环境 nginx+php7.4 并配置称 docker-compose-mysql.yml 文件

Docker是一个开源的容器化平台&#xff0c;旨在简化应用程序的创建、部署和管理。它基于OS-level虚拟化技术&#xff0c;通过将应用程序和其依赖项打包到一个称为容器的标准化单元中&#xff0c;使得应用程序可以在任何环境中快速、可靠地运行。 Docker的优势有以下几个方面&a…

通用定时器,输入捕获

这个图片主要看评论 这个是定时器输入捕获的基本配置步骤&#xff0c;主要也是看评论 注意&#xff1a;输入捕获开了两个中断&#xff0c;一个是捕获中断&#xff0c;只要有上升沿或者下降边沿或者双边沿&#xff0c;&#xff08;主要看设置的捕获什么边沿&#xff09;&#x…

【Python 千题 —— 基础篇】图形的面积(圆形)

Python 千题持续更新中 …… 脑图地址 👉:⭐https://twilight-fanyi.gitee.io/mind-map/Python千题.html⭐ 题目描述 题目描述 编写一个面向对象的程序,定义一个 Circle 类,该类有一个属性 radius(圆的半径),并具有一个方法 area() 来计算圆的面积。请根据以下要求实…

IM项目:进阶版即时通讯项目---文件存储和消息转发

文章目录 文件传输服务基本功能模块划分流程图实现逻辑代码实现 消息转发功能设计模块划分获取转发目标和消息处理代码实现 文件传输服务 基本功能 文件的上传文件的下载 模块划分 基于gflags进行参数和配置文件的解析基于spdlog进行日志输出基于etcd进行服务注册基于brpc进…

关于超长字符串/文本对应的数据从excel导入到PL/SQL中的尝试

问题&#xff1a; 1.字符串太长 2.str绑定之的结尾null缺失 将csv文件导入到PL/SQL表中存在的一些问题 1.本来我是需要将exceL上的几十条数据导入到PL/SQL数据库的一张表中&#xff0c;结果我花了许多时间 去导入。 想想一般情况下也就几十条数据&#xff0c;直接复制粘贴就…