Stm32 serial port interruption

Source: Internet
Author: User
Tags printable characters

I found a lot of good information when studying the stm32 serial port to receive sending interruptions, and now the backup is here. For your reference and convenience.

TC === txe

By the way, I will write a post about serial port data processing recently, starting from query and interruption, as well as data processing methods, from queue and FIFO.

 

Section 1

1234567891011121314151617181920212223242526272829303132333435 /*A strange problem was found during the serial port debugging of stm32. The first port of the serial port was initialized so that after the serial port sending was interrupted, the sending was completed immediately.Carefully read the introduction of the serial port in the stm32 manual:          The following is the configuration process for sending characters. Note that when setting the Te bit in usart_cr1, an idle frame will be sent as the first data transmission, even if you run usart_clearflag (usart1, usart_flag_tc); (this function must be executed before the idle frame data is sent.          Configuration steps:1. Activate usart by setting the UE bit on usart_cr1 register2. program the M bit of usart_cr1 to define the word length.3. program the number of Stop bits in usart_cr2.4. If multi-buffer communication is used, configure the DMA enable (dmat) in usart_303 ). Communicating by multiple BuffersConfigure the DMA register.5. Use the usart_brr register to select the required baud rate.6. Set the Te bit in usart_cr1 and send an idle frame as the first data transmission.7. Write the data to be sent into the usart_dr register (this action clears the txe bit ). When there is only one bufferNext, repeat Step 7 for each data to be sent.8. After writing the last data word to usart_dr, wait for TC = 1, which indicatesTransmission is complete. When you need to disable usart or enter the shutdown mode, you need to confirm that the transmission is complete to avoid damage.The last transmission.*/// Solution:// Method 1// ExecuteUSART_ITConfig(USART1, USART_IT_TC, ENABLE); // Previously, the message was delayed for a period of time, basically a little longer than the sending time of a character, and then executedUSART_ClearFlag(USART1, USART_FLAG_TC);          // Method 2:// ExecuteUSART_ITConfig(USART1, USART_IT_TC, ENABLE);while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET){        // Reset the sending flag after the idle frame is sent.}USART_ClearFlag(USART1,USART_FLAG_TC);

Section 2

 

Let's talk about TC first. That is, Transmission complete. The message is interrupted only when one byte is sent ". Like the original Ti method of 8051, It is interrupted only after sending. You need to first send a byte in the sending function to trigger the interruption. The sending function is as follows:

