STM32 F103 C8T6开发笔记14:与HLK-LD303-24G测距雷达通信

今日尝试配通STM32 F103 ZET6与HLK-LD303-24G测距雷达的串口通信解码

文章提供测试代码......

目录

HLK-LD303-24G测距雷达外观:

线路连接准备:

定时器与串口配置准备:

定时器2的初始化:

 串口1、2初始化:

串口1、2自定义打印printf()函数的编写:

串口通信协议解码与校验配置:

首先了解一下它的通信协议:

​编辑

定义数据接收的结构体:

数据处理函数:

简易状态机接收检验函数:

测试效果:


HLK-LD303-24G测距雷达外观:

线路连接准备:

我选择使用串口2进行与测距雷达的通信,串口1留着连接电脑进行测试:

定时器与串口配置准备:

先建立一个基本工程:初始化定时器2为1ms溢出一次,并初始化串口1和串口2:

定时器2的初始化:

#include "TIMER_init.h"//初始化定时器2用作计时中断定时器:
void Timer2_Init(void)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;	NVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);TIM_InternalClockConfig(TIM2);//选择哪个中断就写哪个TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //修改分频,对实际情况影响不大,可以不修改,这里是不分频(可选1~72)TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上对齐模式,同时还有向下对齐,中央对齐模式TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;							    //计数器周期。该参数决定了计数器计数溢出前的最大值。TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;							//分频器预分频系数。该参数决定了计数器时钟频率的变化程度。TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //高级计数器需要,不需要用到的直接给0就好TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);TIM_ClearFlag(TIM2, TIM_FLAG_Update);                           //用于解决一复位时就先进一次中断的情况TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;       //抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;              //响应优先级NVIC_Init(&NVIC_InitStructure);TIM_Cmd(TIM2, ENABLE);}

 串口1、2初始化:

void Usart1_Init(unsigned int baud)
{GPIO_InitTypeDef gpio_initstruct;USART_InitTypeDef usart_initstruct;NVIC_InitTypeDef nvic_initstruct;// 打开串口GPIO的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);// 打开串口外设的时钟	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//PA9	TXD	// 将USART Tx的GPIO配置为推挽复用模式gpio_initstruct.GPIO_Mode = GPIO_Mode_AF_PP;gpio_initstruct.GPIO_Pin = GPIO_Pin_9;gpio_initstruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &gpio_initstruct);//PA10	RXD  // 将USART Rx的GPIO配置为浮空输入模式gpio_initstruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;gpio_initstruct.GPIO_Pin = GPIO_Pin_10;gpio_initstruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &gpio_initstruct);usart_initstruct.USART_BaudRate = baud;                                 	      //配置波特率usart_initstruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;		//无硬件流控	usart_initstruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;						        //接收和发送	usart_initstruct.USART_Parity = USART_Parity_No;									              //无校验usart_initstruct.USART_StopBits = USART_StopBits_1;								              //配置停止位 1位停止位usart_initstruct.USART_WordLength = USART_WordLength_8b;							          //配置 针数据字长 8位数据位// 完成串口的初始化配置USART_Init(USART1, &usart_initstruct);USART_Cmd(USART1, ENABLE);														                           //使能串口USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);									                 //使能接收中断NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                                  /* 嵌套向量中断控制器组选择 */nvic_initstruct.NVIC_IRQChannel = USART1_IRQn;                                   /* 配置USART为中断源 */nvic_initstruct.NVIC_IRQChannelCmd = ENABLE;                                     /* 使能中断 */nvic_initstruct.NVIC_IRQChannelPreemptionPriority = 0;                           /* 抢断优先级*/nvic_initstruct.NVIC_IRQChannelSubPriority = 2;                                  /* 子优先级 */NVIC_Init(&nvic_initstruct);                                                     /* 初始化配置NVIC */}void Usart2_Init(unsigned int baud)
{GPIO_InitTypeDef gpio_initstruct;USART_InitTypeDef usart_initstruct;NVIC_InitTypeDef nvic_initstruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);//PA2	TXDgpio_initstruct.GPIO_Mode = GPIO_Mode_AF_PP;gpio_initstruct.GPIO_Pin = GPIO_Pin_2;gpio_initstruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &gpio_initstruct);//PA3	RXDgpio_initstruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;gpio_initstruct.GPIO_Pin = GPIO_Pin_3;gpio_initstruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &gpio_initstruct);usart_initstruct.USART_BaudRate = baud;usart_initstruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;		//无硬件流控usart_initstruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;						//接收和发送usart_initstruct.USART_Parity = USART_Parity_No;									//无校验usart_initstruct.USART_StopBits = USART_StopBits_1;								//1位停止位usart_initstruct.USART_WordLength = USART_WordLength_8b;							//8位数据位USART_Init(USART2, &usart_initstruct);USART_Cmd(USART2, ENABLE);														//使能串口USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);									//使能接收中断nvic_initstruct.NVIC_IRQChannel = USART2_IRQn;nvic_initstruct.NVIC_IRQChannelCmd = ENABLE;nvic_initstruct.NVIC_IRQChannelPreemptionPriority = 0;nvic_initstruct.NVIC_IRQChannelSubPriority = 0;NVIC_Init(&nvic_initstruct);
}

