GD32F10 串口通信

news2024/12/25 12:25:34

1. 什么是通信

通信,指人与人或人与自然之间通过某种行为或媒介进行的信息交流与传递,从广义上指需要信息的双方或多方在不违背各自意愿的情况下采用任意方法,任意媒质,将信息从某方准确安全地传送到另方。通信双方如果想正确传输数据就需要约定不违背的协议。

通信在不同的环境下有不同的解释,在出现电波传递通信后通信(Communication)被单一解释为信息的传递,是指由一地向另一地进行信息的传输与交换,其目的是传输消息。

然而,通信是在人类实践过程中随着社会生产力的发展对传递消息的要求不断提升使得人类文明不断进步。

在各种各样的通信方式中,利用“电”来传递消息的通信方法称为电信(Telecommunication),这种通信具有迅速、准确、可靠等特点,且几乎不受时间、地点、空间、距离的限制,因而得到了飞速发展和广泛应用;

在现今因电波的快捷性使得从远古人类物质交换过程中就结合文化交流与实体经济不断积累进步的实物性通信(邮政通信)被人类理解为制约经济发展的阻碍。

在古代,人类通过驿站、飞鸽传书、烽火报警、符号、身体语言、眼神、触碰等方式进行信息传递。

在现代科学水平的飞速发展,相继出现了无线电、固定电话、移动电话、互联网甚至视频电话等各种通信方式。通信技术拉近了人与人之间的距离,提高了经济的效率,深刻地改变了人类的生活方式和社会面貌。

1. 分类

1. 按传输媒质分类

有线通信:是指传输媒质为导线、电缆、光缆、波导、纳米材料等形式的通信,其特点是媒质能看得见,摸得着(明线通信、电缆通信、光缆通信、光纤光缆通信)。

无线通信:是指传输媒质看不见、摸不着(如电磁波)的一种通信形式 [2]  。

(微波通信、短波通信、移动通信、卫星通信、 散射通信)。

2. 按信道中传输的信号分类

模拟信号:凡信号的某一参量(如连续波的振幅、频率、相位,脉冲波的振幅、宽度、位置等)可以取无限多个数值,且直接与消息相对应的,模拟信号有时也称连续信号。 这个连续是指信号的某一参量可以连续变化。

数字信号:凡信号的某一参量只能取有限个数值,并且常常不直接与消息相对应的,也称离散信号 [1]  。

3. 按工作频段分类

长波通信。

中波通信。

短波通信。

微波通信。

4. 按调制方式分类

基带传输:是指信号没有经过调制而直接送到信道中去传输

的通信方式。

频带传输:是指信号经过调制后再送到信道中传输,接收端

有相应解调措施的通信方式。

5.按通信双方的分工及数据传输方向分类。

对于点对点之间的通信,按消息传送的方向,通信方式可分为单工通信、半双工通信及全双工通信三种。

所谓单工通信,是指消息只能单方向进行传输的一种通信工作方式。单工通信的例子很多,如广播、遥控、无线寻呼等。这里,信号(消息)只从广播发射台、遥控器和无线寻呼中心分别传到收音机、遥控对象和BP 机上。

所谓半双工通信方式,是指通信双方都能收发消息,但不能同时进行收和发的工作方式。对讲机、收发报机等都是这种通信方式。

所谓全双工通信,是指通信双方可同时进行双向传输消息的工作方式。在这种方式下,双方都可同时进行收发消息。很明显,全双工通信的信道必须是双向信道。生活中全双工通信的例子非常多,如普通电话、手机等。

2. 组成

实现信息传递所需的一切技术设备和传输媒质的合称为通信系统。

信源:消息的产生地,其作用是把各种消息转换成原始电信号,称之为消息信号或基带信号。电话机、电视摄像机和电传机、计算机等各种数字终端设备就是信源。

发送设备:将信源和信道匹配起来,即将信源产生的消息信号变换为适合在信道中搬移的场合,调制是最常见的变换方式。对需要频谱搬移场合,调制是最常见的变换方式。对数字通信系统来说,发送设备常常又分为信源编码与信道编码。

信道:传输信号的物理媒质。

