STM32F407(CubeMX+HAL+USB(vcp))移植rosserial和ROS通信

发布者:牟牟的侬最新更新时间:2022-08-10 来源: csdn关键字:STM32F407  CubeMX  HAL 手机看文章 扫描二维码
随时随地手机看文章

前言

之前尝试过移植好rosserial的stm32通过串口和ROS系统建立通信,但无奈在类似于发布IMU类似的数据量很大的消息或消息的发布频率较高时经常会出现一些问题(发布频率达不到设定要求,启动rosserial的终端会报一些警告和错误),在一般的学习中还可以,但在实际的应用中基本达不到使用要求。


写道这想说明一点:我对整个rosserial内部的通信机制也不是很了解,类似于通信速度达到多少可以满足通信速度的需求,如何测试通信速度等等问题(我也很纳闷为什么串口就会存在这些问题),如果大家有什么见解欢迎交流。


一、基于STM32CubeMX建立STM32F407USB虚拟串口基本工程

配置STM32F407单片机的时钟源,时钟源选择为晶振

配置时钟源

配置调试方式和时基,此处选择的为SW模式。时基选择为系统滴答定时器。

配置调试方式和时基

3. 配置USB为全速模式下的仅设备模式

配置USB模式

这里使用ST官方提供的USB设备库,并使用CDC类

配置USB设备模式

配置系统时钟,这里晶振频率为8M并将系统时钟配置为最高的168M,并注意USB的时钟为48M

配置时钟频率

这里要特别注意一点,下面红框中标示的,堆空间一定要改大,否则会在设备管理器中显示黄色的感叹号。

配置工程属性

这些都配置完之后便可以点击右上角的生成代码按钮,来生成基本工程代码。

配置工程属性

二、根据基本工程修改USB部分的代码,提供rosserial会用到的串口收发接口。

这一部分推荐看一篇帖子:http://bbs.21ic.com/icview-811704-1-1.html

这里主要修改usbd_cdc_if.c文件,首先我们要明确其中两个函数的功能。


static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)

{

  /* USER CODE BEGIN 6 */

  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);

  USBD_CDC_ReceivePacket(&hUsbDeviceFS);

  return (USBD_OK);

  /* USER CODE END 6 */

}


uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)

{

  uint8_t result = USBD_OK;

  /* USER CODE BEGIN 7 */

  USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;

  if (hcdc->TxState != 0){

    return USBD_BUSY;

  }

  USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len);

  result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);

  /* USER CODE END 7 */

  return result;

}


单从这两个函数的名字上看也比较好理解,上面的时数据接收函数,下面的时数据发送函数。CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)是数据接收的回调函数,USB每次收到数据后都会调用该函数将接收到的数据存入Buf指向的缓冲区当中,Len是接收到数据的长度。USBD_CDC_ReceivePacket()函数的作用是复位OUT端点接收缓冲区,CDC_Itf_Receive()函数在接收完数据之后要调用该函数复位缓冲区。因此如果接收到的数据没有及时处理,就会被下次接收到的数据覆盖掉了。所以在此处要增加数据转存环节。


#define USB_RX_DATA_SIZE 2048


uint8_t usb_rxBuffer[USB_RX_DATA_SIZE];

uint32_t usb_rxBufPtrIn = 0;

uint32_t usb_rxBufPtrOut = 0;


static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)

{

  /* USER CODE BEGIN 6 */

  uint32_t i;

  uint16_t in;

  for(i = 0; i < *Len; ++i)

  {

    in = (usb_rxBufPtrIn + 1) % USB_RX_DATA_SIZE;

    if(in != usb_rxBufPtrOut) //USB接收缓冲区未满

    {

      usb_rxBuffer[usb_rxBufPtrIn] = Buf[i];

      usb_rxBufPtrIn = in;

    }

  }

  

  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);

  USBD_CDC_ReceivePacket(&hUsbDeviceFS);

  return (USBD_OK);

  /* USER CODE END 6 */

}


这样处理最终实现的效果是将接收到的数据存入了一环形缓冲区。再将数据存好之后便可以为rosserial提供接口函数了


//接收缓冲区中的数据大小

int vcp_available(void)

