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
Click freemodbus-v1.5.zip to download.
2. Introduction to freeModbus open source package
Open the folder directory as follows
Then we open the main folder modbus
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.
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.
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.
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
Port is in the directory under the modbus folder
Then create a new Modbus group in the project
Then add the header file path under the project options menu, where PROJDIRPROJDIR is the current project directory
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,
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.
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
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
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
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
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;
Previous article:STM32 is set as I2C slave
Next article:STM8S003 MCU serial port reception conflicts with ADC settings
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Huawei's Strategic Department Director Gai Gang: The cumulative installed base of open source Euler operating system exceeds 10 million sets
- Download from the Internet--ARM Getting Started Notes
- Learn ARM development(22)
- Learn ARM development(21)
- Learn ARM development(20)
- Learn ARM development(19)
- Learn ARM development(14)
- Learn ARM development(15)
- Analysis of the application of several common contact parts in high-voltage connectors of new energy vehicles
- Wiring harness durability test and contact voltage drop test method
- 【RT-Thread Reading Notes】 Week 1: First Introduction
- Detailed explanation of LCD modules of MSP430 microcontroller: LCD, LCD_A, LCD_B, LCD_C, LCD_E
- 1602MAX485 module test program
- Experience in using Ti's C28x series DSP (28069) (28377), ADC experience
- The programming language list has been updated. Python has surpassed C language and ranked first? ? ? ?
- [NUCLEO-L452RE Review] +OLED screen display driver
- 41 "Wanli" Raspberry Pi car - ROS learning (ROSBridge controls the little turtle)
- EETalk| How to design a good antenna?
- Introduction to TI's fifth-generation DSP product TMS320C5X
- 51 Microcontroller timer 0 affects the normal operation of timer 1. How to solve it?