Low-capacity STM8 Modbus protocol transplantation and tailoring

Publisher:LianaiLatest update time:2019-11-29 Source: eefocus Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

1. Download freeModbus open source package


Generally, the development environment used by STM8 is IAR, so here we will talk about porting FreeModbus under IAR. 

Download freemodbus-v1.5.0, the official download address is http://www.freemodbus.org/ and find Download 

Write the picture description here

Click freemodbus-v1.5.zip to download. 

Write the picture description here

2. Introduction to freeModbus open source package


Open the folder directory as follows 

Write the picture description here

Then we open the main folder modbus 

Write the picture description here

We can see ascii, functions, include, rtu, tcp and mb.c source files 

Ascii Modbus ascii communication mode related folders, 

Rtu Modbus Rtu communication mode and CRC check related folders, 

Tcp Modbus Tcp communication mode related folders, 

Functions Modbus function related, 

Include Modbus main header files are here, 

Mb.c Modbus's main header file, including initialization functions, poll functions, etc. 

These are all transplanted without modification. The Modbus protocol layer is hardware-independent, so it is abstracted out and a unified soft interface is provided below. 

Next, let's look at the parts that need to be ported. There are many platform examples in the demo for this part. 

Write the picture description here

Let's open it and see that it contains some common platforms, such as Atmel's ARM processor, AVR microcontroller 

TI's Msp430 microcontroller, Liunx, platforms under Windows operating system, etc., but there is no interface for the STM8 processor we want. 

Write the picture description here

But we can follow the same pattern and port it to other platforms. Here we open the directory under AVR and look at the files under the port folder. These are the files we want to port, including portserial.c related to the serial port driver, porttimer.c related to the timer driver, and port.c related to the main interrupt (this directory is not there, we add it in), etc. 

Write the picture description here

3. Import project


After analyzing the FreeModbus folder, we start the porting work 

First, create a project in IAR, copy the Modbus folder to the directory under the project, and copy the port folder to the Modbus directory. As shown in the figure below 

Write the picture description here

Port is in the directory under the modbus folder 

Write the picture description here

Then create a new Modbus group in the project 

Write the picture description here

Then add the header file path under the project options menu, where PROJDIRPROJDIR is the current project directory 

 Write the picture description here 

After completing the above steps, we start to rewrite the hardware driver, which is mainly divided into three parts:


3.1 Hardware Device Driver Porting


3.1.1 Serial port analysis and transplantation


Open portserial.c and improve the following functions 

Void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable ); 

BOOL xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity ); 

BOOL xMBPortSerialPutByte( CHAR ucByte ); 

BOOL xMBPortSerialGetByte( CHAR * pucByte ); 

As well as the serial port receive interrupt service function and the serial port send completion interrupt service function. 

First is Void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable ); This function mainly enables the interrupts of serial port sending and receiving. The first parameter of the function is the receive enable Boolean parameter, and the second is the transmit enable Boolean parameter. When xRxEnable is true, the serial port receive interrupt is turned on, and when it is false, the serial port receive interrupt is turned off; the same is true for sending. In order to save the limited storage space of low-capacity processors, our subsequent operations on microcontroller related resources are all in the register mode, so let's first look at the STM8 register manual, 

Write the picture description here 
Write the picture description here 

It can be clearly found that the 5th and 6th bits of the UART1_CR2 register are used to control the serial port receive interrupt and the serial port send completion interrupt. Here we only need to set these two bits high and low to achieve the corresponding enable and disable functions. So here our code


void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable ) //Control the serial port's transmit and receive interrupts

{

    if(xRxEnable==TRUE)

    {

            UART1_CR2|=(1<<5);

    }

    else

    {

            UART1_CR2&=~(1<<5);

    }


    if(xTxEnable==TRUE)

    {

            UART1_CR2|=(1<<6);

    }

    else

    {

           UART1_CR2&=~(1<<6);

    }

}


Then comes the implementation of the BOOL xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity ) function. 

Look at the function parameters, the first is the port, the second is the baud rate, the third is the data bit, and the fourth is the check method 

Because the STM8103F3C6 used in this experiment has only one Uart serial port, the first parameter does not need to be implemented. 

The second parameter is the baud rate. We can look at the register manual of the microcontroller. 

Write the picture description here 
Write the picture description here

The baud rate setting is determined by the ratio of the clock to the baud rate divider. By looking at the registers, it is easy to find that the baud rate ratio is composed of two 8-bit registers, but the register arrangement is not in the general data storage method. UART_BRR1 is the 4th to 11th bit data of the baud rate divider coefficient, the lower four bits of UART_BRR2 are the fourth bit of the baud rate divider coefficient, and the upper four bits of UART_BRR2 are the 12th to 15th bits of the baud rate divider coefficient. So here we need to convert 

UART1_BRR2 = div & 0x0f; 

UART1_BRR2 |= ((div & 0xf000) >> 8); 

UART1_BRR1 = ((div & 0x0ff0) >> 4); 

Div is the baud rate division factor 

Then ulBaudRate = f/Div; (f is the system clock). 