噪声源:是通信系统中各种设备以及信道中所固有的,为了分析方便,把噪声源视为各处噪声的集中表现而抽象加入到信道。

接收设备:完成发送设备的反变换,即进行解调、译码、解码等等。它的任务是从带有干扰的接收信号中正确恢复出相应的原始基带信号来。

信宿:传输信息的归宿点,其作用是将复原的原始信号转换成相应的信息

 2. 通信的传输方式。

现在普遍双工比较多。 

3. 通信中的并行,串行

现在普遍串行比较多。 

 4. 通信中的同步,异步。

 

5. (USART)异步通信 的数据帧格式。

1.接收方怎么知道你什么时候发送。当发送完怎么知道你发送结束。所以在发送一个字节时会先发送一个起始位。在空闲的时候因为是高电平。当发送起始位是0,当接收方收到0就知道你要发送数据了就准备好接收数据。当发完一个字节时。这时又会发送一个停止位1。当接收方接收到停止位1就知道你发送完了。发送一个字节需要发送10个位。起始位(一位)+ 一个字节(八位) + 起始位(一位)。如图:奇偶校验位可以先不考虑。
 

2. 具体发送方多久发送一个bit呢?

从而引出波特率。如果波特率是9600。那么1/9600s传输1bit。

1s传输9600bit。但对于接收方以多大的速度去接收呢。如果速度慢会丢bit。一般采样频率是

传输频率的16倍。这样才能保证稳定不丢。

如果单片机是发送方。笔记本电脑是接收方。我们不需要考虑接收问题。笔记本电脑硬件会自己处理。但是显示接收的上位机软件要配置跟下位机一样波特率,停止位,数据位,是否有校验位。

如果单片机是接收方。笔记本电脑是发送方。需要考虑采样频率的问题。

3. 具体波特率怎么产生呢?

在库函数里设置波特率参数。就可以产生。有相应的硬件电路。我们不需要管。如果像有些51单片机是没有波特率产生电路的。需要用一个定时器配置来产生。

对于异步通信字节与字节传输是可以间隔传输的。接收方接收到起始就知道有数据来。接收到停止位知道一个字节接收完毕。等一下字节也是同样方式。

 

6. USART的框图

对于收发就看圈的部分即可

 7. dome (串口发送数据)

使用串口0 RX:PA9 TX:PA10

串口初始化步骤:(这个dome没用中断)

 

usart_comm.h

#ifndef USART_COMM_H
#define USART_COMM_H
/**
@brief: 串口处理的模块
*/

#include "gd32f10x.h"

void usart0_init(uint32_t baudval);

void usart0_send_byte(uint8_t ch);

void usart0_send_string(uint8_t *ch);


#endif

usart_cmm.c

#include "usart_comm.h"

/**
*@brief: usart0的初始化
*@param baudval: 波特率
*@retval NONE
*/
void usart0_init(uint32_t baudval){
	/* 初始化时钟和对应的io口 */
	rcu_periph_clock_enable(RCU_GPIOA);
	rcu_periph_clock_enable(RCU_USART0);
	
	gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9); /* TX 推挽复用 */
	gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10); /* RX 浮空输入 */
	
	// 配置usart0的工作参数
	usart_deinit(USART0); /* 重置初始化 */
  
	usart_baudrate_set(USART0, baudval);        //波特率
	usart_parity_config(USART0, USART_PM_NONE); //无奇偶校验
	usart_word_length_set(USART0, USART_WL_8BIT); //bit长度
	usart_stop_bit_set(USART0, USART_STB_1BIT);   //停止位
	usart_transmit_config(USART0, USART_TRANSMIT_ENABLE); //使能发送
	usart_receive_config(USART0, USART_RECEIVE_ENABLE);   //使能接收
	
	usart_enable(USART0); /* 使能串口 */
}


/**
*@brief: usart0发送一个字节
*@param ch:待发送字节
*@retval NONE
*/
void usart0_send_byte(uint8_t ch){
	usart_data_transmit(USART0, ch);
	
	while(usart_flag_get(USART0, USART_FLAG_TBE)==RESET); /* 等待发送完成 */
}

