【stm32】USART编码部分--详细步骤

news2024/12/28 20:05:12

USART编码部分(文章最后附上源码)

如果看不懂步骤可以根据源码参考此篇文章就能轻而易举学会USART通信啦!

编码步骤

第一步 开启时钟

把需要用到的USART和GPIO的时钟打开

第二部 GPIO初始化

把TX配置成复用输出,RX配置成输入(上拉输入、浮空输入)。

第三步 配置USART初始化

一个结构体配置所有参数

第四步 发送或接收

只需发送功能
  • 就直接开启USART,初始化就结束了
关于发送数据的类型
  1. 首先写发送一个字节数据的函数 SendByte函数

    1. 调用函数USART_SendData

    2. 等待发送寄存器空标志位

  2. 发送数组SendArray的函数

    1. 函数名形参一个字符指针,长度
    2. 函数体内调用SendByte,一位一位的发送数组数据
  3. 发送字符串 SendString 的函数

    1. 形参为一个字符指针

    2. 函数体内使用for循环或while一位一位的发送字符串的每个字节,直到遇到\0停止

  4. 发送数字SendNumber的函数

    1. 形参一个数字,类型给32位,然后还有一个长度

    2. 在函数里面需要把Number的十位个位百位等,以十进制拆分开,然后转换成字符数字对应的数据,一次发送出去

    3. 比如12345, 取万位就是12345/10000%10得到万位

    4. 需要先写一个次方函数, 形参是一个X,一个y,返回值是X的Y次方,都是32位

    5. 在这里插入图片描述

    6. 回到SendNumber,也是每次发送数据的每一位这个逻辑

    7. 在这里插入图片描述

需要接收功能
  • 首先配置PA10为上拉输入或者浮空输入

  • 接着在串口初始化里配置接收模式

  • 可以使用查询和中断两种方法

  • 如果使用查询,那初始化就结束了

    • 查询的流程是:

    • 在主函数里不断判断RXNE标志位,如果置1了(if成立),就说明收到数据了

    • 再调用ReceiveData,读取DR寄存器,就ok了

    • 最后还有清除标志位的问题,根据参考手册的寄存器描述进行相应的判断,是否需要清除标志位

    • 在这里插入图片描述

  • 如果使用中断,还需要在USART_cmd之前开去中断,配置NVIC,那就在开启USART之前,再加上ITConfig和NVIC的代码就行了

    • 接着写中断函数,在启动文件查找函数名

    • 中断函数里判断接收寄存器非空标志位

接收数据步骤(中断函数建立之后)
  1. 定义一个接收数据的变量和一个接受变量的标志位

    1. 在这里插入图片描述
  2. 建立一个接收数据标志位自动请0的函数,函数里清零标志位,返回1

  3. 建立一个返回数据的函数 GetRxData 的函数,把接收到了数据返回

    1. 上面两部也可以通过把两个变量声明为外部可调用的全局变量
  4. 中断函数里引用接收数据函数,赋给接收数据的变量,置标志位为1,证明接收到了数据

  5. 主函数里判断标志位,如果标志位为1,证明接收到了数据

  6. 可以在判断函数里使用OLED显示串口接收到的数据,然后把这个数据使用串口发送函数再发送到电脑串口助手进行显示

初始化之后

  • 初始化之后,如果要发送数据,调用一个发送函数就行了

  • 如果要接收数据,就调用接收的函数

  • 如果要获取发送和接收的状态,就调用获取标志位的函数

USART 函数介绍

  • USART_ClockInit 和 USART_ClockStrustInit 用来配置同步时钟输出的,包括时钟是不是要输出,时钟的极性相位等参数

  • USART_DMACmd 可以开启USART到DMA的触发通道

  • USART_SendData 发送数据

  • USART_ReceiveData 接收数据

      *发送和接收的时候用*
    

关于子函数

传递字符串

由于字符串自带一个结束标志为,所以就不需要传递长度参数;
for(i=0; String[i] != ‘\0’; i++)

换行:Serial_SendString(“\r\n”)

传递数字

  • 加一个偏移

  • 首先定义一个取数字模的函数Serial_Pow

  • Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + 0x30);//0x30可以写成’0’

Printf函数一直方法使用

  1. 使用Printf之前,打开工程选项,勾选Use MicroLIB(是Keil为嵌入式平台优化的一个精简库)

  2. 要用的Printf函数就可以用MicroLIB

  3. 对Printf进行重定向,将Printf打印的东西输出到串口,因为printf函数默认输出到屏幕,单片机没有屏幕,所以要进行重定向。

