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

2023-11-05

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
	}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • JavaScript判断对象是否为空对象的几种方法

    目录 1 空对象对应的字符串为 2 for in 3 jquery 的 isEmptyObject 方法 4 Object getOwnPropertyNames 5 ES6 的 Object keys 6 JSON stringify 扩
  • 服务计算--简单 web 服务与客户端开发实战

    一 概述 利用 web 客户端调用远端服务是服务开发本实验的重要内容 其中 要点建立 API First 的开发理念 实现前后端分离 使得团队协作变得更有效率 任务目标 选择合适的 API 风格 实现从接口或资源 领域 建模 到 API 设
  • C++ 字符串

    C 提供了以下两种类型的字符串表示形式 C 风格字符串 C 引入的 string 类类型 C 风格字符串 C 风格的字符串起源于 C 语言 并在 C 中继续得到支持 字符串实际上是使用 null 字符 终止的一维字符数组 因此 一个以 nu

随机推荐

  • 错误处理-mmdetection-AttributeError: ‘ConfigDict‘ object has no attribute ‘log_level‘

    第一次用商汤的mmdetection 遇到很多错误 mmdetection中网络的配置文件缺东西 至少缺了log level参数的值 此文章将继续更新我在使用过程中的问题与解决办法 敬请期待 祝你学习愉快 1 2 3 4 5 6 7 8 9
  • 数据库常用的四种方法

    排序查询 select 列表属性 列表属性 from 列表名order by 列表属性 列表属性 删除 delete from 列表名 where 列表属性 值 插入 insert into 列表名 values 值 值 值 值 inser
  • 数学知识整理:二重积分

    1 二重积分的性质 1 1 f x y 在有界闭区域上可积的充分条件 必要条件 在有界闭区域D上可积的函数f x y 必然是D上的有界函数 有界闭区域D上的连续函数或者分片连续函数f x y 在D上可积 1 2 线性性质 1 3 积分区域可
  • TCP/IP详解 卷1:协议 学习笔记 第十章 动态选路协议

    静态选路包括在配置接口时 以默认方式生成路由表项 对于直连路由 直连路由是由链路层协议发现的 一般指去往路由器的接口地址所在网段的路径 通过route命令增加表项 通常通过系统自引导程序文件 或通过ICMP重定向生成路由表项 通常在默认方式
  • 代理简介

    1 正向代理 正向代理类似一个跳板机 代理访问外部资源 比如我是一个用户 我访问不了某网站 但是我能访问一个代理服务器 这个代理服务器呢 他能访问那个我不能访问的网站 于是我先连上代理服务器 告诉他我需要那个无法访问网站的内容 代理服务器去
  • eclipse开发burpsuite插件

    安装相关软件 eclipse jee 2019 06 R win32 x86 64 zip burpsuite community edition v1 7 32 burpsuite 插件helloworld demo 下载链接在文章末尾
  • PyQt5之信号与信号槽

    一 信号与信号槽特点 PyQt的窗口控件类中有很多内置信号 开发者也可以添加自定义信号 信号与槽具有如下特点 一个信号可以连接多个槽 一个信号可以连接另一个信号 信号参数可以是任何Python类型 一个槽可以监听多个信号 信号与槽的连接方式
  • 定时删除centos服务器日志

    现在java程序的日志一般是使用log4j slf4j 来打日志 并且一般都喜欢用DailyRollingFileAppender模式 就是每天产生一个日志 还有一种是 RollingFileAppender模式 这个模式是按文件大小来保存
  • QT 实现五子棋

    1 程序简介 五子棋是一款大家都熟系的小游戏 这里给大家一步一步的详细介绍如何用QT开发这个游戏 并通过这款游戏的开发练习 进一步熟系 qvector qpoint qpainter QMouseEvent 产生工具栏等的用法和方法 2 程
  • 小学生报编程机器人有什么益处

    小学生报编程机器人有什么益处 小孩子的学习一直都是很多家长们非常关心和重视的一件事情 很多的家长在培养孩子的学习方面也可以说是相当的耐心的 就拿现在很多的家长想要孩子去学习机器人编程的课程来说 有的家长对于孩子学习机器人编程的好处并不是很清
  • 信号集(未决信号集,阻塞信号集)

    未决信号集和阻塞信号集的关系 阻塞信号集是当前进程要阻塞的信号的集合 未决信号集是当前进程中还处于未决状态的信号的集合 这两个集合存储在内核的PCB中 下面以SIGINT为例说明信号未决信号集和阻塞信号集的关系 当进程收到一个SIGINT信
  • 《从零开始编写一个直播服务器》 C++ 实现一个最简单的RTSP流媒体服务器

    流媒体开发系列文章 文章目录 流媒体开发系列文章 前言 一 rtsp流是什么 二 使用步骤 1 服务器代码 总结 前言 在安防行业中 onvif协议与gb协议是两种标准 gb是国内安防行业的标准 onvif是国外的安防行业的标准 其中gb2
  • 【华为OD机试】数字游戏【2023 B卷

    华为OD机试 真题 点这里 华为OD机试 真题考点分类 点这里 题目描述 小明玩一个游戏 系统发1 n张牌 每张牌上有一个整数 第一张给小明 后n张按照发牌顺序排成连续的一行 需要小明判断 后n张牌中 是否存在连续的若干张牌 其和可以整除小
  • Heroku 部署有关 opencv 的 Django 后端应用(pdf2docx)

    文章目录 场景 解决方案 Aptfile Buildpacks Dashboard 上手动构建 Heroku CLI 终端构建 Requirements txt 提交改变 场景 我使用 heroku 部署了一个 Django 后端项目 里面
  • C/C++内存布局

    下图是c c 的进程的内存分布布局图 搞清楚内存布局对于理解一个程序是非常重要的 一个程序运行起来 操作系统会给每个进程分配一个 4G 的程序地址空间 当然这都是虚拟地址空间 因为如果一个进程分 4G 的内存 那么就算有再多的内存也不够分
  • windows下的另一个辅助工具Devcon.exe(用会了绝对是神器)

    Device Console Help devcon exe r m
  • Unity3D关于iTween回调函数

    ITween一共三个回调函数 onstart onupdate和oncomplete 顾名思义可以从名字中看出来 常用到最后一个 要是我以后项目中用到了前两个函数 我会把例子添加上 关于oncomplete 就是在itween移动完成以后所
  • Spring Data Jpa

    spring data介绍 Spring Data s mission is to provide a familiar and consistent Spring based programming model for data acce
  • 单元测试、集成测试、系统测试

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

    1 实验目的 1 发送两个字节数据 就是16位的数据 每一次发送8位 发送两次 这里要进行数据的拆分 如发送一个0XFF56 接收得到的也是FF56 16进制显示 2 接收两个字节的数据 这里通过串口助手以16进制发送一个数据 将拼接的数据