串口通信——发送和接收数据(8位和16位数据之间的转换)

1. 实验目的

1.发送两个字节数据,就是16位的数据,每一次发送8位,发送两次,这里要进行数据的拆分,如发送一个0XFF56,接收得到的也是FF56(16进制显示);
2.接收两个字节的数据(这里通过串口助手以16进制发送一个数据),将拼接的数据(只能一个字节一个字节接收)除以100展示出来,如通过串口助手发送一个DEEE(16进制发送),其10进制就是57070,最终要展示为570.70。
其中串口是USART1,其端口是GPIOA,引脚是PIN9、PIN10,一个用来收数据,一个用来发收据。

2. 实验流程

初始化串口;
编写发送数据函数;
编写接收中断函数;
main函数调用发送函数。

2.1 初始化串口

//配置中断函数,这个函数下面有调用
 void EXTI_NVIC_Config(void){
	//NVIC初始化结构体
	NVIC_InitTypeDef  NVIC_InitStruct;
	//设置中断优先级的分组
	//就是设置主抢占优先级和子抢占优先级各是几,这里是分组为1,代表主优先级可以是0和1(就是1个位来设置主优先级),子优先级是0-7,是2的3次方
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	//配置USART为中断源
	NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
	//配置抢占优先级
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
	//配置子优先级
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
	//使能中断
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStruct);
}
//串口初始化函数
void USART_Config(void){
	//1.初始化GPIO(PA9(接串口1的TX引脚),这里是PA10(接串口1的RX引脚))
	//初始化结构体 GPIO_InitStruct
	//里面是GPIO的速度,上下拉,输出类型等
	 GPIO_InitTypeDef   GPIO_InitStruct;
	//USART结构体
	 USART_InitTypeDef   USART_InitStruct;
	//打开GPIOA时钟(一般开时钟要放到前面的位置,然后再是设置上拉,输出这些)
	 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);  //使能时钟必须放到前面,不然后面的操作不会使灯点亮
	//打开USART1时钟
	 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟
	//复位串口1
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource9,  GPIO_AF_USART1); //PA9 复用为 USART1
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); //PA10 复用为 USART1
	//驱动是哪个引脚  PA9/PA10
	GPIO_InitStruct.GPIO_Pin  = GPIO_Pin_9|GPIO_Pin_10;
	//模式是复用功能
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
		//输出的速度
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	//推挽复用输出
	GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
	//上拉
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
	//变量获取它的指针,取地址就行(&)
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	//2.初始化串口
	//使能串口时钟 (放在最上面了)
	//配置波特率
	USART_InitStruct.USART_BaudRate = 115200;  //设置波特率115200
	//配置针数据字长
	USART_InitStruct.USART_WordLength = USART_WordLength_8b; //字长为8位数据格式
	//配置停止位
	USART_InitStruct.USART_StopBits = USART_StopBits_1;     //设置为一个停止位
	//配置校验位
	USART_InitStruct.USART_Parity = USART_Parity_No;     //无奇偶校验位
	//配置硬件流控制
	USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //不使用硬件流控制
	//配置工作模式
	USART_InitStruct.USART_Mode =  USART_Mode_Rx|USART_Mode_Tx;  //收发模式
	//完成串口的初始化配置
	USART_Init(USART1,&USART_InitStruct);
	//串口中断优先级配置(初始化)
	EXTI_NVIC_Config();
	//使能串口接收中断(中断配置函数)  这是使能哪种中断,比如在接收到数据的时候(RXNE 读数据寄存器非空),我们要产生中断
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);  //生成串口中断   接收到数据就产生了中断
	USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);	// 开启空闲中断
	//使能串口(串口使能函数)
	USART_Cmd(USART1,ENABLE);
}

2.2 编写发送数据函数

一个16位的数据,先发送的是高8位,再发送第八位。
uint8_t temp_h,temp_l;
取高8位:temp_h = (data&0xFF00) >>8,先把数据按位与上0xFF00,这样低八位全取了0,再右移8位就得到了高8位。
取低8位:temp_l = (data&0x00FF); 把数据按位与上0x00FF就是高八位清零了,只剩下八位了。

//发送一个字节数据,进行了简单封装,判断了发送结束
void Usart_SendByte(USART_TypeDef* USARTx, uint8_t data){
	//串口发送数据
	USART_SendData(USARTx, data);
	//什么时候结束 检测状态寄存器的TXE位(发送数据寄存器为空)  TXE:Transmit data register empty
	while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE)== RESET){} //如果发送完成会结束循环 RESET=0
	//while(!(USART_GetFlagStatus(USARTx, USART_FLAG_TXE))){} //这个应该也是可以的
}

