stm32-USB使用记录(一)

1、USB设备介绍

USB,即为通用串行总线,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯。是应用在PC领域的接口技术。USB接口支持设备的即插即用和热插拔功能。USB是在1994年底由英特尔、康柏、IBM、Microsoft等多家公司联合提出的。

标准 USB 共四根线组成,除 VCC/GND 外,另外为 D+,D-;这两根数据线采用的是差分电压的方式进行数据传输的。在 USB 主机上, D-和 D+都是接了 15K 的电阻到低的,所以在没有设备接入的时候, D+、 D-均是低电平。而在 USB 设备中,如果是高速设备,则会在D+上接一个 1.5K 的电阻到 VCC,而如果是低速设备,则会在 D-上接一个 1.5K 的电阻到 VCC这样当设备接入主机的时候,主机就可以判断是否有设备接入,并能判断设备是高速设备还是低速设备。

正点原子精英板上采用的USB如下所示:
在这里插入图片描述
USB设备框图如下所示:
在这里插入图片描述
这里我们还是不讨论USB过多的原理性的东西,重点还是介绍怎么使用USB这个设备,就是他的驱动,一些相关资料我都传到我的gitee上了,需要的可以自行获取。

这里比较推荐看这个视频,USB讲的还是很不错的 https://www.bilibili.com/video/BV1F64y1U7d8?spm_id_from=333.337.header_right.fav_list.click

2、虚拟串口进行数据收发

1、在stm32F1上进行

首先是配置cubemx开启USB功能
在这里插入图片描述
下面我们要使用USB的功能需要配置这个中间件,说白了就是对应的库
在这里插入图片描述
下面我们来看下这个配置的一些参数,这一部分其实默认即可,不用怎么修改
在这里插入图片描述
继续看设备描述
在这里插入图片描述
这里我们看下插上电脑的设备,已经可以正常运转了,就是正常监测到我们我们刚才设置的端口了
在这里插入图片描述
这个时候我们就可以用虚拟串口收发函数来进行测试了
在这里插入图片描述
将程序下载到开发板,可以看到效果如下:
在这里插入图片描述
当然我们也可以用对他进行格式化包装,让他可以像prinf一样的工作,封装的代码如下所示:

void usb_printf(const char *format, ...)
{
    va_list args;
    uint32_t length;

    va_start(args, format);
    length = vsnprintf((char *)UserTxBufferFS, APP_TX_DATA_SIZE, (char *)format, args);
    va_end(args);
    CDC_Transmit_FS(UserTxBufferFS, length);
}

这样我们就可以在主函数中进行调用了!
在这里插入图片描述

2、在stm32F4上进行

这里如果也是按照就是原设定的步骤的话不太成功,会出现就是找不到设备的问题,采用的f4的板子上采用USB连接图如下:
在这里插入图片描述
这里后面还尝试了好几种方案,反正都是不太成功,如果有正好看到这篇文章的大佬清楚的话欢迎指正!

3、大容量设备

在前面的文章中,已经介绍过相关STM32内部flash的操作,还有读写外部挂在的flash,以及外部挂载的eeprom,以及使用SDIO还有SPI来读写SD卡,这里我们了解了USB,就可以用USB来作为接口,将这些内存设备通过USB接口和电脑等设备进行交互了,实现类似U盘的功能,相关的链接如下,需要的可以去下了解下:

stm32内部Flash读写
sd卡读写移植记录

这里我们再来看下他的这个USB功能描述:
在这里插入图片描述
可以看到USB设备支持的功能还是挺多的,这里就主要介绍这个大容量储存这块的设计,通过设计大容量储存的接口,就可以使得我们得以访问内部的flash以及一些外接的sd卡这样的!

访问内部flash

在前面的文章中已经讲过就是如何将STM32编译出的FLSH表达出来,上次用的是keil的方式,这里我继续采用CUBEIDE的方式介绍下吧!

  • 首先还是看下keil的,编译情况如下,那么它所占的的内存为14236+344=14580的大小,这个单位是字节,那么换算成我们熟悉的点来说就是:14580/1024=14.238KB
    在这里插入图片描述
  • 这里我们可以看下另一个cubeide的工程:
    在这里插入图片描述
    这里有个大佬讲过了这些字段的意思 https://blog.youkuaiyun.com/wxh0000mm/article/details/80364701

详细的解释

text代码和常量
data初始化的全局变量
bss未初始化的变量
dec就是前面三个的加和

这里占用的代码大小就是:
在这里插入图片描述
转化成我们熟悉的kb来说就是:
**加粗样式**
这里我用的是103RCT6,总的FLASH大小是:
在这里插入图片描述
这里再看下我们的FLASH占用情况,可以说是基本一致了,基于这些情况我们就可以开始来设计这个flash的内存设置了
在这里插入图片描述
我们这里内存占用是49kb的样子,因此这里我们就从60KB之后来算(这个只要大于49就都是合理的),具体计算如下所示:
在这里插入图片描述
将他转换成我们熟悉的KB值,因此这个就是60KB了
在这里插入图片描述
我们在新建的工程里来设置这个大小和起始地址:
在这里插入图片描述
之后在这里将我们刚才设置的加入进去
在这里插入图片描述
之后就可以添加读函数还有写函数了
在这里插入图片描述
这里我附上源码,需要参考的可以借鉴查看

int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
  /* USER CODE BEGIN 6 */
	if (lun == 0) {
		memcpy(buf, (uint8_t*) (FLASH_START_ADDR + blk_addr * FLASH_PAGE_SIZE),
				blk_len * FLASH_PAGE_SIZE);
		return USBD_OK;
	}
  return (USBD_OK);
  /* USER CODE END 6 */
}

