首页 > 其他分享 >USART串口协议

USART串口协议

时间:2024-04-08 20:00:39浏览次数:17  
标签:协议 USART void 发送 串口 GPIO Serial

一、串口通信

1、串口定义

• 串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信 • 单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信,极大地扩展了单片机的应用范围,增强了单片机系统的硬件实力

 

              图1:  USB转串口模块               图·2:陀螺仪传感器    图3:蓝牙串口模块

2、硬件电路

                           TX:发送端                                 RX:接收端 • 简单双向串口通信有两根通信线(发送端 TX 和接收端 RX ) • TX 与 RX 要交叉连接   • 当只需单向的数据传输时,可以只接一根通信线 假如只需从设备一向设备二单向通信时,只需接TX到RX这条线,即为单工通信 • 当电平标准不一致时,需要加电平转换芯片 一般从TX发送端出来的一般都是TTL电平,而只有相同的电平才能相互通信,不同的电平信号需要加一个电平转换芯片 上面所说的相同电平,那不同的电平有什么标准呢?具体如下: 电平标准        所谓的电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平标准有如下三种: • TTL 电平: +3.3V 或 +5V 表示 1 , 0V 表示 0 • RS232 电平: -3~-15V 表示 1 , +3~+15V 表示 0

           •RS485电平:两线压差+2~+6V表示1,-2~-6V表示0(差分信号)

3、串口参数及时序

•波特率:指串口通信的速率

•起始位:标志一个数据帧的开始,固定为低电平

•数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行

•校验位:用于数据验证,根据数据位计算得来

•停止位:用于数据帧间隔,固定为高电平

                                                  图一

                                                  图二

如图一所示:串口中每个字节都装载在一个数据帧里面,每个数据帧都由起始位、数据位、和停止位组成,上图的数据位有8个代表一个字节的8位,而图二的D7的8为后面还可再加一位奇偶校验位,这样的数据位就为九位,前8位为有效载荷,代表一个字节,校验位在载荷位的后面占一个位,此为串口数据帧的整体结构

二、USART

1、USART简介

•USART(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步收发器

•USART是STM32内部集成的硬件外设,可根据数据寄存器的一个字节数据自动生成数据帧时序,从TX引脚发送出去,也可自动接收RX引脚的数据帧时序,拼接为一个字节数据,存放在数据寄存器里

•自带波特率发生器,最高达4.5Mbits/s

•可配置数据位长度(8/9)、停止位长度(0.5/1/1.5/2)

•可选校验位(无校验/奇校验/偶校验)

•支持同步模式、硬件流控制、DMA、智能卡、IrDA、LIN

•STM32F103C8T6 USART资源: USART1、 USART2、 USART3

图2.1                              USART基本结构图

2、波特率发生器

• 发送器和接收器的波特率由波特率寄存器 BRR 里的 DIV 确定 • 计算公式:波特率 = f PCLK2/1 / (16 * DIV)

3、配置串口发送配置步骤

①开启USART和GPIO时钟 RCC_APB2PeriphClockCmd(); RCC_APB2PeriphClockCmd(); ②GPIO初始化,把TX配置成复用输出,RX配置成输入 GPIO_Init();

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//选择推挽输出的原因是TX引脚是USART外设控制的输出脚,RX引脚是USART外设数据输入脚,故要选择输入模式

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;        

③配置USART,直接使用结构体配置即可 USART_Init(); USART_Cmd(); ④若只需要发送功能,直接开启USART初始化即可 ⑤若只需要接收功能,还需配置中断,即在开启USART之前加上ITConfig和NVIC USART_ITConfig(); NVIC_Init();

4、串口发送实例

通过串口助手发送数据

//Serial.c源文件
#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>

/**
  * 函    数:串口初始化
  * 参    数:无
  * 返 回 值:无
  */
void Serial_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);	//开启USART1的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟
	
	/*GPIO初始化*/
	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);					//将PA9引脚初始化为复用推挽输出
	
	/*USART初始化*/
	USART_InitTypeDef USART_InitStructure;					//定义结构体变量
	USART_InitStructure.USART_BaudRate = 9600;				//波特率
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;	//硬件流控制,不需要
	USART_InitStructure.USART_Mode = USART_Mode_Tx;			//模式,选择为发送模式
	USART_InitStructure.USART_Parity = USART_Parity_No;		//奇偶校验,不需要
	USART_InitStructure.USART_StopBits = USART_StopBits_1;	//停止位,选择1位
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;		//字长,选择8位
	USART_Init(USART1, &USART_InitStructure);				//将结构体变量交给USART_Init,配置USART1
	
	/*USART使能*/
	USART_Cmd(USART1, ENABLE);								//使能USART1,串口开始运行
}