串口1、2自定义打印printf()函数的编写:

不理解这个的看我之前MSP432的文章有解释:

MSP432自主开发笔记3:串口__编写自定义printf发送函数、编写发送字节字符串函数编写_msp432单片机串口编程-CSDN博客


//选择串口发送数据--自定义Printf
void UsartPrintf (USART_TypeDef *USARTx, char *fmt,...)
{unsigned char UsartPrintfBuf[296];                                  //最大长度296va_list ap;unsigned char *pStr = UsartPrintfBuf;va_start(ap, fmt);vsnprintf((char *)UsartPrintfBuf, sizeof(UsartPrintfBuf), fmt, ap);	//格式化va_end(ap);while(*pStr != 0){USART_SendData(USARTx, *pStr++);while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);}
}

串口通信协议解码与校验配置:

首先了解一下它的通信协议:

这里比较重要的是与它通信的串口的波特率须是115200 :

它有需要我们发送一个固定查询命令的操作来查阅探测结果:  

通信格式如下:

定义数据接收的结构体:

根据以上的学习,我们可以初步决定使用一个结构体来清晰地接收这些数据:

这样对于数据处理与转发就十分清晰与明白了:

//雷达数据反馈结构体
typedef struct {uint8_t length;        // 长度:除帧头及校验字节外的字节数,0x0A,固定字节uint8_t address;         // 地址:固定字节uint16_t distance;       // 距离 cm  uint8_t reserved;  		 // 占 1 个字节,取值 0x00,固定字节uint8_t status;          // 0:无人, 1:有人  uint16_t signalStrength; // 单位 k,信号强度  uint8_t microMotion;     // 0:无微动, 1:有微动  uint8_t radarOff;        // 0:没有关闭, 1:已关闭  uint8_t checksum;  	     // 校验和
}SenserDataFarm;extern SenserDataFarm SDF;          //实例化结构体

数据处理函数:

//处理数据的代码,例如更新距离、状态等变量 
void parse_data(uint8_t *data, uint8_t leng) 
{//校验和正确,提取数据SDF.address=data[0];SDF.distance = (data[1]<<8) | data[2];    //距离SDF.reserved=data[3]; 										//预留SDF.status = data[4];  										//有人、无人SDF.signalStrength = (data[5] << 8) | data[6];  //信强度SDF.microMotion= data[7];								  // 0:无微动, 1:有微动  单位 k,SDF.radarOff=data[8]; 										//0:没有关闭, 1:已关闭 
}

简易状态机接收检验函数:

这里用到了状态机思维进行接收数据:

状态机放在串口中断服务函数调用:

/* 数据帧处理函数帧头:0x55 A5(2字节)长度:0x0A(1字节)地址:0xD3(1字节)距离:高位在前(2字节)预留:0x00(1字节)状态:0x00(无人)或0x01(有人)(1字节)信号强度:高位在前(2字节)微动:0x00(无微动)或0x01(有微动)(1字节)雷达关闭状态:0x00(未关闭)或0x01(已关闭)(1字节)校验和:除校验字节外所有字节的和的低8位(1字节)
*/
//数据帧处理函数  用到简易的状态机
void uart_rx_callback(uint8_t data) 
{  static uint8_t state = 0; // 状态机状态  
//    static uint8_t checksum = 0; // 校验和  static uint8_t expected_length = 10; // 期望的数据长度  static uint8_t received_length = 0; // 已接收的数据长度  switch (state) {  case 0: // 搜索帧头1  if (data== FRAME_HEADER_1) {  state = 1;}  break;case 1: // 搜索帧头2  if (data== FRAME_HEADER_2) {  state = 2;} else{ state = 0; }              // 重新开始搜索帧头1 break;case 2: // 搜索帧头2  if (data== FRAME_LENGTH) {  state = 3;received_length = 0;    // 重置已接收长度	} else{ state = 0; }              // 重新开始搜索帧头1 break;						case 11: // 读取校验和字节parse_data(rx_buffer,received_length); // 处理数据帧state = 0;  //重置状态机,准备接收下一个数据帧  break;default: //处理其他数据字段rx_buffer[received_length++]=data;   // 存储数据到缓冲区if (received_length == expected_length)// 数据接收完毕{ state = 11;} else{ // 继续接收数据字段 state++;  }break; }  
}数据帧处理函数  用到简易的状态机
//void uart_rx_callback(uint8_t data) 
//{  
//    static uint8_t state = 0; // 状态机状态  static uint8_t checksum = 0; // 校验和  
//    static uint8_t expected_length = 10; // 期望的数据长度  
//    static uint8_t received_length = 0; // 已接收的数据长度  
//  
//    switch (state) 
//			{  
//        case 0: // 搜索帧头1  
//            if (data== FRAME_HEADER_1) 
//						{  
//                state = 1;checksum+=data;      // 更新校验和
//            }  
//            break;
//						
//        case 1: // 搜索帧头2  
//            if (data== FRAME_HEADER_2) 
//						{  
//                state = 3;  checksum+=data;      // 更新校验和
//							  received_length = 0;    // 重置已接收长度	
//            } 
//						else
//						{  checksum = 0;        // 重置校验和  
//                state = 0;           // 重新开始搜索帧头1  
//            }  
//            break;
//						case 2: // 读取长度字节  expected_length = data; // 设置期望的数据长度  state = 3; checksum+=data;         // 更新校验和received_length = 0;    // 重置已接收长度				break;
//				
//        // ... 添加其他状态来处理地址、距离、状态等字段 ...  
//				
//        case 11: // 读取校验和字节  
//					  // 校验和匹配if ((checksum & 0xFF) == data) { 
//            parse_data(rx_buffer,received_length); // 处理数据帧} 
//						// 否则,丢弃该数据帧
//            state = 0;  //重置状态机,准备接收下一个数据帧  
//            break;
//						
//        default: //处理其他数据字段
//            rx_buffer[received_length++]=data;   // 存储数据到缓冲区checksum += data;                    // 更新校验和 
//				
//            if (received_length == expected_length)
//							
//						{ 
//								// 数据接收完毕,等待校验和字节 
//                state = 11;
//            } 
//						else
//						{ 
//						    // 继续接收数据字段  
//                state++;  
//            }
//            break; 
//    }  
//}

测试效果:

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

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

相关文章

【Java开发指南 | 第十五篇】Java Character 类、String 类

读者可订阅专栏&#xff1a;Java开发指南 |【CSDN秋说】 文章目录 Java Character 类转义序列 Java String 类连接字符串 Java Character 类 Character 类是 Java 中用来表示字符的包装类&#xff0c;它提供了一系列静态方法用于对字符进行操作&#xff0c;其主要分为静态方法…

