STM32的IO模拟串口

串口的时序就不再多讲了,主要是分享一个比自己写的IO模拟串口的实例

申明:

这个波特率为115200

分频系数为8

自动重载值为68

约等于8.7微秒

使用其他波特率或者IO口,只需要修改.h文件中的对应参数即可

头文件

#ifndef IO_UART_H
#define IO_UART_H#include "tim.h"enum
{N_CMD,	//空闲W_CMD,	//写R_CMD,	//读F_CMD,	//完成
};
enum
{UNWAIT,WAITING,
};#define U_TIM		TIM4			//UART内部定时器
#define	TX_GPIO_PIN	GPIO_PIN_15		//UART对应的TX引脚
#define	RX_GPIO_PIN	GPIO_PIN_14		//UART对应的RX引脚
#define TX_PIN		14				//UART对应的TX引脚编号
#define RX_PIN		15				//UART对应的RX引脚编号
#define	TX_GPIO		GPIOB			//UART对应的TX端口
#define	RX_GPIO		GPIOB			//UART对应的RX端口#define MAX_WAIT 	0x5		//最大等待时间
#define T_RELOAD 	68		//发送一个字节所需的时间
#define T_FIRST		0x33	//延时到第一位的时间#define MAX_BUFSIZE	3000	//收发最大字符数量/************************************
function : 定时器中断回调函数
************************************/
void TIM_UART_Callback(TIM_HandleTypeDef *htim);
/************************************
function : 外部中断回调函数 
************************************/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
/************************************
function : 发送一个字节
input : uint8_t send_data	//要发送的字节
return : void
************************************/
void SEND_BYTE(uint8_t send_data);
/************************************
function : 发送一个字符串
input : uint8_t *send_data	//要发送的字符串
return : void
************************************/
void SEND_STRING(uint8_t *send_data);
/************************************
function : 等待读取一个字符串
input : uint8_t *read_data	//接收目标字符串
return : void
************************************/
void READ_STRING(uint8_t *read_data);
/************************************
function : 清空一个字符串
input : uint8_t *string	//要清楚的字符串	size_t str_len	//清除字符串的长度
return : void
************************************/
void ZERO_STRING(uint8_t *string,size_t str_len);
/************************************
function : UART初始化
input : void
return : void
************************************/
void UART_INIT(void);
#endif

.c文件