/**
  * 函    数:串口发送一个字节
  * 参    数:Byte 要发送的一个字节
  * 返 回 值:无
  */
void Serial_SendByte(uint8_t Byte)
{
	USART_SendData(USART1, Byte);		//将字节数据写入数据寄存器,写入后USART自动生成时序波形
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);	//等待发送完成
	/*下次写入数据寄存器会自动清除发送完成标志位,故此循环后,无需清除标志位*/
}

/**
  * 函    数:串口发送一个数组
  * 参    数:Array 要发送数组的首地址
  * 参    数:Length 要发送数组的长度
  * 返 回 值:无
  */
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
	uint16_t i;
	for (i = 0; i < Length; i ++)		//遍历数组
	{
		Serial_SendByte(Array[i]);		//依次调用Serial_SendByte发送每个字节数据
	}
}

/**
  * 函    数:串口发送一个字符串
  * 参    数:String 要发送字符串的首地址
  * 返 回 值:无
  */
void Serial_SendString(char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i ++)//遍历字符数组(字符串),遇到字符串结束标志位后停止
	{
		Serial_SendByte(String[i]);		//依次调用Serial_SendByte发送每个字节数据
	}
}

/**
  * 函    数:次方函数(内部使用)
  * 返 回 值:返回值等于X的Y次方
  */
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;	//设置结果初值为1
	while (Y --)			//执行Y次
	{
		Result *= X;		//将X累乘到结果
	}
	return Result;
}

/**
  * 函    数:串口发送数字
  * 参    数:Number 要发送的数字,范围:0~4294967295
  * 参    数:Length 要发送数字的长度,范围:0~10
  * 返 回 值:无
  */
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');	//依次调用Serial_SendByte发送每位数字
	}
}

/**
  * 函    数:使用printf需要重定向的底层函数
  * 参    数:保持原始格式即可,无需变动
  * 返 回 值:保持原始格式即可,无需变动
  */
int fputc(int ch, FILE *f)
{
	Serial_SendByte(ch);			//将printf的底层重定向到自己的发送字节函数
	return ch;
}

/**
  * 函    数:自己封装的prinf函数
  * 参    数:format 格式化字符串
  * 参    数:... 可变的参数列表
  * 返 回 值:无
  */
void Serial_Printf(char *format, ...)
{
	char String[100];				//定义字符数组
	va_list arg;					//定义可变参数列表数据类型的变量arg
	va_start(arg, format);			//从format开始,接收参数列表到arg变量
	vsprintf(String, format, arg);	//使用vsprintf打印格式化字符串和参数列表到字符数组中
	va_end(arg);					//结束变量arg
	Serial_SendString(String);		//串口发送字符数组(字符串)
}
//Serial.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, ...);

#endif

//main.c源文件
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"

int main(void)
{
	/*模块初始化*/
	OLED_Init();						//OLED初始化
	
	Serial_Init();						//串口初始化
	
	/*串口基本函数*/
	Serial_SendByte(0x41);				//串口发送一个字节数据0x41
	
	uint8_t MyArray[] = {0x42, 0x43, 0x44, 0x45};	//定义数组
	Serial_SendArray(MyArray, 4);		//串口发送一个数组
	
	Serial_SendString("\r\nNum1=");		//串口发送字符串
	
	Serial_SendNumber(111, 3);			//串口发送数字
	
	/*下述3种方法可实现printf的效果*/
	
	/*方法1:直接重定向printf,但printf函数只有一个,此方法不能在多处使用*/
	printf("\r\nNum2=%d", 222);			//串口发送printf打印的格式化字符串
										//需要重定向fputc函数,并在工程选项里勾选Use MicroLIB
	
	/*方法2:使用sprintf打印到字符数组,再用串口发送字符数组,此方法打印到字符数组,之后想怎么处理都可以,可在多处使用*/
	char String[100];					//定义字符数组
	sprintf(String, "\r\nNum3=%d", 333);//使用sprintf,把格式化字符串打印到字符数组
	Serial_SendString(String);			//串口发送字符数组(字符串)
	
	/*方法3:将sprintf函数封装起来,实现专用的printf,此方法就是把方法2封装起来,更加简洁实用,可在多处使用*/
	Serial_Printf("\r\nNum4=%d", 444);	//串口打印字符串,使用自己封装的函数实现printf的效果
	Serial_Printf("\r\n");
	
	while (1)
	{
		
	}
}

      

