Kami menulis ulang kode Arduino untuk MSP430 menggunakan contoh nRF24_multipro, sebuah proyek untuk mengelola multicopters mainan


Sebelum memulai, saya ingin segera membuat reservasi bahwa kode itu tidak ditulis oleh saya dan diambil dari sini . Program ini ditulis dalam Arduino IDE dan bersama dengan arduino pro mini dan nrf24l01 + memungkinkan Anda untuk mengontrol multicopters mainan (dengan chip radio XN297, klon nrf24l01) dari peralatan kontrol apa pun yang memiliki output PPM. Semua informasi tentang multicopter yang didukung dapat ditemukan di tautan di atas.
Saya memutuskan untuk menulis ulang kode ini untuk mengontrol mini copter Eachine H8 dari peralatan Radiolink AT9. Saya meminta detail di bawah kucing.

MSP430 dipilih karena memiliki tegangan suplai 3,3 volt, tegangan suplai nrf24l01 juga 3,3 volt, dan saya suka MPS430. Di dalam peralatan ada 3V3, OUT, kontak GND, yang akan kita sambungkan.

Jika tidak ada keinginan untuk membongkar peralatan, maka Anda dapat menghubungkan ke konektor pelatihan, tetapi tegangan di atasnya = tegangan baterai, sehingga penstabil tegangan ditambahkan ke sirkuit.


Mari kita lanjutkan ke kode


Pertama-tama, buka proyek di IDE Energia (klon Arduino IDE untuk MSP430 dan chip lain dari TI) dan cobalah untuk mengompilasinya, tetapi segera lihat kesalahan kompilasi. Proyek ini menggunakan perpustakaan tambahan dan akses ke register, dan hal pertama yang Anda perlukan untuk memulainya. Jadi, kami melanjutkan ke analisis terperinci.

Perpustakaan


Kami akan mengedit file nRF24_multipro.ino dan mulai dengan include'ov. Proyek ini menggunakan pustaka atom dan EEPROM.

atom


Kami menghapus garis
#include <util/atomic.h>
dan pada fungsi void update_ppm () kita hapus
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
Alih-alih kawat gigi yang kita tulis
__disable_interrupt();
dan
__enable_interrupt();

Fungsi ATOMIC_BLOCK () mematikan interupsi sementara kode dalam "tubuh" dijalankan dan, tergantung pada parameter, mengaktifkan interupsi atau mengembalikan nilai flag interrupt ke keadaan sebelum fungsi ATOMIC_BLOCK () dipanggil.

Eeprom


MSP430 tidak memiliki memori EEPROM, tetapi ada memori FLASH dan ada perpustakaan MspFlash untuk bekerja dengannya. Karena itu, kami menghapus garis
#include <EEPROM.h>
dan tambahkan perpustakaan MspFlash (Sketch-> Import Library ... -> MspFlash), tambahkan ke segmen mana dari memori FLASH kami akan menulis data
#define flash SEGMENT_D
Dalam fungsi selectProtocol () kosong, ubah baris
else 
	current_protocol = constrain(EEPROM.read(ee_PROTOCOL_ID),0,PROTO_END-1);      
// update eeprom 
EEPROM.update(ee_PROTOCOL_ID, current_protocol);
pada
// update eeprom 
Flash.write(flash+ee_PROTOCOL_ID, & current_protocol,1);
Kami sepenuhnya menghapus pembacaan pengidentifikasi protokol (mengapa, baca di bawah).
Dalam kekosongan set_txid (perpanjangan bool), Anda perlu melakukan sedikit lebih banyak daripada mengganti dua baris. Dalam memori FLASH kita hanya bisa nol bit. Untuk menetapkan nilai 1 dalam bit memori FLASH, Anda harus menghapus seluruh segmen (maka nilai 1 akan dituliskan padanya). Fungsi ini (set_txid) disebut lebih awal dari selectProtocol, jadi kami akan menghapus segmen di sini.
Itu:
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]); 
        }            
    }
}

Itu menjadi:
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); 
        }  	
	}
}
Di sini kita membaca nilai pengidentifikasi pemancar dan protokol, menghapus segmen, dan jika perintah diberikan untuk memperbarui pengenal pemancar, kita menulis nilai baru, jika tidak kita mencatat yang lama. Byte FLASH dari memori dengan alamat flash + ee_PROTOCOL_ID tetap bersih (0xFF), jadi kami tidak membacanya di fungsi selectProtocol (), tetapi segera menulis pengenal protokol di sana.

Daftar


