Implementation of embedded UART communication based on Lua scripting language

Publisher:lidong4069Latest update time:2012-05-07 Source: eefocus Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

introduction

With the gradual improvement of the intelligence level of substations, there is an increasing demand for the collection of field status parameters such as temperature and humidity. At present, in field applications, such devices mostly use UART serial communication methods such as RS232 or RS485 to interact with IED (Intelligent Electronic Device) devices. Generally speaking, different devices use different communication data frame formats. Various serial port data frame formats cause certain difficulties in the software finalization of IED devices. The traditional approach is generally for the device manufacturer to specify the peripheral equipment that matches it, and the flexibility of the device is not ideal. In response to such problems, this paper proposes a solution based on the Lua scripting language, which can effectively improve the adaptability of IED devices to various types of serial port data message frame formats. This solution entrusts the construction and parsing of specific serial port message protocols to Lua scripts for processing, so that designers can only focus on the design of related interfaces in the software development of the device without worrying about the specific serial port communication protocol, thereby facilitating the finalization of the software and improving the flexibility of the device itself in application.

1 Introduction to Lua scripting language

Lua is an open-source, free, lightweight embedded scripting language, and its source code is completely in ANSI (ISO) C. This makes it very suitable for integration into the current embedded development environment dominated by C language. The key to the interaction between the two is a virtual stack. Through the virtual stack and the related interface functions provided by Lua that can operate on the stack, various types of data can be easily transferred between them.

Compared with other scripting languages ​​(such as Perl, Tcl, Python, etc.), Lua has shown sufficient simplicity and very high execution efficiency. Combined with its high platform independence and sufficient scalability [1], it has attracted more and more attention. Therefore, Lua scripts are preferred for design in this paper.

2 System Solution Overview

This solution is mainly designed around the communication between the IED device and the peripheral serial port equipment. The system framework is shown in Figure 1.

Figure 1 System Framework

When the IED device starts running, a read-write scheduling task for UART communication will be created. In this task, the script engine is first started through the interface function provided by Lua, and a Lua virtual machine is created. Then the C function written by the user can be registered in the Lua virtual machine, and the Lua script file that exists in the Flash file system and is independent of the device C program can be loaded into the virtual machine, thereby establishing an interactive environment between Lua and C. In system applications, the specific data content that needs to be sent to the peripheral device is placed in the Lua script file. When the device C program needs to send data, this part of the data is taken out through the cooperation of the communication read-write scheduling program and the virtual machine, and the serial port driver is called to send it to the peripheral device. When the message sent by the peripheral device to the IED device is received, the corresponding data is passed to the script program running in the virtual machine for processing, and Lua calls the registered C function according to the data processing results to perform related business processing.

Figure 2 System program flow

The program flow of this system is shown in Figure 2.

The serial communication chip is implemented using TI's 4-channel programmable UART chip TL16C754B with 64-byte FIFO. Its 4 channels can be programmed independently. At an operating voltage of 3.3 V, the data transmission rate can be as high as 2 Mbps, which is suitable for applications in a variety of UART communication environments [2]. Based on the application environment of the device, this paper adopts the RS485 question-and-answer mechanism and combines it with the query method to design the serial communication solution. In the implementation of the solution, the device will send a query message through the serial port chip at regular intervals. When the correct response message sent by the peripheral device is queried, the relevant business processing will be carried out.

3 Function Implementation

In the field of embedded applications, the application of serial communication is relatively mature, so this article will focus on how Lua serves this application. As can be seen from Figure 2, the use of Lua is mainly reflected in the following aspects:

◆ Establishment of Lua and C interactive environment;

◆ Extract the serial port configuration data in the script;

◆ Call Lua function to set the send buffer;

◆ Process the received buffer data through Lua functions.

3.1 Establishing the interactive environment between Lua and C

To establish an interactive environment, you must first start the Lua script engine and create a virtual machine. Although its mechanism is relatively complex, it is relatively simple for applications and can be achieved through "L = lua_open (NULL);". Among them, L is a pointer variable pointing to the structure type lua_State, which will be responsible for maintaining the running state of Lua. [page]

In order to enable Lua script functions to access the data in the serial port send and receive buffers in the system program, several C functions are defined for script calls, namely, the function set_tx_buf for setting the serial port send buffer, the function get_rx_buf for reading the serial port receive buffer, and the result processing function uart_ok_del, which is called when the Lua script determines that the serial port data interaction is normal.

In Lua script, to successfully call the above functions, they must be loaded into the Lua virtual machine. This article uses a method provided by Lua to register the C function library to achieve this. The specific loading process is as follows:

