[应用相关] STM32CubeMX 真的不要太好用

[复制链接]
899|22
 楼主| liuqiangdong 发表于 2022-3-31 20:07 | 显示全部楼层 |阅读模式
由于工作内容的变动,我已经很久没有正经的玩过单片机了,近期又要用它做个小玩意了,还是选 stm32 吧,外设库开发不要太方便,哈哈哈

先去 stm32 社区逛了逛,发现了一个新字眼 STM32CubeMX,简单看了下,大概明白是个 ST 公司新推出的一个配置工具,直接由图形界面简单配置下,生成初始化代码,并对外设做了进一步的抽象,让开发人员更只专注应用的开发,挺不错的样子,下来玩玩。

详细的入门教程我就不写了,网上太多,这里说下我是怎么用它快速的实现了一个虚拟串口终端和点灯吧,也算是入门教程吧,哈哈哈

我需要用的外设有 usb 接口和一个普通的 GPIO,需要使用的中间件库有 FreeRTOS 和 USB_DEVICE,要完成的功能是实现一个虚拟串口,然后适配上 FreeRTOS 的 CLI 制作一个虚拟串口终端,同时让一个 LED 闪烁,这里我选用经典的 STM32F103C8T6 来完成这些。


 楼主| liuqiangdong 发表于 2022-3-31 20:08 | 显示全部楼层
那让我们开始吧,

第一步,直接打开 STM32CubeMX,在主界面选到 ACCESS TO MCU SELECTOR 开始一个工程,这里需要注意的一点是此时 STM32CubeMX 会去联网检查一些更新,如果你的防火墙是开的话,很可能会检测失败,关掉防火墙就好。
 楼主| liuqiangdong 发表于 2022-3-31 20:10 | 显示全部楼层
第二步,在 MCU Filters 栏直接输入我们使用的型号,只需要输入 103C8 就找到啦,然后选中它,右边有它的介绍,而且还可以直接下载它的 Datasheet 也不要太方便了,然后点击 Start Project 按钮开始一个工程。
 楼主| liuqiangdong 发表于 2022-3-31 20:11 | 显示全部楼层
第三步,把我们需要的外设和中间件库选上,有 USB 接口,GPIO 接口,FREERTOS 和 USB_DEVICE 的支持,最后如下图:
6946862459a2d2d3c4.png
 楼主| liuqiangdong 发表于 2022-3-31 20:12 | 显示全部楼层
配置的时候有以下几点要注意的:

1、时钟的配置在 RCC 选项,根据实际情况是选内部 RC 还是外部晶振,外部晶振的话要占用两个引脚,我这里是 8 Mhz 外部晶振,配置如下:
1511662459a6af37f8.png
 楼主| liuqiangdong 发表于 2022-3-31 20:13 | 显示全部楼层
2、关于 debug 口子的配置,默认它是认为我们不需要 debug 口的,所以如果不更改的话生成代码下载进去后 debug 口就关闭了,哈哈哈

如果你真的不小心 debug 口子被关闭了也不用担心,可以通过如下方法再次下载程序:

按住复位按钮要不要放,然后在 Keil 下点击下载按钮,等它提示错误并说检测到被锁掉 debug 口的片子,然后点击确定的同时,松开复位按钮就可以下载啦,如果不行则再多试几次,时序和时机很重要。
 楼主| liuqiangdong 发表于 2022-3-31 20:19 | 显示全部楼层
然后在 SYS 里面选择 debug 工具连接的类型,我这里是 SWD 的方式连接的,选择串行线,如下图:
7052162459afbc030b.png
 楼主| liuqiangdong 发表于 2022-3-31 20:20 | 显示全部楼层
3、由于 STM32CubeMX 使用的 HAL 库有一个 delay 接口默认是使用 SysTick 定时器来实现的,而由于这里我们选用了 FreeRTOS,它使用的心跳时钟在 Cortex 内核上的移植都是依赖于 SysTick 定时器,这里会有冲突,这一点在点击生成代码按钮时 STM32CubeMX 也会发出警告,这里我们为 HAL 库使用的定时器选过一个就可以了,如下图,这里我把它选到了 TIM1
9876862459c6784fa8.png
 楼主| liuqiangdong 发表于 2022-3-31 20:22 | 显示全部楼层
4、由于后续我们还要在 FreeRTOS 上加入许多线程,我们把他的堆大小设置大一点,在 FREERTOS 的 Config parameters 里面的 TOTAL_HEAP_SIZE,这里比较任性,我配置了 1024 字节,哈哈哈
 楼主| liuqiangdong 发表于 2022-3-31 20:24 | 显示全部楼层
第四步,我们再来为 FreeRTOS 上加入一个 LED 闪烁的线程。这里我们选到 FREERTOS 的 Taks and Queues,然后点击 Add 按钮即可添加了,取名为 ledTask。

到这里配置工作就差不多了,接下来见证奇迹的时刻到了,点击 GENERATE CODE 然后整个工程就生成了,然后编译下载到板子上,插上电脑,叮咚,成功识别为串口,在 win10 上驱动都不用自己装,是不是很爽,哈哈哈

到这里我们的 LED 还是不能闪的,这需要我们加入几条代码,这个简单,找到我们在工具上创建的 ledTask 线程,在线程函数实体里面加入如下代码再编译下载后灯就开始闪了,简单吧。
 楼主| liuqiangdong 发表于 2022-3-31 20:27 | 显示全部楼层
 楼主| liuqiangdong 发表于 2022-3-31 20:28 | 显示全部楼层
我想我的介绍就到这里结束吧,这才简单嘛,哈哈哈,但等等,说好的虚拟终端呢,

