通信搬运工(开源)

目录

 


1. stm32与openmv通信

2. stm32与stm32通信

2.1 stm32 USART通信

2.1.1 stm32蓝牙与串口上位机

2.1.2 stm32与匿名上位机

2.2 stm32 SPI通信

2.2.1 stm32 2.4G

 

通过百度网盘分享的文件:开源文件.zip
链接:https://pan.baidu.com/s/1emgW2Q42Jg8jGXW6uKtZKA?pwd=1111 
提取码:1111

 

前言

哈喽,各位小伙伴们大家好。我们在学习单片机或者其他外设的时候,我们都希望可以查看他们的状态或者与电脑取得联系,来帮助我们更加的了解他们。其实在很多网站上面都有很多学习资料了,我也是这样学习过来的,哈哈。其实我也是一枚忠实的搬运工,下面我给大家总结和开源了我自己用过的一些通信方法与经验,大家可以挑自己喜欢的部分看哦,如果可以帮助到大家,那就收藏起来用吧,有时间可以看看。如果我讲的不对,还希望大佬们指导指导,谢谢啦。

百度网盘链接:

 

 

1. stm32与 openmv通信

 stm32与通过串口与openmv进行通信,串口通信还是很容易上手的,只要我们把主要的一些参数设置规定好,像波特率、停止位啥的,引脚也连接正确就可以通信了。

(树莓派跟openmv串口通信方法都是差不多的)

openmv的实物引脚图:

a859b97deb8a4127b30ec7dcf9198929.jpeg

接线(交叉相接):

openmv P4(TX)--stm32(RX)

openmv P5(RX)--stm32(TX)

 

openmv端

其实openmv端串口的使用就是直接调用他自带的库函数就行了,非常方便。不过就是发送的数据格式可能不是自己想要的。比如我做了一个自动捡球小车的系统,我想实时发送小球的坐标,但是直接调用库函数只能发送字节序列或者发送字符串,不可以直接发送int型数据。那咋办呢,那这时候我们就可能想到可以把int型数据转换成字节序列和字符型数据就可以发送了,没错我也是这样做的。下面我介绍一下我的两种写法,我也会在百度链接里面标明,供大家参考。

1. 转字符型再发送

步骤:

1.打开对应串口外设并配置对应参数

uart=UART(3,115200)     #初始化串口3

#uart.init(9600,bits=8,parity=None,stop=1)  #配置串口3,波特率115200,数据位8,无校验位,停止位1位

当然对应的库也要导入

from machine import UART
from pyb import UART
import pyb

2.接下来把要发送的int型数据转换为字符型数据(我这里准备把x,y点的坐标都设置为三位数),并发送:

 

                if 9<c.x()<100:
                    my_x='0'+str(c.x())

                if 0<c.x()<10:
                    my_x='00'+str(c.x())

                if 99<c.x():
                    my_x=str(c.x())

                if 9<c.y()<100:
                    my_y='0'+str(c.y())

                if 0<c.y()<10:
                    my_y='00'+str(c.y())

                if 99<c.y():
                    my_y=str(c.y())

               temp=my_x+my_y#拼接成字符串发送
                #可以加入自己的帧头帧尾,我这里没加
                temp=int(temp)
                print(temp)
                uart.write("@%d \r\n" % temp)#发送

 

2. 转字节序列后再发送

步骤:

1.跟“转字符型再发送”步骤1一样。