Next, we analyze the third parameter, the data bit. As shown in the figure below, the 4th bit of the UART_CR1 register, when 0, is a start bit, 8 

Write the picture description here

Data bit, n stop bits, the stop bit here needs to be set through the UART_CR3 register; when it is 1, it is a start bit, 9 data bits, and a stop bit. Then we analyze the UART_CR3 register 

Write the picture description here 

By checking the register, we found that there are three types of stop bits: 1, 1.5, and 2. In general applications, we use one stop bit, so we can just keep the default value. So the code can be


if(ucDataBits == 8)

{

   UART1_CR1&=~(1<<4);

}else

{

   UART1_CR1|=(1<<4);

}


Finally, let's look at the implementation of the serial port parity check parameters and check the register UART1_CR1 

Write the picture description here

The first bit PS parity check selection, when it is 0, it is even check; when it is 1, it is odd check. 

The second parity check enable bit, when it is 0, disables the check; when it is 1, enables the check. 

Before these codes, please note the parameter eMBParity eParity, which is an enumeration type variable. Look at the definition 

Write the picture description here 

So the code is


switch(eParity)

{

    case MB_PAR_NONE:

        UART1_CR1&=~(1<<2);

        break;

    case MB_PAR_ODD: 

        UART1_CR1|=(1<<2);

        UART1_CR1|=(1<<1);

        break;

    case MB_PAR_EVEN:

        UART1_CR1|=(1<<2);

        UART1_CR1&=~(1<<1);

        break;

    default:break;

}


So far, the main functions of the serial port are basically implemented, and there is BOOL xMBPortSerialPutByte( CHAR ucByte ); 

BOOL xMBPortSerialGetByte( CHAR * pucByte ) is mainly used for writing and reading data, that is, directly reading and writing UART_DR.


BOOL xMBPortSerialPutByte( CHAR ucByte )

{

    while((UART1_SR & 0x80)==0x00);

      UART1_DR=ucByte;

    return TRUE;

}


//Serial port receiving

BOOL xMBPortSerialGetByte( CHAR * pucByte )

{


    *pucByte = UART1_DR;

    return TRUE;

}


3.1.2 Interrupt Analysis and Migration


In addition, we also need to process two interrupt service functions.


/* Create an interrupt handler for the transmit buffer empty interrupt

 * (or an equivalent) for your target processor. This function should then

 * call pxMBFrameCBTransmitterEmpty() which tells the protocol stack that

 * a new character can be sent. The protocol stack will then call 

 * xMBPortSerialPutByte() to send the character.

 */

 void prvvUARTTxReadyISR( void )

{

    pxMBFrameCBTransmitterEmpty() ;

}


/* Create an interrupt handler for the receive interrupt for your target

 * processor. This function should then call pxMBFrameCBByteReceived() . The

 * The protocol stack will then call xMBPortSerialGetByte() to retrieve the

 * character.

 */

void prvvUARTRxISR( void )

{

     pxMBFrameCBByteReceived() ;

}


//Send the received data again

#pragma vector = UART1_R_RXNE_vector

__interrupt void UART1_R_RXNE_IRQHandler(void)

{


      if(UART1_SR&(1<<3))

      {

       //UART1_SR&=~(1<<3);

      }

      else

      {

        prvvUARTRxISR(); //Accept interrupt


        //UART1_SR&=~(1<<5);

      }


      return;

}


//Send the received data again

#pragma vector = UART1_T_TC_vector

__interrupt void UART1_T_TC_IRQHandler(void)

{


      prvvUARTTxReadyISR(); //Send completion interrupt

      //UART1_SR&=~(1<<6);


      return;

}


3.1.3 Timer Analysis and Transplantation


Next, we will start porting the timer. The register function setting of the timer is similar to the serial port register setting explained above, so we will only comment the code appropriately. I believe that everyone can understand it easily. The porting of the timer mainly involves the porting of the registers in porttimer.c. 

BOOL xMBPortTimersInit( USHORT usTim1Timerout50us ); 

void vMBPortTimersEnable( ); 

void vMBPortTimersDisable( ); 

prvvTIMERExpiredISR(); callback function 

xMBPortTimersInit( USHORT usTim1Timerout50us ); is mainly a 50us time base, which is used to generate and judge 1.5-3.5 character times as the end standard for generating and judging data frames. Then, to generate a 50us time base, we can use timer frequency division. First, 1/50us is converted into a frequency of 20kHz, that is, when the counter frequency of the timer is 20kHz, the time required for each increase or decrease of the counter is 50us. Therefore, our frequency division coefficient is 8MHz/20KHz = 400; and the USHORT usTim1Timerout50us parameter is the number of 50us,


    /* Set the Prescaler value */

    TIM1_PSCRH = (unsigned char)((period >> 8)&0xff);

    TIM1_PSCRL = (unsigned char)(period&0xff);


    usTim1Timerout50us = usTim1Timerout50us-1;

[1] [2]
Reference address:Low-capacity STM8 Modbus protocol transplantation and tailoring

Previous article:STM32 is set as I2C slave
Next article:STM8S003 MCU serial port reception conflicts with ADC settings

Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号