/**
*@brief: usart0发送字符串
*@param ch:待发送字符串指针
*@retval NONE
*/
void usart0_send_string(uint8_t *ch){
	uint32_t k = 0;
	while(*(ch+k) != '\0'){
		usart0_send_byte(*(ch+k));
		k++;
	}
}

main.c

#include "systick.h"
#include "usart_comm.h"

int main(){
	systick_config();
	usart0_init(9600);
	
	while(1){
		usart0_send_string((uint8_t *)"hello  UART.\n"); //自动会填充字符串结束符'\0'
		delay_1ms(1000);  //等待1s
	}
}

结果:

8.  dome (串口发送接收数据中断)

通过上位机发指令来控制下位机的LED,继电器的操作。

继电器硬件图:

J1接到PB15. 控制PB15来控制继电器是否工作。

LED硬件图:

具体上下位机的协议规定:

一帧有5个字节:帧头(0xFF),设备ID,设备号,设备指令,帧尾(0x00).

 

 relay_ctrl.h(继电器)

#ifndef RELAY_CTRL_H
#define RELAY_CTRL_H

#include "gd32f10x.h"

//定义继电器序号的宏
#define RELAY_1 0x01

void relay_init(void);

void relay_connect(uint8_t relay_num);
void relay_disconnect(uint8_t relay_num);

#endif

 relay_ctrl.c(继电器)

#include "relay_ctrl.h"

// 继电器控制io口的初始化
void relay_init(void){
	rcu_periph_clock_enable(RCU_GPIOB);
	
	gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_15);
	
	//默认让继电器断开
	relay_disconnect(RELAY_1);
}

// 控制继电器吸合
void relay_connect(uint8_t relay_num){
	switch(relay_num){
		case RELAY_1:
			gpio_bit_set(GPIOB, GPIO_PIN_15);
			break;
		default:
			break;
	}
}

// 控制继电器断开
void relay_disconnect(uint8_t relay_num){
	switch(relay_num){
		case RELAY_1:
			gpio_bit_reset(GPIOB, GPIO_PIN_15);
			break;
		default:
			break;
	}
}

led_ctrl.h(LED)

#ifndef LED_CTRL_H
#define LED_CTRL_H

#include "gd32f10x.h"

//LED序号的宏定义
#define LED_1 0x01
#define LED_2 0x02

void led_init(void);

void led_open(uint8_t led_num);   //led点亮
void led_close(uint8_t led_num);  //led熄灭

#endif

 led_ctrl.c(LED)

#include "led_ctrl.h"

void led_init(void){
	rcu_periph_clock_enable(RCU_GPIOB);
	
	gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0|GPIO_PIN_1);
	
	led_close(LED_1);
	led_close(LED_2);
	
}

//led点亮
void led_open(uint8_t led_num){
	switch(led_num){
		case LED_1:
			gpio_bit_set(GPIOB, GPIO_PIN_0);
			break;
		case LED_2:
			gpio_bit_set(GPIOB, GPIO_PIN_1);
			break;
		default:
			break;
	}
}

//led熄灭
void led_close(uint8_t led_num){
	switch(led_num){
		case LED_1:
			gpio_bit_reset(GPIOB, GPIO_PIN_0);
			break;
		case LED_2:
			gpio_bit_reset(GPIOB, GPIO_PIN_1);
			break;
		default:
			break;
	}
}

 usart_comm.h(串口)

#ifndef USART_COMM_H
#define USART_COMM_H
/**
@brief: 串口处理的模块
*/

#include "gd32f10x.h"

// 定义数据帧的宏
#define HEX_HEAD 0xFF
#define HEX_TAIL 0x00
#define LED_ID 0x01
#define RELAY_ID 0x02


void usart0_init(uint32_t baudval);

void usart0_send_byte(uint8_t ch);

void usart0_send_string(uint8_t *ch);

void deal_rec_buff(void);  // 串口通信协议hex数据帧缓存处理函数

#endif

 usart_comm.c(串口)

#include "usart_comm.h"
#include "led_ctrl.h"
#include "relay_ctrl.h"