2.接下来把要发送的int型数据转换为字节序列数据(因为x,y坐标在这最大值为3位,所以我把转换后的字节序列设置为8位的。如果你们需要传递的int数据超过8位的,你们只要改变转换格式就行了。8位是B,16位的是H,32位是I。

我举个例子以便大家理解(32位的):
import struct

# 假设我要传输一个整数变量
int_value = 12345

# 使用struct.pack将整数转换为字节序列
byte_array = struct.pack('<I', int_value ) #改这个I就行了

#byte_array的打印结构为b'\x39\x03\x00\x00'

开始我们的传输代码:


# 使用struct.pack将整数转换为字节序列
byte_array1 = struct.pack('<B', c.x() ) 
byte_array2 = struct.pack('<B', c.y() ) 


UART_TXDATA=bytearray([0XFF,byte_array1,byte_array2,0XFE])
#自己设置帧头帧尾,加校验位,数据位都是没问题的,我这里帧头是0XFF,帧尾是0XFE。
#自己的数据帧需要stm32端有对应的解码就行

uart.write(UART_TXDATA)

2. stm32与stm32通信

2.1 stm32  USART通信

stm32之间串口通信就不多说了,还是很容易上手的。我们直接将步骤和上代码部分吧(代码部分我就用接收openmv的代码):

注意点:

波特率两端参数设置一致,连线要RX、TX交叉相连就行。

引脚图:

97e6bb72725443f49e4a5acb8cdfe613.png

接线(交叉相接):

openmv P4(TX)--stm32 PA10(RX)

openmv P5(RX)--stm32 PA9(TX)

代码部分:

//配置部分我删除了,不然会有点多


uint8_t Serial_TxPacket[2];				//FF 01 02 FE
uint8_t Serial_RxPacket[2];
uint8_t Serial_RxFlag;


void Serial_SendPacket(void)
{
	Serial_SendByte(0xFF);
	Serial_SendArray(Serial_TxPacket, 2);
	Serial_SendByte(0xFE);
}


//接收字节序列部分
void USART1_IRQHandler(void)
{
	static uint8_t RxState = 0;
	static uint8_t pRxPacket = 0;
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		uint8_t RxData = USART_ReceiveData(USART1);
		
		if (RxState == 0)
		{
			if (RxData == 0xFF)
			{
				RxState = 1;
				pRxPacket = 0;
			}
		}
		else if (RxState == 1)
		{
			Serial_RxPacket[pRxPacket] = RxData;
			pRxPacket ++;
			if (pRxPacket >= 2)
			{
				RxState = 2;
			}
		}
		else if (RxState == 2)
		{
			if (RxData == 0xFE)
			{
				RxState = 0;
				Serial_RxFlag = 1;
			}
		}
		
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}
}

下面是解码部分:

// 解码就是把字节序列转换成一开始我们的坐标原始数据int型


uint8_t x_data,x_data;
x_data = (int)Serial_RxPacket[0];
y_data = (int)Serial_RxPacket[1];


/*
//假如解码16位字节序列
uint8_t x_data,x_data;
x_data = ((int)Serial_RxPacket[1] << 8)  |
                (int)Serial_RxPacket[0];
y_data = ((int)Serial_RxPacket[3] << 8)  |
                (int)Serial_RxPacket[2];


//32位就再移,依次类推
*/

 

外加 stm32int转字节序列代码:

//这个是我问AI的,有兴趣可以看看

// 假设你有以下数据
int data = 123456; // 你想要发送的int数据

// 准备一个字节缓冲区
uint8_t dataBytes[4]; // 假设int为32位

// 将int数据转换为字节序列
memcpy(dataBytes, &data, 4); // 假设字节对齐正确

// 如果需要处理字节顺序,可以调整这里
// 例如,对于大端模式,可能需要反转字节顺序

// 发送数据
HAL_UART_Transmit(&huart1, dataBytes, 4, HAL_MAX_DELAY);

 

2.1.1 stm32蓝牙与串口上位机通信

他们都是通过串口传输数据的,那他们具体是什么一个工作流程呢?疑惑?

d154b2572287435389376ba5397a9240.jpeg

 

有没有小伙伴跟我一样,刚开始接触蓝牙的时候,疑惑过他们是怎么传输数据的呢?没事奥,现在带大家以我的视角重新浅浅认识一下,哈哈。其实我们只需要把他们两个模块当作是一条断开的线,当我使用魔法给他接上时,他就是一条电线。

c504fcd9ce7047a198202dba1729b112.jpeg

(当然奥,这个是我叠起来的效果,不是真的可以接上奥,哈哈)

接线部分:

蓝牙   USB转TTL

VCC- 5V

GND-GND

RX-TX

TX-RX

下面开始展示我的魔法,哈哈。不好意思奥,我是戏精。

在此之前我先给大家分享文字上的教程(也是我自己的笔记,我的字太丑了就不拍照了,我给你们打出来吧):

(在让他们相连之前需要下载一个串口助手,我用的是,其他的串口助手也是可以的)

2be5c2353cd945faad55c5aac930a055.png

 

