赞
踩
寒假无聊,在家里整了个航模遥控器。遥控器的代码大体算是完成了,但略显粗糙,计划写个蓝牙软件对这个遥控器进行调参,开学了,就没整软件。
接收机的代码写的也差不多了,我自己只试过无刷电调的单向驱动,还不错。双向电调家里边没有,所以双向电调的对中信号也没算出来。
左遥杆 X轴Y轴 A0,A1
右遥杆 X轴Y轴 A2,A3
OLED屏幕 SDA SCL A4,A5
电位器1,2 A6,A7
电容触摸按键 2自锁2点动 D2,D3,D4,D5
指示灯LED PWM输出 D6
二段开关 D7,D8
NRF24L01P引脚 D9,D10,D11,D12,D13
蓝牙串口 RX0,TX1
指示灯我用的是共阳极的三色LED,之前,我还不知道有2812这种好东西 o(0…0)o ,所以就自己整了个电路
由于NANO只剩一个6号io口,使用6号口的pwm,利用LM339电压比较器将电压分开,对LED分开控制;
下边是LM339接线图;
但实际接线过程中,不懂什么原理,1.2-2.5v那一栏是没有用的,而且直接用直流电源接输入端与用方波信号输入出现不同的结果,不知哪位大神能解答一下
但这些问题不影响使用,只用了两个状态
遥控器的代码大体算完成,不改也能直接使用,但推荐按实际情况修改。
/* THE ZG NANO遥控器 by 微风萧萧 引脚分配: A0 A1 A2 A3 遥杆4通道 A5 A6 OLED液晶屏SCL SDA A7 A8 电位器1 电位器2 D2 D3 D4 D5 4触摸按键 2自锁 2点动 D6 PWM LED 输出 D7 D8 二段开关 SW1 SW2 nrf24l01p: CE -> D9 CSN -> D10 MOSI -> D11 MISO -> D12 SCK -> D13 IRQ -> \ VCC -> 3.3V GND -> GND */ #include <SPI.h> #include <nRF24L01.h> #include <RF24.h> #include <U8g2lib.h> #include <Wire.h> U8G2_SH1106_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0,U8X8_PIN_NONE); static const unsigned char PROGMEM bitmap[] ={ //59*31 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0xF8,0x7F,0x00,0x00,0x7F,0x00,0x00,0x80,0xFF,0x7F,0x00,0xC0,0xFF,0x00, 0x00,0xF8,0xFF,0x7F,0x00,0xE0,0xFF,0x00,0x00,0xF8,0x7F,0xFC,0x00,0xF8,0xF7,0x00, 0x00,0xF8,0x01,0x7E,0x00,0xFC,0xE1,0x00,0x00,0x00,0x00,0x3F,0x00,0x7E,0x00,0x00, 0x00,0x00,0x80,0x1F,0x00,0x3F,0x00,0x00,0x00,0x00,0xC0,0x0F,0x80,0x0F,0x00,0x00, 0x00,0x00,0xE0,0x07,0xC0,0x07,0x00,0x00,0x00,0x00,0xF8,0x03,0xE0,0x03,0x00,0x00, 0x00,0x00,0xFC,0x00,0xE0,0x01,0xFC,0x00,0x00,0x00,0x7E,0x00,0xF0,0x81,0xFF,0x00, 0x00,0x00,0x3F,0x00,0xF0,0xF0,0xFF,0x01,0x00,0x00,0x1F,0x00,0x78,0xF8,0xFF,0x01, 0x00,0xC0,0x0F,0x00,0x78,0xF8,0xF3,0x00,0x00,0xE0,0x07,0x00,0x3C,0x78,0xF8,0x00, 0x00,0xF8,0x03,0x00,0x3C,0x00,0xF8,0x00,0x00,0xFC,0x00,0x00,0x3C,0x00,0x7C,0x00, 0x00,0x7E,0x00,0x3C,0x3C,0x00,0x3E,0x00,0x00,0x3F,0x00,0x3E,0x3C,0x00,0x3F,0x00, 0x80,0x1F,0x80,0x3F,0x7C,0x80,0x1F,0x00,0xC0,0x0F,0xF0,0x1F,0xFC,0xE0,0x0F,0x00, 0xE0,0xFF,0xFF,0x07,0xF8,0xF9,0x07,0x00,0xF0,0xFF,0xFF,0x03,0xF8,0xFF,0x01,0x00, 0xF0,0xFF,0x7F,0x00,0xF0,0xFF,0x00,0x00,0xF8,0xFF,0x07,0x00,0xC0,0x1F,0x00,0x00, 0xF0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; static const unsigned char PROGMEM bitmapa[] ={0x0C,0x1D,0x27,0x36,0x1C,0x1C,0x36,0x27,0x1D,0x0C}; // 蓝牙图标6*9 RF24 radio(9, 10); // CE, CSN const byte address[6] = "zg111"; //定义通讯地址 struct Signal { byte vlx; byte vly; byte vrx; byte vry; byte potentialA; //电位器a byte potentialB; //电位器b byte switchA; //开关a ------>F->1001 B->1110 byte switchB; //开关b ------>O->1011 X->1100 byte touchA; //触摸开关a ------>NL->1010 LI->1000 byte touchB; //触摸开关b ------>NL->1111 LI->0000 }; Signal data; int SWC1,SWC2,SWC3,SWC4; int SW5,SW6; //系统操作按键 int cont1,cont2,cont3,cont4; //按键消抖中间变量 int mode; //系统模式更换变量 mode=0 操作模式 mode=1设置模式 int ym; //oled页面变量 ym=1,2,3 int Bluetooh; //蓝牙开启,默认开启 char sreialData; // 储存蓝牙指令 void page1() { u8g2.setFont(u8g2_font_timB18_tf); u8g2.setFontPosTop(); u8g2.setCursor(2,2); u8g2.print("THE ZG"); u8g2.drawHLine(1,21,126); //直线 (x,y,长度) u8g2.setFont(u8g2_font_helvR08_tf); u8g2.setFontPosTop(); u8g2.drawFrame(1,23,78,22); //矩形框 (起点x,起点y,长,宽) u8g2.setCursor(2,24);u8g2.print("LX:");u8g2.setCursor(18,24);u8g2.print(data.vlx); u8g2.setCursor(40,24);u8g2.print("RX:");u8g2.setCursor(57,24);u8g2.print(data.vrx); u8g2.setCursor(2,34);u8g2.print("LY:");u8g2.setCursor(18,34);u8g2.print(data.vly); u8g2.setCursor(40,34);u8g2.print("RY:");u8g2.setCursor(57,34);u8g2.print(data.vry); u8g2.setCursor(2,45);u8g2.print("ReU:");u8g2.setCursor(26,45);u8g2.print(data.potentialA); u8g2.setCursor(48,45);u8g2.print("RxD:");u8g2.setCursor(73,45);u8g2.print(data.potentialB); u8g2.setCursor(85,24);u8g2.print("SW1:"); //------------------------- if (SWC1 == 1) {u8g2.setCursor(112,24);u8g2.print("F"); } else {u8g2.setCursor(112,24);u8g2.print("B");} u8g2.setCursor(85,34);u8g2.print("SW2:"); //---------------------- if (SWC2 == 1) {u8g2.setCursor(112,34);u8g2.print("X"); } else {u8g2.setCursor(112,34);u8g2.print("O");} u8g2.setCursor(94,44);u8g2.print("S3:"); //---------------------- if (SWC3 == 1) {u8g2.setCursor(112,44);u8g2.print("T"); } else {u8g2.setCursor(112,44);u8g2.print("K");} u8g2.setCursor(94,54);u8g2.print("S4:"); //---------------------- if (SWC4 == 1) {u8g2.setCursor(112,54);u8g2.print("R"); } else {u8g2.setCursor(112,54);u8g2.print("C");} u8g2.setFont(u8g2_font_ncenR08_tf); u8g2.setFontPosTop(); u8g2.setCursor(2,54);u8g2.print("[Back]"); //---------------------- } void page2() { u8g2.drawXBMP(34, 2, 59, 31, bitmap); u8g2.setFont(u8g2_font_helvR08_tf); u8g2.setFontPosTop(); if(Bluetooh ==1){ u8g2.drawXBMP(120, 2, 6, 10, bitmapa);}else{ u8g2.setCursor(120,2);u8g2.print(" ");} if(mode ==1){ u8g2.setCursor(2,42);u8g2.print("Setup"); }else if(mode ==0){ u8g2.setCursor(2,42);u8g2.print("Operation");} u8g2.setFont(u8g2_font_ncenR08_tf); u8g2.setFontPosTop(); u8g2.setCursor(2,54);u8g2.print("[Select]"); u8g2.setCursor(80,54);u8g2.print("[DataSita]"); } void page3() { u8g2.setFont(u8g2_font_timB18_tf); u8g2.setFontPosTop(); u8g2.setCursor(2,2); u8g2.print("THE ZG"); u8g2.drawHLine(1,21,126); //直线 (x,y,长度) u8g2.setFont(u8g2_font_helvR08_tf); u8g2.setFontPosTop(); u8g2.setCursor(44,24);u8g2.print("Sorry,"); u8g2.setCursor(12,34);u8g2.print("no time,come out, OK"); u8g2.setCursor(5,44);u8g2.print(">"); if (Bluetooh ==1){ u8g2.setCursor(12,44);u8g2.print("Turn off the Bluetooth?"); }else if(Bluetooh ==0 ){ u8g2.setCursor(12,44);u8g2.print("Turn on the Bluetooth?"); } u8g2.setFont(u8g2_font_ncenR08_tf); u8g2.setFontPosTop(); u8g2.setCursor(2,54);u8g2.print("[Back]"); u8g2.setCursor(102,54);u8g2.print("[OK]"); } void setup(){ radio.begin(); radio.openWritingPipe(address);// 写入地址 radio.setPALevel(RF24_PA_MIN); //小功率 radio.stopListening(); //nrf24l01设为发射模式 Serial.begin(9600); //打开串口接收蓝牙数据 u8g2.begin(); u8g2.enableUTF8Print(); pinMode(6, OUTPUT); //led指示灯 pinMode(7, INPUT); //通道开关1 pinMode(8, INPUT); //通道开关2 pinMode(2, INPUT); pinMode(3, INPUT); //通道开关3 pinMode(4, INPUT); pinMode(5, INPUT); //通道开关4 mode=0; ym=2; cont1 = HIGH; cont2 = HIGH; cont3 = HIGH; cont4 = HIGH; Bluetooh = 1; //开启蓝牙 =0时关闭串口接收 if (analogRead(A6)>20||analogRead(A7)>20){ //检测电位器初始值,不为零时led提示 for(int i=0;i<3;i++){ analogWrite(6,0);//led闪烁3次 delay(500); analogWrite(6,250); delay(500); } } else{ digitalWrite(6,0);//led闪烁1次 delay(500); digitalWrite(6,250); } } int chValue(int val, int lower, int middle, int upper) { val = constrain(val, lower, upper); //将val限制在lower~upper范围内 if ( val < middle ) val = map(val, lower, middle, 0, 127); else val = map(val, middle, upper, 128, 255); return val; } void loop(){ SW5 = digitalRead(2); SW6 = digitalRead(4); if( Bluetooh == 1){ if (Serial.available() > 0) { delay(5); sreialData = Serial.read(); if (sreialData == 'S') { //设置模式 mode=1; digitalWrite(6,0); } else if (sreialData == 'P') { //操作模式 mode = 0;digitalWrite(6,255); } else if (sreialData == 'M') { //页面1 ym=1; } else if (sreialData == 'U') { //页面2 ym=2; }else if (sreialData == 'N') { //页面3 ym=3; } delay(4); Serial.println(sreialData); } } if(SW5 == 1&&SW6 == 1&&cont3==HIGH){ delay(5); if(mode==0){delay(10);mode = 1 ;digitalWrite(6,0);} else if(mode==1){delay(10);mode =0;digitalWrite(6,255);} }else if(SW5 == 0&&SW6 == 0&&cont3==LOW){ delay(5); cont3 = !cont3; } if(mode ==0){ SWC1 = digitalRead(7); SWC2 = digitalRead(8); SWC3 = digitalRead(3); SWC4 = digitalRead(5); data.vlx =255- chValue(analogRead(A0), 150, 478, 900); data.vly = chValue(analogRead(A1), 140, 505, 910); data.vrx = chValue(analogRead(A2), 160, 492, 900); data.vry =255- chValue(analogRead(A3), 140, 513, 910); data.potentialA = map(analogRead(A6),0, 1023, 0, 255); data.potentialB = map(analogRead(A7),0, 1023, 0, 255); if(SWC1 ==1){ data.switchA = 1001 ;}else{data.switchA = 1110 ;} if(SWC2 ==1){ data.switchB = 1100 ;}else{data.switchB = 1011 ;} if(SWC3 ==1){ data.touchA = 1000 ;}else{data.touchA = 1010 ;} if(SWC4 ==1){ data.touchB = 1101 ;}else{data.touchB = 1111 ;} radio.write(&data, sizeof(Signal)); }else if(mode ==1){ if(ym==1){ if (SW6 == HIGH && cont2 == HIGH) { delay(5); ym =2; cont2 = !cont2; } else if (SW6 == LOW && cont2 == LOW) { delay(5); cont2 = !cont2; } }else if(ym==2){ if (SW6 == HIGH && cont2 == HIGH) { delay(5); ym =3; cont2 = !cont2; } else if (SW6 == LOW && cont2 == LOW) { delay(5); cont2 = !cont2; } if (SW5 == HIGH && cont1 == HIGH) { delay(5); ym = 1; cont1 = !cont1; } else if (SW5 == LOW && cont1 == LOW) { delay(5); cont1 = !cont1; } }else if(ym ==3){ if (SW6 == HIGH && cont2 == HIGH) { delay(5); ym =2; cont2 = !cont2; } else if (SW6 == LOW && cont2 == LOW) { delay(5); cont2 = !cont2; } if (SW5 == HIGH && cont1 == HIGH) { delay(5); if(Bluetooh == 1){ delay(5); Bluetooh =0; }else if(Bluetooh ==0){ delay(5); Bluetooh =1; } cont1 = !cont1; } else if (SW5 == LOW && cont1 == LOW) { delay(5); cont1 = !cont1; } } } //--- u8g2.firstPage(); do{ if(ym==3){page3();} else if(ym==2){page2();} else if(ym==1){page1();} } while (u8g2.nextPage()); delay(50); }
代码仅供参考,实际使用得根据实际情况改写
注意:接收机的24L01P 与nano的接口与遥控器的接法不同
//这是遥控器的
RF24 radio(9, 10 ); // CE, CSN
//这是接收机的
RF24 radio(7, 8); // CE, CSN
模式1:接收机采用PCA9685模块扩展PWM接口;50Hz 无刷电调上升沿为1ms-2ms 对应值为187-373; 舵机上升沿102为0度 187为45度 280为90度 373为135度 510为180度模拟通道
数值算法:
0.05 X 4096 X 0.915 ~= 187 ;
0.1 X 4096 X 0.915 ~= 374 ;
以此类推。
模式2:接收机采用nano自带的3,5,6,9,10 PWM引脚输出。11脚被占用,用软件模拟的话会占用单片机资源,所以,只有五路PWM输出口。
模式3:自行定义~
/* * THE ZG 接收机主程序 * BY:微风萧萧 * nrf24l01p: CE -> D07 CSN -> D08 MOSI -> D11 MISO -> D12 SCK -> D13 IRQ -> \ VCC -> 3.3V GND -> GND */ #include <SPI.h> #include <nRF24L01.h> #include <RF24.h> #include <Servo.h> #include <Wire.h> #include <EEPROM.h> #include "Adafruit_PWMServoDriver.h" Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x40); // 遥杆1 遥杆2 遥杆3 遥杆4 电位器A 电位器B int cha1, cha2, cha3, cha4, cha5, cha6; // 开关A 开关B 开关R 开关L int swA, swB, swR, swL; // 定义数据变量 int mode =0,Rexo,Reup,Redo,cont; int addr; Servo ch1; Servo ch2; Servo ch3; Servo ch4; Servo ch5; struct Signal { byte vlx; byte vly; byte vrx; byte vry; byte potentialA; //电位器a byte potentialB; //电位器b byte switchA; //开关a ------>F->1001 B->1110 byte switchB; //开关b ------>O->1011 X->1100 byte touchA; //触摸开关a ------>NL->1010 LI->1000 byte touchB; //触摸开关b ------>NL->1111 LI->0000 }; Signal data; const byte address[6] = "zg111"; RF24 radio(7, 8); // CE, CSN void setup() { ch1.attach(3); ch2.attach(5); ch3.attach(6); ch4.attach(9); ch5.attach(10); pwm.begin(); //PCA9685初始化 pwm.setPWMFreq(50); //50HZ Serial.begin(9600); //打开串口 radio.begin(); //nrf24l01p 初始化 radio.openReadingPipe(0, address); radio.setPALevel(RF24_PA_MIN); radio.startListening(); pinMode(A0,INPUT); pinMode(A1,OUTPUT); pinMode(A2,OUTPUT); pinMode(A3,OUTPUT); mode = EEPROM.read(addr); cont = HIGH; pinMode(LED_BUILTIN,OUTPUT);//LED推挽输出 digitalWrite(LED_BUILTIN,HIGH); digitalWrite(A1,HIGH); digitalWrite(A2,HIGH); digitalWrite(A3,HIGH); } unsigned long lastRecvTime = 0; void recvData(){ while( radio.available() ) { radio.read(&data, sizeof(Signal));//接收数据 lastRecvTime = millis(); //当前时间ms } } void loop() { recvData(); unsigned long now = millis(); if ( now - lastRecvTime > 500 ) {digitalWrite(LED_BUILTIN,HIGH);}else digitalWrite(LED_BUILTIN,LOW); Rexo = analogRead(A0); Reup = analogRead(A6); Redo = analogRead(A7); swA = data.switchA; swB = data.switchB; swR = data.touchA; swL = data.touchB; if(Rexo <= 20&&cont == HIGH){ //模式转换 delay(4); mode++; if(mode >=4){ mode =0; } cont =!cont; }else if(Rexo >=1000 &&cont ==LOW){ delay(4); cont =!cont; } /* if(Reup <= 20&&cont == HIGH){ //功能暂定 delay(4); cont =!cont; }else if(Reup >=1000 &&cont ==LOW){ delay(4); cont =!cont; } if(Redo <= 20&&cont == HIGH){ //功能暂定 delay(4); cont =!cont; }else if(Redo >=1000 &&cont ==LOW){ delay(4); cont =!cont; }*/ if(mode==0){ digitalWrite(A1,1); digitalWrite(A2,1); digitalWrite(A3,1); }else if(mode==1){ // 蓝色 模式一 cha1 = map(data.vlx, 0, 255, 1000, 2000); // cha2 = map(data.vly, 0, 255, 185,370); // cha3 = map(data.vrx, 0, 255, 1000, 2000); // cha4 = map(data.vry, 0, 255, 1000, 2000); // cha5 = map(data.potentialA, 0, 255, 185, 370); //50Hz 无刷电调上升沿为1ms-2ms 对应值为187-373 cha6 = map(data.potentialB, 0, 255, 185, 370); //舵机上升沿102为0度 187为45度 280为90度 373为135度 510为180度 digitalWrite(A1,0); digitalWrite(A3,1); pwm.setPWM(12,0,cha5); pwm.setPWM(13,0,cha6); if(cha2<=310&&cha2>=245){ pwm.setPWM(4,0,227); }else pwm.setPWM(4,0,cha2); } else if(mode==2){ //绿色 模式二 cha1 = map(data.vlx, 0, 255, 950, 1900); // cha2 = map(data.vly, 0, 255, 950, 1900); // cha3 = map(data.vrx, 0, 255, 950, 1900); // cha4 = map(data.vry, 0, 255, 950, 1900); // cha5 = map(data.potentialA, 0, 255, 185, 370); cha6 = map(data.potentialB, 0, 255, 185, 370); digitalWrite(A1,1); digitalWrite(A2,0); ch1.writeMicroseconds(cha1); // 3号引脚 lx ch2.writeMicroseconds(cha2); // 5号引脚 ly ch3.writeMicroseconds(cha3); // 6号引脚 rx ch4.writeMicroseconds(cha4); // 9号引脚 ry //ch5.writeMicroseconds(cha2); //1000 --2000 对应1ms-2ms } else if(mode==3){ //红色 模式三 digitalWrite(A2,1); digitalWrite(A3,0); } EEPROM.write(addr, mode); delay(50); }
接收机代码未完整,仅供参考;
接收机可选三种模式,通过按键A0端口选取,使用EEPROM记录当前值保存;防止下次上电是模式复位。4个数字通道未定义;可以根据实际需要修改。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。