//发送两个字节数据
void Usart_SendHalfWord(USART_TypeDef* USARTx, uint16_t data){
	//定义高八位和低八位
	uint8_t temp_h,temp_l;
	//高8位的值是
	temp_h = (data&0xff00) >>8;
	temp_l =  data&0x00ff;   //高8位清0
	//串口发送高8位数据
	USART_SendData(USARTx,temp_h); //这里的USART_SendData是可以发送16位数据的
  //检测发送完成 检测状态寄存器的TXE位(发送数据寄存器为空)  TXE:Transmit data register empty
	while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE)== RESET){} //如果发送完成会结束循环 RESET=0
	//串口发送低8位数据
	USART_SendData(USARTx, temp_l);
  //检测发送完成 检测状态寄存器的TXE位(发送数据寄存器为空)  TXE:Transmit data register empty
	while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE)== RESET){} //如果发送完成会结束循环 RESET=0	
}

2.3 编写接收中断函数

	uint8_t rx_buff[50];  //声明一个数组
    uint8_t rx_cnt = 0;   //数组索引为0
    uint8_t usart_idle_flag = 0;
    uint16_t temp;
    //接收数据中断函数
void USART1_IRQHandler(void){
	uint8_t i;
	unsigned int data;
  if(USART_GetITStatus(USART1,USART_IT_RXNE)){  //每当接收到1个字节,会产生USART_IT_RXNE中断
		rx_buff[rx_cnt] = USART_ReceiveData(USART1);  //把这个数据放到数组中去
		rx_cnt++;
	}
  if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET){  //当接收到一帧数据,就会产生USART_IT_IDLE中断
		data = USART1->SR;		 // 清空闲中断
		data = USART1->DR;       
		usart_idle_flag = 1;	//产生空闲中断,没有用到
	//展示接收到的数据
	for(i=0;i<2;i++){
		printf("value = %x\n",rx_buff[i]);
	}
	//拼接数据
	temp = (rx_buff[0]<<8)|(rx_buff[1]); //或者是 (uint16_t)rx_buff[0]<<8 + (uint16_t)rx_buff[1]
		printf("value = %.2f\n",(float)temp/100);
		memset(rx_buff,0,sizeof(rx_buff));   //清空数组
		rx_cnt = 0;                          //索引置0
	}
}

2.4 main.c函数

int main(void){
  USART_Config();       //初始化串口
  Usart_SendHalfWord(USART1,0XFF56);  //调用发送两个字节函数
  while(1){}
}

3. 实验结果

发送两个字节展示如下图所示:
在这里插入图片描述
接收两个字节如下图所示:
在这里插入图片描述

4. 总结发现

在编写接收数据中断函数时,如果使用printf进行接收数据的打印时候,只会打印接收到的第一个字节,这里是把printf放到接收和空闲中断之间,会产生问题。