uint8_t recv_buff[5]; /* 保存结束的数据 */
uint8_t recv_buff_len = 0;

/**
*@brief: usart0的初始化
*@param baudval: 波特率
*@retval NONE
*/
void usart0_init(uint32_t baudval){
	/* 初始化时钟和对应的io口 */
	rcu_periph_clock_enable(RCU_GPIOA);
	rcu_periph_clock_enable(RCU_USART0);
	
	gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);  /* TX 推挽复用 */
	gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10); /* RX 浮空输入 */
	
	// 配置usart0的工作参数
	usart_deinit(USART0);
	usart_baudrate_set(USART0, baudval);        //波特率
	usart_parity_config(USART0, USART_PM_NONE); //无奇偶校验
	usart_word_length_set(USART0, USART_WL_8BIT); //bit长度
	usart_stop_bit_set(USART0, USART_STB_1BIT);   //停止位
  
	usart_transmit_config(USART0, USART_TRANSMIT_ENABLE); //使能发送
	usart_receive_config(USART0, USART_RECEIVE_ENABLE);   //使能接收
	
	usart_enable(USART0); /* 使能串口 */
	
	// 使能usart0的中断
	usart_interrupt_enable(USART0, USART_INT_RBNE);
  
  /* 中断优先级 */
	nvic_irq_enable(USART0_IRQn, 2U, 2U);
	
	usart0_send_string((uint8_t *)"usart0 opened succeed.");
	
}


/**
*@brief: usart0发送一个字节
*@param ch:待发送字节
*@retval NONE
*/
void usart0_send_byte(uint8_t ch){
	usart_data_transmit(USART0, ch);
	
	while(usart_flag_get(USART0, USART_FLAG_TBE)==RESET); /* 等待发送完成 */
}

/**
*@brief: usart0发送字符串
*@param ch:待发送字符串指针
*@retval NONE
*/
void usart0_send_string(uint8_t *ch){
	uint32_t k = 0;
	while(*(ch+k) != '\0'){
		usart0_send_byte(*(ch+k));
		k++;
	}
}

// USART0的中断响应函数
void USART0_IRQHandler(void){
	uint8_t temp;
	if(SET == usart_interrupt_flag_get(USART0, USART_INT_FLAG_RBNE)){
		usart_interrupt_flag_clear(USART0, USART_INT_FLAG_RBNE);
		temp = usart_data_receive(USART0);
		if(temp == HEX_HEAD){         //数据帧帧头
			recv_buff_len = 0;
			recv_buff[recv_buff_len] = temp;
			recv_buff_len++;			
		}else if(temp == HEX_TAIL){   //数据帧帧尾
			if(recv_buff_len == 4){
				recv_buff[recv_buff_len] = temp;
				deal_rec_buff();
			}else{
				usart0_send_string((uint8_t *)"error");
			}
		}else{
			if(recv_buff_len > 0 && recv_buff_len < 4){
				recv_buff[recv_buff_len] = temp;
				recv_buff_len++;
			}else{
				usart0_send_string((uint8_t *)"error");
			}
		}
	}
}

// 串口通信协议hex数据帧缓存处理函数
void deal_rec_buff(void){
	switch(recv_buff[1]){
		case LED_ID:    //LED的控制
			if(recv_buff[3] == 0x01){
				led_open(recv_buff[2]);
			}else if(recv_buff[3] == 0x02){
				led_close(recv_buff[2]);
			}
			break;
		case RELAY_ID:    //继电器的控制
			if(recv_buff[3] == 0x01){
				relay_connect(recv_buff[2]);
			}else if(recv_buff[3] == 0x02){
				relay_disconnect(recv_buff[2]);
			}
			break;
		default:      //出错
			usart0_send_string((uint8_t *)"error");
			break;
		
	}
}

 main.c

#include "systick.h"
#include "usart_comm.h"
#include "led_ctrl.h"
#include "relay_ctrl.h"

int main(){
	systick_config();
	usart0_init(9600); /* 波特率:9600 */
	led_init();
	relay_init();
	
	while(1){
	}
}

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

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

相关文章

SystemUI导航栏