给蓝牙模块进行AT指令我们需要,按住模块上的按键不动,然后把USB_TTL模块插入电脑。此过程不松手,当蓝牙指示灯开始慢闪,大约2秒闪1次,就可以松手了。俩个蓝牙模块都这样上电。

4d184e8e55944f8d8d920d72e7b31104.jpeg

有指令在旁边的,也可以自己更改再发送

1f7c38f4c8a649f082cac77dfab68457.jpeg

随便选一个蓝牙作为从机(从机部分):

1.AT 进入指令模式(返回OK表示进入AT指令成功)

2.AT+ORGL 先恢复出厂设置,并拔出来,再重新上电

3.AT 再次进入指令模式

4.AT+NAME 修改蓝牙名称      //修改格式为AT+NAME="名称"

5.AT+PSWD修改蓝牙配对密码        //“AT+ROLE="密码"(主从的密码要一致)

6.AT+CMODE=0 设置从模式

7.AT+ADDR ?获取蓝牙地址并记下

 

另外一个蓝牙作为主机(从机部分):

1.AT 进入指令模式(返回OK表示进入AT指令成功)

2.AT+ORGL 先恢复出厂设置,并拔出来,再重新上电

3.AT 再次进入指令模式

4.AT+NAME 修改蓝牙名称      //修改格式为AT+NAME="名称"

5.AT+PSWD修改蓝牙配对密码        //“AT+ROLE="密码"(主从的密码要一致)

6.AT+CMODE=1 设置主模式

7.AT+CMODE=0 设置为指定蓝牙地址连接模式。

8.AT+BIND=xxx,xxx,xxx  绑定蓝牙地址,中间用逗号隔开。

 

 

 

2.1.2 stm32与匿名上位机

 

学会了蓝牙,我们现在用蓝牙把姿态信息传到匿名上位机上面进行显示。我就用官网的资料给大家展示吧。

其实我们要想把自己小车或者飞控的姿态信息,在匿名上面进行展示的话,只需要按照匿名给的通信协议来写,然后把他发送到上位机,他就会自己姿态跟随了。(还是非常方便的)

ab06ace51aaf43578ddea5956709b01f.png

这个是V7版的通信协议。

要想完成姿态跟随我们只需要按照官网的要求写对应的数据包就可以了。下面我们就以传输欧拉角格式数据帧讲解。

协议已经给出了明确的,

帧头:0XAA

目标地址: 0XFF

功能码:0X03

数据长度:0X07

数据内容: 一共有7位,2位ROL,2位PIT,2位YAW,1位姿态融合姿态

要求姿态角度精确到0.01(*100),两位。

数据内容的格式如下图:

6a7952c0567c4e7da29b2abe60c5772b.jpeg

 

 

和校验:就是从帧头开始,对每一字节进行求和,直到DATA区结束的一个值。

附加校验:每一字节的求和操作,进行一次累加。如果和校验和附加校验相等,代表数据包校验通过。

可以看一下官方的资料:

516a00698f224bc9a4dc1c01df5d2f30.png

 

 了解完这些我们就可以来编写我们自己的数据包了:

在此之前,我先展示一下这整个数据包的格式,和内容:

02ff88cb8a764afb9ed38fbd21d14caf.jpeg

这个数据包,一共13个字节。

展示代码:

#大家也可以写自己的数据帧,只要符合通信协议就可以

void nmswj_Reveal(float roL,float pit,float yaw)
{
    u8 i;
    unsigned int data_temp;
    u8 sumcheck = 0;
    u8 addcheck = 0;
    u8 buf[13]={0};
    
    buf[0]=0xAA;//帧头
    buf[1]=0xFF;//目标地址
    buf[2]=0x03;//功能码
    
    buf[3]=0x07;//数据长度
    
    
    //2字节横滚角
    data_temp= (int)(Roll * 100);
    buf[4]=(u8)data_temp;
    buf[5]=(u8)(data_temp>>8);
    
    
    //2字节俯仰角
    data_temp=-(int)(pit* 100);
    buf[6]=(u8)data_temp;
    buf[7]=(u8)(data_temp>>8);

    
    //2字节航向角
    data_temp= (int)(yaw* 100);
    buf[8]=(u8)data_temp;
    buf[9]=(u8)(data_temp>>8);
    
    
    //1字节融合状态
    buf[10]=0x00;
    
    for(i=0; i < 11; i++)
    {
        sumcheck += buf[i]; //从帧头开始,对每一字节进行求和,直到DATA区结束
        addcheck += sumcheck; //每一字节的求和操作,进行一次sumcheck的累加
    }
    buf[11]=sumcheck;
    buf[12]=addcheck;

    if(sumcheck == buf[11] && addcheck == buf[12]) //数据帧校验判断
    {Serial_SendArray(buf,13);}
    
    
}