Pertama, mari kita berurusan dengan pin. Dalam proyek ini, implementasi perangkat lunak SPI digunakan, di mana makro digunakan untuk "berkedut" kaki melalui register.
Tulis ulang definisi pin
#define PPM_pin   2  // PPM in
//SPI Comm.pins with nRF24L01
#define MOSI_pin  3  // MOSI - D3
#define SCK_pin   4  // SCK  - D4
#define CE_pin    5  // CE   - D5
#define MISO_pin  A0 // MISO - A0
#define CS_pin    A1 // CS   - A1
#define ledPin    13 // LED  - D13
#define PPM_pin   P1_5  // PPM in
//SPI Comm.pins with nRF24L01
#define MOSI_pin  P2_0  // MOSI 
#define SCK_pin   P2_1  // SCK  
#define CE_pin    P2_2  // CE 
#define MISO_pin  P2_3 // MISO 
#define CS_pin    P2_4 // CS   
#define ledPin    P1_4 // LED  
#define MOSI_on PORTD |= _BV(3)  // PD3
#define MOSI_off PORTD &= ~_BV(3)// PD3
#define SCK_on PORTD |= _BV(4)   // PD4
#define SCK_off PORTD &= ~_BV(4) // PD4
#define CE_on PORTD |= _BV(5)    // PD5
#define CE_off PORTD &= ~_BV(5)  // PD5
#define CS_on PORTC |= _BV(1)    // PC1
#define CS_off PORTC &= ~_BV(1)  // PC1
// SPI input
#define  MISO_on (PINC & _BV(0)) // PC0
#define MOSI_on P2OUT |= _BV(0)// P2_0
#define MOSI_off P2OUT &= ~_BV(0)// P2_0
#define SCK_on P2OUT |= _BV(1)// P2_1
#define SCK_off P2OUT &= ~_BV(1)// P2_1
#define CE_on P2OUT |= _BV(2)// P2_2
#define CE_off P2OUT &= ~_BV(2)// P2_2
#define CS_on P2OUT |= _BV(4)// P2_4
#define CS_off P2OUT &= ~_BV(4) // P2_4
// SPI input
#define  MISO_on (P2IN & _BV(3)) // P2_3

Dalam ATMEL MK, register PORTx dalam MSP430 PxOUT bertanggung jawab atas status output. Untuk status input, PINX dan PxIN masing-masing mendaftar. Omong-omong, tidak ada fungsi _BV (x) di IDE Energia, jadi tambahkan sendiri:
#define _BV(val) 1<<val
Dalam fungsi void setup () kita mengubah nilai pin input analog menjadi gratis
randomSeed((analogRead(A4) & 0x1F) | (analogRead(A5) << 5));
misalnya pada
randomSeed((analogRead(A0) & 0x1F) | (analogRead(A1) << 5));
Dalam MSP430, input analog A0, A1, A2, ..., A7 sesuai dengan pin P1_0, P1_1, P1_2, ..., P1_7.
Saat menghubungkan perubahan interupsi
attachInterrupt(PPM_pin - 2, ISR_ppm, CHANGE);
pada
attachInterrupt(PPM_pin , ISR_ppm, CHANGE);
Di Arduino Uno, Nano, Mini, dll. Pada mega328, hanya 2 pin (2, 3) yang tersedia untuk menghubungkan interupsi, dan dalam fungsi attachInterrupt, argumen pertama adalah angka interrupt, bukan pin seperti pada MSP430. Lebih lanjut tentang attachInterrupt () .

Timer


Ubah dalam pengaturan yang tidak berlaku ()
TCCR1A = 0;  //reset timer1
TCCR1B = 0;
TCCR1B |= (1 << CS11);  //set timer1 to increment every 1 us @ 8MHz, 0.5 us @16MHz
Aktif
TACTL = TASSEL_2 + ID_3 + MC_2 + TACLR; //16000000 / 8
Pengatur waktu diperlukan untuk menentukan durasi pulsa dalam PPM. Kami mengaturnya ke mode penghitungan langsung dengan frekuensi 2 MHz (frekuensi clock 16 MHz dan pembagi 8).
Dalam fungsi void ISR_ppm () kita berubah
counterPPM = TCNT1;
TCNT1 = 0;
pada
counterPPM = TAR;
TAR = 0;
Register TCNT1 dan TAR adalah penghitung waktu.

acak ()


Saya tidak tahu mengapa, tetapi fungsi acak () tidak dipanggil tanpa argumen di Energia, tetapi karena kami membutuhkan nomor byte tunggal acak, kami mengganti nRF24_multipro.ino dan Bayang.ino dalam file
random() & 0xFF; 
pada
random(0xFF);
dan
random() % 0x42;
pada
random(0x41);

???


Dan akhirnya, dalam file MJX.ino, dalam fungsi void MJX_bind (), kami menambahkan tanda kurung ke pemanggilan fungsi mjx_init2;
Kami menyusun proyek dan mendapatkan kesimpulan yang sukses.

Kode sumber proyek
Mengubah kode proyek

Untuk berhasil mentransfer suatu program ke platform lain, Anda perlu memahami apa, bagaimana dan mengapa itu dieksekusi dalam kode ini, memahami fitur-fitur perpustakaan yang terhubung, tujuan register dan, dalam perjalanan kerja, sering melihat log kompilasi untuk menemukan kesalahan.
Nah, jika Anda melakukan sesuatu yang baik, Anda perlu mentransfer proyek ke lingkungan pengembangan lain, hubungkan SPI perangkat keras dan hanya bekerja dengan register, tetapi ini adalah cerita yang sama sekali berbeda.

Source: https://habr.com/ru/post/id392609/


All Articles