//接收数据中断函数
void USART1_IRQHandler(void){
	uint8_t i;
	unsigned int data;
	if(USART_GetITStatus(USART1,USART_IT_RXNE)){  //每当接收到1个字节,会产生USART_IT_RXNE中断
		rx_buff[rx_cnt] = USART_ReceiveData(USART1);  //把这个数据放到数组中去
		rx_cnt++;
	}
 
 //---------------------------------------------
  //放到两者之间的时候
  for(i=0;i<2;i++){
		printf("value = %x\n",rx_buff[i]);
	}
 //---------------------------------------------
	if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET){  //当接收到一帧数据,就会产生USART_IT_IDLE中断
		data = USART1->SR;		 // 清空闲中断
		data = USART1->DR;           
		usart_idle_flag = 1;	//产生空闲中断,没有用到
		temp = (rx_buff[0]<<8)|(rx_buff[1]); //或者是 (uint16_t)rx_buff[0]<<8 + (uint16_t)rx_buff[1]
		printf("value = %.2f\n",(float)temp/100);
		memset(rx_buff,0,sizeof(rx_buff));   //清空数组
		rx_cnt = 0;                          //索引置0
	}
}
### 回答1: Python串口通信是指使用Python编程语言操作串口进行通信。它是一种简单、灵活、可移植的工具,能够很方便地实现单片机与电脑之间的通讯。下面我们通过一个实例来了解Python串口通信。 该实例涉及到的硬件设备为Arduino UNO开发板和电脑,通过串口进行通讯,并使用Python编写程序。首先,我们需要在Arduino开发板上编写程序,如下所示: void setup() { Serial.begin(9600); } void loop() { Serial.println("Hello World!"); delay(1000); } 代码简单地实现了向串口发送"Hello World!"的功能,并且每隔1秒进行一次发送。 接下来,我们在电脑上使用Python编写程序,在Windows系统下可使用pyserial库进行串口通信。代码如下所示: import serial ser = serial.Serial('COM3', 9600) # 串口参数:端口号、波特率 while True: if ser.in_waiting: # 等待串口接收数据 data = ser.readline().decode().strip() # 读取数据 print(data) # 打印数据 代码进行了如下操作: 1. 引入pyserial库并创建串口对象ser,指定端口号为COM3,波特率为9600。 2. 在无限循环中,等待串口接收数据,当接收到数据时,通过readline()函数读取数据,并使用decode()函数将字节流转换为字符串,并使用strip()函数去除字符串中的空格和换行符。 3. 最后将读取的数据打印出来。 这样就可以通过Python实现串口通信的功能,而且在Linux和Mac OS X等操作系统上同样适用,因为pyserial库为跨平台支持。 ### 回答2: Python串口通信是Python语言在串口通信领域的应用实践,具有以简洁、清晰、易学易用、可扩展等优点。下面就Python串口通信实例进行介绍,以帮助读者更好地了解并运用Python串口通信。 Python串口通信的实现主要涉及到pySerial模块的运用,该模块提供了类似于Windows API的串口通信接口,可用于串口数据的读写操作。在运用pySerial模块实现Python串口通信前,我们需要了解串口通信需要的一些参数,如波特率、数据、校验和停止等。 了解了这些基础知识后,接下来我们可以实现一个Python串口通信的实例——读取传感器数据。假设我们需要从串口中读取连接到电脑的传感器的数据。步骤如下: 1. 导入pySerial模块:使用import语句导入pySerial模块。 2. 打开串口:使用pySerial的Serial()函数打开串口,例如:ser = serial.Serial('COM1', 9600, timeout=0.5)。 3. 读取数据:使用read()函数读取串口传回的数据。 4. 解析数据:将串口读取到的二进制数据转换成“人类可以读懂”的文本格式。 5. 处理数据:对数据进行适当的处理,如进行计算或存储。 该实例完整代码为: import serial ser = serial.Serial('COM1', 9600, timeout=0.5) while True: data = ser.read(12) if data != b'': data_str = data.decode('utf-8') data_list = data_str.split(',') data_1 = float(data_list[0]) data_2 = float(data_list[1]) # 对数据进行处理,如进行计算或存储 通过以上步骤,我们就可以成功读取传感器数据并进行相应的处理。以上实例只是Python串口通信的一个简单例子,具体的实现方法还需要根据实际情况进行调整,但是总体思路是相似的。Python串口通信具有较广泛的应用场景,如连接机器人、太阳能电池等,可以大大提高系统效率,开发者可以根据自己的需求,更好地运用Python串口通信技术。 ### 回答3: Python是一种非常流行的编程语言,它有很强的可扩展性和通用性,用于开发各种应用程序。其中一个典型的应用是串口通信,它可以将电脑连接到其他设备上。本文将介绍Python串口通信实例的基本原理和使用方法。 首先,在Python中使用串口通信需要安装PySerial库。这个库可以通过pip安装,具体命令为“pip install pyserial”。安装完成后,可以打开Python环境,在命令行中导入serial库,开始使用串口通信功能。 其次,串口通信需要打开串口,指定通信的波特率和字节大小等参数。在PySerial库中,可以使用serial.Serial()来创建一个串口对象。例如: ``` import serial ser = serial.Serial('COM1', 9600, timeout=1) ``` 其中,'COM1'是串口的名字,9600是波特率,timeout=1表示超时时间为1秒。当串口打开后,就可以开始发送接收数据了。 最后,使用串口通信时,一般要使用循环来读取数据。例如: ``` while True: data = ser.read(1) if data: print("Received: ", data) ``` 这个循环会一直执行,从串口中读取一个字节的数据,并将其打印出来。 以上就是Python串口通信的基本使用方法。通过安装PySerial库,创建串口对象,并使用循环读取数据,可以实现串口和电脑的通信。这种方法可以应用于各种场景,例如机器人控制、传感器数据采集等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值