STM32-CubeMX USB学习
STM32-CubeMX USB学习
1. 虚拟com学习
1.1 开发环境
- 软件环境:
STM32CubeMX
版本:SetupSTM32CubeMX-6.0.1.exe
Firmware:STM32Cube FM_F1 V1.8.0
keil 5 V5.29—支持并行编译,可以加速编译效率(最新的版本就可以)
keil的固件包版本:
Keil.STM32F1xx_DFP.2.0.0.pack
keil相关资料的下载
https://www.cnblogs.com/armfly/p/12564643.html
java版本–有遇到过java版本太新导致出问题的
jre-8u201-windows-x64.exe
以下版本亲测有问题,请勿使用
jdk-14.0.2_windows-x64_bin.exe
版本的差异会导致各种报错,切记核对相关版本.
路径中不能出现中文空格,出现会报错.
版本问题导致的报错之一
Error: L6218E: Undefined symbol USB_FlushRxFifo (referred from stm32f1xx_hal_pcd.o).
- 硬件环境
Stm32F103c8t6–淘宝上最便宜的开发板
1.2 使用STM32CubeMX配置代码
-
选择芯片型号,我这边是C8t6
-
debug选择 SW模式
-
配置外部时钟输入
-
配置USB device的功能
-
将USB的模式配置成COM口的功能
-
时钟树配置,如果前面没有配置外部晶振输入,这边无法配置成功。正常的话自动会配置成功
-
工程配置,配置成对应keil的版本
框出来的位置有时候因为尺寸太小会出错,有人说默认的也可以,反正我改了,如下图
- 第一栏里面选择第一个和第二个都一样的,有问题的话可以换了试一下
第二栏里勾选将文件分为.c和.h
- 生成工程文件
1.3 串口自发自收
- 实现串口输出ABCD,需要更改的部分
//1.添加头文件
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usb_device.h"
#include "gpio.h"
#include "usbd_cdc_if.h"
更改main函数
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void USB_Disconnected(void) {
__HAL_RCC_USB_FORCE_RESET();
HAL_Delay(200);
__HAL_RCC_USB_RELEASE_RESET();
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_Initure.Pin = GPIO_PIN_11 | GPIO_PIN_12;
GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_Initure.Pull = GPIO_PULLDOWN;
GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_Initure);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_RESET);
HAL_Delay(300);
}
/* USER CODE END 0 */
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
//USB 卸载操作,取消按复位键后无法识别的问题
USB_Disconnected();
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USB_DEVICE_Init();
/* USER CODE BEGIN 2 */
//2.添加数组
unsigned char buff[10] = {"abcd\n\r"};
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
//3. 在while循环中添加如下代码
HAL_Delay(1000);
CDC_Transmit_FS(buff,sizeof(buff)); //USB 串口发送数据
}
/* USER CODE END 3 */
}
串口助手
- 读取输入的值和上一次是否相同,从而输出不同的值
首先需要将main函数恢复成初始的状态
更改下面的函数
CDC_Receive_FS();这个函数在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 a=0,a1=1;
unsigned char buff1[4] = {"abcd"};
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
a = *Buf;
if(a == a1)
CDC_Transmit_FS(Buf,*Len);//自收自发
else
{
CDC_Transmit_FS(buff1,sizeof(buff1));
a1 = a;
}
/* USER CODE BEGIN 6 */
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
//CDC_Transmit_FS(Buf,*Len);//自收自发
return (USBD_OK);
/* USER CODE END 6 */
}
会对比此次的和上一次的差异,如果一样则输出 接收到的值,如果不一样则输出abcd
PS:有一个BUG,数字大了后识别会出错,只能识别发送的第一个数据的差异
1.4 串口定向printf
参考文档:
文件的配置教程
https://www.jianshu.com/p/579783d28044
1.驱动下载链接
https://www.st.com/content/st_com/en/products/development-tools/software-development-tools/stm32-software-development-tools/stm32-utilities/stsw-stm32102.html
2. 代码操作
https://blog.csdn.net/u010779035/article/details/104369515
假装的Print—使用sprintf 这个函数将数据处理到串口发送的数组中,串口通过设置中断或者定时发送,进行数据的发送,但需要占用比较大的数据资源。实时性不确定。
1.5 串口接收的数据存到数组中
如下代码需要在main函数中进行更改
定义初始化函数
/* USER CODE BEGIN PTD */
uint8_t uart_number[64]="nihao\n\r";
/* USER CODE END PTD */
如下使用串口发送函数,将数组 uart_number 发送出去
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
CDC_Transmit_FS(uart_number,sizeof(uart_number)); //USB 串口发送数据
HAL_Delay(1000);
}
/* USER CODE END 3 */
CDC_Receive_FS();这个函数在usbd_cdc_if.c的文件下面的位置
extern uint8_t uart_number[64];
uint8_t* aa;
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
uint32_t i;
/* USER CODE BEGIN 6 */
//会对比此次的和上一次的差异,如果一样则输出 接收到的值,如果不一样则输出abcd
//最多11个汉字 64个16进制数
memset(uart_number, 0, sizeof uart_number); //清除数组uart_number
//循环函数,将接收到的数字,存到数组中
aa = Buf;
for(i = 0;i < *Len;i++)
{
uart_number[i] = *aa;
aa++;
}
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
return (USBD_OK);
/* USER CODE END 6 */
}
另外PS一个bug:
可能由于数组的问题,在接收数据太大后会出现溢出?//最多11个汉字 64个16进制数
能够满足基本的使用,但是不推荐太长的数据,或者控制单次发送的数据长度,分多次发送。
解决BUG:关于在按下reset之后,串口可以识别,但是无法打开的问题
在USB初始化前强制USB时钟复位
void USB_Disconnected(void) {
__HAL_RCC_USB_FORCE_RESET();
HAL_Delay(200);
__HAL_RCC_USB_RELEASE_RESET();
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_Initure.Pin = GPIO_PIN_11 | GPIO_PIN_12;
GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_Initure.Pull = GPIO_PULLDOWN;
GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_Initure);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_RESET);
HAL_Delay(300);
}
再USB初始化之前,执行一下这些就行了,相当于告诉电脑断开链。这样按下复位键后会自动断开连接,软件上重新选择com口和重新打开旧可以正常识别。
PS:这样的方式就使得USB虚拟的串口,会有一段空白的阶段,使得其无法输出初始化状态下的串口信息。有着一丝的鸡肋?
上面的程序放在如下的main.c 文件中
/* USER CODE BEGIN SysInit */
//注销USB
USB_Disconnected();
/* USER CODE END SysInit */
总结:
待完善STM32的其他功能,HID,Audio等功能