在开始之前,我想立即保留一下代码不是我写的,而是从这里获取的。该程序是用Arduino IDE编写的,与arduino pro mini和nrf24l01 +结合使用,使您可以从任何具有PPM输出的控制设备控制玩具多旋翼飞机(带有XN297无线电芯片,nrf24l01克隆)。有关受支持的多旋翼机的所有信息,可以在上面的链接中找到。我决定重写此代码,以从Radiolink AT9设备控制Everyine H8小型直升机。我要求猫下提供详细信息。之所以选择MSP430,是因为它的电源电压为3.3伏,电源电压nrf24l01也为3.3伏,我某种程度上喜欢MPS430。设备内部有3V3,OUT,GND触点,我们将连接这些触点。如果不想拆卸设备,则可以连接至教练连接器,但是其上的电压=电池电压,因此在电路中添加了稳压器。让我们开始讨论代码
首先,在IDE Energia(用于MSP430和TI的其他芯片的Arduino IDE克隆)中打开项目,并尝试对其进行编译,但立即会看到编译错误。该项目使用其他库和对寄存器的访问,并且首先需要从它们开始。因此,我们进行详细分析。图书馆
我们将编辑nRF24_multipro.ino文件,并从include'ov开始。该项目使用原子库和EEPROM库。原子的
我们删除线#include <util/atomic.h>
并在函数void update_ppm()中删除ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
我们写括号而不是大括号__disable_interrupt();
和__enable_interrupt();
ATOMIC_BLOCK()函数在执行其“主体”中的代码时关闭中断,并根据参数打开中断或将中断标志的值恢复到调用ATOMIC_BLOCK()函数之前的状态。埃普罗姆
MSP430没有EEPROM存储器,但是有FLASH存储器,并且有一个MspFlash库可供使用。因此,我们删除了该行#include <EEPROM.h>
并添加MspFlash库(Sketch->导入库...-> MspFlash),然后将数据写入FLASH存储器的哪一部分#define flash SEGMENT_D
在void selectProtocol()函数中,更改行else
current_protocol = constrain(EEPROM.read(ee_PROTOCOL_ID),0,PROTO_END-1);
EEPROM.update(ee_PROTOCOL_ID, current_protocol);
在
Flash.write(flash+ee_PROTOCOL_ID, & current_protocol,1);
我们完全删除了协议标识符的读取内容(为什么读取以下内容)。在void set_txid(布尔更新)中,您需要做的不仅仅是替换两行。在闪存中,我们只能将零位。要在FLASH存储器位中设置值1,您需要擦除整个段(然后将值1写入其中)。此函数(set_txid)的调用早于selectProtocol,因此我们将在此处删除该段。那是:void set_txid(bool renew)
{
uint8_t i;
for(i=0; i<4; i++)
transmitterID[i] = EEPROM.read(ee_TXID0+i);
if(renew || (transmitterID[0]==0xFF && transmitterID[1]==0x0FF)) {
for(i=0; i<4; i++) {
transmitterID[i] = random() & 0xFF;
EEPROM.update(ee_TXID0+i, transmitterID[i]);
}
}
}
它变成了:void set_txid(bool renew)
{
uint8_t i;
unsigned char p;
for(i=0; i<4; i++) {
Flash.read(flash+ee_TXID0+i,&p,1);
transmitterID[i] =p;
}
Flash.read(flash+ee_PROTOCOL_ID,&p,1);
current_protocol = constrain(p,0,PROTO_END-1);
Flash.erase(flash);
if(renew || (transmitterID[0]==0xFF && transmitterID[1]==0x0FF)) {
for(i=0; i<4; i++) {
transmitterID[i] = random(0xff) & 0xFF;
p = transmitterID[i];
Flash.write(flash+ee_TXID0+i, &p,1);
}
}else{
for(i=0; i<4; i++) {
p = transmitterID[i];
Flash.write(flash+ee_TXID0+i, &p,1);
}
}
}
在这里,我们读取发送器和协议的标识符的值,擦除该段,如果给出了更新发送器的标识符的命令,我们将写入一个新值,否则将记录旧值。地址为flash + ee_PROTOCOL_ID的存储器的FLASH字节保持干净(0xFF),因此我们不在selectProtocol()函数中读取它,而是立即在其中写入协议标识符。寄存器
首先,让我们处理一下引脚。在该项目中,使用了SPI的软件实现,其中的宏用于通过寄存器“抽动”支路。重写引脚的定义#define PPM_pin 2
#define MOSI_pin 3
#define SCK_pin 4
#define CE_pin 5
#define MISO_pin A0
#define CS_pin A1
#define ledPin 13
#define PPM_pin P1_5
#define MOSI_pin P2_0
#define SCK_pin P2_1
#define CE_pin P2_2
#define MISO_pin P2_3
#define CS_pin P2_4
#define ledPin P1_4
#define MOSI_on PORTD |= _BV(3)
#define MOSI_off PORTD &= ~_BV(3)
#define SCK_on PORTD |= _BV(4)
#define SCK_off PORTD &= ~_BV(4)
#define CE_on PORTD |= _BV(5)
#define CE_off PORTD &= ~_BV(5)
#define CS_on PORTC |= _BV(1)
#define CS_off PORTC &= ~_BV(1)
#define MISO_on (PINC & _BV(0))
#define MOSI_on P2OUT |= _BV(0)
#define MOSI_off P2OUT &= ~_BV(0)
#define SCK_on P2OUT |= _BV(1)
#define SCK_off P2OUT &= ~_BV(1)
#define CE_on P2OUT |= _BV(2)
#define CE_off P2OUT &= ~_BV(2)
#define CS_on P2OUT |= _BV(4)
#define CS_off P2OUT &= ~_BV(4)
#define MISO_on (P2IN & _BV(3))
在ATMEL MK中,MSP430 PxOUT中的PORTx寄存器负责输出状态。对于输入状态,分别为PINx和PxIN寄存器。顺便说一下,Energia IDE中没有_BV(x)函数,因此请自己添加:#define _BV(val) 1<<val
在功能void setup()中,我们将模拟输入的引脚值更改为freerandomSeed((analogRead(A4) & 0x1F) | (analogRead(A5) << 5));
例如在randomSeed((analogRead(A0) & 0x1F) | (analogRead(A1) << 5));
在MSP430中,模拟输入A0,A1,A2,...,A7对应于引脚P1_0,P1_1,P1_2,...,P1_7。连接中断时attachInterrupt(PPM_pin - 2, ISR_ppm, CHANGE);
在attachInterrupt(PPM_pin , ISR_ppm, CHANGE);
在mega328的Arduino Uno,Nano,Mini等中,只有2个引脚(2、3)可用于连接中断,在attachInterrupt函数中,第一个参数是中断号,而不是MSP430中的引脚。有关attachInterrupt()的更多信息。计时器
更改空隙设置()TCCR1A = 0;
TCCR1B = 0;
TCCR1B |= (1 << CS11);
开TACTL = TASSEL_2 + ID_3 + MC_2 + TACLR;
需要一个计时器来确定PPM中的脉冲持续时间。我们将其设置为频率为2 MHz(时钟频率为16 MHz,分频器为8)的直接计数模式。在void函数ISR_ppm()中,我们进行更改counterPPM = TCNT1;
TCNT1 = 0;
在counterPPM = TAR;
TAR = 0;
寄存器TCNT1和TAR是定时器计数器。随机()
我不知道为什么,但是Energia中不是不带参数地调用random()函数,但是由于我们需要一个随机的单字节数字,因此我们在文件中替换了nRF24_multipro.ino和Bayang.inorandom() & 0xFF;
在random(0xFF);
和random() % 0x42;
在random(0x41);
???
最后,在MJX.ino文件的void MJX_bind()函数中,我们在mjx_init2函数调用中添加了括号;我们编译该项目并获得成功的结论。项目源代码更改后的项目代码为了成功地将程序转移到另一个平台,您需要了解在此代码中执行什么,如何以及为什么执行它,了解所连接的库的功能,寄存器的用途,并且在工作过程中经常查看编译日志以查找错误。好吧,如果您做得很好,则需要将项目转移到另一个开发环境,连接硬件SPI并仅与寄存器一起使用,但这是完全不同的事情。