Modbus pada mikrokontroler Rusia K1986BE92QI

Saya jatuh ke tangan mikrokontroler Rusia K1986BE92QI yang diproduksi oleh PKK Milander JSC dengan core RISC 32-bit ARM Cortex-M3 128kB Flash dan 32kB RAM, saya segera ingin belajar dan mengujinya dalam aksi.


Mikrokontroler datang dalam sebuah paket yang membuat iri orang Cina dengan AliExpress. Chip itu terletak di kaset aluminium foil tebal, yang dibungkus kertas foil, diletakkan dengan karet busa, dan seluruh "sandwich" ini dalam kotak kardus dengan dinding bagian dalam ditutupi dengan foil. Secara umum, perlindungan terhadap listrik statis pada ketinggian.




Untuk mikrokontroler adalah label dan protokol pemilihan produk, yang sangat bagus.



Untuk memulainya, perlu mengembangkan diagram sirkuit papan debug dan menentukan komponen. Ia berhenti pada komponen minimum: stabilizer 3.3v untuk daya dari port USB, resonator kuarsa 8MHz, konektor miniUSB, tombol reset, resistor pull-up dan konektor sip. Saya pikir untuk percobaan awal dengan mikrokontroler sudah cukup. Atur juga sakelar smd untuk memilih mode bootloader bawaan. Mikrokontroler memungkinkan Anda untuk memilih metode mengunduh program menggunakan salah satu dari dua antarmuka serial UART atau JTAG / SWD, sementara JTAG memungkinkan Anda untuk men-debug program di mikrokontroler. Pilihan metode pemuatan program ditentukan oleh level logika pada output PF4, PF5, PF6. Semua opsi yang mungkin disajikan dalam tabel:



Mikrokontroler adalah chip yang dibuat dalam wadah plastik LQFP64 dengan pin 0,3 mm dan 0,2 mm di antaranya, yang menunjukkan ketidakmungkinan membuat papan sirkuit tercetak dengan kualitas yang dapat diterima menggunakan teknologi LUT, tetapi pengalaman telah mengkonfirmasi sebaliknya. Dalam beberapa jam, gambar PCB dibuat dalam Sprint Layout, dicetak pada kertas kepadatan tinggi Lamond dan dipindahkan ke fiberglass. Etching terjadi dalam larutan peroksida dan asam sitrat oleh mata dan memakan waktu sekitar satu jam, secara mengejutkan kualitas konduktor dapat diterima pertama kali, yang menyenangkan.



Dan begitu papan dibuat, semua komponen disolder, tetap diprogram. Kami akan menggunakan lingkungan pengembangan dari Keil - MDK ARM uVision 5.0, paket perangkat lunak Standard Peripherals Library + didistribusikan kepadanya oleh pabrikan mikrokontroler. Saya tidak ingin memprogram di UART, jadi saya memutuskan untuk menggunakan programmer / debugger di-sirkuit ST-Link v2, atau lebih tepatnya, klonnya dari produsen Cina yang tidak dikenal. Keil mendukungnya di luar kotak, tetapi mikrokontroler, meskipun dokumentasi mengatakan bahwa ia mendukung antarmuka SWD, lupa bagaimana dan di mana menghubungkannya. Setelah mencari di internet untuk: "JTAG - SWD adapter", ditemukan bahwa jalur SWDIO terhubung ke JTAG-TMS, dan SWCLK ke JTAG-TCK dan "Oh miracle!" Setelah semuanya berhasil, program uji dimasukkan ke dalam mikrokontroler.



Ini adalah akhir dari kegembiraan, karena setelah firmware mikrokontroler, meskipun berfungsi, tampaknya telah berhenti bekerja dengan debugger. Rupanya, setelah flashing, garis port JTAG-A didefinisikan ulang untuk tujuan fungsional lain, meskipun dalam program port B di mana JTAG-A berada bahkan tidak diinisialisasi. Saya tidak ingin mengerti ini, karena ada juga JTAG-B. Ketika terhubung ke antarmuka JTAG alternatif, semuanya bekerja seperti jam. Di masa depan, kami akan menggunakannya untuk pemrograman dan debugging.


