简单来说,如果你通过检索从而看到这篇文章,那就假设你已经知道Pixy2是用来干什么的(一款功能强大的开源视觉传感器),以及你已拥有一些STM32基础。你可以通过访问官方手册来获得更多关于Pixy2的相关信息。
如果你已经非常了解Pixy2的运作模式,只是想快速与STM32建立通信,那么你可以直接参考我的代码:
链接: https://pan.baidu.com/s/1AaIs...
提取码:11qb
通常情况下Pixy2是搭配Arduino使用的,并且Pixy2能通过SPI以2 Mbits/秒的速度向Arduino发送信息。不过如果让Pixy2与不同的平台进行通信,首先就要确定以哪种方式进行通信。官方给出Pixy2支持的通信方式有SPI、I2C、UART、USB和Analog/digital,并且通信速度USB>SPI>I2C>UART>A/D。本文将具体描述Pixy2与STM32的SPI通信。
设置与连接
首先,你需要去官网下载一个叫PixyMon的软件,它能让你在Windows或Mac平台对Pixy2进行设置。
将你的Pixy2与电脑用USB线连接后,打开软件,在Configure-Interface-Data out port选项中,我们选择Arduino ICSP SPI。是的,即使是与Arduino通信的SPI选项,也可以应用到STM32上,其他选项不用更改。
设置好后,我们把Pixy2与电脑连接的USB断开,用杜邦线将Pixy2与STM32连接,我这里用的STM32是正点原子的STM32mini开发板。在连接之前,我们先看一下Pixy2的管脚图:
在Arduino ICSP SPI模式中主要用到(1)(3)(4)三个管脚,还有5V和GND与STM32的5V和GND直接相连就行了,两者具体的连接方法如下:
-
Pin 1
(SPI MISO) ➜PA6
(STM32 SPI MISO signal) -
Pin 4
(SPI MOSI) ➜PA7
(STM32 SPI MOSI signal) -
Pin 3
(SPI SCK) ➜PA5
(STM32 SPI SCK signal) -
Pin 2
➜5V
(STM32 5V) -
Pin 6
➜GND
(STM32 GND)
串口协议
Pixy2是以数据包的形式来和上位机进行通信的,也就是说,想要和Pixy2通信,你必须向Pixy2发送一个请求数据包,然后Pixy2再把你想要得到的数据或者状态用数据包发给你。所以你的请求/反馈数据包就像下面的格式:
Requests-(你发给pixy的)
字节 | 说明 | 数值 |
---|---|---|
0-1 | 16-bit sync | 174, 193 (0xc1ae) |
2 | Type of packet | (varies) |
3 | Length of payload in bytes (len) | (varies) |
4-len | Variable length payload | (varies) |
Responses-(pixy发给你的)
字节 | 说明 | 数值 |
---|---|---|
0-1 | 16-bit sync | 175, 193 (0xc1af) |
2 | Type of packet | (varies) |
3 | Length of payload in bytes (len) | (varies) |
4-5 | 16-bit checksum | sum of payload bytes |
6-len | Variable length payload | (varies) |
就拿请求数据包来说,上位机向Pixy2发送长度为 len
字节的数据包,其中0-1字节是同步码,同步码又分为:
- 带校验位的同步码
0xc1af
- 不带校验位的同步码
0xc1ae
所以你的请求数据包里的0-1字节一般是固定的,然后剩下的字节根据你想要Pixy2反馈的功能来改变。至于每种功能的详细格式,官网的手册已经详细列出了,你细品。
Pixy2收到上位机发送的数据包后,会根据要求返送一个包含着数据的包,也是以同步码打头,后面跟着就是你想要的数据了,不同的请求数据包有不同的反馈数据包,至于Pixy2发出的同步码有什么用,我们会在实例中具体讲述。你可以用UART串口把这些数据打印在电脑屏幕上,这会更好的帮助你了解Pixy2的通信原理。
实例1
现在,就以STM32用SPI通信向Pixy2发送一个请求版本的数据包,来获取Pixy2版本,并将Pixy2返回的数据打印在屏幕上的一个实例。
根据官网的说明:
getVersion()
Request:
字节 | 说明 | 数值 |
---|---|---|
0-1 | 16-bit sync | 174, 193 (0xc1ae) |
2 | Type of packet | 14 |
3 | Length of payload | 0 |
就是说,你想获取Pixy2的版本,你要发送4个字节的数据包给Pixy查询,前两个字节是同步码,第三个是14
,第四个是0
,我们来看看,怎么样用Keil来写这个发送数据包的程序。
#define PIXY_CHECKSUM_SYNC 0xc1af //带校验位的同步码
#define PIXY_NO_CHECKSUM_SYNC 0xc1ae //不带校验位的同步码
#define GETVERSION_LENSEND 4 //发送数据包长度
#define GETVERSION_LENRECEIVED 22 //接收数据包长度,先假设是22个字节
uint8_t i, header_buf[16]; //header_buf用来存放发送的数据
uint8_t recvBuf[32]; //recvBuf用来存放接收到的数据
void Pixy2_SendRecvPacket_getVersion(uint8_t* received)
{
header_buf[0] = PIXY_NO_CHECKSUM_SYNC&0xff; //把同步码拆开
header_buf[1] = PIXY_NO_CHECKSUM_SYNC>>8;
header_buf[2] = 0x0e; //14
header_buf[3] = 0x00; //0
for (i=0;i
跟着注释,是不是也不难看懂?虽然这些程序并不完整,但它能够完整的表达与Pixy2通信的整个过程。按下开发板上WK_UP按键后,发送并接收数据包,然后用串口显示接收到的字节,我们打开串口调试助手来康康:
仔细看,接收到的字节,第一个是0x6c
,第二个是0
,讲道理不应该是0xaf
和0xc1
吗?因为Pixy2发送的数据包,一定会以同步码打头,那现在接收到的这两个是啥东西?我也不知道,但我知道这两个数据肯定不是我们想要的。可以看到字节7,8,9分别是0xaf
,0xaf
,0xc1
。有两个0xaf
,而且好像字节8,9是我们想要的同步码,那是不是可以写一个语句来判断字节7如果是0xaf
,那么接下来所有的数据都是我们想要的,所以只用将字节7之后的字节放入recvBuf[]
就行了呢?看如下的程序:
uint8_t PIXY_GET_FLAG_AF=0XAF;//af标志字节
void Pixy2_SendRecvPacket_getVersion(uint8_t* received)
{
header_buf[0] = PIXY_NO_CHECKSUM_SYNC&0xff;
header_buf[1] = PIXY_NO_CHECKSUM_SYNC>>8;
header_buf[2] = 0x0e;
header_buf[3] = 0x00;
for (i=0;i
对之前的程序进行修改,加入了一行关键语句,我们再来看看串口调试助手的输出:
好像有点像我们希望看到的数据了,其实在官网上有一段说明,就是通过向Pixy2发送获取版本(getVersion())数据包,你会得到的字节,如下图:
对比看下我们获得的字节,发现我们的数据是正确的(虽然根据版本不同,数据可能不同),程序也是可行的。
其实Pixy2是一款非常好玩的视觉传感器,它能应用到许多场合,在它的官网手册中列出了所有的功能数据包格式,获取版本就是其中之一,每种功能包的格式以请求数据包格式和其对应的反馈数据包格式给出,你可以根据手册中的请求数据包格式来写程序,然后对比手册中的反馈数据包格式和你真正接收到的数据,看看自己的程序是否有效。下面列出了一些我写的,认为比较重要的一些请求数据包程序库,你可以根据我的格式来写其他你需要的功能程序库,当然你也可以用更优化的方法来自己写。
pixy2.c
#include "delay.h"
#include "sys.h"
#include "spi.h"
#include "pixy2.h"
uint8_t i, header_buf[16], PIXY_GET_FLAG_AF=0XAF;
//getVersion()获取版本
void Pixy2_SendRecvPacket_getVersion(uint8_t* received)
{
header_buf[0] = PIXY_NO_CHECKSUM_SYNC&0xff;
header_buf[1] = PIXY_NO_CHECKSUM_SYNC>>8;
header_buf[2] = 0x0e;
header_buf[3] = 0x00;
for (i=0;i>8;
header_buf[2] = 0x20;
header_buf[3] = 0x02;
header_buf[4] = sigmap;
header_buf[5] = numBlocks;
for (i=0;i>8;
header_buf[2] = 0x10;
header_buf[3] = 0x01;
header_buf[4] = brightness;
for (i=0;i>8;
header_buf[2] = 0x16;
header_buf[3] = 0x02;
header_buf[4] = upper;
header_buf[5] = lower;
for (i=0;i
pixy2.h
#ifndef __PIXY2_H
#define __PIXY2_H
#include "sys.h"
#define PIXY_DEFAULT_ARGVAL 0x80000000
#define PIXY_BUFFERSIZE 0x104
#define PIXY_CHECKSUM_SYNC 0xc1af
#define PIXY_NO_CHECKSUM_SYNC 0xc1ae
#define PIXY_SEND_HEADER_SIZE 4
#define PIXY_MAX_PROGNAME 33
#define GETVERSION_LENSEND 4
#define GETVERSION_LENRECEIVED 22
#define GETBLOCKS_LENSEND 6
#define GETBLOCKS_LENRECEIVED 20
#define setBrightness_LENSEND 5
#define setBrightness_LENRECEIVED 10
#define setLamp_LENSEND 6
#define setLamp_LENRECEIVED 10
void Pixy2_SendRecvPacket_getVersion(uint8_t* received);
void Pixy2_SendRecvPacket_getBlocks(uint8_t* received, uint8_t sigmap, uint8_t numBlocks);
void Pixy2_SendRecvPacket_setCameraBrightness(uint8_t* received, uint8_t brightness);
void Pixy2_SendRecvPacket_setLamp(uint8_t* received, uint8_t upper, uint8_t lower);
#endif
当然,你们可以下载整个project来参考:
链接: https://pan.baidu.com/s/1AaIs...
提取码:11qb
传送门:
Pixy2 Index:https://docs.pixycam.com/wiki/doku.php?id=wiki:v2:start
How to talk to Pixy2:https://docs.pixycam.com/wiki/doku.php?id=wiki:v2:porting_guide
Pixy2 Downloads:https://pixycam.com/downloads-pixy2/
欢迎大家讨论与指正~!
以上。