مودبوس على متحكم الروسي K1986BE92QI

لقد وقعت في يد متحكم روسي K1986BE92QI من تصنيع PKK Milander JSC مع ARIS Cortex-M3 128kB Flash و 32 كيلو بايت من ذاكرة RISC الأساسية ، وأردت على الفور دراسته واختباره في العمل.


متحكم يأتي في الحزمة التي الحسد الصيني مع AliExpress. تقع الرقاقة في كاسيت من رقائق الألمنيوم السميك ، والملفوفة بورق فويل ، ومغطاة بمطاط رغوي ، وكل هذا "شطيرة" كاملة في صندوق من الورق المقوى مع جدران داخلية مغطاة برقائق. بشكل عام ، وحماية ضد الكهرباء الساكنة في الارتفاع.




إلى متحكم هو تسمية وبروتوكول اختيار المنتج ، وهو لطيف جدا.



بادئ ذي بدء ، كان من الضروري تطوير رسم تخطيطي للوحة لوحة التصحيح وتحديد المكونات. لقد توقف عند الحد الأدنى من المكونات: عامل استقرار 3.3 فولت للحصول على الطاقة من منفذ USB ، مرنان كوارتز 8 ميجا هرتز ، موصل miniUSB ، زر إعادة الضبط ، مقاومات قابلة للسحب وموصلات رشفة. أعتقد أن التجارب الأولية مع المتحكم كافية. قم أيضًا بتعيين مفتاح smd لتحديد وضع أداة تحميل التشغيل المدمجة. يسمح لك المتحكم الدقيق باختيار طريقة تنزيل البرنامج باستخدام واحدة من واجهات تسلسلية UART أو JTAG / SWD ، بينما يتيح لك JTAG تصحيح البرنامج في المتحكم الدقيق. يتم تحديد اختيار طريقة تحميل البرنامج من خلال المستويات المنطقية في المخرجات PF4 ، PF5 ، PF6. يتم عرض جميع الخيارات الممكنة في الجدول:



المتحكم الدقيق عبارة عن شريحة مصنوعة في علبة بلاستيكية LQFP64 مع دبابيس بعرض 0.3 مم و 0.2 مم بينهما ، مما يشير إلى استحالة إنشاء لوحة دوائر مطبوعة بجودة مقبولة باستخدام تقنية LUT ، لكن التجربة أكدت العكس. في غضون ساعتين ، تم عمل رسم ثنائي الفينيل متعدد الكلور في Sprint Layout ، مطبوع على ورق لاموند عالي الكثافة ونقل إلى الألياف الزجاجية. حدث النقش في محلول بيروكسيد وحمض الستريك لكل عين واستغرق حوالي ساعة ، ومن المثير للدهشة أن جودة الموصلات كانت مقبولة في المرة الأولى ، مما يسر.



وهكذا يتم إنشاء لوحة ، ملحوم جميع المكونات ، لا يزال البرنامج. سوف نستخدم بيئة التطوير من Keil - MDK ARM uVision 5.0 ، يتم توزيع حزمة البرامج Standard Peripherals Library + عليها من قبل الشركة المصنعة للتحكم الدقيق. لم أكن أرغب في البرمجة في UART ، لذلك قررت استخدام مبرمج / مصحح الأخطاء ST-Link v2 داخل الدائرة ، أو بالأحرى ، استنساخه من مصنع صيني غير معروف. يدعمها Keil خارج الصندوق ، لكن المتحكم الدقيق ، على الرغم من أن الوثائق تشير إلى أنه يدعم واجهة SWD ، نسي كيف وأين يتم توصيله. بعد البحث في الإنترنت عن: "محول JTAG - SWD" ، وجد أن خط SWDIO يتصل بـ JTAG-TMS ، و SWCLK إلى JTAG-TCK و "يا معجزة!" كل شيء يعمل ، تم اختبار برنامج اختبار في متحكم.



