背景:室友要做一个航模,我来给他写控制系统和动力系统,也就是遥控器和电调。
目前进度:几乎完成。
先看代码,代码下面有分析。
发送端(arduino uno):
#include <Arduino.h>
#include <Servo.h>
#include <nRF24L01.h>
#include <RF24.h>
RF24 radio(6,7);//CE,CSN
int unsigned sendNumber;
const int analogInPin = A0;
const int analogInPinpin = A1;
int unsigned sensorValue = 0;
int unsigned sensorValuepin = 0;
const byte address[6]="00001";
const byte channel=108;
const int ce=6;
void setup() {
/**
* 串口打印初始化
*/
Serial.begin(9600);
Serial.println();
Serial.println("Connecting");
/**
* 引脚初始化
*/
pinMode(analogInPin,INPUT);
pinMode(analogInPinpin,INPUT);
/**
* lora模块初始化
*/
radio.begin();
radio.openWritingPipe(address);
radio.setChannel(channel);
radio.setPALevel(RF24_PA_HIGH);
radio.setDataRate(RF24_250KBPS);
radio.stopListening();
}
void loop() {
/**
* 读取模拟口数据并转为0~180之间
*/
sensorValue = analogRead(analogInPin);
sensorValuepin = analogRead(analogInPinpin);
sensorValue=map(sensorValue,0,1023,0,180);
sensorValuepin=map(sensorValuepin,0,1023,0,180);
/**
* 拼接数据
*/
sendNumber=sensorValue<<8;
sendNumber=sendNumber+sensorValuepin;
/**
* 发送数据
*/
// digitalWrite(ce,HIGH);
radio.write(&sendNumber,sizeof(sendNumber));
// digitalWrite(ce,HIGH);
delay(100);
// digitalWrite(ce,LOW);
// delay(50);
}
接收端(arduino nano):
#include <SPI.h>
#include "RF24.h"
#include "printf.h"
#include <Servo.h>
/**
* 创建对象
*/
RF24 radio(2,3);//CE,CSN
Servo myservo;
Servo myservo2;
/**
* 引脚定义
*/
const int pina=9;//舵机
const int pinb=10;//舵机2
/**
* 对象参数
*/
const byte address[6]="00001";//通信ip
const byte channel=108;//通信信道
int sensorValue = 0;//初始化舵机角度
int sensorValuepin = 0;//初始化舵机2角度
void setup() {
/**
* 串口打印初始化
*/
Serial.begin(9600);
Serial.println();
Serial.println("Connecting");
/**
* 引脚初始化
*/
pinMode(pina,OUTPUT);
pinMode(pinb,OUTPUT);
/**
* 模块初始化
*/
radio.begin();//lora模块初始化
radio.openReadingPipe(0,address);
radio.setChannel(channel);
radio.setPALevel(RF24_PA_HIGH);
radio.setDataRate(RF24_250KBPS);
radio.startListening();
myservo.attach(pina);//舵机1初始化
myservo2.attach(pinb);//舵机2初始化
}
void loop() {
while(1){
/**
* 判断模块是否可用
*/
if(radio.available()){
Serial.println("123");
/**
* 接收数据
*/
int receivedData;
radio.read(&receivedData,sizeof(receivedData));
/**
* 拆分数据
*/
sensorValue=receivedData&0b11111111;
sensorValuepin=(receivedData>>8)&0b11111111;
/**
* 控制舵机
// */
Serial.println(sensorValue);
Serial.println(sensorValuepin);
myservo.write(sensorValue);
myservo2.write(sensorValuepin);
delay(10);
}
}
}
注意:
nrf24l01必须设置信道!!!!
nrf24l01必须设置信道!!!!
nrf24l01必须设置信道!!!!
网上许多教程没写信道,我实测在有多个路由器的室内,1000米的模块5米就没信号了,没设置信道极其容易受到周围2.4G信号干扰!!!
radio.setPALevel(RF24_PA_MAX); // 设置最大功率
radio.setChannel(40); // 设置信道为40
接收端和发送端信道需要一致,上面设置为40信道。
接下来分析代码:现在我的示例代码中只是用摇杆控制了两个舵机(左右控制一个,上下控制另一个)。原理:发送端(arduino uno)读取A0口数据(范围0~1023),用map()函数转化为0~180(因为舵机的角度是0~180)。将转化后的这个数据对应的二进制数左移8位(直接左移也是操作的158对应的二进制数,所以不用来回转化),例如:158度对应二进制数1001,1110,左移八位得到1001,1110,0000,0000;然后读取A1口数据比如是96,和158左移后的数字相加,刚好占据1001,1110,0000,0000的后八位(八位二进制数的取值范围是0-255大于180够用)得到1001,1110,0110,0000,然后发送这个数据。(可以用串口打印一下确认,接收端接受到这个数据右移八位就是左边八位二进制数对应的数据158;0b1111,1111与接受到数据异或操作就是后八位(右边)二进制数对应数据96,然后调用pwm函数(sero.write...(158或者96))控制舵机角度。整个过程结束。
有不会的可以留言讨论!祝大家不踩坑。
上面的程序有个大坑,我现在来说明一下,C语言中int类型最大为16位二进制数,我代码中左移动8位,刚刚好够用,如果你想控制更多的舵机(更多通道),就会不够用,这时候可以用int64_t,但是int64_t发送会失败,因为radio.write()不支持这种数据类型。这时候可以用int64_t来进行移位运算和加减,最后转化为字符串,发动这个字符串,接收端接收字符串,并把它转化为int64_t,然后在去拆分数据。。。我实测直接发送int64_t接收端接受到数字是0也就是接收不到