那好吧,那我们先再说个注意点,接下来往上加代码的时候,往由工具生成的文件里面加代码一定要加在标注了 USER CODE BEGIN 和 USER CODE END 的注释里面,这样下次更新配置的时候你加的代码才不会消失,自己加入的文件则无所谓。具体实现我这里也说个大致思路和要注意的点,具体实现,请到我的 github 上去取吧,如果你能点颗星星我就更开心了,哈哈哈

串口终端我们都上 FreeRTOS 了当然有现成的实现了,这里我们主要做的工作就是把 FreeRTOS 提供的串口终端实现即 CLI ,对接上我们的虚拟串口。
 楼主| liuqiangdong 发表于 2022-3-31 20:30 | 显示全部楼层
第一步,下载 FreeRTOS 的 CLI 扩展库,这里 STM32CubeMX 默认是没有提供的,没关系,我们去 FreeRTOS 的官网下载,注意最好下载当前使用 FreeRTOS 版本对应版本的完整包,然后解压得到 CLI 扩展库加入到我们的工程,同时把它的 Demo 也加进来。
 楼主| liuqiangdong 发表于 2022-3-31 20:31 | 显示全部楼层
第二步,经阅读 CLI 的 Demo 后发现它依赖的如下四个接口我们实现一下就好了。我们要做的内容就是完善这四个接口,把虚拟串口下来的数据传进来,然后把输出传回去。
 楼主| liuqiangdong 发表于 2022-3-31 20:32 | 显示全部楼层
  1. xComPortHandle xSerialPortInitMinimal(int baudRate, int queueLength);

  2. int xSerialGetChar(xComPortHandle xPort, signed char *cRxedChar, int timeout);

  3. int vSerialPutString(xComPortHandle xPort, signed char *pcWelcomeMessage, unsigned short len);

  4. int xSerialPutChar(xComPortHandle xPort, signed char c, int timeout);
 楼主| liuqiangdong 发表于 2022-3-31 20:33 | 显示全部楼层
这里实际上设计是依赖实际的串口的,但没关系我们虚拟的也可以,只要把数据接收发送打通即可。
 楼主| liuqiangdong 发表于 2022-3-31 20:34 | 显示全部楼层
第三步,完善发送数据接口。发送接口比较简单,经阅读 ST 对虚拟串口的实现了解到往 USB 发送数据,使用 CDC_Transmit_FS 接口即可,所以实现如下:
  1. int vSerialPutString(xComPortHandle xPort, signed char *pMessage, unsigned short len)
  2. {
  3.         xPort = xPort;

  4. retry:

  5.         if(0x00 != CDC_Transmit_FS(pMessage, len))
  6.         {
  7.                 osDelay(10);
  8.                 goto retry;
  9.         }

  10.         return 0x00;
  11. }
 楼主| liuqiangdong 发表于 2022-3-31 20:35 | 显示全部楼层
请放过不要吐槽这里的 goto,哈哈哈,这里一定要去检查 CDC_Transmit_FS 接口的返回值,刚开始我只检查了,没有动作,后面发现会漏字符,后面才把 retry 加上去的,然后就使用了 goto,我觉的这样很简洁也好理解,当然加上超时机制就更好了,这里勉强先这样吧,哈哈哈

 楼主| liuqiangdong 发表于 2022-3-31 20:38 | 显示全部楼层
第四步,对接数据接收。这里稍微有点麻烦,CDC 的数据是在 CDC_Receive_FS 以 callback 的方式传上来的,应该是使用中断接收,我们串口终端是一个线程通过 xSerialGetChar 接口来获取数据的,这里当然首先想到的就是使用 FreeRTOS 提供的 queue 功能了,但最后发现 queue 只能一个个入列,效果很不理想,会漏字符,如果只传递数据的指针过来的话,又要不停的 malloc 和 free 内存我想效率也不会太高,这里索性搬出来我经常使用的一个 fifo 实现,配合 FreeRTOS 任务通知功能,也算是达到预期吧,哈哈哈,最终它们的实现如下:
 楼主| liuqiangdong 发表于 2022-3-31 20:38 | 显示全部楼层
  1. static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
  2. {
  3.         /* USER CODE BEGIN 6 */
  4.         extern TaskHandle_t xConsoleHandle;
  5.         uint32_t count = 0x00;
  6.         BaseType_t xHigherPriorityTaskWoken;
  7.                
  8.         USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
  9.         USBD_CDC_ReceivePacket(&hUsbDeviceFS);
  10.        
  11.         count = kfifo_put(&cdcRxFifo, Buf, *Len);
  12.        
  13.         if(        count != *Len)
  14.         {
  15.                 CDC_Transmit_FS((uint8_t*) "cdc rx buffer full!!!", strlen("cd rx buffer full!!!"));
  16.         }
  17.        
  18.         if(NULL != xConsoleHandle)
  19.         {
  20.                 vTaskNotifyGiveFromISR(xConsoleHandle, &xHigherPriorityTaskWoken);
  21.        
  22.                 if(xHigherPriorityTaskWoken)
  23.                 {
  24.                         taskYIELD();
  25.                 }
  26.         }
  27.        
  28.         return (USBD_OK);
  29.         /* USER CODE END 6 */
  30. }

  31. int xSerialGetChar(xComPortHandle xPort, signed char *cRxedChar, int timeout)
  32. {
  33.         static uint32_t i = 0x00;

  34.         xPort = xPort;

  35.         if(i == 0x00)
  36.         {
  37.                 ulTaskNotifyTake(pdTRUE, timeout);

  38.                 i = kfifo_len(&cdcRxFifo);
  39.         }

  40.         if(0x01 == kfifo_get(&cdcRxFifo, cRxedChar, 0x01))
  41.         {
  42.                 i--;
  43.         }

  44.         return pdPASS;
  45. }
您需要登录后才可以回帖 登录 | 注册

本版积分规则

5

主题

97

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部