printf使用步骤

  1. 最开始加上,#include<stdio.h>

  2. 在最后重写fputc函数。 int fputc(int ch, FILE *F) 这是fputc函数的原型

  3. 然后在函数里面把fputc重定向到串口 (Serial_SendByte(ch));

  4. return ch;

  5. 这样printf函数就移植好了

  6. 最后在串口头文件中包含#include<stdio.h>,相当于main函数内也包含stdio.h

fputc 与 Printf的关系

  • 因为fputc是pritf函数的底层

  • pritf函数在打印的时候,就是不断调用fputc函数一个个打印的

  • 我们把fputc函数重定向到了串口,那printf自然就输出到了串口

printf函数在主函数中使用方法

printf(“Num=%d\r\n”,666);

如果多个串口都想用Printf的方法

这时就可以用Spritf

  • Spritf可以把格式化字符输出到,一个字符串里
  1. 先定义一个字符串(主函数里) char string[100]

  2. 然后sprintf第一个参数是打印输出的位置, sprintf(string, “Num=%d\r\n”,666);

  3. 目前这个格式化的字符在String里

  4. 接着Serial_SendString

  • sprintf可以设置打印位置,不涉及重定向

  • 所以每个串口都有可以使用Sprintf进行打印

封装Sprintf

  • 由于printf这类函数比较特殊,它支持可变的参数
  1. 在串口模块里添加头文件 #include <stdarg.h>

  2. 然后在最后对printf函数进行封装 void Serial_Printf(char *format, …) format这个参数用来接收格式化字符串 …三个点用来接收后面的可变参数列表

  3. 在函数里面

    1. 首先定义输出的字符串 char string[100]

    2. va_list arg 定义一个参数列表变量

    3. va_start(arg, format) 从format位置开始接收参数表,放在arg里面

    4. 之后 vsprintf(string, format, arg); 对于这种封装格式要用vsprintf

    5. va_end(arg) 释放参数表

    6. 最后是 Serial_SendString(String) 把String发送出去

    7. 在这里插入图片描述

关于乱码

在这里插入图片描述

Serial.c文件程序//也就是串口的.c文件

#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>

uint8_t Serial_RxData;
uint8_t Serial_RxFlag;

void Serial_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate = 9600;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_Init(USART1, &USART_InitStructure);
	
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
	
	USART_Cmd(USART1, ENABLE);
}

void Serial_SendByte(uint8_t Byte)
{
	USART_SendData(USART1, Byte);
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}

void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
	uint16_t i;
	for (i = 0; i < Length; i ++)
	{
		Serial_SendByte(Array[i]);
	}
}

void Serial_SendString(char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i ++)
	{
		Serial_SendByte(String[i]);
	}
}

uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;
	while (Y --)
	{
		Result *= X;
	}
	return Result;
}

void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i ++)
	{
		Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
	}
}

int fputc(int ch, FILE *f)
{
	Serial_SendByte(ch);
	return ch;
}

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);
}

uint8_t Serial_GetRxFlag(void)
{
	if (Serial_RxFlag == 1)
	{
		Serial_RxFlag = 0;
		return 1;
	}
	return 0;
}

uint8_t Serial_GetRxData(void)
{
	return Serial_RxData;
}

void USART1_IRQHandler(void)
{
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		Serial_RxData = USART_ReceiveData(USART1);
		Serial_RxFlag = 1;
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}
}

Serial.h文件程序//也就是串口的.h文件

#ifndef __SERIAL_H
#define __SERIAL_H

#include <stdio.h>

void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array, uint16_t Length);
void Serial_SendString(char *String);
void Serial_SendNumber(uint32_t Number, uint8_t Length);
void Serial_Printf(char *format, ...);

uint8_t Serial_GetRxFlag(void);
uint8_t Serial_GetRxData(void);

#endif

main.c文件程序

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"

uint8_t RxData;

int main(void)
{
	OLED_Init();
	OLED_ShowString(1, 1, "RxData:");
	
	Serial_Init();
	
	while (1)
	{
		if (Serial_GetRxFlag() == 1)
		{
			RxData = Serial_GetRxData();
			Serial_SendByte(RxData);
			OLED_ShowHexNum(1, 8, RxData, 2);
		}
	}
}

