目录
3.STM32接收激光测距模块数据并打印到电脑和在OLED屏上显示
1.前言
因为一个项目需要用到测距模块,所以接触到正点原子的MS53L1M激光测距模块,刚好最近有在调试串口接收数据包,于是我就尝试写一个标准库接收的代码。
2.配置VL53L0X激光测距模块
在与STM32通信之前先使用正点原子自带的上位机对激光测距模块进行配置
上位机下载地址: https://pan.baidu.com/s/10eQFh6TeAuCfJO3vPgCJew 提取码:fcak
1.接线部分
如上图所示正点原子的这个激光测距模块,有2种通信方式串口通信和IIC通信,我使用的是串口通信方式,用USB转TTL模块将激光测距模块连接上电脑
USB转TTL模块 | 激光测距模块 |
3.3V | 红线 |
GND | 黑线 |
RXD | 黄线 |
TXD | 白线 |
2.上位机配置
首先选择对应串口,配置对应波特率,再打开串口选择TOF_4M后,点击搜索模块,找到模块后就可以进行配置了。
设备ID:更改不同的ID,可以通过串口读取所有的模块的测距距离,本文未涉及。
工作模式:工作模式有三种,正常串口模式,IIC模式,MODBUS模式。我就使用了正常模式。
3.分析接收数据
对激光测距模块配置好后,随便使用一个串口助手接收一下数据,先使用ASCII码接收,显示数据为:
真正需要的数据为d:462 MM 此时我们在将数据接收模式换成HEX的模式,显示数据为:
可以发现每组距离数据前后都会有d: (空格)MM,对应的HEX为64 4A 20 6D 6D(空格的ASCII为0x20),那我们只需要写一个数据包格式为帧头1 64,帧头2 4A帧尾为20的数据包,就可以接收激光测距模块的数据了。
3.STM32接收激光测距模块数据并打印到电脑和在OLED屏上显示
1.接线部分
激光测距模块 | STM32F103 |
3.3V | 3.3V |
GND | GND |
黄线 | PA10 |
STM32F103 | USB转TTL模块 |
3.3V | 3.3V |
GND | GND |
PA2 | RXD |
2.STM32F103代码
1.主函数代码
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "Serial.h"
#include "Serial2.h"
int main (void)
{
OLED_Init();
Serial_Init();
Serial2_Init();
OLED_ShowString(1,1,"d: mm");
while(1)
{
int D = Cx*1000+Cy*100+Cz*10+Cw;
OLED_ShowNum(1,4,D,4);
SendData(Cx,Cy,Cz,Cw);//将数据发送到电脑
}
}
2.串口1代码
#include "stm32f10x.h" // Device header
#include <stdio.h>
#include <stdarg.h>
uint8_t Cx,Cy,Cz,Cw;
void Serial_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//USART1_RX PA10
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode =USART_Mode_Rx;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART1, ENABLE);
}
void USART1_IRQHandler(void)
{
u8 com_data;
u8 i;
static u8 RxCounter1=0;
static u16 RxBuffer1[7]={0};
static u8 RxState = 0;
if( USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET) //接收中断
{
USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中断标志
com_data = USART_ReceiveData(USART1);
if(RxState==0&&com_data==0x64) //0x2c帧头
{
RxState=1;
RxBuffer1[RxCounter1++]=com_data;
}
else if(RxState==1&&com_data==0x3A) //0x12帧头
{
RxState=2;
RxBuffer1[RxCounter1++]=com_data;
}
else if(RxState==2)
{
RxBuffer1[RxCounter1++]=com_data;
if(RxCounter1==7 && com_data == 0x20) //RxBuffer1接受满了,接收数据结束
{
Cx=RxBuffer1[RxCounter1-5];
Cy=RxBuffer1[RxCounter1-4];
Cz=RxBuffer1[RxCounter1-3];
Cw=RxBuffer1[RxCounter1-2];
if(Cx<48)
{
Cx=0;
}
else
{
Cx-=48;
}
if(Cy<48)
{
Cy=0;
}
else
{
Cy-=48;
}
if(Cz<48)
{
Cz=0;
}
else
{
Cz-=48;
}
if(Cw<48)
{
Cw=0;
}
else
{
Cw-=48;
}
RxCounter1 = 0;
RxState = 0;
}
else if(RxCounter1 > 7)
{
RxState = 0;
RxCounter1=0;
for(i=0;i<7;i++)
{
RxBuffer1[i]=0x00; //将存放数据数组清零
}
}
}
else //接收异常
{
RxState = 0;
RxCounter1=0;
for(i=0;i<7;i++)
{
RxBuffer1[i]=0x00; //将存放数据数组清零
}
}
}
}
此接收代码接收数据包的逻辑在我的上一篇文章STM32与K210串口通信已经讲过了,这里就不重复在说了,感兴趣的话可以去那篇文章看一看。
唯一不同的就是对接收到的数据进行了一点处理,因为我们接收到的数据为ASCII对应的数字,所以要进行一定的转化。
if(Cx<48)
{
Cx=0;
}
else
{
Cx-=48;
}
if(Cy<48)
{
Cy=0;
}
else
{
Cy-=48;
}
if(Cz<48)
{
Cz=0;
}
else
{
Cz-=48;
}
if(Cw<48)
{
Cw=0;
}
else
{
Cw-=48;
}
因为ASCII数据与我们所需要数据差48,所以需要将每个数据减掉48,但因为激光测距模块的首位数据为零的话,它会发送0x20也就是空格,所以我们需要使用判断将其置零。
3.串口2代码
#include "stm32f10x.h" // Device header
#include <stdio.h>
#include <stdarg.h>
#include "Delay.h"
char sendBuf2[10];
void Serial2_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//USART2_TX
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//USART2_RX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART2, &USART_InitStructure);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =5;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 5;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART2, ENABLE);
}
void Serial2_SendByte(uint8_t Byte)
{
USART_SendData(USART2, Byte);
while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
}
void Serial2_SendString(char *String)
{
uint16_t i;
for (i = 0; String[i] != '\0'; i ++)
{
Serial2_SendByte(String[i]);
}
}
void Serial2_Printf(char *format, ...)
{
char String[100];
va_list arg;
va_start(arg, format);
vsprintf(String, format, arg);
va_end(arg);
Serial2_SendString(String);
}
void SendData(u8 a1,u8 a2,u8 a3,u8 a4)
{
sprintf((char *)sendBuf2, "d:%d%d%d%dmm\r\n",a1,a2,a3,a4);
Serial2_SendString(sendBuf2);
Delay_ms(100);
}
此代码是将从激光测距模块获得的数据发送给电脑。
4.实验现象和完整源码
OLED显示距离
串口打印显示