其实还有很多上位机,他们都有对应数据帧,需要我们按照官方给的资料进行编写也是可以使用他们的。而且上位机的功能不止于姿态的显示,大家可以多多试试,都是有规律的(我看过一些视频感觉的,哈哈)。

 

2.2 stm32 SPI通信

2.2.1 stm32 2.4G

通信方式千万种,2.4G也是其中一种(顺口溜,哈哈)。关于2.4G很多网站上面都有资料,还挺多的。大家就去网上直接拿资料就行了,我就不多说了,因为我也是在网上学习的。不过我还是可以展示一下我自己从零开始学习的笔记和2.4G寄存器地址,希望可以帮助到一些自己配置过IIc传感器的外设、并且学习过SPI协议的各位小伙伴。

 

发送端初始化过程:

1.写发送端地址        TX_ADDR

2.写接收端地址    RX_ADDR_P0

3.使能AutoACK        EN_AA

4.使能PIPE0        EN_RXADDR

5.配置自动重发数        SETUP_RETR

6.选择通信频率        RF_CH

7.配置发送参数(低噪声放大器增益、发射功率、无线速率)        RF_SETUP

8.选择通道0有效数据宽度        RX_PW_P0

9.配置24l01的基本参数以及工作模式        CONFIG

 

接收端初始化过程:

1.写节点RX的地址        RX_ADDR_P0

2.使能AutoACK        EN_AA

3.使能PIPE0        EN_RXADDR

4.选择通信频率        RF_CH

5.选择通道0有效数据宽度        RX_PW_P0

6.配置发送参数(低噪声放大器增益、发射功率、无线速率)        RF_SETUP

7.配置24l01的基本参数以及工作模式        CONFIG

 

 

通信条件(必要条件):

1.频道相同(设置频道寄存器RF_CH)

2.地址相同(设置TX_ADDR和RX_ADDR_P0相同)

3.每次发送接收的字节数相同(如果设置了通道的有效数据宽度为n,那么每次发送的字节数也必须为n,n<=32)

(在写入寄存器之前,一定要进入待机模式)

 


//NRF24L01寄存器操作命令  
#define nRF_READ_REG        0x00 
#define nRF_WRITE_REG       0x20 
#define RD_RX_PLOAD     0x61  
#define WR_TX_PLOAD     0xA0  
#define FLUSH_TX        0xE1  
#define FLUSH_RX        0xE2  
#define REUSE_TX_PL     0xE3  
#define NOP             0xFF  
//NRF24L01寄存器地址
#define CONFIG          0x00                           
#define EN_AA           0x01  
#define EN_RXADDR       0x02  
#define SETUP_AW        0x03  
#define SETUP_RETR      0x04  
#define RF_CH           0x05  
#define RF_SETUP        0x06  
#define STATUS          0x07  
#define OBSERVE_TX      0x08  
#define CD              0x09  
#define RX_ADDR_P0      0x0A  
#define RX_ADDR_P1      0x0B  
#define RX_ADDR_P2      0x0C  
#define RX_ADDR_P3      0x0D  
#define RX_ADDR_P4      0x0E  
#define RX_ADDR_P5      0x0F  
#define TX_ADDR         0x10  
#define RX_PW_P0        0x11   
#define RX_PW_P1        0x12   
#define RX_PW_P2        0x13   
#define RX_PW_P3        0x14   
#define RX_PW_P4        0x15  
#define RX_PW_P5        0x16  
#define FIFO_STATUS     0x17  

//STATUS寄存器bit位定义
#define MAX_TX      0x10        //达到最大发送次数中断
#define TX_OK       0x20        //TX发送完成中断
#define RX_OK       0x40        //接收到数据中断

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值