/**
  * @brief  .
  * @param  lun: .
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
  /* USER CODE BEGIN 7 */
	if (lun == 0) {
		uint16_t i;
		HAL_FLASH_Unlock();

		FLASH_EraseInitTypeDef f;
		f.TypeErase = FLASH_TYPEERASE_PAGES;
		f.PageAddress = FLASH_START_ADDR + blk_addr * FLASH_PAGE_SIZE;
		f.NbPages = blk_len;
		uint32_t PageError = 0;
		HAL_FLASHEx_Erase(&f, &PageError);

		for (i = 0; i < blk_len * FLASH_PAGE_SIZE; i += 4)
			HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,
					FLASH_START_ADDR + blk_addr * FLASH_PAGE_SIZE + i,
					*(uint32_t*) (&buf[i]));

		HAL_FLASH_Lock();
		return USBD_OK;
	}
  return (USBD_OK);
  /* USER CODE END 7 */
}

这样我们就完成了读写了部分了,只要就是连接上对应的USB口就行了,一般开发板上都会设置的,我们只需要根据实际情况连接就行了
在这里插入图片描述

哦,居然失败了,就一直这样啊,后面查了原因才知道不对劲啊,前面的文章讲了就是小容量的芯片就是移动单位是一个字节,但是RCT6是大容量芯片,他是按照两个字节为基本单位的,所以这里就不行小于我们两个字节
在这里插入图片描述
这里选择大小为2048个比特,就是2kb了,这样我们修改好之后再次编译就可以了
在这里插入图片描述
哦对了就是这里也要注意就是我们这里的VID还有PID可以做一些适当的修改,不然电脑就会把他们认为是同一种USB设备,那就不太好了
这些东西的含义涉及到USB外设的一些理论知识,USB是一个庞大的系统,涉及的东西比较多,这里就不一一介绍了(我也不会),可以参考下面的这篇文章:https://www.cnblogs.com/airoot/p/10673090.html
在这里插入图片描述
这样我们就可以开始把设备插进电脑了,第一次的话会提示需要格式化,之后就可以看到我们的设备了
在这里插入图片描述
这里我们可以尝试将数据文本文件写入U盘,直接拖拽即可,可以看到成功写入
在这里插入图片描述
当然我们把U盘拔掉,在插入这个数据也是不会丢失的!

### 解决Content Security Policy (CSP) img-src 'self' data: base64 错误 当遇到 `img-src` CSP 指令违反策略的问题时,通常是由于网页尝试加载不符合指定来源的图像资源引起的。以下是可能的原因以及解决方案: #### 原因分析 1. **CSP 策略定义不足** 当前 CSP 中设置了 `img-src 'self'`,这意味着只有来自同源(即当前域名)的图片才能被加载。如果页面中有通过 `data:` 或者其他外部 URL 加载的图片,则会被阻止[^1]。 2. **Base64 图像嵌入问题** 使用 Base64 编码的内联图像是种常见的优化手段,但如果未显式允许 `data:` 协议,在 CSP 下这些图像将无法正常显示。 3. **动态生成的内容冲突** 动态注入 HTML 内容可能导致意外行为,尤其是当内容中包含不受信任的数据时,这可能会触发 CSP 警告或错误。 --- #### 解决方案 ##### 方法:扩展 `img-src` 定义范围 修改 `<meta>` 标签中的 CSP 策略以支持更多类型的图像来源。例如: ```html <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; img-src 'self' data:;"> ``` 上述配置表示除了允许同源的图片外,还允许基于 Base64 的编码图像加载。 ##### 方法二:调整服务器端响应头 如果 CSP 是由 HTTP 头部设置而非 `<meta>` 标签控制,则需更新 Web 服务器配置文件。对于 Nginx 和 Apache 分别有以下示例: - **Nginx** ```nginx add_header Content-Security-Policy "default-src 'self'; script-src 'self'; img-src 'self' data;"; ``` - **Apache** ```apache Header set Content-Security-Policy "default-src 'self'; script-src 'self'; img-src 'self' data;" ``` 以上更改确保浏览器能够识别并接受 Base64 数据作为合法的图像来源[^1]。 ##### 方法三:移除违规代码片段 检查前端代码是否存在非法调用第三方资源的情况。比如某些框架库自动插入了跨域请求或者使用了未经许可的协议加载媒体资产。清理掉不必要的部分有助于减少潜在风险。 ##### 方法四:启用报告机制捕获异常事件 为了更好地监控实际运行状况,建议开启 CSP Reports 功能收集反馈日志以便后续改进措施制定。 ```html <meta http-equiv="Content-Security-Policy" content="... report-uri /csp-report-endpoint"> ``` 此操作会把每次发生的违禁访问记录提交至指定 URI 地址供管理员审查处理。 --- ### 示例代码展示 下面给出段简单的 PHP 页面演示如何正确应用增强后的 CSP 设置防止类似问题再次发生。 ```php <?php header('Content-Security-Policy: default-src \'self\'; script-src \'self\'; img-src \'self\' data:'); ?> <!DOCTYPE html> <html lang="en"> <head> <title>CSP Example</title> </head> <body> <!-- 合法本地图片 --> <img src="/images/example.jpg"> <!-- 合法base64编码图片 --> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA..." alt="Embedded Image"> <h1>Secure Page Loaded Successfully!</h1> </body> </html> ``` ---
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

桃成蹊2.0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值