模拟串口LV2,解决硬件串口资源不足问题!!!!

模拟串口通信 2.0 版本!!

我在前面的文章里面有写了 虚拟串口通信,虽然说能用,但是用过的小伙伴都说 “好!”

优缺点:

先说一点,2.0版本并不适用于同硬件串口的所有场合,仅仅针对自己开发的电子垃圾的主从结构,比如自己的两块板子通信,或者硬件串口没得了又想追加串口不得已的情况。

优点:

1.可以设置任意波特率, 并且从机不可以识别任意波特率数据(只要主时钟频率高就行了)。
2.可以实现不定长度数据收发,并且用户能完成收发标志 1.0版本可不行。
3.减少资源消耗,同比1.0版本,在芯片内部外设资源上面有所减少。
4.同比1.0版本 大大提高收发数据稳定性。反正我实验没有丢过数据。

好下面说缺点:

缺点:

1. 2.0版本相对于1.0版本,硬件接线上面多出了1根时钟线(相当于 一个串口收发需要三根线,三根线,三根线,如果有多路虚拟串口,则每一路仅需要追加 2 根线,笑哭!!! )。
2. 因为是任意波特率所以无法和其他硬件串口做对接 如果非要接 那你就吧波特率规定到和硬件一样。
3. 串口通信点对点,懂得都懂。只不过用的IO模拟 ,有些引脚上面的驱动能力要强那么丢丢,一对多可试试。
好!!到这里有人就会问了:三根线,你走SPI啥!再不济你走I2C,I2C还少根线。你三根线还是模拟的数据玩个鸡毛!!
嗯?问的好!我竟无言以对,但是这是全双工通信,而且没有比较严格的主从关系,而且通信只能主机发起,不能从机发起。

好!!那又有人会问:那和SPI 有啥子区别啥,都是三线全双工通信。

好那就看下面:
在这里插入图片描述
这是一个数据收发的时序图,上面可以看到从主模块出来的TX是在时钟的下降沿发出通信起始位,然后在每个下降沿到达时改变信号状态,在时钟上升沿进行数据采集,而RX则是反过来,在上升沿发起通信并且修改电平状态,下降沿采集状态。所以在两数据通信的时候上升和下降沿都有意义。



首先是主控板 :

下面来看配置情况:

这里我定义的三个通用IO口
IO_CLK :时钟输出脚(GPIO)
IO_RX :接受输入脚(GPIO)
IO_TX :数据输出脚(GPIO)
开一个定时器 使能 更新溢出中断(定时时间自己设置一个就行)

在这里插入图片描述
在这里插入图片描述

以上就是基本的软件配置信息,这一块比较简单大家大概配置一下就行了,剩下的就是代码部分了