AAAI-24 | EarnHFT:针对高频交易的分层强化学习(RL)框架

AAAI-24 | EarnHFT:针对高频交易的分层强化学习&#xff08;RL&#xff09;框架 原创 QuantML QuantML 2024-04-15 09:25 上海 EarnHFT 摘要(Abstract):高频交易&#xff08;HFT&#xff09;使用计算机算法在短时间内&#xff08;例如秒级&#xff09;做出交易决策&#xff…

C++实战——日期类的实现

日期类的实现 前言一、日期类概念实现运用场景 二、日期类的具体实现代码构造函数拷贝构造函数获取日期&#xff08;内联函数&#xff09;赋值加等减等加减小于小于等于大于大于等于相等不相等前置后置前置- -后置- -关于类里重载的比较运算符为什么要加外部const示例 Date.hDa…

【人工智能】机器学习算法综述及常见算法详解

目录 推荐 1、机器学习算法简介 1.1 机器学习算法包含的两个步骤 1.2 机器学习算法的分类 2、线性回归算法 2.1 线性回归的假设是什么&#xff1f; 2.2 如何确定线性回归模型的拟合优度&#xff1f; 2.3 如何处理线性回归中的异常值&#xff1f; 3、逻辑回归算法 3.1 …

现代数据中心中智能网卡/DPU的演进

数据中心是一个大型的连接服务器和存储系统池&#xff0c;通常由组织用于远程存储、处理或分发大量数据。组织可以拥有和管理其数据中心&#xff0c;也可以租用由第三方&#xff08;亚马逊或谷歌云等云服务提供商&#xff09;管理的基础设施&#xff0c;并通过互联网访问资源。…

IS62LV256AL-45ULI功能参数介绍及如何优化电源稳定性以适应

IS62LV256AL-45ULI功能参数介绍-公司新闻-配芯易-深圳市亚泰盈科电子有限公司 制造商:ISSI 产品品种:静态随机存取存储器 RoHS:是 存储容量:256 kbit 组织:32 k x 8 拜访时刻:45 ns 接口类型:Parallel 电源电压-最大:3.63 V 电源电压-最小:2.97 V 电源电流—最大值:5…

前端学习<四>JavaScript基础——38-offset相关属性和匀速动画(含轮播图的实现)

前言 JS动画的主要内容如下&#xff1a; 1、三大家族和一个事件对象&#xff1a; 三大家族&#xff1a;offset/scroll/client。也叫三大系列。 事件对象/event&#xff08;事件被触动时&#xff0c;鼠标和键盘的状态&#xff09;&#xff08;通过属性控制&#xff09;。 2…

java算法day59 | 单调栈part02 ● 503.下一个更大元素II ● 42. 接雨水

503.下一个更大元素II 思路&#xff1a; 相比于单纯寻找下一个最大元素&#xff0c;要遍历两边数组&#xff0c;注意i%nums.length。 class Solution {public int[] nextGreaterElements(int[] nums) {int[] resnew int[nums.length];for(int i0;i<res.length;i){res[i]-1;…

【大数据】bigtable,分布式数据库的鼻祖

目录 1.概述 2.数据模型 3.API 4.架构 5.一个完整的读写过程 6.如何查找到要的tablet 7.LSM树 1.概述 本文是作者阅读完bigtable论文后对bigtable进行的一个梳理&#xff0c;只涉及核心概念不涉及具体实操&#xff0c;具体实操会在后续的文章中推出。 GFS的出现虽然解…

指针专题(2)

前言 上一节我们学习了指针的相关内容&#xff0c;本节我们继续学习指针专题&#xff0c;更加深入的了解指针&#xff0c;那么废话不多说&#xff0c;我们正式进入今天的学习 1.对数组名的深入理解 在上一节的内容中&#xff0c;我们提到了用指针来访问数组的操作&#xff0c…

Linux 基于 TCP 协议的简单服务器-客户端应用