① Define the calling function in the following format:

static int set_tx_buf(lua_State *L);

static int get_rx_buf(lua_State *L);

static int uart_ok_del(lua_State *L);

② Declare a structure array, each array element is the call name of the C function in the Lua script and the corresponding C function, that is, it appears in the form of a "name-function" pair, as shown below: static const struct luaL_reg uartLib[] = {

{"set_tx_buf", set_tx_buf},

{"get_tx_buf", get_tx_buf},

{"uart_ok_del", uart_ok_de},

{NULL, NULL}

};

③ Call the following function to register the C function library: luaL_register (L, "ied", uartLib); the parameter L is the function return value when the virtual machine is created (the same below), and the string "ied" is the library name registered in the virtual machine. The third parameter uartLib is the structure array declared above, corresponding to the library function table that needs to be registered.

Through the above steps, the registration process of the three C functions that need to be called in the Lua script can be completed, so that they can be called in the Lua script in the form of "library name.library function", such as "ied.set_tx_buf(function parameter)".

The loading of the script file itself is relatively simple, just call the following function:

luaL_dofile(L, "uart_script.lua");

The parameter L is the same as the above function call, and the second parameter is the specific storage path of the script file in Flash.

At this point, a Lua and C interactive environment has been successfully established.

3.2 Extracting serial port configuration data from the script

To correctly carry out the interaction process between Lua and C, we must first have a deeper understanding of the role and operation of the virtual stack used when Lua and C interact. In the interaction between Lua and C, the function parameters and return values ​​between them will be passed through the stack. Lua and C have slightly different stack operations. Lua uses a strict LIFO method, while C can also use an index method. Taking three parameters as an example, parameter 1 is pushed onto the stack first, followed by parameters 2 and 3. The Lua virtual stack storage structure and index correspondence are shown in Figure 3.

Figure 3 Lua virtual stack structure example

If you want to access parameter 1 in C, you can use index 1 or index -3. The positive index increases from 1 in the order in which it is pushed onto the stack, and the negative index decreases from -1 in the order in which it is popped off the stack.

Usually, the configuration of the serial port mainly includes the following items: whether to enable, the number of data bits, the number of stop bits, the parity flag and the baud rate. Therefore, in the Lua script, this article uses the Lua table structure to set it, as shown in the following example (the italic code in this article indicates the Lua script, the same below):

uart_p0={

enable=1, --enable bit

dataBits=8, --number of data bits

stopBits=1, --number of stop bits

parityBit=2, --parity check

baudRate=9600 --baud rate

};

This example enables the P0 port of the UART chip and uses a frame format of 8 data bits, 1 stop bit, even parity (this article defines the value of parityBit as 0 for no parity, 1 for odd parity, and 2 for even parity), and a baud rate of 9 600 bps.

In C language, to obtain the value of the enable attribute field in the table, you can use the following steps:

① Call the interface function and use the table name as a parameter to push the table into the stack:

lua_getglobal(L, "uart_p0");

② Call the interface function to push the attribute name of the enable attribute field into the stack:

lua_pushstring(L, "enable");

③ Call the interface function to extract the attribute value. This operation can be seen as a process of popping the stack and then pushing it to the stack in C. As a result, the attribute value will be filled in the position where the attribute name pushed into the stack in ② is located:

lua_gettable(L, -2);

The parameter "-2" is the index number in the stack.

④ Call the interface function to take out the value of the attribute field at the top of the stack, and call the pop function to restore the calling environment:

p0_enable = (int)lua_tonumber(L, -1);

lua_pop(L, 1);

The parameter "-1" of the lua_tonumber function is also the index number in the stack. This operation will take out the value of the top element of the stack. Since all data in Lua are floating point numbers, they need to be converted to integer data. The parameter "1" in lua_pop is not an index, which only means to pop an element from the top of the stack.

Through the above operation, the value of the enable attribute field in the p0 port parameter setting table in the script can be correctly extracted. The extraction of other attribute fields is the same. The content changes in the virtual stack are shown in Figure 4.

Figure 4 Schematic diagram of virtual stack operation when extracting attribute values ​​in the table [page]

3.3 Call Lua function to set send buffer

To set the serial port send buffer through the Lua script, the following function is defined in the script:

data ={0x11, 0x22, 0x33, 0x44, 0x55};

function uart_p0_set_txBuf()

local port=0;

local p0_send_num=5;

for i=1, p0_send_num do

ied.set_tx_buf(port,i-1,data[i])

end

return p0_send_num

end

