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.
Previous article:AVR MCU Hardware/Software Co-simulation Using VMLAB
Next article:Design of indoor lighting system based on Atmega16
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- Practical application of winding distributed capacitance
- [N32L43X Review] 6. Transplanting the ultra-small Gui uGui
- [Home Smart Lighting Control and Indoor Environment Monitoring System]--7. Modify Bluetooth device name and address
- Wireless Wi-Fi product coverage is not good, Wi-Fi 6 iFEM can solve it
- Basic knowledge before learning FPGA
- We all know that sleep is important, but we just can't bear to give up the good time at night. What time do you go to bed?
- Optical waveguide problem help
- recruitment
- [New version of Zhongke Bluexun AB32VG1 RISC-V development board] - 8: PWM
- TI Real-Time Kernel SYSBIOS Boot Process