首先你要能调的通stm32cubemx生成的USB虚拟串口程序,具体的前置操作看下面的帖子
历经7天时间总算把USB虚拟串口CDC或者叫VCP完整调试结束,每天的调试过程和调试时候的想法都记录在下面,希望对本站用户调试usb或者其他外设有所帮助!
帖子里面的顺序可能不是正常的我发帖的顺序,因为只要有人点赞就会导致该楼层被置顶,所以,大家查阅的时候注意好每层楼的编号!!
同时希望大家也能将你调试外设的过程或者期间的想法分享出来,也许你的一个想法就能帮助好多人!
注意:
-----------------------------------------------------------
禁止转载!
一定要转载,请注明本站出处!!
-----------------------------------------------------------
下面的连接先别点的,听我说完
1.按照图示的stm32cubemx配置,先设置好硬件外设
[
]usb相关的参数都不要去改!任它默认就行![/][
]生成工程后,会提示是否要用keil打开,切记选择不打开,后面有地方要改[/][
]找到你刚才生成的工程文件夹,在文件夹上面点[i]选择[/i]
的钩钩去掉,应用到所有文件[/][
]现在可以去文件夹中找到工程打开了[/][
]打开后,首先别编译,直接打开找到图片中的文件,打开后,将Heap Size 改为1500[/]
好了,现在可以去看下面的连接里面的配置了,祝你好运!
http://www.stm32cube.com/question/26二楼继续!!!!
22 个回复
admin
赞同来自: 【福清】Paderboy 、春水长天
额,对了,一楼的程序直接编译后烧写进入片子.
插上usb口,会提示发现硬件,然后再电脑的****里面能看到
看到这里就说明你这个VCP成功了...现在就是缺个驱动安装了.
安装驱动要分32位电脑和64位电脑,他们的驱动不同,看看下面的连接进行选择
http://www.stm32cube.com/article/40
切记:下载的压缩包里面有一个实用文档,一步一步来一定会成功的!
成功之后就是下面的图片
!(http://www.stm32cube.com/uploads/article/20141216/dc54173806fb51163f0c9955762aa4b5.png)
admin
赞同来自: 【福清】Paderboy 、春水长天
上面的如果实现了,那么恭喜你,可以进行下步了!
这个帖子的目的是研究USB虚拟串口,所以帖子的相关程序不适用于实际使用!
===================================================
二楼的程序是根据前篇我转载的一个国外的VCP的帖子来的,声明不是原创!
实验目的:串口发送到片子数据,片子返回你发送的这些数据
打开工程文件中的usbd_cdc_if.c
这个文件英文名应该是interface,所以是VCP的接口函数定义文件,大部分函数设置都在这里进行
首先:定义一个结构体,存放接收到的数据相关参数
第一个是数据缓存,第二个是读写位置和长度,第三个是是否可读标志
在定义一个初始化标志,用来说明初始化完成
我们来初始化CDC,因为是接收在直接返回的,所以只需初始化接收部分
找到static int8_t CDC_Init_FS(void)这个函数,将里面修改为
以上是设置USB_CDC的接收缓存为s_RxBuffer.Buffer
初始化结束后,接下来对接收函数进行改造!
上面的意思是,接收到一帧数据就将s_RxBuffer这个数据相关的读写位置复位,长度记录,数据可读标志置位
以上,若发送数据下来,那么数据会存储到缓存buffer,并且提醒片子可读了
以下继续构造两个函数,供main中大循环调用
我先不解释了,先把所有需要改的都写完,然后统一解释吧
打开usbd_cdc_if.h文件
添加
打开main.c文件:
添加
大循环中写入
好了,所有要改造的都改好后,编译,烧写,打开串口
随便发数据,就能看到效果了.
图上是我按照10进制发送的34567这个数,它会告诉你你发送了哪些数据.
四楼继续解释!!!!
admin
赞同来自: 【福清】Paderboy 、春水长天
其实我觉得完全么有必要一个一个解释......
先说
然后再看看
再来看看while的吧
ok解释完了,
五楼继续研究,改造!!
admin
赞同来自: 春水长天
接上面的程序分析,根据分析来看,如果将上述代码中的发送改成一个数组,一次发送多个应该也是没有问题的,
于是,将
改为
使byte变量成为一个数组的首地址
这样若是想要发送多个数据,那么while中改为
以上代码意思是:
读取usb接收到的数据的前3个给数组byte,此时byte数组中的中就是usb接受到的数据的前三个数据了.
注意,此时若是发送的数据超过了3个,那么串口调试助手返回的数据只是前三个,后面的数据不会显示.
若此时下发的数据少于3个,那么串口调试助手不会被返回任何数据.
admin
赞同来自: 春水长天
以上的VCP程序,函数vcp_write没有任何问题,因为发送的时候是可以知道发送字节的长度的
但是,接收数据方面用
而CDC_DATA_FS_OUT_PACKET_SIZE=64
这样就限制了我们每次接收的数据和发送的数据必须小于64字节
这是其一,
其二,假如我们数据处理的速度跟不上接收的速度,那么数据就会错乱...
于是考虑到利用环形缓存来试试
环形队列的话,usb端口接收的数组不变,每次接收完数据立即取出到外部环形队列中,主程序就根据通信协议特征码进行数据的读取和相应的操作
例如:前面我们用到串口屏的通信程序既是如此!不过那个时候用的是硬件串口,而现在用的事usb虚拟串口
于是,我们先移植串口屏的那个程序出来
7楼继续!
admin
赞同来自: 【福清】Paderboy 、春水长天
串口屏的那个程序先不移植的...先弄个环形缓冲实验下
为了使用方便去移植了RTos里面的一个环形缓冲代码如下:
新建文件 ringbuffer.c
新建文件 ringbuffer.h
将新建的那个c文件添加到工程中.
打开文件 usbd_cdc_if.c
添加包含文件代码
修改CDC_Receive_FS函数代码
其他的内容如楼上所写,不用更改
此时来修改main.c文件
添加包含文件
添加全局变量供调用
在usb初始化之后添加环形缓存的初始化函数
修改while内容如下:
上面的意思,其实和5楼说的功能是一样的,不过这里利用了环形缓存而已
现象就是,串口调试助手打入什么,usb就返回什么
此时如果用debug调试查看数据,可以看到头尾的变化
注意:
此代码按照上面写的时候,串口调试助手可一次写入小于256个数据,然后数据依次缓慢读出到助手
如果usb正在向串口调试助手输出数据期间,用串口助手下发数据,那么usb调试助手就会死机
所以以上程序还需改进
请看8楼!!
admin
赞同来自: 春水长天
其实从上面的代码里面的注释就可以看出问题所在.
VCP_write()函数中死等造成的冲突
于是我们删除这个函数,直接利用Hal库提供的函数来发送
于是,我们注释掉usbd_cdc_if.c文件中的函数定义
VCP_write和VCP_read,并删除main.c文件中的此函数
于是改为:
调试查看助手的输出,此时,如果usb正在输出,同时下发数据,不会导致串口助手死机,而且上发的数据完全按照我们输入的数据先后输出,即FIFO
通过以上实验,已经初步完成环形缓存的写入,那么写入缓存后,应该怎么使用呢?
通常的做法是定义好数据的协议,通过协议来判断功能
方法一,定义一个定长的数据列,例如20个字节的数据列
如果下发数据长度不足20个字节,自动填充至20字节,然后下发
这样的好处就是:数据处理更加简单,不需要去判断一帧数据的长度,每次使用的时候,只需20个字节取一次,然后按照协议分解数据,判断功能,但是缺点也是明显,当程序既定的时候,缓存大小为固定值, 然而每次需下发的有效数据并不一定需要20字节长度,有时5个字节足够了,那么剩下的15个字节空间就浪费了,这个就是所谓的以空间换时间!
方法二,定义一个协议的头和尾,来判断是否是一帧完整数据
如上面提到的串口屏协议既是如此
它定义了数据 0xEE为数据的头,定义0xFF 0xFC 0xFF 0xFF四个字节为数据尾,当中的数据为有效数据位
这样的好处是,数据协议长度可变,能够稍微充分的利用空间,缺点也很明显,头和尾已经占用了5个字节位置,
每次数据下发每个有效数据前后需添加他们,这样如果是短数据传输,那么显然浪费了很多通信时间
比较两种方式,第一种,假如数据传输过程中丢失了一个数据,那么导致的后果很严重!
因为每次系统启动后从第0个数据开始每次取20个作为一个有效数据,那么丢失其中任何一个字节数据,会导致后面所有的数据错乱!
所以这种方式最不可取!!!
当然,usb虚拟串口是利用 帧数据传输,按道理上时不会丢失里面的一个字节的,丢失的话也是整个数据包丢失,哈
那么第二种方式的优点就体现出来了,即使数据中的某个字节丢失了,那么在程序中我们可以判断,去除这个错误的数据
具体的程序参考9楼
admin
赞同来自: 春水长天 、lion187
先来说说楼上说的第一种方式.
这个就比较简单了,主要问题再你每次下发数据的时候记得不能超过定义的协议长度例如20字节.
当下发数据不足20字节,自己需补全20字节,保证下发的数据每帧都是20字节即可.
单片机处理的时候,每次用
这句来一次读出20字节然后进行分解,得到你想要的协议操作,再去执行相应操作即可.
admin
赞同来自: 【福清】Paderboy 、春水长天 、小七
大彩的串口屏分两部分,
一部分是串口接收入栈部分,一部分是出栈部分
入栈部分我们用上面提到的
函数即可.
出栈部分就不能在使用
函数了,需要对出栈函数进行简单的修改.
在 ringbuffer.c文件中添加一个新的函数:
定义其内容如下:
以上程序,如果缓冲区有完整协议那么就返回一个协议字节长度,否则返回0
这样我们需要在大循环中判断是否获取到了一帧协议来确定是否对协议进行解析.
注意在ringbuffer.h文件中添加这个函数的外部引用
然后,去修改main.c里面的大循环while();
我们修改原来的main()函数中初始化之后变量的定义如下:
修改了byte的长度,和定义了一个size来存放取得的协议的长度
之后修改while如下:
意思是:大循环中连续查询是否有协议存在,如果有那么size会有一个协议长度值,我们根据长度值来返回这个取得的协议给串口调试助手!
下面这幅图片显示的是测试以上协议的结果,
协议的格式是
如果没有按照这样的协议发送数据那么该帧数据不会被返回,
admin
赞同来自: 【福清】Paderboy 、春水长天
1.测试27个协议数据在10ms连续发送,长时间发送接收无错.
]测试协议数据大于64字节发现不能返回数据,减少一个字节后,可以正常接收和返回数据.[/[
]
究其原因归结为usb端点的最大字节64的问题,但是为毛64字节不行呢,非要63字节??? 有知道的吗?ok,usb的cdc测试结束!
下图是63字节以10ms发送的结果,发送和接收字节数相同,此时的速率应该是100*63=6300波特率
还没有达到最低的9600,有谁的串口调试助手速度更快的可以测试下!
希望测试的人能给个回复,看看这样做的最大不丢帧速度是多少,谢谢
lion187 - 好吧!80后IT男
NESTS
NESTS
conquerusb
让疾风丶吹呀吹
ZJZTO - 各种打酱油
上图中的byte ,是 byte[1],or ....?
这个问题主要是为了下面的情况发送长度为1时,返回值都是第一个字节,当然发送长度匹配后返回值就对了。请问示例的实际效果是不是也像下图这样的?
这个是设置了byte[6]发送刚好6字节。
ZJZTO - 各种打酱油
uint8_t rb_get_cmd(struct rb *rb, uint8_t *ptr)
函数有问题吧,
ptr = *buff;
ptr是不是没啥用咧
ZJZTO - 各种打酱油
不知道是不是数组\指针定义有问题
buff 里面的数据一直不变,楼主吞代码的编辑器太坑,有没有打包的原函数参考?
赵振林 - 90后,,,
电脑端的驱动想找个最新的,能支持win8的,官方网站找了半天没找到,能买帮忙提供一个官方下载地址吗?
蒋符之
有哪位同仁尝试过应用UBS虚拟串口实际应用控制中吗?类似USART控制指令对灯的点亮等
匿名用户
你好高手,请教你个问题,我用STM32做了个USB 4串口的程序,在WINDOS XP下可以正常使用,到了WIN7,或WIN10都不能使用,WIN10无法正常驱动,而WIN7 一插入USB就立刻蓝屏,根本没法找问题的机会,电脑都死了,请问什么问题??期待回复,谢谢!
星期五
你好,我想请教一个问题。上位机串口助手对串口参数的设置,是如何在单片机的串口端实现的?例如上位机修改了波特率为9600,那么单片机是如何获得波特率变动并重新初始化串口。