As can be seen from the script content, a loop structure in Lua is used here to set the send buffer and return the number of data set. Among them, the global variable data is a table in the Lua script, similar to an array, which represents the buffer content to be set; ied.set_tx_buf() is a function in the C function library that has been registered in the virtual machine mentioned in Section 3.1. Its parameter port represents the port number, i-1 represents the buffer index number, and data[i] represents the specific data content. It should be noted in the application that in Lua, the array index starts from 1 by default, instead of starting from 0 like in C. In addition, no parameters are set when the set_tx_buf function is defined in C. This is mainly because the extraction of parameters must be achieved with the help of a virtual stack. When calling in the script, its parameters will be pushed into the stack in order from left to right. When taking out parameters in C, just take out according to the corresponding index number in the stack. In Lua, each function call has an independent stack. Therefore, if the call is taken when i is 2 as an example, the stack content seen in the C function set_tx_buf will be as shown in Figure 5.

Figure 5 Example of a virtual stack during a function call

Therefore, in the C program, you only need to call the following statement to set the memory area with index 1 in the serial port send buffer to 0x22:

port = (int)lua_tonumber(L, 1); //get the port number

index = (int)lua_tonumber(L, 2); //get index

data = (char)lua_tonumber(L,3); //get data

uart_port_tx_buf[port].data[index]=data;

When the serial port send buffer needs to be set in the C program, the script function will be called as follows:

lua_getglobal(L, "uart_p0_set_txBuf");

lua_pcall(L, 0, 1, 0);

Among them, the parameter "uart_p0_set_txBuf" of the function lua_getglobal is the name of the script function to be called, and the function prototype of the function lua_pcall is:

int (lua_pcall) (

lua_State *L,

int nargs, //The number of parameters to call the function

int nresults, //number of parameters returned

int errfunc //error handling function number

);

Because the script function uart_p0_set_txBuf called has no parameters but a return value, nargs and nresults are set to 0 and 1 respectively, and the error handling function is not used yet, so it is set to 0.

The return value in the script will be placed at the top of the virtual stack where the lua_pcall calling environment is located when the script function call ends, and can be retrieved by the C program according to the index.

After the above process, the content setting of the serial port send buffer is completed, and then it can be sent to the peripheral device through the serial port chip driver.

When applied on site, it is only necessary to modify the data array and the content of the p0_send_num variable in the script according to the requirements of the inquiry message of different peripheral devices, without making any changes to the C program of the device.

3.4 Processing the receive buffer data through Lua functions

The method of processing serial port receive buffer data through the interaction of Lua and C is basically similar to the processing of send buffer.

After the device places the data sent by the peripheral device into the receiving buffer through the serial port driver, the script function is called in the C function:

lua_getglobal(L, "uart_p0_del_rxBuf");

lua_pushnumber(L, size);

ret=lua_pcall(L, 1, 1, 0);

The parameter uart_p0_del_rxBuf is the name of the buffer data processing function defined in the script. The size of the received data is pushed into the stack through lua_pushnumber, and then passed to the Lua script function. The prototype of the script function is as follows:

function uart_p0_del_rxBuf(rx_size)

In this function, you can get the contents of the receive buffer by calling the registered C function get_rx_buf:

data[i] = ied.get_rx_buf(port, index)

Among them, data is a table type similar to an array in the script. Port is the port number of the serial port chip, and index is the index number of the buffer. In the C program, the following statement is used to return the data value to the script:

port = (int)lua_tonumber(L, 1); //get the port number

index = (int)lua_tonumber(L, 2); //get index

data=uart_port_rx_buf[port].data[index];

lua_pushnumber(L, data);//return value is pushed onto the stack

It can be seen that the script also uses the virtual stack to obtain the return value of the C program. After successfully obtaining the content of the serial port receiving buffer through the above method, the correctness of the received data can be judged in the script according to the specific peripheral device. If the judgment result is correct, the previously registered C function uart_ok_del is called to perform related business processing.

ied.uart_ok_del(port)

Conclusion

From the solution provided in this article, it can be seen that from the beginning to the end, the C language application of the IED device is not responsible for the processing of specific data services between the Lua virtual machine and the peripheral device, except for the transparent transmission function of the message. This makes it completely unnecessary to consider the serial communication data format adopted by the peripheral device in the design of the C program. The specific data content can be set and processed in the script file. In the field application, the data interaction function between the IED device and different serial communication peripheral devices can be completed by modifying the Lua script file, thereby realizing the field configurability of the device serial communication protocol.

Reference address:Implementation of embedded UART communication based on Lua scripting language

Previous article:AVR MCU Hardware/Software Co-simulation Using VMLAB
Next article:Design of indoor lighting system based on Atmega16

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号