开发板(原子的mini stm32)主控stm32F103RCT6
模块:维特智能VL53-400S激光测距仪(以下简称VL53)
模块与主控之间串口通信
目录
将VL53设置为Modbus模式
需要一个USB转TTL的串口模块,某宝上大概5块一个,CH340的
用串口模块连接VL53和电脑
5V接VCC,GND接GND
串口模块的RX接VL53的TX
串口模块的TX接VL53的RX
登录维特智能官网下载维特智能上位机
按照上面产品说明书中给出的步骤用维特的上位机连接VL53并设置为Modbus模式
设置为Modbus后VL53不再自动返回测量数据,用XCOM验证一下
具体步骤也在产品说明书里,确定成功设定
代码验证
用开发板连接VL53和电脑,原子的mini可以用串口1和电脑通信,在XCOM上显示,如果你的板不能直连的话可以考虑用0.96那个OLED显示或者用前面的串口模块连接开发板和电脑,有点麻烦
主要使用了两个串口和一个按键中断,串口1给电脑发数据,串口2和VL53通信,按键中断里发起一次读取测量数据的请求
main.c
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "uart2.h"
#include "key.h"
extern u8 rx_buffer[100]; //串口2接收的数据
extern u8 counter; //串口2数据接收计数
extern u8 flag; //串口2接收到7个数据标志
extern u8 printf_flag; //按键中断后打印测量数据标志
int main(void)
{
u8 i;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
uart_init(115200); //串口1初始化为115200
Initial_UART2(115200);//串口2初始化
LED_Init(); //初始化与LED连接的硬件接口
EXTIX_Init(); //按键中断初始化
printf("usart1_on\r\n");//初始化结束后示意串口1已开启
for(i=0;i<50;i++)//保险起见前50个先置零,其实用不了这么多
rx_buffer[i] = 0;
while(1)
{
if(printf_flag == 1){ //只有每发起一次读数据请求后才打印测量值避免不断输出
if(flag == 1){ //串口2收到7个数据
if(rx_buffer[0] == 0x50) //验证数据头是否为0x50
printf("head_right\r\n"); //数据头正确则提示
for(i=0;i<=counter;i++){
printf("%x__",rx_buffer[i]);
//打印测量数据,建议格式化输出,我用的下划线
rx_buffer[i] = 0; //输出后清零,其实也可以不清
if(i == 6) //输出7个数据后换行方便观察
printf("\r\n");
}
counter = 0; //重置计数位,下一次接收数据从零开始
flag = 0; //标志位清零
}
else
printf("head_wrong\r\n"); //数据错误
printf_flag = 0; //打印标志清零,避免反复打印
}
}
}
uart_init(115200); //串口1初始化为115200
前面还有重定向的部分没粘
void uart_init(u32 bound){
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);
//使能USART1,GPIOA时钟
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
//USART1_RX GPIOA.10初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口1
USART_Cmd(USART1, ENABLE); //使能串口1
}
Initial_UART2(115200);//串口2初始化
#include "uart2.h"
#include "usart.h"
//串口2初始化
void Initial_UART2(unsigned long baudrate)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //USART2_TX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; USART2_RX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_InitStructure.USART_BaudRate = baudrate;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART2, &USART_InitStructure);
USART_ITConfig(USART2, USART_IT_TXE, DISABLE);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
USART_ClearFlag(USART2,USART_FLAG_TC);
USART_Cmd(USART2, ENABLE);
}
void USART2_IRQHandler(void)
{
u8 Res;
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET){
Res =USART_ReceiveData(USART2); //读串口接收到的数据
rec_data_handle(Res); //处理数据,写的有点啰嗦
USART_ClearITPendingBit(USART2, USART_IT_RXNE);
}
USART_ClearITPendingBit(USART2,USART_IT_RXNE);
}
void UART2_Put_Char(unsigned char DataToSend){
USART_SendData(USART2,DataToSend);
while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);
}
u8 rx_buffer[100]; //接收的数据先放在这里面,在while(1)里面处理
u8 counter;
u8 flag = 1;
void rec_data_handle(u8 rec_data){
rx_buffer[counter++] = rec_data;
if(counter == 7) //接到7个数据就表明有一个完整的数据包
flag = 1;
}
//用串口2给VL53发送指令
void sendcmd_usart2(char cmd[])
{
char i;
for(i=0;i<8;i++){
UART2_Put_Char(cmd[i]);
}
}
EXTIX_Init();//按键中断初始化,在中断里发起一次读数据请求
#include "key.h"
#include "delay.h"
#include "uart2.h"
//按键初始化函数
//PC5 设置成输入
void KEY_Init(void){
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//使能PORTC时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//PC5
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化GPIOC5
}
void EXTIX_Init(void){
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//外部中断,需要使能AFIO时钟
KEY_Init();//初始化按键对应io模式
//GPIOC.5 中断线以及中断初始化配置
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource5);
EXTI_InitStructure.EXTI_Line=EXTI_Line5;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
//使能按键所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; //子优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure);
}
char read_data[8] = {0x50,0x03,0x00,0x34,0x00,0x01,0xc8,0x45};//在维特官网上有
u8 printf_flag; //每进入一次中断在XCOM上输出一次数据
void EXTI9_5_IRQHandler(void){
delay_ms(10); //消抖
if(KEY0==0) {
sendcmd_usart2(read_data);//发送读数据请求
printf_flag = 1;
}
EXTI_ClearITPendingBit(EXTI_Line5); //清除LINE5上的中断标志位
}
结果
没搞明白这几个零哪来的,而且每次得按两次,比较勉强,数据处理的有点糙
有需要完整工程的评论留邮箱
小白一个,有错还请指正