感谢各位能坚持看到这里!

如果能有机会得到您的一个小赞那我就更有动力了!

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

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

相关文章

VMware虚拟机添加磁盘

在VMware中添加磁盘 &#xff08;虚拟机关闭状态下执行&#xff09; 然后选择默认一步一步点下去&#xff0c;最后创建好新磁盘 开启虚拟机&#xff0c;挂载磁盘 通过命令 lsblk -f 查看未挂载的新磁盘 lsblk -f 通过fdisk命令进行磁盘分区 # 1. 给硬盘/dev/sdb进行分区&am…

2024年04月数据库流行度最新排名

点击查看最新数据库流行度最新排名&#xff08;每月更新&#xff09; 2024年04月数据库流行度最新排名 TOP DB顶级数据库索引是通过分析在谷歌上搜索数据库名称的频率来创建的 一个数据库被搜索的次数越多&#xff0c;这个数据库就被认为越受欢迎。这是一个领先指标。原始数…

Qt6.6添加多媒体模块Multimedia报错问题

问题 QT包含多媒体模块Multimedia时提示未知的模块&#xff1a; error: Project ERROR: Unknown module(s) in QT: multimedia 在帮助文档中只可以找到QMediaPlayer类&#xff0c;但是点进去是空的&#xff0c;这是因为没有安装多媒体模块及对应的帮助文档。 解决 使用在线…

RTOS中临界区嵌套保护的实现原理(基于RT-Thread)

0 前言 什么是临界区&#xff08;临界段&#xff09;&#xff1f; 裸机编程中由于不涉及线程和线程切换&#xff0c;因此没有临界区这一个概念。在RTOS中由于存在线程切换等场景&#xff0c;便有了临界区这个概念。简单来说&#xff0c;临界区就是不允许被中断的代码区域。什么…

【操作系统】FCFS、SJF、HRRN、RR、EDF、LLF调度算法及python实现代码

文章目录 一、先来先服务调度算法&#xff08;FCFS&#xff09; 二、短作业优先调度算法&#xff08;SJF&#xff09; 三、高响应比优先调度算法&#xff08;HRRN&#xff09; 四、轮转调度算法&#xff08;RR&#xff09; 五、最早截至时间优先算法&#xff08;EDF&#…

ES学习日记(七)-------Kibana安装和简易使用

前言 首先明确一点&#xff0c;Kibana是一个软件&#xff0c;不是插件。 Kibana 是一款开源的数据分析和可视化平台&#xff0c;它是 Elastic stack 成员之一&#xff0c;设计用于和Elasticsearch 协作。您可以使用 Kibana 对 Elasticsearch 索引中的数据进行搜索&#xff0c;…

机器学习——卷积的变种

机器学习——卷积的变种 卷积神经网络&#xff08;Convolutional Neural Networks, CNNs&#xff09;是深度学习领域中最重要的技术之一&#xff0c;它在图像处理、语音识别、自然语言处理等领域取得了巨大成功。在CNN中&#xff0c;卷积层是最核心的组成部分之一&#xff0c;…

Java与Go的并发世界:理解Work Sharing与Work Stealing

概述 最近在理解Golang中的Per P概念&#xff0c;于是我就去Go的源码中挖呀挖&#xff0c;结果挖到了Go的调度器设计。 Golang的调度器设计文档提到了Go中的P(OS线程)调度器使用的是work-stealing调度算法论文。 论文中提到了两个多线程调度算法&#xff1a;work sharing和wor…

ETL工具-nifi干货系列 第六讲 处理器JoltTransformJSON

1、处理器作用 使用Jolt转换JSON数据为其他结构的JSON,成功的路由到success,失败的failure。处理JSON的实用程序不是基于流的&#xff0c;因此大型JSON文档转换可能会消耗大量内存。 Jolt&#xff1a;JSON 到 JSON 转换库&#xff0c;用 Java 编写&#xff0c;其中转换的 &qu…

自动驾驶---Motion Planning之轨迹Speed优化

1 背景 在之前的几篇文章中&#xff0c;不管是通过构建SL图《自动驾驶---Motion Planning之Path Boundary》&#xff0c;ST图《自动驾驶---Motion Planning之Speed Boundary》&#xff0c;又或者是构建SLT图《自动驾驶---Motion Planning之构建SLT Driving Corridor》&#xff…