SystemUI导航栏 1、系统中参数项1.1 相关开关属性2.2 属性设置代码 2、设置中设置“三按钮”导航更新流程2.1 属性资源覆盖叠加2.2 SystemUI导航栏接收改变广播2.3 SystemUI导航栏布局更新2.4 时序图 android13-release 1、系统中参数项 1.1 相关开关属性 设置->系统->…

C++算法 —— 动态规划(9)完全背包问题

文章目录 1、动规思路简介2、完全背包【模板】3、零钱兑换4、零钱兑换Ⅱ5、完全平方数 背包问题需要读者先明白动态规划是什么&#xff0c;理解动规的思路&#xff0c;并不能给刚接触动规的人学习。所以最好是看了之前的动规博客&#xff0c;以及01背包博客&#xff0c;才能看完…

学习C++语言可以适用于哪些方面

学习C可以让你具备开发各种类型软件和系统的能力&#xff0c;它是一种通用的、高性能的编程语言。以下是学习C的一些用途和应用领域&#xff1a; 系统开发&#xff1a;C被广泛用于操作系统、驱动程序和嵌入式系统的开发。通过学习C&#xff0c;你可以编写底层的系统代码&#x…

java大富翁

一、 概述 Java Swing大富翁游戏是一个经典的大富翁桌面游戏的简单实现&#xff0c;使用Java Swing库创建。该游戏允许玩家在一个虚拟棋盘上掷骰子&#xff0c;购买和升级属性&#xff0c;赚取租金和尽量丰富自己。这个文档说明将介绍如何安装和运行游戏&#xff0c;以及游戏规…

【C++】C++11——右值引用和移动语义、左值引用和右值引用、右值引用使用场景和意义、完美转发、新的类功能

文章目录 C115.右值引用和移动语义5.1左值引用和右值引用5.2左值引用与右值引用比较5.3右值引用使用场景和意义5.4右值引用引用左值及其一些更深入的使用场景分析5.5完美转发 6.新的类功能 C11 5.右值引用和移动语义 右值引用是C11引入的一个新特性&#xff0c;用于支持移动语义…

冯诺依曼体系结构与进程的初步理解

目录 一&#xff0c;冯诺依曼体系结构 1.是什么&#xff1f;特点 2.为什么&#xff1f; 二&#xff0c;操作系统 三&#xff0c;进程 1.什么是进程&#xff1f; 2.查看进程 3.进程的管理 4.fork()创建子进程 1.fork()简介 2.fork()干了啥 3.fork()为什么会有两个返回…

【Java】微服务——Ribbon负载均衡(跟进源码分析原理)

添加LoadBalanced注解&#xff0c;即可实现负载均衡功能&#xff0c;这是什么原理 1.负载均衡原理 SpringCloud底层其实是利用了一个名为Ribbon的组件&#xff0c;来实现负载均衡功能的。 2.源码跟踪 为什么我们只输入了service名称就可以访问了呢&#xff1f;之前还要获取…

mstsc无法保存RDP凭据, 100%生效

问题 即使如下两项都打勾&#xff0c;其还是无法保存凭据&#xff0c;特别是连接Ubuntu (freerdp server)&#xff1a; 解决方法 网上多种复杂方法&#xff0c;不生效&#xff0c;其思路是修改后台配置&#xff0c;以使mstsc跟平常一样自动记住凭据。最后&#xff0c;如下的…

Python无废话-办公自动化Excel写入操作

Python 办公自动化-Excel写入 创建并保存Excel文件 import openpyxl workbookopenpyxl.Workbook() #创建空Excel文件 sheetworkbook.active #获取活动的工作表 sheet.title“测试“ #修改sheet工作表名称为测试 workbook.save(“data\input\Test.xlsx”) #保存Excel文件 …

R中的min()函数 和max()函数