Tugas pertama yang saya buat adalah menyambungkan pengontrol ke sistem SCADA menggunakan protokol Modbus. Agar tidak menemukan kembali roda, ambil freemodbus freemodbus cross-platform perpustakaan dan port ke mikrokontroler kami.


Untuk membuat proyek di Keil pada mikrokontroler dari Milander, Anda harus menginstal paket perangkat lunak terlebih dahulu. Ini dilakukan dengan mengklik dua kali pada file. Selanjutnya Keil akan melakukan semuanya sendiri.


Jadi kami membuat proyek baru. Kami memilih komponen mikrokontroler dan perpustakaan yang kami butuhkan:



Di pohon proyek, buat grup Modbus Slave dan tambahkan file berikut dari perpustakaan Freemodbus di sana:



Dan jangan lupa dalam opsi proyek untuk menunjukkan ke kompiler jalur berikut ke direktori perpustakaan.



Sekarang Anda dapat mulai secara khusus mem-port perpustakaan Freemodbus ke mikrokontroler kami menggunakan Perpustakaan Periferal Standar. Untuk melakukan ini, dalam file portserial.c, tulis fungsi inisialisasi port UART xMBPortSerialInit


BOOL xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity ) { //    F RST_CLK_PCLKcmd(RST_CLK_PCLK_PORTF, ENABLE); //      PORT_InitTypeDef uart2_port_set; //   F   UART //     PORT_StructInit(&uart2_port_set); //    uart2_port_set.PORT_FUNC = PORT_FUNC_OVERRID; //    uart2_port_set.PORT_SPEED = PORT_SPEED_MAXFAST; //     uart2_port_set.PORT_MODE = PORT_MODE_DIGITAL; //   PF1  UART_TX () uart2_port_set.PORT_Pin = PORT_Pin_1; uart2_port_set.PORT_OE = PORT_OE_OUT; PORT_Init(MDR_PORTF, &uart2_port_set); //   PF0  UART_RX () uart2_port_set.PORT_Pin = PORT_Pin_0; uart2_port_set.PORT_OE = PORT_OE_IN; //    UART //   UART2 RST_CLK_PCLKcmd(RST_CLK_PCLK_UART2, ENABLE); //      UART UART_InitTypeDef UART_InitStructure; //    UART = 1 UART_BRGInit(MDR_UART2,UART_HCLKdiv1); //  UART //    – 115200  UART_InitStructure.UART_BaudRate = ulBaudRate; //     – 8 UART_InitStructure.UART_WordLength = UART_WordLength8b; //  - UART_InitStructure.UART_StopBits = UART_StopBits1; //    UART_InitStructure.UART_Parity = UART_Parity_No; //    FIFO   , // ..      UART_InitStructure.UART_FIFOMode = UART_FIFO_OFF; //      UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_RXE | UART_HardwareFlowControl_TXE; //  UART2    UART_Init(MDR_UART2, &UART_InitStructure); //   UART UART_Cmd(MDR_UART2, ENABLE); return TRUE; } 

fungsi tulis dan baca:


 BOOL xMBPortSerialPutByte( CHAR ucByte ) { //  UART_SendData(MDR_UART2,ucByte); return TRUE; } BOOL xMBPortSerialGetByte( CHAR * pucByte ) { //  *pucByte = (uint8_t) UART_ReceiveData(MDR_UART2); return TRUE; } 

Penangan interupsi UART


  void USART2_IRQHandler(void) { /*     ---------------------------------------------------*/ if((UART_GetITStatus(MDR_UART2,UART_IT_RX)) != RESET) { prvvUARTRxISR( ); } /*     ------------------------------------------------*/ if((UART_GetITStatus(MDR_UART2,UART_IT_TX)) !=RESET) { prvvUARTTxReadyISR( ); } } 

Setelah ini, kami mengedit file portimer.c di mana timer dikonfigurasi yang menghasilkan laporan sementara untuk melacak akhir paket protokol modbus.


 BOOL xMBPortTimersInit( USHORT usTim1Timerout50us ) { MDR_RST_CLK->PER_CLOCK |= (1<<14); //   TIM1 MDR_RST_CLK->TIM_CLOCK = 0x0; MDR_RST_CLK->TIM_CLOCK |= (1<<24); // TIM1_CLK_EN MDR_RST_CLK->TIM_CLOCK |= 0x07; // HCLK/8   MDR_TIMER1->CNTRL = 0x00000002; //   MDR_TIMER1->CNT = 0x00000000; //  MDR_TIMER1->PSG = 0x2; //f/1   while((MDR_TIMER1->CNTRL & 0x004) != 0) {__NOP();} //    MDR_TIMER1->ARR = usTim1Timerout50us; //     while((MDR_TIMER1->CNTRL & 0x004) != 0) {__NOP();} //     MDR_TIMER1->IE = 0x00000002; //(CNT==ARR)->IE      NVIC->ISER[0] = (1<<14); // Global EN for IRQ14   MDR_TIMER1->CNTRL |= (1<<0); //Timer1 ON   return TRUE; } inline void vMBPortTimersEnable( ) { /*    */ MDR_TIMER1->CNTRL |= (1<<0); //Timer1 ON } inline void vMBPortTimersDisable( ) { /*    */ MDR_TIMER1->CNTRL &= ~(1<<0); //Timer1 OFF } static void prvvTIMERExpiredISR( void ) { ( void )pxMBPortCBTimerExpired( ); } void Timer1_IRQHandler(void) { //   MDR_TIMER1->STATUS &= ~0x002; //IE FLAG=0 prvvTIMERExpiredISR( ); } 

Di main.c kita akan menambahkan fungsi pemrosesan register modbus, kita akan meredam register yang tidak digunakan dengan bertopik


 /* ----------------------- Defines ------------------------------------------*/ #define REG_INPUT_START 1000 #define REG_INPUT_NREGS 4 /* ----------------------- Static variables ---------------------------------*/ static USHORT usRegInputStart = REG_INPUT_START; static USHORT usRegInputBuf[REG_INPUT_NREGS]; eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs ) { eMBErrorCode eStatus = MB_ENOERR; int iRegIndex; if( ( usAddress >= REG_INPUT_START ) && ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) ) { iRegIndex = ( int )( usAddress - usRegInputStart ); while( usNRegs > 0 ) { *pucRegBuffer++ = ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 ); *pucRegBuffer++ = ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF ); iRegIndex++; usNRegs--; } } else { eStatus = MB_ENOREG; } return eStatus; } eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode ) { return MB_ENOREG; } eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode ) { return MB_ENOREG; } eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete ) { return MB_ENOREG; } 

Ini adalah akhir dari porting, tetap hanya dalam fungsi int utama (void) untuk menginisialisasi perpustakaan dan memanggil eMBPoll () dalam satu lingkaran;


 int main (void) { eMBErrorCode eStatus; // UART    ,   portserial.c  xMBPortSerialInit    eStatus = eMBInit( MB_RTU, 0x0A, 0, 19200, MB_PAR_NONE ); /* Enable the Modbus Protocol Stack. */ eStatus = eMBEnable( ); while(1) { eStatus = eMBPoll( ); //  if (eStatus!= MB_ENOREG){}; /* Here we simply count the number of poll cycles. */ usRegInputBuf[0]++; } } 

Kami mengkompilasi semuanya tanpa kesalahan, tetapi tidak ada yang berhasil. Dalam mode debug, kami mengetahui bahwa paket sedang diproses dan program hang pada inisialisasi transmisi. Ketika interupsi dihidupkan dari pemancar UART, interupsi tidak dipanggil, dan program masuk ke loop tak terbatas. Setelah mempelajari bagian "Deskripsi UART" spesifikasi pada mikrokontroler menemukan Catatan:


Gangguan pemancar bekerja di tepi, bukan di level sinyal. Jika modul dan interupsi diizinkan sebelum data ditulis ke buffer FIFO pemancar, interupsi tidak terjadi. Interupsi hanya terjadi ketika buffer FIFO kosong.

Yah, itu tidak masalah, kami mencari di mana transfer dimulai, di file mbrtu.c kami menemukan baris kode


 /* Activate the transmitter. */ eSndState = STATE_TX_XMIT; vMBPortSerialEnable( FALSE, TRUE ); 

dan secara paksa mengirim byte ke pemancar UART, untuk ini kami menambahkan baris: "xMBRTUTransmitFSM ();" dan semuanya mulai berfungsi dengan baik, paket berjalan, register dibaca, dan kemudian itu masalah teknologi.

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


All Articles