/* *****************************************************************
*Copyright (C), 2019-2023, TTT
*Filename:          M_File_Oled.c
*Author  :          ZY
*Created Date :     15/02/2023
*Abstract   :       处理全局参数
*History :
*V1.0.0   : Initial (by ZY,15/02/2023)
***************************************************************** */
#include "M_File_IOUart.h"//定义结构体
struct IOUart  IOUart_h_Struct={ .IO_UART_RecvStat = COM_STOP_BIT};
/*****************************************
* 函数名: IoUartSendByte
* 功能说明: 模拟串口发送1个字节数据
* 形参:Byte 要发送的字节
* 返回值: 无
******************************************/
void IoUartSendByte(uint8_t Byte)
{uint8_t tmp = 0;static uint8_t count = 0;static uint8_t Old_IO_UART_StartTXFlag  = 0;// 开始位if(IOUart_h_Struct.IO_UART_StartTXFlag1BIT != Old_IO_UART_StartTXFlag) {if(IOUart_h_Struct.IO_UART_StartTXFlag1BIT == 1){IO_UART_TXD(0); //将TXD的引脚的电平置低count = 0;}Old_IO_UART_StartTXFlag = IOUart_h_Struct.IO_UART_StartTXFlag1BIT;}else {if(count < 8)	{				tmp = (Byte >> count) & 0x01;if(tmp==0){IO_UART_TXD(0);}else{IO_UART_TXD(1);}count++;}else{IO_UART_TXD(1);//将TXD的引脚的电平拉高IOUart_h_Struct.IO_UART_StartTXFlag1BIT = 0;   //结束 发送数据Old_IO_UART_StartTXFlag = 0;count =0;}}   
}/*******************************************************************************
*Name :            IO_UART_SendData
*Syntax :          void  IO_UART_SendData(const char *Data,uint32_t size)
*Parameters(in) :
*Parameters(out) : 无
*Return value :    无
*Description :     IO串口发送字符串
********************************************************************************/
void  IO_UART_SendString(const char *String)
{for(int i=0; i<strlen(String); i++){IoUartSendByte(String[i]);}
}/*******************************************************************************
*Name :            IO_UART_SendData
*Syntax :          void  IO_UART_SendData(const char *Data,uint32_t size)
*Parameters(in) :
*Parameters(out) : 无
*Return value :    无
*Description :     IO串口发送数据
********************************************************************************/
void IO_UART_SendData(const char *Data,uint32_t size)
{if(IOUart_h_Struct.IO_UART_StartTXFLAGBuff == 0){IOUart_h_Struct.IO_Send_Size = size;memcpy(IOUart_h_Struct.IO_UART_TXBuff,Data,size);		IOUart_h_Struct.IO_UART_StartTXFLAGBuff = 1;}
}/*******************************************************************************
*Name :            IO_UART_ReciveData
*Syntax :          void  IO_UART_ReciveData(void)
*Parameters(in) :
*Parameters(out) : 无
*Return value :    无
*Description :     IO串口接收字符串
********************************************************************************/
void IO_UART_ReciveData(void)
{if(IOUart_h_Struct.IO_UART_StartRxFlag == 1){IOUart_h_Struct.IO_UART_RecvStat++;if(IOUart_h_Struct.IO_UART_RecvStat == COM_STOP_BIT){									//接收到完整的1个字节数据if(IOUart_h_Struct.IO_UART_RxNum < _IO_RX_LENGHT){IOUart_h_Struct.IO_UART_RxBuff[IOUart_h_Struct.IO_UART_RxNum++] = IOUart_h_Struct.IO_UART_RecvData;	//存入缓冲区}else{IOUart_h_Struct.IO_UART_RxNum = 0;										}IOUart_h_Struct.IO_UART_StartRxFlag = 0;							IOUart_h_Struct.IO_UART_RecvData = 0;return;}if(IO_UART_RXD)//读取接收引脚的状态{IOUart_h_Struct.IO_UART_RecvData |= (1 << (IOUart_h_Struct.IO_UART_RecvStat - 1));}else{IOUart_h_Struct.IO_UART_RecvData &= ~(1 << (IOUart_h_Struct.IO_UART_RecvStat - 1));}}
}/*******************************************************************************
*Name :            IO_UART_Send_Buff
*Syntax :          void IO_UART_Send_Buff(void)
*Parameters(in) :
*Parameters(out) : 无
*Return value :    无
*Description :     IO串口发送数据处理
********************************************************************************/
void IO_UART_Send_Buff(void)
{static uint8_t OLD_IO_UART_StartTXFLAGBuff = 0;static uint8_t OLD_Send_Count = 0;if(OLD_IO_UART_StartTXFLAGBuff!= IOUart_h_Struct.IO_UART_StartTXFLAGBuff){		 if(IOUart_h_Struct.IO_UART_StartTXFLAGBuff == 1){OLD_Send_Count = 0;			  IOUart_h_Struct.IO_UART_StartTXFlag1BIT = 1; //发送数据}		 OLD_IO_UART_StartTXFLAGBuff = IOUart_h_Struct.IO_UART_StartTXFLAGBuff;		}else{if(IOUart_h_Struct.IO_UART_StartTXFLAGBuff == 1){if(OLD_Send_Count<IOUart_h_Struct.IO_Send_Size){IoUartSendByte(IOUart_h_Struct.IO_UART_TXBuff[OLD_Send_Count]);if(IOUart_h_Struct.IO_UART_StartTXFlag1BIT == 0){						OLD_Send_Count++;if(OLD_Send_Count<IOUart_h_Struct.IO_Send_Size){IOUart_h_Struct.IO_UART_StartTXFlag1BIT = 1; //发送数据}}else{}		 }else{IOUart_h_Struct.IO_UART_StartTXFLAGBuff = 0;IOUart_h_Struct.IO_Send_Size =0 ;	}}}
}/*******************************************************************************
*Name :            IO_UART_Time_CountDown_Deal
*Syntax :          void IO_UART_Time_CountDown_Deal(void)
*Parameters(in) :
*Parameters(out) : 无
*Return value :    无
*Description :     IO串口倒计时处理
********************************************************************************/
void IO_UART_Time_CountDown_Deal(void)
{if(IOUart_h_Struct.IO_UART_RxTimeOut>0){if(IOUart_h_Struct.IO_UART_RxTimeOut == 1){IOUart_h_Struct.IO_UART_RxTimeOut --;IOUart_h_Struct.IO_UART_RxOK = 1;     //一条数据接收完成IOUart_h_Struct.IO_UART_RxNum = 0;//完整接受到一条数据//TsUserM_h_Flag.e_u_UartAppceptFlag[0] = ON;return ;}IOUart_h_Struct.IO_UART_RxTimeOut--;	}else{}
}
/* *****************************************************************
*Copyright (C), 2019-2023, TTT
*Filename:          M_File_IOUart.h
*Author  :          ZY
*Created Date :     15/02/2023
*Abstract   :       处理全局参数
*History :
*V1.0.0   : Initial (by ZY,15/02/2023)
***************************************************************** */
#ifndef __M_FILE_IOUart_H__
#define __M_FILE_IOUart_H__//#include "M_File_Flag.h"
/*自己定义导入的.h 文件 ******************************************************/#define _IO_RX_LENGHT        200       																//接收数据长度
#define _IO_RX_TIMECOUNTDOWN  15																	//接收数据超时倒计时
/*
*@串口接收字节
*/
enum 
{COM_START_BIT = 0,COM_D0_BIT,COM_D1_BIT,COM_D2_BIT,COM_D3_BIT,COM_D4_BIT,COM_D5_BIT,COM_D6_BIT,COM_D7_BIT,COM_STOP_BIT,
};struct IOUart{uint8_t 	IO_UART_RecvData; 							//接收数据uint8_t 	IO_UART_RecvStat;  							//接收状态		uint16_t    IO_UART_RxNum;								//接收数据长度uint8_t 	IO_UART_RxBuff[_IO_RX_LENGHT];				//模拟串口接收数据缓冲区uint8_t     IO_UART_TXBuff[_IO_RX_LENGHT];				//模拟串口发送数据缓冲区uint32_t 	IO_UART_RxTimeOut;            				//模拟串口接收超时计数uint8_t 	IO_UART_RxOK;               				//数据接收完成标志uint8_t 	IO_UART_StartRxFlag;						//开始接收标志,1开始接收,0不接收			uint8_t   IO_UART_StartTXFlag1BIT;						//开始发送标志,1开始发送,0不发送uint8_t   IO_UART_StartTXFLAGBuff;						//多字节发送uint16_t  IO_Send_Size;	
};/*把下面的引脚重新指定到自己指定的引脚上面 打开宏定义 ******************************************************/
#if 0    
//读取Rx脚
#define IO_UART_RXD  HAL_GPIO_ReadPin(IO_RX_GPIO_Port,IO_RX_Pin)     //模拟串口RX端
//设置Tx脚拉高拉低
#define IO_UART_TXD(n)  if(n) HAL_GPIO_WritePin(IO_TX_GPIO_Port, IO_TX_Pin, GPIO_PIN_SET); \else  HAL_GPIO_WritePin(IO_TX_GPIO_Port, IO_TX_Pin, GPIO_PIN_RESET);
//设置时钟脚													
#define IO_UART_CLK(n)  if(n) HAL_GPIO_WritePin(IO_CLK_GPIO_Port, IO_CLK_Pin, GPIO_PIN_SET); \else  HAL_GPIO_WritePin(IO_CLK_GPIO_Port, IO_CLK_Pin, GPIO_PIN_RESET);
#endifextern struct IOUart  IOUart_h_Struct;extern void IO_UART_Send_Buff(void);
extern void IO_UART_SendData(const char *Data,uint32_t size);
extern void IO_UART_Time_CountDown_Deal(void);
extern void IO_UART_ReciveData(void);#endif
定时器中断回调里面处理部分:
			HAL_GPIO_TogglePin(IO_CLK_GPIO_Port, IO_CLK_Pin);				//翻转输出时钟if(HAL_GPIO_ReadPin(IO_CLK_GPIO_Port, IO_CLK_Pin))      		//判断电平 当前输出为 高电平{IO_UART_Send_Buff();}else    //引脚拉低{IO_UART_Time_CountDown_Deal(); 			IO_UART_ReciveData();										 //处理虚拟串口接收数据	if((IO_UART_RXD == GPIO_PIN_RESET)&&(IOUart_h_Struct.IO_UART_StartRxFlag == 0))  //判定是否有低电平数据进入{if(IOUart_h_Struct.IO_UART_RecvStat == COM_STOP_BIT)			//状态为停止位{IOUart_h_Struct.IO_UART_RecvStat = COM_START_BIT;			//设置状态为起始位							IOUart_h_Struct.IO_UART_StartRxFlag = 1;					//开始接收					IOUart_h_Struct.IO_UART_RecvData = 0;  						//接收数据							IOUart_h_Struct.IO_UART_RxTimeOut = _IO_RX_TIMECOUNTDOWN;//接收到数据把接收超时清零																}		 }}

上面是核心代码,如果接受不定长度代码 可在 IO_UART_Time_CountDown_Deal 函数里面 写接受完成标志。

模拟串口 printf 数据

/*******************************************************************************
Name           	 :FlagM_Uart_Printf
Syntax           :void UartM_485Printf(char *fmt,...)
Parameters(in)   :None              :-
Parameters(out)  :None              :-
Return value     :-                 :-
Description      :模拟串口数据打印
|******************************************************************************/
__align(8) char usart_txBuff[USART_TXBUFF_SIZE];                //字节对齐缓冲区
void FlagM_IOUart_Printf(char *fmt,...)
{uint32_t length;va_list ap;va_start(ap,fmt);vsprintf(usart_txBuff,fmt,ap);va_end(ap);length=strlen((const char*)usart_txBuff);   IO_UART_SendData(usart_txBuff,length);    
}


从机部分(时钟来来自主机):

IO_CLK :外部中断脚(EXIT)上升下降沿触发
IO_RX :接受输入脚(GPIO)
IO_TX :数据输出脚(GPIO)
在这里插入图片描述
在这里插入图片描述
基本配置比较简单

代码部分:

核心部分一样的,差异就是 主机在定时回调里面处理数据,而从机则是在外部中断中回调里处理数据

	if(GPIO_Pin == IO_CLK_Pin){if(IO_UART_CLK == GPIO_PIN_RESET)							//RX 时钟引脚为低电平  {			IO_UART_Time_CountDown_Deal();  						//处理虚拟串口接收数据			 IO_UART_ReciveData();								//处理接受的数据if((IO_UART_RXD == GPIO_PIN_RESET)&&(IOUart_h_Struct.IO_UART_StartRxFlag == 0)){if(IOUart_h_Struct.IO_UART_RecvStat == COM_STOP_BIT)//状态为停止位{IOUart_h_Struct.IO_UART_RecvStat = COM_START_BIT;	//设置状态为起始位IOUart_h_Struct.IO_UART_StartRxFlag = 1;					//开始接收					IOUart_h_Struct.IO_UART_RecvData = 0;  						//接收数据IOUart_h_Struct.IO_UART_RxTimeOut = _IO_RX_TIMECOUNTDOWN;//接收到数据把接收超时清零																}}}else if(IO_UART_CLK == GPIO_PIN_SET)		{//这里是数据发送部分 上升沿发送数据IO_UART_Send_Buff(); }}

如有问题可以加群讨论: 764284134

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

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

相关文章

[office] 网优必备的10大经典函数公式! #知识分享#媒体

网优必备的10大经典函数公式! Excel软件看似简单&#xff0c;其实花样很多&#xff0c;尤其Excel表格。但其实只要用心多练&#xff0c;效率轻松提升个十倍百倍真不是问题!赶紧一起来get新技能吧~ ▋函数公式一 我们都知道从网管中查询出来的经纬度是没有小数点的。我看到不…

护眼灯色温多少合适?推荐五款合适色温的护眼台灯

很多人在购买台灯之后只会根据周围环境灯光的明暗调节亮度&#xff0c;对于色温的了解并不多&#xff0c;不知道色温应该调节到什么数值比较合适&#xff0c;有些人也根本没有意识到色温在影响人情绪方面起着重要作用&#xff0c;接下来就一起来看一下色温的标准。 一、什么色…

Day4.

单链表 #include <head.h>typedef struct List{int value;struct List *pointe; }*list; list create_space() {list s(struct List *)malloc(sizeof(struct List)); //向堆区申请空间s->pointe NULL;//初始化s->value 0;return s; } list inserhead_list(lis…

AI改编游戏大电影《使命召唤:幽灵重生》(下)

AI改编游戏大电影《使命召唤&#xff1a;幽灵重生》&#xff08;下&#xff09; 幽灵重生携生化武器毁灭人类&#xff0c;普莱斯上尉点上雪茄拿起武器&#xff0c;英雄再次迎来使命的召唤&#xff01; 《使命召唤&#xff1a;幽灵重生》&#xff08;下&#xff09;&#xff1a…

电力负荷预测 | 基于TCN的电力负荷预测(Python)———结果比对

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 电力负荷预测 | 基于TCN的电力负荷预测(Python)———结果比对 python3.8 keras2.6.0 matplotlib3.5.2 numpy1.19.4 pandas1.4.3 tensorflow==2.6.0

【宝藏系列】嵌入式入门概念大全

【宝藏系列】嵌入式入门概念大全 0️⃣1️⃣操作系统&#xff08;Operating System&#xff0c;OS&#xff09; 是管理计算机硬件与软件资源的系统软件&#xff0c;同时也是计算机系统的内核与基石。操作系统需要处理管理与配置内存、决定系统资源供需的优先次序、控制输入与输…

jquery写表格,通过后端传值,并合并单元格

<!DOCTYPE html> <html> <head><title>Table Using jQuery</title><style>#tableWrapper {width: 100%;height: 200px; /* 设置表格容器的高度 */overflow: auto; /* 添加滚动条 */margin-top: -10px; /* 负的外边距值&#xff0c;根据实际…

NLP_神经概率语言模型(NPLM)

文章目录 NPLM的起源NPLM的实现1.构建实验语料库2.生成NPLM训练数据3.定义NPLM4.实例化NPLM5.训练NPLM6.用NPLM预测新词 NPLM小结 NPLM的起源 在NPLM之前&#xff0c;传统的语言模型主要依赖于最基本的N-Gram技术&#xff0c;通过统计词汇的共现频率来计算词汇组合的概率。然而…

【自然语言处理】微调 Fine-Tuning 各种经典方法的概念汇总

【自然语言处理】微调 Fine-Tuning 各种经典方法的概念汇总 前言请看此微调 Fine-TuningSFT 监督微调&#xff08;Supervised Fine-Tuning&#xff09;概念&#xff1a;监督学习&#xff0c;无监督学习&#xff0c;自监督学习&#xff0c;半监督学习&#xff0c;强化学习的区别…

Jetpack之RadionBtton、Switch、Checkbox组件介绍

Jetpack Compose系列(9) - RadionBtton、Switch、Checkbox组件介绍 RadioButton 跟View体系一样&#xff0c;Compose也有RadioButton单选按钮组件&#xff0c;遵从Material Design风格。 其构造函数如下&#xff1a; Composable fun RadioButton(selected: Boolean,onClick…

uniapp+uView 【详解】录音,自制音频播放器

效果预览 代码实现 <template><view class"btnListBox"><view class"audioBox" v-if"audioLength"><u-row><u-col span"2"><u--text aligncenter :text"currentTime"></u--text>…

YOLOv8改进 | 检测头篇 | 独创RFAHead检测头超分辨率重构检测头(适用Pose、分割、目标检测)

一、本文介绍 本文给大家带来的改进机制是RFAHead,该检测头为我独家全网首发,本文主要利用将空间注意力机制与卷积操作相结合的卷积RFAConv来优化检测头,其核心在于优化卷积核的工作方式,特别是在处理感受野内的空间特征时。RFAConv主要的优点就是增加模型的特征提取能力,…

arcgis各种版本下载

arcgic 下载&#xff01;&#xff01;&#xff01; ArcGIS是一款地理信息系统软件&#xff0c;由美国Esri公司开发。它提供了一系列完整的GIS功能&#xff0c;包括地图制作、空间数据管理、空间分析、空间信息整合、发布与共享等。ArcGIS是一个可扩展的GIS平台&#xff0c;提供…

恒创科技:服务器内存不足影响大吗?

​  服务器在为网站、应用程序和在线服务提供支持方面发挥着关键作用。这些服务器需要提供最佳性能&#xff0c;以确保正常无缝的用户体验&#xff0c;而RAM是显著影响服务器性能的关键配置之一。 RAM 是一种随机存取存储器&#xff0c;计算机和服务器使用它来临时存储正在使…

【AG32VF407】国产MCU+FPGA,更新官方固件解决8Mhz内部晶振不准,Verilog实测7.9Mhz!

视频讲解 [AG32VF407]国产MCUFPGA&#xff0c;更新官方固件解决8Mhz内部晶振不准&#xff0c;Verilog实测7.9Mhz&#xff01; 实验过程 之前出现的双路pll不同频率的测试中&#xff0c;提出了内部晶振输出不准的问题&#xff0c;和官方沟通后得到极大改善&#xff0c;方法如下…

探索Web API SpeechSynthesis:给你的网页增添声音

Web API SpeechSynthesis是一项强大的浏览器功能&#xff0c;它允许开发者将文本转换为语音&#xff0c;并通过浏览器播放出来。本文将深入探讨SpeechSynthesis的控制接口&#xff0c;包括其功能、用法和一个完整的JavaScript示例。 参考资料&#xff1a;SpeechSynthesis - Web…

Python程序设计 函数

简单函数 函数&#xff1a;就是封装了一段可被重复调用执行的代码块。通过此代码块可以实现大量代码的重复使用。 函数的使用包含两个步骤&#xff1a; 定义函数 —— 封装 独立的功能 调用函数 —— 享受 封装 的成果 函数的作用&#xff0c;在开发程序时&#xff0c;使用…

2024年第九届信号与图像处理国际会议(ICSIP 2024)

2024第九届信号与图像处理国际会议&#xff08;ICSIP 2024&#xff09;将于2024年7月12-14日在中国南京召开。ICSIP每年召开一次&#xff0c;在过去的七年中吸引了1200多名与会者&#xff0c;是展示信号和图像处理领域最新进展的领先国际会议之一。本次将汇集来自亚太国家、北美…

LeetCode:13.罗马数字转整数

13. 罗马数字转整数 - 力扣&#xff08;LeetCode&#xff09; 目录 思路&#xff1a; 官解代码&#xff1a; 作者辣眼代码: 每日表情包&#xff1a; 思路&#xff1a; 思路已经很明了了&#xff0c;题目已经给出一般规则和特殊规则&#xff08;而且题目确保给定的是正确的…

活动图(Activity Diagram)

一、定义 动态图。显示人或对象的活动&#xff0c;其方式类似于流程图 二、构成 包含有&#xff1a; 初始节点(开始)最后一个节点(结束)活动转换判定(决策),同步条分岔或汇合泳道 1、 初始节点(开始) 实心圆表示初始节点 2、最后一个节点(结束) 圆圈内加一个实心圆来表…