STM32 freertos 使用软件模拟串口uart

如题,为什么要这样做?

最近做的一个项目上使用了74HC595作为指示灯板使用;

这个灯板与驱动板是通过排线连接,排线约25cm长;

在实验室测试一切正常,发到客户手上使用就出现了某个LED跳动情况;

跳动原因:传输线收到干扰。

这种显示方式抗干扰能力非常差且没有校验功能,满足不了需求;

因为传输线是必须要有的,所以只能通过增加校验的方式来处理干扰。

解决方法:

  1. 指示灯板增加MCU;
  2. 驱动板与灯板改为UART通讯增加校验功能;

因为驱动板与灯板连接的IO口没有UART外设功能,只能通过软件模拟UART使用;

代码

代码来自于:发个软件UART代码吧 (amobbs.com 阿莫电子技术论坛)

#include "SimComIO.h"
#include <string.h>//为了提高接收的准确率和纠错性能,采用3倍采样率,定时中断的频率是波特率的3倍。例如:需要波特率9600bps的话,需要1/(9600*3)=34.72us的定时中断。//#define SC_RXD 6
//#define SC_RXD_SET_INPUT() 	{DDRD&=(~BIT(SC_RXD));}
//#define SC_RXD_GET() 				((PIND&(BIT(SC_RXD))))
#define SC_RXD_GET() 				(HAL_GPIO_ReadPin(SIM_UART_RX_GPIO_Port, SIM_UART_RX_Pin))//#define SC_TXD 7
//#define SC_TXD_0() 					{PORTD&=(~BIT(SC_TXD));}
//#define SC_TXD_1() 					{PORTD|=BIT(SC_TXD);}
//#define SC_TXD_SET_OUTPUT() {DDRD|=BIT(SC_TXD);}
#define SC_TXD_0() 					{HAL_GPIO_WritePin(SIM_UART_TX_GPIO_Port, SIM_UART_TX_Pin, GPIO_PIN_RESET);}
#define SC_TXD_1() 					{HAL_GPIO_WritePin(SIM_UART_TX_GPIO_Port, SIM_UART_TX_Pin, GPIO_PIN_SET);}uint8_t sc1_rxd_scan_ct=0;
uint8_t sc1_rxd_scan_next_time=0;
uint8_t sc1_rxd_scan_step=0;
uint8_t sc1_rxd_dat;
uint8_t sc1_rxd_ready=0;
uint8_t sc1_rxd_tmpdat;volatile uint8_t sc_txd_ready=0;//模拟串口变量
volatile uint8_t sc_txd_bit_pt=0;
volatile uint8_t sc_txd_data=0;
volatile uint8_t sc_txd_ct=0;// typedef sim_uart_def{// uint8_t sc1_rxd_scan_ct;// uint8_t sc1_rxd_scan_next_time;// uint8_t sc1_rxd_scan_step;// uint8_t sc1_rxd_dat;// uint8_t sc1_rxd_ready;// uint8_t sc1_rxd_tmpdat;// uint8_t sc_txd_ready;//模拟串口变量// uint8_t sc_txd_bit_pt;// uint8_t sc_txd_data;// uint8_t sc_txd_ct;
// }TYPE_SIM_UART_DEF;// TYPE_SIM_UART_DEF su1,su2,su3,su4,su5,su6;// void SC_RxdSrv(TYPE_SIM_UART_DEF *pSU);
// void SC_TxdSrv(TYPE_SIM_UART_DEF *pSU);void SC_Recv_Pro(uint8_t dat){}void SC_RxdSrv(void){if(sc1_rxd_scan_step==0){if(!SC_RXD_GET()){sc1_rxd_scan_step=1;return;}}if(sc1_rxd_scan_step==1){if(!SC_RXD_GET()){sc1_rxd_scan_step=2;                //rxd start bit ok,goto next stepsc1_rxd_scan_ct=0;sc1_rxd_scan_next_time=3;sc1_rxd_tmpdat=0;return;}else{sc1_rxd_scan_step=0;        //rxd start bit is avalidreturn;}}if(sc1_rxd_scan_step>=2){sc1_rxd_scan_ct++;if(sc1_rxd_scan_ct<sc1_rxd_scan_next_time) return;sc1_rxd_scan_ct=0;if(sc1_rxd_scan_step<10){sc1_rxd_tmpdat>>=1;if(SC_RXD_GET()){sc1_rxd_tmpdat|=0x80;}sc1_rxd_scan_step++;       return;}if(sc1_rxd_scan_step==10){if(SC_RXD_GET()){sc1_rxd_dat=sc1_rxd_tmpdat;sc1_rxd_ready=1;//Receive a byte OK       #if 0sc_txd_data=sc1_rxd_dat;sc_txd_ready=1;#endif#if 0Test_Uart1(sc1_rxd_dat);#endifSC_Recv_Pro(sc1_rxd_dat);}sc1_rxd_scan_step=0;return;}}}void SC_TxdSrv(void){sc_txd_ct++;if(sc_txd_ct<3) return;sc_txd_ct=0;if(sc_txd_ready){                                                        //Data Readyif(sc_txd_bit_pt<10){if(sc_txd_bit_pt==0){SC_TXD_0();                                //Start BIT}else{if(sc_txd_bit_pt>=9){SC_TXD_1();                        //End BIT}else{                                                        //数据位if((sc_txd_data>>(sc_txd_bit_pt-1))&0x01){       SC_TXD_1();}else{SC_TXD_0();}}                       }}               if(sc_txd_bit_pt>10){               sc_txd_bit_pt=0;                        //发送完后延时两个时钟,复位各标志sc_txd_ready=0;               }else{sc_txd_bit_pt++;                        //位指针自加               }}}void SC_send_char(uint8_t b){sc_txd_data=b;sc_txd_ready=1;while(sc_txd_ready==1);}
void SC_send_str(uint8_t *str){while((*str)!=0){SC_send_char(*str);str++;}}void SC_send_arr(uint8_t *arr,uint8_t len){while(len--){SC_send_char(*arr);}
}void init_SimComIO(void){//	SC_TXD_SET_OUTPUT();SC_TXD_1();
//	SC_RXD_SET_INPUT();}// #pragma interrupt_handler ISR_T1:8
// void ISR_T1(void)
// {
// //compare occured TCNT1=OCR1A// SC_RxdSrv();// SC_TxdSrv();
// }

移植

定时器

        波特率9600,3倍采样34.72us,使用定时器2完成

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{/* USER CODE BEGIN Callback 0 *//* USER CODE END Callback 0 */if (htim->Instance == TIM4) {HAL_IncTick();}/* USER CODE BEGIN Callback 1 */if (htim->Instance == TIM2) {
//    HAL_GPIO_TogglePin(SIM_UART_TX_GPIO_Port, SIM_UART_TX_Pin);SC_TxdSrv();
//		SC_RxdSrv();}/* USER CODE END Callback 1 */
}

示波器观察IO引脚反转周期,符合需求。 

Freertos

HAL_TIM_Base_Start_IT(&htim2);    

在开启定时器的时候,整个任务调度接近瘫痪。

问题分析:

freertos心跳是1ms,35us这样频繁中断会影响调度的。

现在的问题是:freertos 能用35us这样的中断吗?如果能应该怎么用?

于是chatgpt开始对话,问题主要是问gpt freertos中这种35us 频繁中断应该怎么使用?

没有得到想要的答案;

网络上没得到答案就咨询身边大佬吧;

转义:

就是咱们这个发送也不是连续不断发送,实际使用中1S发送1帧就行了。

使用

taskENTER_CRITICAL();
//code
taskEXIT_CRITICAL(); 

    加入代码测试,发现问题:进入临界区之后定时器2中断不进了,被关了。

于是想,那就使用停止调度的呗

vTaskSuspendAll();         /* 开启调度锁 */    printf("任务vTaskLed1正在运行\r\n");   if(!xTaskResumeAll())      /* 关闭调度锁,如果需要任务切换,此函数返回pdTRUE,否则返回pdFALSE */{taskYIELD ();}    

测试还是不行。

二问大佬:

于是查代码,freertos在哪里管理中断的;

taskENTER_CRITICAL();

进这个接口查源码

最后查到了下面那个地方

打开cubemx 找修改优先级的地方

上面是修改优先级的地方,那定时器2的优先级是多少呢?

发现这个优先级是灰色的,是与freertos的 

是绑定的,比如你将 LIBRARY MAX SYSCALL INTERRUPT PRIORITY修改为6,定时器的优先级也会跟着修改为6;

那好办,在代码中手动修改定时器2优先级

HAL_NVIC_SetPriority(TIM2_IRQn, 4, 0);HAL_NVIC_GetPriority(TIM2_IRQn, TIM2_PriorityGroup, &TIM2_PreemptPriority, &TIM2_SubPriority);printf(" HAL_NVIC_GetPriority TIM2_PriorityGroup:%d, TIM2_PreemptPriority:%d,TIM2_SubPriority:%d  \r\n" ,TIM2_PriorityGroup,TIM2_PreemptPriority,TIM2_SubPriority);

验证修改成功。

验证

SC_send_char(0x55);

发现使用上面代码会卡在这个while里面,单步调试查看 sc_txd_ready 变量已经变为0了,为什么还会卡在这里? 

void SC_send_char(uint8_t b){sc_txd_data=b;sc_txd_ready=1;while(sc_txd_ready==1);}

解决方法

加入volatile 修饰符;

volatile uint8_t sc_txd_ready=0;

总结

        通过上面学习使用方法与故障排除,STM32 freertos 使用软件模拟串口uart已经正常可以使用了。通过这个测试也对freertos 有了进一步认识。

感谢

babyos 作者 提供的帮助;

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

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

相关文章

假期刷题打卡--Day16

一、码题集正常刷题 1、MT1159 指定集合 某数组含有N个元素&#xff0c;输出那些数字来自集合{4,5,6}的元素&#xff0c;按原序。没有就输出-1。 格式 输入格式&#xff1a; 第一行输入数组长度N&#xff0c;第二行输入数组元素&#xff0c;整型&#xff0c;空格分隔。 输…

GitHub 一周热点汇总第7期(2024/01/21-01/27)

GitHub一周热点汇总第7期 (2024/01/21-01/27) &#xff0c;梳理每周热门的GitHub项目&#xff0c;离春节越来越近了&#xff0c;不知道大家都买好回家的票没有&#xff0c;希望大家都能顺利买到票&#xff0c;一起来看看这周的项目吧。 #1 rustdesk 项目名称&#xff1a;rust…

解决Linux部署报错No main manifest attribute, in XXX.jar

这是我近期遇到的一个问题&#xff0c;报错原因就是没找到主类&#xff0c;首先你在你本地运行&#xff0c;本地运行ok的话&#xff0c;解压生成的jar包&#xff0c;里面有个META-INF文件&#xff0c;打开MANIFEST.MF文件&#xff0c;该文件是一个清单文件。该文件包含有关JAR文…

vulnhub靶场之Five86-2

一.环境搭建 1.靶场描述 Five86-2 is another purposely built vulnerable lab with the intent of gaining experience in the world of penetration testing. The ultimate goal of this challenge is to get root and to read the one and only flag. Linux skills and fa…

凭证卷发放流程优化方案

背景 上周线上有多个大促活动&#xff0c;创建了多个凭证卷模版&#xff0c;并导入了大量劵码&#xff0c;其中有多个卷模版下的劵码超过50w, 在发放劵的时候&#xff0c;会先查询一次卷码库存&#xff0c;其中劵模版ID是分库分表键&#xff0c;所以在统一模版下的数据量过多了…

vusui css 使用,简单明了 适合后端人员 已解决

vusui-cssopen in new window 免除开发者繁复的手写 CSS 样式&#xff0c;让 WEB 前端开发更简单、灵活、便捷&#xff01;如果喜欢就点个 ★Staropen in new window 吧。 移动设备优先&#xff1a; vusui-css 包含了贯穿于整个库的移动设备优先的样式。浏览器支持&#xff1a…

三数之和----双指针

https://leetcode.cn/problems/3sum/description/?envType=study-plan-v2&envId=top-100-liked “三数之和”在某些人的口中被叫做“程序员之梦破碎的地方”。既然如此,这个题肯定是有难度的,尤其是其中的细节,很多,很细。 其中nums代表给定的数组,numsSize代表给定数…

GLog开源库使用

Glog地址&#xff1a;https://github.com/google/glog 官方文档&#xff1a;http://google-glog.googlecode.com/svn/trunk/doc/glog.html 1.利用CMake进行编译&#xff0c;生成VS解决方案 &#xff08;1&#xff09;在glog-master文件夹内新建一个build文件夹&#xff0c;用…

C# 学习笔记-构造自己的类型

用 OOP 构建自己的类型 Building Your Own Types with Object-Oriented Programming 本章主题&#xff1a; 讨论 OOP构建类库在字段 field 中存储数据使用方法与元组 tuple使用属性和索引器控制访问使用 object 进行模式匹配&#xff08;Pattern matching&#xff09;使用 r…

【JAVA】什么是自旋

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;JAVA ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 结语 我的其他博客 前言 在计算机科学的领域中&#xff0c;多线程和并发编程已成为处理复杂任务和提高系统性能的不可或缺的手段。…

【时间序列篇】基于LSTM的序列分类-Pytorch实现 part2 自有数据集构建

系列文章目录 【时间序列篇】基于LSTM的序列分类-Pytorch实现 part1 案例复现 【时间序列篇】基于LSTM的序列分类-Pytorch实现 part2 自有数据集构建 【时间序列篇】基于LSTM的序列分类-Pytorch实现 part3 化为己用 在一个人体姿态估计的任务中&#xff0c;需要用深度学习模型…

深度学习(6)--Keras项目详解

目录 一.项目介绍 二.项目流程详解 2.1.导入所需要的工具包 2.2.输入参数 2.3.获取图像路径并遍历读取数据 2.4.数据集的切分和标签转换 2.5.网络模型构建 2.6.绘制结果曲线并将结果保存到本地 三.完整代码 四.首次运行结果 五.学习率对结果的影响 六.Dropout操作…

Compose | UI组件(三) | TextField() 输入框组件

文章目录 TextField() 简介TextField() 输入框例子TextField() 输入框添加装饰OutlinedTextField 边框样式输入框BasicTextField 输入框组件 总结 TextField() 简介 在 Compose 中&#xff0c;TextField() 组件表示文本输入框 ExperimentalMaterial3Api Composable fun TextF…

一个基于electron自动化桌面应用-流程图构建

前期工作已搞定&#xff0c;现在可以搭建桌面应用了。这个阶段可以结合前面定义好的数据格式构建流程图。 模板 还是使用熟悉的技术栈vite react electron&#xff0c;模板 流程图 官方文档 自定义 节点样式 因为配置化的操作类型较多&#xff0c;因此可以利用自定义节…

【开源】基于JAVA语言的就医保险管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 科室档案模块2.2 医生档案模块2.3 预约挂号模块2.4 我的挂号模块 三、系统展示四、核心代码4.1 用户查询全部医生4.2 新增医生4.3 查询科室4.4 新增号源4.5 预约号源 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVue…

Atlassian Confluence Data Center and Server 权限提升漏洞复现(CVE-2023-22515)

0x01 产品简介 Atlassian Confluence是一款由Atlassian开发的企业团队协作和知识管理软件,提供了一个集中化的平台,用于创建、组织和共享团队的文档、知识库、项目计划和协作内容。是面向大型企业和组织的高可用性、可扩展性和高性能版本。 0x02 漏洞概述 Atlassian Confl…

在JavaScript中创建自定义错误

&#x1f9d1;‍&#x1f393; 个人主页&#xff1a;《爱蹦跶的大A阿》 &#x1f525;当前正在更新专栏&#xff1a;《VUE》 、《JavaScript保姆级教程》、《krpano》、《krpano中文文档》 ​ 目录 ✨ 前言 ✨ 正文 简介 创建自定义错误 自定义错误属性 instanceof 检…

STM正点mini-跑马灯

一.库函数版 1.硬件连接 &#xff27;&#xff30;&#xff29;&#xff2f;的输出方式&#xff1a;推挽输出 &#xff29;&#xff2f;口输出为高电平时&#xff0c;P-MOS置高&#xff0c;输出为&#xff11;&#xff0c;LED对应引脚处为高电平&#xff0c;而二极管正&#…

N-141基于springboot,vue网上拍卖平台

开发工具&#xff1a;IDEA 服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8 项目构建&#xff1a;maven 数据库&#xff1a;mysql5.7 系统分前后台&#xff0c;项目采用前后端分离 前端技术&#xff1a;vueelementUI 服务端技术&#xff1a;springbootmybatis-plusredi…

虚拟局域网、广播域、冲突域

目录 广播风暴 安全问题 虚拟局域网 VLAN 虚拟局域网优点 划分虚拟局域网的方法 基于交换机端口的方法 基于计算机网卡的 MAC 地址的方法 基于协议类型的方法 基于 IP 子网地址的方法 基于高层应用或服务的方法 虚拟局域网使用的以太网帧格式 以太网存在的主要问题&…