Fórum témák

» Több friss téma
Fórum » 8051 Kontroller MODBUS RTU implementáció
Lapozás: OK   1 / 1
(#) Zekageri hozzászólása Dec 3, 2019 /
 
Sziasztok!
Egy 8051-es családból származó kontrollert szeretnék MODBUS RTU SLAVE-é tenni.

A projekt lényege:

Egy esp32-höz szeretnék több I/O expandert csinálni.
Ehhez ezt a chipet választottam : EFM8UB20F64G-B-QFP48R
Itt az adatlap


Nem használhatok sem i2c-t sem SPI-t egyéb okok miatt, szóval egy modbus protokollra esett a választás. Ez a chip tökéletes lenne a feladatra, sok lába van, van UARTja és saját oszcija stb.
Nos hogy ezt elérjem kénytelen vagyok írni embedded C-ben egy modbus slave protokollt erre a chipre. Még nincs kéznél a kontroller szóval félig meddig vaktában tapogatózom de meg szeretném írni mielőtt ide ér és össze rakom.
Nagyon új nekem a C nyelv és a bit műveletek meg ilyesmik hiszen eddig arduinoban programoztam.
Az esp oldalról nem lesz gond mivel van modbus rtu lib és ott már ki tudom egészíteni ahogy kedvem tartja.
A lényeg hogyha valaki tudna nekem segíteni ebben egy pár szóval vagy jó tanáccsal vagy rá tudna nézni a kódra annak nagyon örülnék.

Amit eddig írtam az efm8ub2-re az így néz ki:

Main:

  1. #include <SI_EFM8UB2_Register_Enums.h>
  2. #include "retargetserial.h"
  3. #include "InitDevice.h"
  4.  
  5. uint8_t UART_Buffer_Size = 0;
  6. uint8_t TX_Ready =1;
  7. bool Can_Check_MSG = false;
  8. char Byte;
  9. extern void Check_Message();
  10.  
  11. void SiLabs_Startup (void)
  12. {
  13.         PCA0CPH4 = 0x00;                                                // Disable the watchdog
  14. }
  15.  
  16. SI_INTERRUPT(TIMER0_ISR, TIMER0_IRQn)           // Timer interrupt fired, data transfer end.
  17. {
  18.         Can_Check_MSG = true;
  19. }
  20.  
  21. void Check_Timeout(){
  22.         if(Can_Check_MSG){
  23.                 Can_Check_MSG = false;
  24.                 TX_Ready = 0;
  25.                 Check_Message();                                        // Get the whole message and brake it into pieces
  26.         }
  27. }
  28.  
  29. void main (void)
  30. {
  31.    enter_DefaultMode_from_RESET();
  32.  
  33.    while(1)
  34.    {
  35.            Check_Timeout();
  36.    }
  37. }


UART Interrupt és modbus egyebek:

  1. #include <SI_EFM8UB2_Register_Enums.h>
  2.  
  3. #define UART_BUFFERSIZE 64
  4.  
  5. /* Supported function codes */
  6. #define _READ_SINGLE_REGISTER   0x04
  7. #define _SET_SINGLE_REGISTER    0x06
  8.  
  9. /** TIMER INTERRUPT INIT **/
  10. #define SYSCLK             12000000/8           // SYSCLK in Hz (12 MHz internal oscillator / 8) the internal oscillator has a tolerance of +/- 2%
  11. #define TIMER_PRESCALER            48           // Based on Timer CKCON0 settings
  12. #define TOGGLE_RATE                2            // toggle rate in milliseconds if TOGGLE_RATE = 1, It will trigger an interrupt in 1millisec.
  13. // There are SYSCLK/TIMER_PRESCALER timer ticks per second, so
  14. // SYSCLK/TIMER_PRESCALER/1000 timer ticks per millisecond.
  15. #define TIMER_TICKS_PER_MS  SYSCLK/TIMER_PRESCALER/1000
  16.  
  17. // Note: TOGGLE_RATE*TIMER_TICKS_PER_MS should not exceed 65535 (0xFFFF)for the 16-bit timer
  18. #define AUX1     TIMER_TICKS_PER_MS*TOGGLE_RATE
  19. #define AUX2     -AUX1
  20. #define AUX3     AUX2&0x00FF
  21. #define AUX4     ((AUX2&0xFF00)>>8)
  22.  
  23. #define TIMER0_RELOAD_HIGH       AUX4           // Reload value for Timer0 high byte
  24. #define TIMER0_RELOAD_LOW        AUX3           // Reload value for Timer0 low byte
  25. /** TIMER INTERRUPT INIT **/
  26.  
  27. uint8_t UART_Buffer[UART_BUFFERSIZE];
  28. uint8_t UART_Input_First;
  29. uint8_t UART_Output_First;
  30. uint8_t Register_Response;
  31.  
  32. char Chip_Address;
  33.  
  34. extern uint8_t UART_Buffer_Size;
  35. extern uint8_t TX_Ready;
  36. extern char Byte;
  37.  
  38. bool CrC_is_Error       = false;
  39. bool IO_Toggled         = false;
  40. bool IO_Status          = false;
  41.  
  42.  
  43. void ReLoad_Timeout_Time(){
  44.         TH0 = TIMER0_RELOAD_HIGH;               // Reinit Timer0 High register
  45.         TL0 = TIMER0_RELOAD_LOW;                // Reinit Timer0 Low register
  46. }
  47.  
  48. void Generate_Toggled_MSG(uint8_t Address,uint8_t Code,uint8_t Data1,uint8_t Data2,uint8_t Crc1,uint8_t Crc2,int i){
  49.         IO_Toggled = false;
  50.                         // GPIO Toggled message
  51.         for(i = 0;i<UART_Buffer_Size;i++){
  52.                 if(i < 1){
  53.                         UART_Buffer[i] = Address;
  54.                 }else if(i < 2){
  55.                         UART_Buffer[i] = Code;
  56.                 }else if(i < 3){
  57.                         UART_Buffer[i] = Data1;
  58.                 }else if(i < 4){
  59.                         UART_Buffer[i] = Data2;
  60.                 }else if(i < 5){
  61.                         UART_Buffer[i] = Crc1;
  62.                 }else if(i < 6){
  63.                         UART_Buffer[i] = Crc2;
  64.                 }else{
  65.                         break;
  66.                 }
  67.         }
  68. }
  69. void Generate_IO_Status_MSG(uint8_t Address,uint8_t Code,uint8_t Crc1,uint8_t Crc2,int i){
  70.         IO_Status = false;
  71.                         // GPIO Status message
  72.         for(i = 0;i<UART_Buffer_Size;i++){
  73.                 if(i < 1){
  74.                         UART_Buffer[i] = Address;
  75.                 }else if(i < 2){
  76.                         UART_Buffer[i] = Code;
  77.                 }else if(i < 4){
  78.                         UART_Buffer[i] = Register_Response;
  79.                 }else if(i < 5){
  80.                         UART_Buffer[i] = Crc1;
  81.                 }else if(i < 6){
  82.                         UART_Buffer[i] = Crc2;
  83.                 }else{
  84.                         break;
  85.                 }
  86.         }
  87. }
  88.  
  89. void Generate_Crc_Error_MSG(){
  90.         CrC_is_Error = false;
  91.         /** WE DONT NEED THIS?! o_O */
  92. }
  93. static void DO_Request_Message(uint8_t Address,uint8_t Code,uint8_t Data1,uint8_t Data2,uint8_t Crc1,uint8_t Crc2){
  94.         // I have to do a request message based on the things i do?
  95.         int i = 0;
  96.         if(CrC_is_Error){
  97.                 Generate_Crc_Error_MSG();
  98.         }else if(IO_Toggled){
  99.                 Generate_Toggled_MSG(Address,Code,Data1,Data2,Crc1,Crc2,i);
  100.         }else if(IO_Status){
  101.                 Generate_IO_Status_MSG(Address,Code,Crc1,Crc2,i);
  102.         }
  103.         SCON0_TI = 1;
  104. }
  105.  
  106. static void Check_GPIO_Status(uint8_t *Data){
  107.         switch(Data[0]){
  108.                 case 1:
  109.                         Register_Response = P1;
  110.                         break;
  111.                 case 2:
  112.                         Register_Response = P2;
  113.                         break;
  114.                 case 3:
  115.                         Register_Response = P3;
  116.                         break;
  117.                 default:
  118.                         /* NO DEFAULT OPERATION */
  119.                         break;
  120.                 }
  121.         IO_Status = true;
  122. }
  123.  
  124. static void Toggle_IO_Pins(uint8_t *Data){              // Need to toggle the I/O pins based on the master request
  125.         switch(Data[0]){
  126.                 case 1:
  127.                         P1 = Data[1];
  128.                         break;
  129.                 case 2:
  130.                         P2 = Data[1];
  131.                         break;
  132.                 case 3:
  133.                         P3 = Data[1];
  134.                         break;
  135.                 default:
  136.                         /* NO DEFAULT OPERATION */
  137.                         break;
  138.         }
  139.         IO_Toggled = true;
  140. }
  141.  
  142. static int Check_Chip_Address(uint8_t Msg_Address){             // ADRESS BASED ON THE P0.1-P0.4 GPIOS
  143.         uint8_t Chip_Address = P0;
  144.         if(Chip_Address == Msg_Address){
  145.                 return 1;
  146.         }else{
  147.                 return -1;
  148.         }
  149. }
  150.  
  151. static uint16_t Crc_Check(uint8_t *req, uint8_t req_length)
  152. {
  153.     uint8_t j;
  154.     uint16_t crc;
  155.     crc = 0xFFFF;
  156.     while (req_length--) {
  157.         crc = crc ^ *req++;
  158.         for (j = 0; j < 8; j++) {
  159.             if (crc & 0x0001)
  160.                 crc = (crc >> 1) ^ 0xA001;
  161.             else
  162.                 crc = crc >> 1;
  163.         }
  164.     }
  165.     return (crc << 8 | crc >> 8);
  166. }
  167.  
  168. static int check_integrity(uint8_t *msg, uint8_t msg_length)
  169. {
  170.     uint16_t crc_calculated;
  171.     uint16_t crc_received;
  172.     if (msg_length < 2)
  173.         return -1;
  174.     crc_calculated = Crc_Check(msg, msg_length - 2);
  175.     crc_received = (msg[msg_length - 2] << 8) | msg[msg_length - 1];
  176.     /* Check CRC of msg */
  177.     if (crc_calculated == crc_received) {
  178.         return msg_length;
  179.     } else {
  180.         return -1;
  181.     }
  182. }
  183.  
  184. void Check_Message(){
  185.         uint8_t Address,Code;
  186.         uint8_t Data[2];
  187.         uint8_t Crc[2];
  188.         int k = 0;
  189.         int i = 0;
  190.         // Get the whole message in separate variables for further analization
  191.         for(i = 0; i < UART_Input_First;i++){
  192.                 if (i < 1){
  193.                         Address = UART_Buffer[i];
  194.                 }
  195.                 else if (i < 2){
  196.                         Code = UART_Buffer[i];
  197.                 }
  198.                 else if (i <= 3){
  199.                         if(i < 3){
  200.                                 Data[0] = UART_Buffer[i];
  201.                         }else{
  202.                                 Data[1] = UART_Buffer[i];
  203.                         }
  204.                 }else if (i >= 4){
  205.                         Crc[k] = UART_Buffer[i];
  206.                         k++;
  207.                 }
  208.         }
  209.         // Checking the separated variables
  210.         if(Check_Chip_Address(Address) != -1){                                  // Check if Message is ours.
  211.                 if(check_integrity(Crc,UART_Buffer_Size) != -1){        // Check if no errors on crc
  212.                         CrC_is_Error = false;
  213.                         if(Code == _READ_SINGLE_REGISTER){
  214.                                 /** MASTER WANTS TO READ THE GPIOS **/
  215.                                 Check_GPIO_Status(Data);
  216.                         }else if(Code == _SET_SINGLE_REGISTER){
  217.                                 /** MASTER WANTS TO TOGGLE THE GPIOS **/
  218.                                 Toggle_IO_Pins(Data);
  219.                         }
  220.                 }else{
  221.                         CrC_is_Error = true;
  222.                 }
  223.                 DO_Request_Message(Address,Code,Data[0],Data[1],Crc[0],Crc[1]);
  224.         }
  225. }
  226.  
  227. //-----------------------------------------------------------------------------
  228. //
  229. // UART0 ISR Content goes here. Remember to clear flag bits:
  230. // SCON0::RI (Receive Interrupt Flag)
  231. // SCON0::TI (Transmit Interrupt Flag)
  232. //
  233. //-----------------------------------------------------------------------------
  234. SI_INTERRUPT(UART0_ISR, UART0_IRQn)
  235. {
  236.    if (SCON0_RI == 1)
  237.    {
  238.       if( UART_Buffer_Size == 0){                       // If new word is entered
  239.          UART_Input_First = 0;
  240.       }
  241.       ReLoad_Timeout_Time();
  242.       SCON0_RI = 0;                             // Clear interrupt flag
  243.       Byte = SBUF0;                                     // Read a character from UART
  244.       //if (UART_Buffer_Size < UART_BUFFERSIZE)
  245.       //{
  246.          UART_Buffer[UART_Input_First] = Byte;  // Store in array
  247.          UART_Buffer_Size++;                            // Update array's size
  248.          UART_Input_First++;                            // Update counter
  249.       //}
  250.    }
  251.  
  252.  
  253. //-----------------------------------------------------------------------------
  254. //                                                      ECHO BACK THE MESSAGE
  255. //-----------------------------------------------------------------------------
  256.  
  257.    if (SCON0_TI == 1)                                   // Check if transmit flag is set
  258.    {
  259.       SCON0_TI = 0;                             // Clear interrupt flag
  260.       if (UART_Buffer_Size != 1)                        // If buffer not empty
  261.       {
  262.          // If a new word is being output
  263.          if ( UART_Buffer_Size == UART_Input_First ) {
  264.               UART_Output_First = 0;  }
  265.          // Store a character in the variable byte
  266.          Byte = UART_Buffer[UART_Output_First];
  267.          SBUF0 = Byte;                                  // Transmit to Hyperterminal
  268.          UART_Output_First++;                           // Update counter
  269.          UART_Buffer_Size--;                            // Decrease array size
  270.       }
  271.       else
  272.       {
  273.          UART_Buffer_Size = 0;                          // Set the array size to 0
  274.          TX_Ready = 1;                                  // Indicate transmission complete
  275.       }
  276.    }
  277. }


A program eddig a fejemben:

Megkapom az UART interruptot, tehát jött adat.
Elkezdtem kiszedni egyesével az uartból byteonként az adatot egy bufferbe.
Ha az adatok közötti idő nem haladja meg a 2msecet akkor szedem ki továbbra is.
Ha meghaladta akkor úgy veszem hogy vége az adatfolyamnak, tehát átjött az összes.
Megnézem az adatot, szétszedem darabokra ahogy a modbus kéri.
Address, Funkció Kód, Adat, CRC.
Ha az address a minék ( amit egy kapcsolón lehet majd beállítani fizikailag a port0-n lévő első 4 biten)
Akkor megnézem a CRC-t. ( A crc error check kódot egy fórumról szedtem ).
Ha jó a crc kiszedem a funkció kódot, és az alapján nézem meg az adatot.
Ha a funkció kód 0x04 akkor _READ_SINGLE_REGISTER ha pedig 0x06 akkor _SET_SINGLE_REGISTER.

Köszönöm előre is!
(#) Zekageri válasza Zekageri hozzászólására (») Dec 3, 2019 /
 
Amit még elfelejtettem:
Az IDE amiben programozom az a Simplicity Studio.
Ezen belül felhasználtam az UART0 példa programot ami echozza a karaktereket a serialra amit beütöttem. A baud rate-t nem igazán jöttem rá hogy hogyan kell beállítani, de ha jól olvastam akkor a default az 115200, ami pont jó is az esp-hez.
(#) vargham válasza Zekageri hozzászólására (») Jan 8, 2020 /
 
Idézet:
„Ehhez ezt a chipet választottam : EFM8UB20F64G-B-QFP48R”

Miért pont ezt? Mik voltak a szempontok?
I2C, SPI miért lett kizárva?
Következő: »»   1 / 1
Bejelentkezés

Belépés

Hirdetés
XDT.hu
Az oldalon sütiket használunk a helyes működéshez. Bővebb információt az adatvédelmi szabályzatban olvashatsz. Megértettem