目录 一、相关函数 1、listen() 2、accept() 3、connect() 4、两种IP地址转换方式 5、TCP和UDP数据发送和接收函数对比 5、log.hpp自定义记录日志 二、udp_server.hpp单进程版本 三、tcp_server.cc 四、Telnet客户端&#xff08;代替tcp_client.cc&#xff09; 五…

ColBERT和ColBERTv2:兼具Bi-encoder和cross-encoder优势的多向量排序模型

文章目录 简介ColBERTColBert 原理ColBERT如何训练ColBERT 如何使用离线索引用ColBERT 实现top-k Re-ranking用ColBERT 实现top-k 端到端的检索 ColBERTv2ColBERTv2原理SupervisionRepresentation IndexingRetrieval 总结参考资料 简介 ColBERT是一种多向量排序模型&#xff0…

数据分析案例-中国黄金股票市场的EDA与价格预测

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

Redis的Stream 和 实现队列的方式【List、SortedSet、发布订阅、Stream、Java】

Redis队列与Stream、Redis 6多线程详解 Redis队列与StreamStream总述常用操作命令生产端消费端单消费者消费组消息消费 Redis队列几种实现的总结基于List的 LPUSHBRPOP 的实现基于Sorted-Set的实现PUB/SUB&#xff0c;订阅/发布模式基于Stream类型的实现与Java的集成 消息队列问…

算法打卡day39

今日任务&#xff1a; 1&#xff09;卡码网57. 爬楼梯&#xff08;70. 爬楼梯进阶版&#xff09; 2&#xff09;322.零钱兑换 3&#xff09;279.完全平方数 4&#xff09;复习day14 卡码网57. 爬楼梯&#xff08;70. 爬楼梯进阶版&#xff09; 题目链接&#xff1a;57. 爬楼梯…

ipv4Bypass:一款基于IPv6实现的IPv4安全绕过与渗透测试工具

关于ipv4Bypass ipv4Bypass是一款基于IPv6实现的安全绕过与渗透测试工具&#xff0c;该工具专为红队研究人员设计&#xff0c;可以帮助广大研究人员通过IPv6绕过目标安全策略&#xff0c;以此来检测安全检测机制的健壮性。 20世纪90年代是互联网爆炸性发展时期&#xff0c;随着…

Llama 3王者归来,可与GPT-4分庭抗礼,开源模型即将追上闭源模型了?

“有史以来最强大的开源大模型”Llama 3引爆AI圈&#xff0c;马斯克点赞&#xff0c;英伟达高级科学家Jim Fan直言&#xff0c;Llama 3将成为AI大模型发展历程的“分水岭”&#xff0c;AI顶尖专家吴恩达称Llama3是他收到的最好的礼物。 4月18日&#xff0c;AI圈再迎重磅消息&a…

写一个uniapp的登录注册页面

目录 一、效果图 二、代码 1、登录 &#xff08;1&#xff09;页面布局代码 &#xff08;2&#xff09;逻辑实现代码 &#xff08;3&#xff09;css样式 2、注册 &#xff08;1&#xff09;页面布局代码 &#xff08;2&#xff09;逻辑实现代码 &#xff08;3&#x…

一个完全用rust写的开源操作系统-Starry

1. Starry Starry是2023年全国大学生计算机系统能力大赛操作系统设计赛-内核实现赛的二等奖作品。Starry是在组件化OS的arceos的基础上&#xff0c;进行二次开发的操作系统内核&#xff0c;使用宏内核架构&#xff0c;能够运行Linux应用的内核。 原始的操作系统大赛的仓库为 …

51-42 NÜWA:女娲,统一的多模态预训练模型

21年11月&#xff0c;微软、北大联合发布了NUWA模型&#xff0c;一个统一的多模态预训练模型&#xff0c;在 8 个下游任务上效果惊艳。目前该项目已经发展成为一系列工作&#xff0c;而且都公开了源代码。 Abstract 本文提出了一种统一的多模态预训练模型N̈UWA&#xff0c;该…