#include "io_uart.h"volatile uint8_t uart_flag = N_CMD;
uint8_t cnt_bit = 0;
uint8_t uart_data = 0;
uint8_t wait_flag = UNWAIT;
uint8_t **buf = NULL;
uint32_t i = 0;/************************************
function : 拉高TXD
************************************/
static void SET_TXD(void)
{TX_GPIO->BSRR = TX_GPIO_PIN;
}
/************************************
function : 拉低TXD
************************************/
static void RESET_TXD(void)
{TX_GPIO->BSRR = (uint32_t)TX_GPIO_PIN << 16u;
}
/************************************
function : 读取RXD电平
************************************/
static uint8_t READ_RXD(void)
{return ((RX_GPIO->IDR & RX_GPIO_PIN) >> TX_PIN);
}
/************************************
function : 定时器中断回调函数
************************************/
void TIM_UART_Callback(TIM_HandleTypeDef *htim)
{//写一个字节if(uart_flag == W_CMD){if(cnt_bit == 0){//拉低TXDRESET_TXD();}else if(cnt_bit > 0 && cnt_bit < 9){if(uart_data & (0x01 << (cnt_bit - 1))){//输出高电平SET_TXD();}else{//输出低电平RESET_TXD();}}else{//拉高TXDSET_TXD();cnt_bit = 0;uart_flag = N_CMD;uart_data = 0;//关闭定时器中断U_TIM->CR1 &= ~(TIM_CR1_CEN);return;}cnt_bit++;}//读一个字节else if(uart_flag == R_CMD){if(cnt_bit == 0){//设置定时器定时时间U_TIM->ARR = T_RELOAD;}else if(cnt_bit == 8){cnt_bit = 0;/****new****///设置定时器定时时间U_TIM->CNT = 0x00;U_TIM->ARR = T_RELOAD*MAX_WAIT;(*buf)[i] = uart_data;i++;uart_data = 0;wait_flag = WAITING;cnt_bit = 0;//打开外部中断EXTI->PR = (RX_GPIO_PIN);EXTI->IMR |= (0x1 << TX_PIN);/****new****/return;}uart_data |= (READ_RXD() << cnt_bit);cnt_bit++;//判断是否读取完成if(wait_flag == WAITING){//读取完成uart_flag = F_CMD;wait_flag = UNWAIT;//关闭定时器中断U_TIM->CR1 &= ~(TIM_CR1_CEN);//关闭外部中断EXTI->IMR &= ~(0x1 << TX_PIN);return;}}
}
/************************************
function : 外部中断回调函数 
************************************/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{switch(GPIO_Pin){case RX_GPIO_PIN:EXTI->PR = (RX_GPIO_PIN);if(uart_flag != R_CMD)return;else{wait_flag = UNWAIT;//关闭定时器中断U_TIM->CR1 &= ~(TIM_CR1_CEN);//设置定时器定时时间U_TIM->CNT = 0x00;U_TIM->ARR = T_FIRST;//打开定时器中断U_TIM->SR = ~(TIM_IT_UPDATE);U_TIM->CR1 |= (TIM_CR1_CEN);//关闭外部中断EXTI->IMR &= ~(0x1 << TX_PIN);EXTI->PR = (RX_GPIO_PIN);}break;default:break;}
}
/************************************
function : 发送一个字节
input : uint8_t send_data	//要发送的字节
return : void
************************************/
void SEND_BYTE(uint8_t send_data)
{while(uart_flag != N_CMD);uart_flag = W_CMD;cnt_bit = 0;uart_data = send_data;//打开定时器中断U_TIM->SR = ~(TIM_IT_UPDATE);U_TIM->CR1 |= (TIM_CR1_CEN);while(uart_flag != N_CMD);
}
/************************************
function : 发送一个字符串
input : uint8_t *send_data	//要发送的字符串
return : void
************************************/
void SEND_STRING(uint8_t *send_data)
{uint32_t j = 0;for(j = 0; (send_data[j] != 0 || send_data[j+1] != 0) && i < MAX_BUFSIZE-1; j++){SEND_BYTE(send_data[j]);}
}
/************************************
function : 等待读取一个字符串
input : uint8_t *read_data	//接收目标字符串
return : void
************************************/
void READ_STRING(uint8_t *read_data)
{while(uart_flag != N_CMD);i = 0;buf = &read_data;cnt_bit = 0;uart_flag = R_CMD;//打开外部中断EXTI->PR = (RX_GPIO_PIN);EXTI->IMR |= (0x1 << TX_PIN);while(uart_flag != F_CMD);//read_data[255]	read_data[254] read_data[256] read_data[258] read_data[0] read_data[1] buf = NULL;uart_data = 0;cnt_bit = 0;uart_flag = N_CMD;
}
/************************************
function : 清空一个字符串
input : uint8_t *string	//要清楚的字符串	size_t str_len	//清除字符串的长度
return : void
************************************/
void ZERO_STRING(uint8_t *string,size_t str_len)
{int i = 0;for(i = 0; i < str_len; i++){string[i] = 0;}return;
}
/************************************
function : UART初始化
input : void
return : void
************************************/
void UART_INIT(void)
{//清空定时器中断标志位U_TIM->SR = ~(TIM_IT_UPDATE);//关闭定时器中断U_TIM->DIER |= (TIM_IT_UPDATE);U_TIM->CR1 &= ~(TIM_CR1_CEN);//关闭外部中断EXTI->IMR &= ~(0x1 << TX_PIN);//清空外部中断标志位EXTI->PR = (RX_GPIO_PIN);
}
//

/************************************
function : 定时器中断回调函数
************************************/
void TIM_UART_Callback(TIM_HandleTypeDef *htim);这个定时器回调函数写在对应的HAL的回调函数中,

/************************************
function : 外部中断回调函数 
************************************/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);如果使用了其他的外部中断,可以像定时器中断那样改一个名字后放入对应的HAL库的外部中断函数中

 如果程序出现了什么问题,欢迎和我交流

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

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

相关文章

Service Mesh:如何为您的微服务架构带来可靠性和灵活性

在云原生架构中&#xff0c;Service Mesh 技术成为了微服务架构中不可或缺的一环。本文灸哥将和你一起探讨 Service Mesh 技术的原理、功能和实践&#xff0c;帮助架构师和开发人员更好地理解和应用这一关键技术。 1、Service Mesh 技术概述 Service Mesh 又称为服务网格&…

世界的本质是旋转(5)-在复平面上驱动软件无线电SDR发射BPSK波形

在上一篇文章中&#xff0c;我们介绍了复平面、拍照采样的一些思维实验。从本节开始&#xff0c;转入现实应用&#xff0c;通过控制复平面向量的位置&#xff0c;实现一个完整的BPSK全双工通信通道。 发射方&#xff1a;通过控制复平面向量在各个时刻的位置来携带信息的技术&a…

Axure RP 10:让原型设计更快、更直观、更智能 mac版

Axure RP 10是一款强大的原型设计工具&#xff0c;它能够帮助设计师快速创建高保真、交互式的原型&#xff0c;从而更好地展示和测试设计方案。这款软件凭借其直观易用的界面和丰富的功能&#xff0c;已经成为了许多设计师的首 选工具。 Axure RP 10 for Mac版软件获取 首先&a…

将D*算法应用到llm解码

将D算法应用于LLM解码是一个非传统的尝试&#xff0c;因为D算法通常用于动态环境中的路径规划&#xff0c;而语言模型解码是一个序列生成问题。然而&#xff0c;我们可以尝试将D算法的原理应用到解码过程中&#xff0c;特别是在处理动态变化的环境或者需要实时更新解码路径的场…

C++之进程管理

目录 1、创建进程 2、获取指定进程PID 3、结束进程 4、进程枚举 进程是计算机中的程序关于某数据集合上的一次运行活动&#xff0c;是系统进行资源分配的基本单位&#xff0c;也是操作系统结构的基础。它是操作系统动态执行的基本单元&#xff0c;在传统的操作系统中&#…

AI论文速读 | 【综述】城市计算中跨域数据融合的深度学习:分类、进展和展望

题目&#xff1a;Deep Learning for Cross-Domain Data Fusion in Urban Computing: Taxonomy, Advances, and Outlook 作者&#xff1a;Xingchen Zou, Yibo Yan, Xixuan Hao, Yuehong Hu, Haomin Wen&#xff08;温皓珉&#xff09;, Erdong Liu, Junbo Zhang&#xff08;张钧…

进程之舞:操作系统中的启动、状态转换与唤醒艺术

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua&#xff0c;在这里我会分享我的知识和经验。&#x…

解决QT cc1plus.exe: error: out of memory allocating

QT中增加资源文件过大时&#xff0c;会编译不过&#xff0c;报错&#xff1a; cc1plus.exe: out of memory allocating 1073745919 bytes 使用qrc资源文件&#xff0c;也就是在QT的工程中添加资源文件&#xff0c;就是添加的资源文件&#xff08;如qrc.cpp&#xff09;会直接被…

简明固体物理--晶体的形成与晶体结构的描述

简明固体物理-国防科技大学 chapter 1 Formation of Crystal Contents and roadmapQuantum Mechanics and atomic structureElectronsOld quantum theoryMethod of Quantum MechanicsDistributing functions of micro-particles BindingCrystal structure and typical crystal…

Compose基础之State状态

Compose基础之State状态 Stateless和Stateful什么是Stateless&#xff0c;让我看下面代码Stateless它有什么特点呢Stateless它是如何实现避免无效重组的呢什么是Stateful&#xff0c;让我看下面代码 Compose中的State<T>State子类之MutableState 状态的恢复与持久化remem…

Go-Gin-example 第五部分 加入swagger

上一节链接 swagger 为什么要用swagger 问题起源于 前后端分离&#xff0c; 后端&#xff1a;后端控制层&#xff0c;服务层&#xff0c;数据访问层【后端团队】前端&#xff1a;前端控制层&#xff0c;视图层&#xff0c;【前端团队】 所以产生问题&#xff1a;前后端联调…

Keepalived+LVS构建高可用集群

目录 一、Keepalive基础介绍 1. Keepalive与VRRP 2. VRRP相关技术 3. 工作原理 4. 模块 5. 架构 6. 安装 7. Keepalived 相关文件 7.1 配置组成 7.2 全局配置 7.3 VRRP实例配置&#xff08;lvs调度器&#xff09; 7.4 虚拟服务器与真实服务器配置 二、Keepalived…

HTML静态网页成品作业(HTML+CSS)——花主题介绍网页设计制作(1个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有1个页面。 二、作品演示 三、代…

C语言:基于单链表实现的泊车管理系统

一、需求 &#xff08;1&#xff09;管理员方账号登录&#xff1b; &#xff08;2&#xff09;车位管理显示&#xff1a;车位状态&#xff1b; &#xff08;3&#xff09;收费管理&#xff1a;小轿车 5元/小时&#xff0c;面包车6元/小时&#xff0c;大货车或客车7元/小时&a…

node.js 下 mysql2 的 CURD 功能极简封装

此封装适合于使用 SQL 直接操作数据库的小型后端项目&#xff0c;更多功能请查阅MySQL2官网 // 代码保存到单独的 js 文件const mysql require(mysql2/promise)const debug true let conn/*** 执行 SQL 语句* param {String} sql* param {*} params* returns {Array}*/ const…

ChatGPT提示技巧——零,一和少量示例提示

ChatGPT提示技巧——零&#xff0c;一和少量示例提示 ​ 零样本(zero-shot)、少样本(few-shot)和单样本(one-shot)提示是用于在最少或没有示例的情况下从ChatGPT生成文本的技巧。这些技巧用于当某个具体任务有限定数据的时候或者任务是新的并且没有很好的定义的时候。 提示格…

JVM的各种垃圾回收器(GC)

1. Serial GC Serial GC 是用于单线程环境的垃圾回收器&#xff0c;它使用复制算法&#xff08;Copy&#xff09;进行年轻代的垃圾回收&#xff0c;而老年代则使用标记-整理&#xff08;Mark-Compact&#xff09;算法。由于它在进行垃圾回收时会暂停其他所有的工作线程&#xf…

严密的逻辑会不会影响创新

严密的逻辑可以对创新产生积极的影响&#xff0c;也可能对创新产生负面的影响。以下是两种可能的情况&#xff1a; 积极影响&#xff1a;严密的逻辑可以帮助创新者更好地理解问题&#xff0c;并找到解决问题的方法。它可以帮助人们分析和评估不同的创新想法&#xff0c;以确定哪…

设计模式之——简单工厂模式

上图为简单工厂模式的架构图。 1&#xff0c;产品&#xff08;Product&#xff09; 将会对接口进行声明。 2&#xff0c;具体产品&#xff08;Concrete Products&#xff09;是产品接口的不同实现。 3&#xff0c;创建者&#xff08;Concrete Creators&#xff09;将会重写基…

二刷代码随想录算法训练营第十五天 |层序遍历 10、 226.翻转二叉树 、101.对称二叉树 2

目录 一、102. 二叉树的层序遍历 二、226. 翻转二叉树 三、101. 对称二叉树 一、102. 二叉树的层序遍历 题目链接&#xff1a;力扣 文章讲解&#xff1a;代码随想录 视频讲解&#xff1a; 讲透二叉树的层序遍历 | 广度优先搜索 | LeetCode&#xff1a;102.二叉树的层序遍历…