كانت هذه هي نهاية الفرح ، لأنه بعد البرنامج الثابت ، يبدو أن المتحكم الدقيق ، رغم أنه نجح ، توقف عن العمل مع المصحح. على ما يبدو ، بعد وميض ، يتم إعادة تعريف خطوط منفذ JTAG-A لغرض وظيفي آخر ، على الرغم من أنه لم يتم تهيئة منفذ المنفذ B الذي يوجد عليه JTAG-A. لم أكن أريد أن أفهم هذا ، نظرًا لوجود JTAG-B أيضًا. عند الاتصال بواجهة JTAG بديلة ، كان كل شيء يعمل على مدار الساعة. في المستقبل ، سوف نستخدمها للبرمجة وتصحيح الأخطاء.


كانت المهمة الأولى التي تم تعيينها بنفسي هي توصيل جهاز التحكم بنظام SCADA باستخدام بروتوكول Modbus. لكي لا نعيد اختراع العجلة ، نأخذ مكتبة freemodbus freemodbus عبر منصة ونضعها في وحدة التحكم الصغيرة الخاصة بنا.


لإنشاء مشاريع في Keil على متحكم دقيق من Milander ، تحتاج أولاً إلى تثبيت حزمة البرامج. يتم ذلك عن طريق النقر المزدوج البسيط على الملف. كايل المقبل سوف تفعل كل شيء بنفسها.


وهكذا نقوم بإنشاء مشروع جديد. نختار عناصر متحكم ومكتبتنا التي نحتاجها:



في شجرة المشروع ، أنشئ مجموعة Modbus Slave وأضف الملفات التالية من مكتبة Freemodbus هناك:



ولا تنس في خيارات المشروع أن تشير إلى المترجم المسارات التالية إلى أدلة المكتبة.



الآن يمكنك البدء في نقل مكتبة Freemodbus على وجه التحديد إلى متحكمنا باستخدام مكتبة الأجهزة الطرفية القياسية. للقيام بذلك ، تحتاج إلى تحديد وظيفة التهيئة لمنفذ UART xMBPortSerialInit في ملف porterial.c


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; } 

وظيفة الكتابة والقراءة:


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

معالج المقاطعة 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( ); } } 

بعد ذلك ، نقوم بتحرير ملف portimer.c الذي يتم فيه تكوين جهاز ضبط وقت يولد تقارير مؤقتة لتتبع نهاية حزمة بروتوكول 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( ); } 

في main.c سنقوم بإضافة وظائف معالجة سجل modbus ، وسنقوم بإخطار السجلات غير المستخدمة بالعبث


 /* ----------------------- 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; } 

هذا هو نهاية النقل ، يبقى فقط في الدالة int main (void) لتهيئة المكتبة واستدعاء eMBPoll () في حلقة ؛


 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]++; } } 

نحن نجمع كل شيء دون أخطاء ، لكن لا شيء يعمل. في وضع التصحيح ، اكتشفنا أن الحزم تتم معالجتها وأن البرنامج معلق على تهيئة الإرسال. عند تشغيل المقاطعة من جهاز إرسال UART ، لا يتم استدعاء المقاطعة وينتقل البرنامج إلى حلقة لا نهائية. بعد دراسة قسم "وصف UART" المواصفات على متحكم جاء عبر ملاحظة:


يعمل انقطاع المرسل على الحافة ، وليس على مستوى الإشارة. إذا تم السماح للوحدة النمطية والمقاطعات منه قبل كتابة البيانات إلى المخزن المؤقت FIFO للمرسل ، لا يتم إنشاء مقاطعة. تحدث المقاطعة فقط عندما يكون المخزن المؤقت FIFO فارغاً.

حسنًا ، لا يهم ، نحن نبحث عن مكان بدء النقل ، في ملف mbrtu.c ، نجد سطور الكود


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

وأرسل البايت بالقوة إلى جهاز إرسال UART ، ولهذا نضيف السطر: "xMBRTUTransmitFSM ()؛" وكل شيء يبدأ في العمل بشكل جيد ، وتشغيل الحزم ، وقراءة السجلات ، ومن ثم فهي مسألة تقنية.

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


All Articles