vivado 配置存储器器件编程2

为双 QSPI (x8) 器件创建配置存储器文件 您可使用 write_cfgmem Tcl 命令来为双 QSPI (x8) 器件生成 .mcs 镜像。此命令会将配置数据自动拆分为 2 个独立 的 .mcs 文件。 注释 &#xff1a; 为 SPIx8 生成 .mcs 时指定的大小即为这 2 个四通道闪存器件的总大小。…

生产制造园区数字孪生3D大屏展示提升运营效益

在智慧园区的建设中&#xff0c;3D可视化管理平台成为必不可少的工具&#xff0c;数字孪生公司深圳华锐视点打造的智慧园区3D可视化综合管理平台&#xff0c;致力于将园区的人口、经济、应急服务等各项业务进行3D数字化、网络化处理&#xff0c;从而实现决策支持的优化和管理的…

前端二维码生成工具小程序:构建营销神器的技术解析

摘要&#xff1a; 随着数字化营销的不断深入&#xff0c;二维码作为一种快速、便捷的信息传递方式&#xff0c;已经广泛应用于各个领域。本文旨在探讨如何通过前端技术构建一个功能丰富、操作简便的二维码生成工具小程序&#xff0c;为企业和个人提供高效的营销支持。 一、引言…

【目标检测】YOLOv6 的网络结构,图解RepBlock重参数化

YOLOv6 是美团推出的&#xff0c;在这个版本里面&#xff0c;不再使用之前 YOLOv4 和 YOLOv5 的带 CSP 结构的 CSPDarknet-53 作为 backbone 了&#xff0c;而是在 RepVGG 的启发下&#xff0c;推出了新的 EfficientRep 作为 YOLOv6 的 backbone。 RepVGG 最重要的一点是&…

学透Spring Boot 003 —— Spring 和 Spring Boot 常用注解(附面试题和思维导图)

这是 学透 Spring Boot 专栏 的第三篇&#xff0c;欢迎关注我&#xff0c;与我一起学习和探讨 Spring Boot 相关知识&#xff0c;学透 Spring Boot。 从面试题说起 今天我们通过一道和Spring Boot有关的常见面试题入手。 面试题&#xff1a;说说 Spring Boot 中有哪些常用注解…

助力瓷砖生产智造,基于YOLOv5全系列参数【n/s/m/l/x】模型开发构建瓷砖生产制造场景下1280尺寸瓷砖表面瑕疵检测识别系统

砖生产环节一般经过原材料混合研磨、脱水、压胚、喷墨印花、淋釉、烧制、抛光&#xff0c;最后进行质量检测和包装。得益于产业自动化的发展&#xff0c;目前生产环节已基本实现无人化。而质量检测环节仍大量依赖人工完成。一般来说&#xff0c;一条产线需要配数名质检工&#…

Windows系统搭建TortoiseSVN客户端并实现无公网IP访问内网服务端

文章目录 前言1. TortoiseSVN 客户端下载安装2. 创建检出文件夹3. 创建与提交文件4. 公网访问测试 前言 TortoiseSVN是一个开源的版本控制系统&#xff0c;它与Apache Subversion&#xff08;SVN&#xff09;集成在一起&#xff0c;提供了一个用户友好的界面&#xff0c;方便用…

Mysql的基本命令

1 服务相关命令 命令描述systemctl status mysql查看MySQL服务的状态systemctl stop mysql停止MySQL服务systemctl start mysql启动MySQL服务systemctl restart mysql重启MySQL服务ps -ef | grep mysql查看mysql的进程mysql -uroot -hlocalhost -p123456登录MySQLhelp显示MySQ…

使用 Django 构建简单 Web 应用

当我们在使用Django构建Web应用时&#xff0c;通常将会涉及到多个步骤&#xff0c;从创建项目到编写视图、模板、模型&#xff0c;再到配置URL路由和静态文件&#xff0c;最后部署到服务器上。所以说如果有一个环节出了问题&#xff0c;都是非常棘手的&#xff0c;下面就是我们…

vim copilot插件安装使用

copilot简介 在使用不熟悉的开发语言或函数库进行开发工作时&#xff0c;虽然可以通过阅读开发文档或示例代码的方式学习开发&#xff0c;但这种方式学习成本较高、效率较低&#xff0c;且后续不一定会用上。 GitHub Copilot是一个由GitHub开发的机器学习工具&#xff0c;可以…