标签:协议,USART,void,发送,串口,GPIO,Serial
From: https://blog.csdn.net/Zwgsnm/article/details/137471579

相关文章

  • FPGA入门笔记011_B——搭建串口收发与存取双口RAM简易应用系统
    1、实验现象​ 通过串口发送数据到FPGA中,FPGA接收到数据后将数据存储在双口ram的一段连续空间中,通过QuartusII软件提供的In-SystemMemoryContentEditor工具查看RAM中接收到的数据。当需要时,按下设计好的按键,则FPGA将RAM中存储的数据通过串口发送出去。2、......
  • 开箱即用的28181协议视频平台
    一、文档wvp使用文档:https://doc.wvp-pro.cnZLM使用文档:https://github.com/ZLMediaKit/ZLMediaKit二、ZLMediaKit流媒体服务框架#此镜像为github持续集成自动编译推送,跟代码(master分支)保持最新状态dockerrun-id-p1935:1935-p8080:80-p8443:443-p8554:554-p10000:1......
  • PS端通过串口输出helloword
    创建工程:创建一个RTL工程:选择器件:而我用的zedboard的SOC型号:XC7Z020CLG484-1创建PS工程:第1步:对设计进行命名:等待一会后出现如下的界面:第2步:选择sources第3步:添加IP:第4步:搜索ZYNQ的PS部分的IP核:等待一段时间后此界面的放缩方法:①Ctrl+鼠标滚轮②左键......
  • EBS 采用API生成一揽子采购协议
    程序包头createorreplacepackagecux_ws_scs_op_pba_pubis/*===============================================*===============================================*PROGRAMNAME:*cux_ws_op_vendor_scs_pub*DESCRIPTION:*......
  • 网络协议层
    一、OSI概念模型与TCP/IP模型 二、网络的分层结构: 物理层(PhysicalLayer):物理层是整个网络通信的基础层,它负责传输比特流。在物理层中,主要关注的是如何在通信媒介上传输数据,包括电压、频率、光强度等物理特性。物理层还涉及数据的数字与模拟信号的转换,以及物理连接的......
  • ELRS射频协议
    ELRS:基于LORA(LongRangeRadio):低功耗远距离无线电,semtech公司创建采用FHSS(FrequencyHoppingSpreadSpectrum):跳频和扩频指标:频率:2.4G、915MHz刷新率:<500Hz    遥控器ELRS打包速率越高,要求接受灵敏度(信号强度)越好 延时:ELRS系统硬件组成:ELRS发射机:外置ELRS高频......
  • 开源许可协议简述
     一、开源许可协议简述开源许可协议是指开源社区为了维护作者和贡献者的合法权利,保证软件不被一些商业机构或个人窃取,影响软件的发展而开发的协议。它的中文名:开源许可协议;外文名:opensourcelicense。二、开源许可协议之间的区别与联系通过上图,可以很清晰的了解到6......
  • 何为网络协议?一图知晓网络过程。
    网络协议就是计算机之间沟通的语言为了有效地交流,计算机之间需要一种共同的规则或协议,就像我们和老外沟通之前,要先商量好用哪种语言,要么大家都说中文,要么大家都说英语,这才能有效地沟通。网络协议就是计算机之间的语言,它们有一定的规则,规定了数据是怎么传输的,确保了数......
  • ERC314协议代币开发及合约开发详解
    ERC314是一种新的代币标准,旨在为BASE链上的代币提供更便捷、高效的交易体验。它由DAPJ项目团队开发,并于2023年8月首次发布。ERC314的特点无需依赖DEX或SWAP进行交易: ERC314代币可以像原生代币一样直接转账,无需借助DEX或SWAP进行交易。这使得交易更加......
  • 教你如何使用Zig实现Cmpp协议
    本文分享自华为云社区《华为云短信服务教你用Zig实现Cmpp协议》,作者:张俭。引言&协议概述中国网络通信集团短信网关协议(CNGP)是中国网通为实现短信业务而制定的一种通信协议,全称叫做ChinaNetcomShortMessageGatewayProtocol,用于在PHS短消息网关(SMGW)和服务提供商(SP)之间、短消......