/*******
Function: Send a string in the interrupt mode. Use the TC Method to Determine the interrupt bit after sending.
Input: the first address of the string.
Output: None
*******/
Void usart_senddatastring (u8 * pdata)
{
Pdatabyte = pdata;

Usart_clearflag (usart1, usart_flag_tc); // clear the transfer completion flag. Otherwise, 1st bytes of data may be lost.

Usart_senddata (usart1, * (pdatabyte ++); // The value must be ++. Otherwise, the first character T will be sent twice.
}


The interrupt processing function is as follows:
/********
* Function name: usartpolicirqhandler
* Description: This function handles usart1 Global interrupt request.
* Input: None
* Output: None
* Return: None
*********/
Void usartpolicirqhandler (void)
{
If (usart_getitstatus (usart1, usart_it_tc) = set)
{
If (* pdatabyte = '\ 0') // TC must read Sr + write Dr to clear 0. When it is sent to the end, when it reaches' \ 0', use an if to judge and turn it off.
Usart_clearflag (usart1, usart_flag_tc); // otherwise, TC is always set, and tcie is also enabled, which leads to interruption and clear. You do not need to turn off tcie.
Else
Usart_senddata (usart1, * pdatabyte ++ );
}

}

U8 * pdatabyte is an external pointer variable.

In the interrupt processing program, after sending this string, you do not need to disable the TC interrupt enabling tcie, but only need to clear the flag TC; in this way, the TC = set can be avoided, resulting in repeated interruptions.

 

The serial port initialization function is as follows:

/*********
Name: usart_config
Function: sets serial port parameters.
Input: None
Output: None
Return: None
**********/
Void usart_config ()
{
Usart_inittypedef usart_initstructure; // defines a struct containing serial Parameters

Usart_initstructure.usart_baudrate = 9600; // The baud rate is 9600.
Usart_initstructure.usart_wordlength = usart_wordlength_8b; // 8-Bit Data bit
Usart_initstructure.usart_stopbits = usart_stopbits_1; // one-bit stop bit
Usart_initstructure.usart_parity = usart_parity_no; // no verification is performed.
Usart_initstructure.usart_hardwareflowcontrol = usart_hardwareflowcontrol_none; // no hardware Flow Control
Usart_initstructure.usart_mode = usart_mode_rx | usart_mode_tx; // Input and Output Modes
Usart_initstructure.usart_clock = usart_clock_disable; // The clock is disabled.
Usart_initstructure.usart_cpol = usart_cpol_low;
Usart_initstructure.usart_cpha = usart_cpha_2edge;
Usart_initstructure.usart_lastbit = usart_lastbit_disable;
Usart_init (usart1, & usart_initstructure); // set it to usart1

Usart_itconfig (usart1, usart_it_tc, enable); // After the tramsimssion complete, an interruption occurs. The Tc interrupt must be placed here; otherwise, the first byte is lost.

Usart_cmd (usart1, enable); // enable usart1
}
Here is a question: Enable TC to interrupt usart_itconfig (). If it is placed in my usart_senddatastring (), the first byte of the string will be lost. It must be placed in the serial port initialization function. I don't know why ??

 

Here I can give an explanation. If you look at Section1, you can see why. Your principle of doing so is similar to that explained in Section1, which is equivalent to latency, the main reason you haven't lost data is that you have such a usart_clearflag (usart1, usart_flag_tc) in your code; // clear the transfer complete flag, otherwise, 1st bytes of data may be lost. provided by netizens.

 

 

Determine txe. That is, TX Dr empty, the sending register is empty. When txeie is enabled, as long as the Tx Dr is empty, interruption will occur. Therefore, after sending the string, you must turn it off; otherwise, it will lead to repeated interruptions. This is also different from TC.

The sending function is as follows:
/*******
Function: Send a string in the interrupt mode. Use the TC Method to Determine the interrupt bit after sending.
Input: the first address of the string.
Output: None
*******/
Void usart_senddatastring (u8 * pdata)
{
Pdatabyte = pdata;
Usart_itconfig (usart1, usart_it_txe, enable); // as long as the sending register is empty, there will always be interruptions. Therefore, if no data is sent, disable the sending interruption, it is enabled only when sending is started.

}

The interrupt handling function is as follows:

/********
* Function name: usartpolicirqhandler
* Description: This function handles usart1 Global interrupt request.
* Input: None
* Output: None
* Return: None
********/
Void usartpolicirqhandler (void)
{
If (usart_getitstatus (usart1, usart_it_txe) = set)
{
If (* pdatabyte = '\ 0') // The bytes to be sent are sent to the end of null.
Usart_itconfig (usart1, usart_it_txe, disable); // because the sending register is empty, it must be disabled after sending the string. Otherwise, it will be interrupted if it is empty.
Else
Usart_senddata (usart1, * pdatabyte ++ );
}

}

You do not need to open txe interruption in the serial port initialization function (opened in the sending function) as follows:
/************
Name: usart_config
Function: sets serial port parameters.
Input: None
Output: None
Return: None
************/
Void usart_config ()
{
Usart_inittypedef usart_initstructure; // defines a struct containing serial Parameters

Usart_initstructure.usart_baudrate = 9600; // The baud rate is 9600.
Usart_initstructure.usart_wordlength = usart_wordlength_8b; // 8-Bit Data bit
Usart_initstructure.usart_stopbits = usart_stopbits_1; // one-bit stop bit
Usart_initstructure.usart_parity = usart_parity_no; // no verification is performed.
Usart_initstructure.usart_hardwareflowcontrol = usart_hardwareflowcontrol_none; // no hardware Flow Control
Usart_initstructure.usart_mode = usart_mode_rx | usart_mode_tx; // Input and Output Modes
Usart_initstructure.usart_clock = usart_clock_disable; // The clock is disabled.
Usart_initstructure.usart_cpol = usart_cpol_low;
Usart_initstructure.usart_cpha = usart_cpha_2edge;
Usart_initstructure.usart_lastbit = usart_lastbit_disable;

Usart_init (usart1, & usart_initstructure); // set it to usart1

Usart_cmd (usart1, enable); // enable usart1

}

 

Section 3

 

There are two registers on the sending end of usart. One is the usart_dr register that the program can see (the TDR in the shadow part ), the other is the shift register invisible to the Program (transmit shift register in the shadow part ).

There are two signs for sending usart data. One is txe = the sending data register is empty, and the other is Tc = the sending end. When the data in the TDR is transferred to the shift register, txe is set, at this time, the shift register starts to transmit data to the Tx signal line in bit, but because the TDR has become empty, the program can write the next byte (usart_dr operation) to the TDR, instead of waiting until all the bits in the shift register are sent, the TC flag is set in the hardware when all bits are sent (after the bits are sent.

On the other hand, when the initialization of usart has not sent any data, the txe flag also exists because the data sending register is empty.

The significance of txeie and tcie is very simple. txeie allows interruption when txe is marked as '1', while tcie allows interruption when TC is marked as '1.

You need to decide when to use the logo based on your needs. However, I think txe allows the program to have more time to fill in the TDR register to ensure that the sent data streams are uninterrupted. TC allows the program to know the exact sending end time, which facilitates the program to control the timing of external data streams.

 

Section 4

In general, the serial port of the stm32 microcontroller is still well understood, and programming is not complicated. Of course, I prefer to make the disconnection system as simple as 51 single-chip microcomputer.

For the Receiving Terminal, It is rxne, which is generated only after receiving is complete. ISR is not entered when the usart_itconfig (usart1, usart_it_rxne, enable) code is executed. But the trouble is that the sending is interrupted: txe or TC. According to the data and test results, txe is set to 1 after the reset, that is, usart_itconfig (usart1, usart_it_txe, an interrupt request is generated immediately. Therefore, this creates a troublesome problem: If no real data is sent, txe will be interrupted and there will be no compaction, which will take a lot of CPU time and even affect the running of other programs!

Therefore, we recommend that you do not enable txe interruption during initialization. You only need to enable txe when sending data (especially series of data such as strings and arrays. Disable it immediately after sending the message to avoid unnecessary troubles.

For sending, pay attention to the differences between txe and TC. Here we will briefly describe the serial port data register DR, serial port shift register SR, and txd pin txdpin, the relationship is Dr-> Sr-> txdpin. When data in the DR is transferred to the SR, txe is set to 1. If data is written to the DR, txe can be set to 0. If all data in the SR is removed through txdpin and no data enters the DR, then TC is set to 1. Note that txe can only be set to 0 by Writing Dr, rather than directly resetting txe, while TC can directly set 1 to 0.

For sending a single character, you can directly query it without interrupting it.

For sending string/array data, the only thing to consider is to disable sending interruption only after the last character is sent. There are two situations: for sending a printable string, 0x00 is used as the end, so 0x00 is used as the condition to disable sending interruption (txe or TC) in ISR. The second case is to send binary data, that is, 0x00 ~ For any data in the 0xff, you cannot use 0x00 to determine the end. At this time, you must know the specific length of the data.

Here, we will analyze the execution process of the above Code: txe interruption occurs when the previous character is sent from Dr to SR, and the execution result is that the last character is sent to dr. In the first case, if it is a printable character, run usart_senddata to write the DR (txe is also cleared). When the last printable character is sent from the Dr to the SR, the txe interrupt is generated. It is indicated that the character 0x00 is sent to the dr. -- this is not acceptable. In this case, the txe interrupt is disabled, and the string sending process ends. Of course, an implicit result cannot be ignored at this time: that is, after the last printable character is transferred from Dr to SR, txe is set to 1, but txe interruption is disabled, therefore, as long as the txe interrupt is Enabled Next time, the ISR will be started immediately. In the second case, the result is the same as that in the first case.

In the first case, the program can write as follows: TXS stores the string to send data, and txcounter1 is the index value:

Extern _ IO uint8_t txcounter1;
Extern uint8_t * TXS;
Extern _ IO uint8_t txlen;

Void usartpolicirqhandler (void)
{
If (usart_getitstatus (usart1, usart_it_txe )! = Reset)
{
If (TXS [txcounter1]) // if it is a printable character
{Usart_senddata (usart1, TXS [txcounter1 ++]);}
Else // disable txe interruption after sending is complete,
{Usart_itconfig (usart1, usart_it_txe, disable );}
}
}

In the second case, txlen indicates the length of the binary data to be sent:

Void usartpolicirqhandler (void)
{
If (usart_getitstatus (usart1, usart_it_txe )! = Reset) // write operation on usart_dr. This bit is cleared.
{
If (txcounter1 <txlen)
{Usart_senddata (usart1, TXS [txcounter1 ++]);}
Else // disable txe interruption after sending is complete
{Usart_itconfig (usart1, usart_it_txe, disable );}
}
}

In fact, the first case is the second special form, that is to say, you can use the second case to send printable characters-of course, no one has a spare time to count the number of letters, spaces, and punctuation marks in a sentence!

In use, you only need to point TXS to the string or array to be sent, set txlen to the length of the data to be sent, and then run usart_itconfig (usart1, usart_it_txe, enable) to start the sending process immediately. You can check txcounter1 to determine the number of bytes sent. Take the second case as an example:

Uint32_t * TXS;
Uint8_t txbuffer1 [] = "0123456789 abcdef ";
Uint8_t dst2 [] = "asdfghjkl ";
_ IO uint8_t txlen = 0x00;

Txlen = 8; // send 8 characters, and the final message is 01234567 characters.
TXS = (uint32_t *) txbuffer1; // point txs to the string txbuffer1
Txcounter1 = 0; // reset the index value
Usart_itconfig (usart1, usart_it_txe, enable); // enable txe interruption to start the sending Process
While (txcounter1! = Txlen); // wait until the sending is completed

TXS = (uint32_t *) txbuffer2; // same as above, the final message is asdfghjk.
Txcounter1 = 0;
Usart_itconfig (usart1, usart_it_txe, enable );
While (txcounter1! = Txlen );

The above is what I think is the best solution, but the serial port interrupt mode data is interrupted several times, I think it still takes a lot of CPU time, in contrast, the DMA mode is much better, this is because the DMA sends a string at most two interruptions (half-transmission is complete, full transmission is complete), and the serial port is converted into a device similar to 16C550.

 

Stm32 serial port interruption

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.