通过min()函数和max()函数产生Inf 数值空集的最小值和最大值是Inf和–Inf(按此顺序&#xff01;)这确保了传递性&#xff0c;例如min(x1&#xff0c;min(x2)) min(x1&#xff0c;x2)。对于数值x&#xff0c;每当length (x) 0时&#xff0c;max(x) - Inf和min(x) Inf(如果需…

C#餐饮收银系统

一、引言 餐饮收银系统是一种用于管理餐馆、咖啡厅、快餐店等餐饮业务的计算机化工具。它旨在简化点餐、结账、库存管理等任务&#xff0c;提高运营效率&#xff0c;增强客户体验&#xff0c;同时提供准确的财务记录。C# 餐饮收银系统是一种使用C#编程语言开发的餐饮业务管理软…

SDK Vitis记录

文章目录 SDK记录SDK中报错“undefined reference to sqrt”的解决方法通过XML文件导入工程的include路径方法说明 其他设置编译选项设置某些文件/文件夹不编译单独设置文件的编译选项 向存储区中导入/导出数据通过GUI操作使用命令行操作 产生C代码的MAP文件在Xilinx SDK 工程的…

Golang 中的调试技巧

掌握有效的策略和工具&#xff0c;实现顺畅的开发 调试是每位开发人员都必须掌握的关键技能。它是识别、隔离和解决代码库中问题的过程。在 Golang 的世界中&#xff0c;掌握有效的调试技巧可以显著提升您的开发工作流程&#xff0c;并帮助您创建更可靠和健壮的应用程序。在本…

C语言 —— 函数栈帧的创建和销毁

在我们之前学习函数的时候&#xff0c;我们可能有很多困惑? 比如: 局部变量是怎么创建的?为什么局部变量的值是随机值?函数是怎么传参的?传参的顺序是怎样的?形参和实参是什么关系?函数调用是怎么做的?函数调用是结束后怎么返回的? 那么要解决这些问题, 我们就需要知道…

Raspberry Pi 5 新平台 新芯片组

Raspberry Pi 5 的 CPU 和 GPU 性能提高了两到三倍&#xff1b;内存和 I/O 带宽大约是两倍&#xff1b;并且是首款采用英国剑桥内部设计的芯片的 Raspberry Pi 计算机&#xff0c;4GB 型号的售价为 60 美元&#xff0c;8GB 版本的售价为 80 美元 主要特点包括&#xff1a; 2.4…

Zama的fhEVM:基于全同态加密实现的隐私智能合约

1. 引言 Zama的fhEVM定位为&#xff1a; 基于全同态加密实现的隐私智能合约 解决方案 开源代码见&#xff1a; https://github.com/zama-ai/fhevm&#xff08;TypeScript Solidity&#xff09; Zama的fhEVM协议中主要包含&#xff1a; https://github.com/zama-ai/tfhe-…

Windows11+VS2022+OCCT7.6.0安装配置记录

Windows11VS2022OCCT7.6.0安装配置记录 工具及源码准备VS2022以及CMake下载OCCT源码下载第三方库 CMake修改occt_toolkit.cmake进行CMake Visual Studio环境配置配置包含目录配置库目录配置链接器设置系统环境变量配置项目调试环境环境测试 其他方法 主要参考此文&#xff0c;在…

自然语言处理的分类

动动发财的小手&#xff0c;点个赞吧&#xff01; 简介 作为理解、生成和处理自然语言文本的有效方法&#xff0c;自然语言处理&#xff08;NLP&#xff09;的研究近年来呈现出快速传播和广泛采用。鉴于 NLP 的快速发展&#xff0c;获得该领域的概述并对其进行维护是很困难的。…

Golang 语言学习 01 包含如何快速学习一门新语言

Golang方向 区块链 go服务器端 (后台流量支撑程序) 支撑主站后台流量&#xff08;排序&#xff0c;推荐&#xff0c;搜索等&#xff09;&#xff0c;提供负载均衡&#xff0c;cache&#xff0c;容错&#xff0c;按条件分流&#xff0c;统计运行指标 (qps&#xff0c; latenc…

java飞机大战

一、 概述 1.1 项目简介 本次Java课程设计是做一个飞机大战的游戏&#xff0c;应用Swing编程&#xff0c;完成一个界面简洁流畅、游戏方式简单&#xff0c;玩起来易于上手的桌面游戏。该飞机大战项目运用的主要技术即是Swing编程中的一些窗口类库、事件监听以及贴图技术。 1…