{

  return ((uint32_t)(USB_RX_DATA_SIZE + usb_rxBufPtrIn - usb_rxBufPtrOut)) % USB_RX_DATA_SIZE;

}

//从接收缓冲区中读取

int vcp_read(void)

{

  // if the head isn't ahead of the tail, we don't have any characters

  if(usb_rxBufPtrIn == usb_rxBufPtrOut)

  {

    return -1;

  }

  else

  {

    unsigned char ch = usb_rxBuffer[usb_rxBufPtrOut];

    usb_rxBufPtrOut = (uint16_t)(usb_rxBufPtrOut + 1) % USB_RX_DATA_SIZE;

    return ch;

  }

}

//通过usb_vcp向外发送

void vcp_write(uint8_t* Buf, uint16_t Len)

{

  while(CDC_Transmit_FS(Buf, Len) != HAL_OK);

}


三、将ros_lib增加到工程中,并修改STM32Hardware.h文件

ros_lib 可以根据rosserial wiki 的教程中执行产生。

ros_lib增加到工程中之后会报找不到round函数的错误,和一系列警告消息。

在这里插入图片描述

针对找不到round()函数的错误可以在增加__USE_C99_MATH的宏,针对大量警告的问题可以在Misc Controls 的位置增加如:–diag_suppress=num,(num,为警告信息#号后面的数字)。

接下来的重点便是修改STM32Hardware.h文件了。

这里试了一下不能直接粘贴太多代码,就介绍一下如何修改好了。

在开头的地方增加:


extern __IO uint32_t uwTick;

将类内部的读写函数修改为:


int read(){

     if(vcp_available()){

    return vcp_read();

     }else{

     return -1;

     } 

     void write(uint8_t* data, int length){

     vcp_write(data, length);

    }


将时间函数改为


unsigned long time(){return uwTick;}

到此整个移植工作便结束了,接下来可以按照rosserial wiki上面的教程开始测试学习了。

关键字:STM32F407  CubeMX  HAL 引用地址:STM32F407(CubeMX+HAL+USB(vcp))移植rosserial和ROS通信

上一篇:基于STM32指纹识别模块(TFS-M64)的学习
下一篇:WS2812灯珠(三)-- STM32 PWM+DMA方式驱动

推荐阅读最新更新时间:2024-11-17 10:38

STM32CubeMX中FreeRTOS系统CPU使用率监测测试
1.测试描述: 使用STM32CubeMX自动配置的工程,对其提供的FreeRTOS系统的CPU使用率进行监测,并通过串口打印。 2.测试环境: (1)软件环境:STM32CubeMX-4.22.0,IAR-7.5,串口调试工具 (2)硬件环境:原子战舰V3开发板 3.测试准备: (1)STM32CubeMX软件主要配置: 管脚和其他外设的配置直接省略了,具体的可查看源码文件里的ioc文件。下面贴出主要的系统方面配置图: 首先是Configuration界面,从图中可以看出测试工程使用的东西并不多; 点击中间层的FREERTOS进入系统配置界面,主要注意下图中红色标注的部分;
[单片机]
STM32<font color='red'>CubeMX</font>中FreeRTOS系统CPU使用率监测测试
STM32CubeMX系列 | 待机唤醒
1. 低功耗模式简介 系统或电源复位后,微处理器处于运行状态,运行状态下HCLK为CPU提供时钟,内核执行程序代码。当CPU不需继续运行时(例如等待某个外部事件),可以利用多个低功耗模式来节省功耗。用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。STM32提供了3种低功耗模式,以达到不同层次的降低功耗的目的: - 睡眠模式(CM3内核停止工作,外设仍在运行)(功耗最高) - 停止模式(所有时钟都停止)(典型电流消耗20uA左右) - 待机模式(1.8V内核电源关闭)(最低电流消耗2uA左右) 在运行模式下,也可以通过如下方式降低功耗: - 降低系统时钟 - 关闭APB和AHB总线上未被使用的
[单片机]
分享一种STM32F407的锁相环PLL重新配置方法
老农最近搞基于STM32F407的IAP升级固件升级功能,遇到了这样一个问题:IAP引导程序和APP程序都是基于STM32CUBEMX的程序模板生成,单独调试运行APP功能也都正常,但是只要采用IAP方式将APP程序的bin文件烧写到程序存储区,再跳转到APP的地址运行就死掉了。 这个问题困扰了老农挺长时间,后来才发现问题所在:那就是STM32系列的单片机一旦完成PLL时钟设置后,是不能再次配置的。 本例中IAP引导程序首先对PLL进行了成功配置,当跳转到APP程序运行后,APP程序初始化部分又对PLL进行了一次配置,结果配置失败,因为程序是基于STM32CUBEMX的模板,配置失败后调用模板的Error_Handler(
[单片机]
分享一种<font color='red'>STM32F407</font>的锁相环PLL重新配置方法
STM32F4串口接收(HAL库)使用笔记
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size); 这个是一个类似于串口接收中断使能作用的函数,注释是Receives an amount of data in non blocking mode以非阻塞方式接收大量数据。想要使用此函数接收却不确定能接收到多少数据,则将uint16_t Size写作1,例如: HAL_UART_Receive_IT(&UartHandle1, (uint8_t *)Rx1Buffer, 1);//通过串口1接收,数据保存到Rx1Buffer,每次接收
[单片机]
stm32HAL库之can操作
基于STM32CubeMx的CAN配置信息 volatile 1.系统时钟APB1=36MHZ 2.CAN计算通信率计算公式,参考数据手册, CAN bit timing register (CAN_BTR) 寄存器 NominalBitTime计算公式: NominalBitTime =1 t × q + tBS1 + tBS2 3.STM32CubeMx设置的Prescaler为8- 对应BRP=7,TimeSeg1=6- 对应TS1=5,TimeSeg2=2- 对应TB2=2,STM32F103ZE对应APB1设置为36M,即Time for one Bit的时间为(1 + TimeSeg1+ TimeSeg2)
[单片机]
stm32<font color='red'>HAL</font>库之can操作
STM32CubeMX之RTC电子钟
1.简介 实时时钟是一个独立的定时器。 RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。 2.特性  ● 可编程的预分频系数:分频系数最高为220。  ● 32位的可编程计数器,可用于较长时间段的测量。  ● 2个分离的时钟:用于APB1接口的PCLK1和RTC时钟(RTC时钟的频率必须小于PCLK1时钟频率的四分之一以上)。  ● 可以选择以下三种RTC的时钟源: ─ HSE时钟除以128; ─ LSE振荡器时钟; ─ LSI振荡器时钟  ● 3个专门的可屏蔽中断: ─ 闹钟中断,用来产生一个软件可编程的闹钟中断。 ─ 秒中断,用来产生一个可编程的周期性
[单片机]
STM32<font color='red'>CubeMX</font>之RTC电子钟
STM32CubeMX学习教程之七:ADC读取电压并输出到串口
软件: STM32CubeMX V4.25.0 System Workbench V2.4 固件库版本: STM32Cube FW_F1 V1.6.1 硬件: OneNet 麒麟座V2.3 在STM32CubeMX中新建项目,选择正确的MCU型号 首先设置RCC和SYS,如下图 配置USART1为Asychronous模式 UART1配置用默认的115200,8, None和1就好。 然后设置PA6引脚为ADC2_IN6, 完整引脚配置如下图: 然后根据板子实际情况设置时钟(麒麟座外部晶振是12M,STM32F103x的最高主频是72M),注意CubeMX
[单片机]
STM32<font color='red'>CubeMX</font>学习教程之七:ADC读取电压并输出到串口
STM32CubeMX学习教程之十:硬件I2C读写AT24C02
网上有流传已久一种说法,就是STM的I2C有bug,不好用。确实很多人在实际应用中都遇到了各种问题,所以绝大部分人都是在用软件模拟IIC。 有了STM32CubeMX,我们可以尝试使用硬件I2C了,官方的优化总不会有错了吧?(其实还是有个小bug,不过可以改过来的)。本文的目标就是使用STM32CubeMX的硬件I2C对麒麟座板载的AT24C02 EEPROM进行完整的读写操作。 软件版本: STM32CubeMX V4.25.0 System Workbench V2.4 固件库版本: STM32Cube FW_F1 V1.6.1 固件库版本: STM32Cube FW_F1 V1.6.1 硬件
[单片机]
STM32<font color='red'>CubeMX</font>学习教程之十:硬件I2C读写AT24C02
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved