stm32-serial port accepts indefinite length data method (3 kinds)

Source: Internet
Author: User
Tags printf reset

Method 1: The serial port accepts the data, the timer to determine whether the timeout accepts data completion.

Method 2:DMA Accept +idle interrupts

Implementation of the idea: the use of stm32f103 serial 1, and configured to idle interrupt idle mode and enable DMA receive, and simultaneously set the receive buffer and initialize the DMA. Then after the initialization is completed, when the external to the microcontroller to send data, assuming that the length of the frame data is 200 bytes, then the microcontroller received a byte when it will not produce a serial interrupt, but the DMA in the background to carry data silently into the buffer you specified. When the entire frame data is sent, the serial port will not produce an interrupt, at this time the Dma_getcurrdatacounter () can be used to calculate the data acceptance length, thus data processing.

Application object: Applicable to a variety of serial port-related communication protocols, such as: Modbus,ppi; there are similar to the GPS data reception analysis, serial WiFi data reception, etc., are very good application objects.

Key Code Analysis:

1 2 3 4 5 6
void Uart_init (u32 bound);

void Mydma_enable (DMA_CHANNEL_TYPEDEF*DMA_CHX); #endif Usart.
    C//Initialize IO serial 1//bound: baud rate void Uart_init (u32 bound) {//gpio port set gpio_inittypedef gpio_initstructure;
    Usart_inittypedef usart_initstructure;
    Nvic_inittypedef nvic_initstructure;

   Dma_inittypedef dma_initstructure; Rcc_apb2periphclockcmd (rcc_apb2periph_usart1| rcc_apb2periph_gpioa,enable); Enable Usart1,gpioa clock Rcc_ahbperiphclockcmd (RCC_AHBPERIPH_DMA1, enable);  Enable DMA to transmit Rcc_apb1periphclockcmd (rcc_apb1periph_usart2,enable);//enable USART2 clock Usart_deinit (USART1); Reset serial port 1//usart1_tx pa.9 gpio_initstructure.gpio_pin = gpio_pin_9;
    pa.9 gpio_initstructure.gpio_speed = Gpio_speed_50mhz; Gpio_initstructure.gpio_mode = gpio_mode_af_pp; multiplexed push-Pull output gpio_init (Gpioa, &gpio_initstructure);
    Initialize PA9//usart1_rx pa.10 gpio_initstructure.gpio_pin = gpio_pin_10; Gpio_initstructure.gpio_mode = gpio_mode_in_floating;//Float input gpio_init (GPIOA, &gpio_initstructure);
    Initialize PA10//usart1 NVIC configuration Nvic_initstructure.nvic_irqchannel = usart1_irqn; nvic_initstructure.nvic_irqchannelpreemptionpriority=3;//preemption Priority 3 Nvic_initstructure.nvic_irqchannelsubpriority = 3 ; Sub-priority 3 Nvic_initstructure.nvic_irqchannelcmd = ENABLE; IRQ Channel enable Nvic_init (&nvic_initstructure);
  Initializes the VIC register//usart initialization setting According to the specified parameters usart_initstructure.usart_baudrate = bound; Usart_initstructure.usart_wordlength = usart_wordlength_8b;//Word length is 8-bit data format usart_initstructure.usart_stopbits = USART_ stopbits_1;//a stop bit usart_initstructure.usart_parity = usart_parity_no;//no parity bit usart_initstructure.usart_ Hardwareflowcontrol =usart_hardwareflowcontrol_none;//No hardware data flow control Usart_initstructure.usart_mode = USART_Mode_Rx | Usart_mode_tx; Transceiver Mode Usart_init (USART1, &usart_initstructure);   Initialize the serial port usart_itconfig (USART1, Usart_it_idle, enable);//Open idle Interrupt usart_dmacmd (usart1,usart_dmareq_rx,enable);   Enable serial 1 DMA to receive Usart_cmd (USART1, enable);                Enable the serial//corresponding DMA configuration dma_deinit (DMA1_CHANNEL5); Set the DMA Channel 5 register to the default value serial 1 corresponds to DMA Channel 5 dma_initstructure.dma_peripheralbaseaddr = (u32) &USART1->DR;  DMA peripheral Usart Base Address dma_initstructure.dma_memorybaseaddr = (u32) dma_rece_buf;  DMA Memory Base Address Dma_initstructure.dma_dir = DMA_DIR_PERIPHERALSRC;  Data transmission direction, from peripheral read Send to memory dma_initstructure.dma_buffersize = Dma_rec_len; DMA Channel DMA Cache Size dma_initstructure.dma_peripheralinc = dma_peripheralinc_disable;  Peripheral address Register unchanged dma_initstructure.dma_memoryinc = dma_memoryinc_enable; Memory address Register Increment dma_initstructure.dma_peripheraldatasize = dma_peripheraldatasize_byte; Data width is 8 bits dma_initstructure.dma_memorydatasize = Dma_memorydatasize_byte;  Data width is 8 bits dma_initstructure.dma_mode = Dma_mode_normal; Working in normal cache mode dma_initstructure.dma_priority = Dma_priority_medium;  DMA Channel X has medium-priority dma_initstructure.dma_m2m = dma_m2m_disable;  DMA channel X is not set to memory-to-memory transfer dma_init (DMA1_CHANNEL5, &dma_initstructure); Initializes the DM based on the parameters specified in the Dma_initstructA channel dma_cmd (DMA1_CHANNEL5, ENABLE);  Official Drive DMA Transfer}//re-restore DMA pointer void mydma_enable (DMA_CHANNEL_TYPEDEF*DMA_CHX) {dma_cmd (Dma_chx, DISABLE); Turn off the channel Dma_setcurrdatacounter (Dma_chx,dma_rec_len) indicated by USART1 TX DMA1; the size of the DMA cache for//DMA channels Dma_cmd (Dma_chx, ENABLE)  ;
    Open the channel indicated by the USART1 TX DMA1}//Send len bytes//buf: Send to the first address//len: The number of bytes sent void Usart1_send (U8 *buf,u8 len) {U8 T;   
        for (t=0;t<len;t++)//loop send data {while (Usart_getflagstatus (USART1, usart_flag_tc) = = RESET);
    Usart_senddata (Usart1,buf[t]);     
} while (Usart_getflagstatus (USART1, usart_flag_tc) = = RESET);  }//serial interrupt function void Usart1_irqhandler (void)//serial 1 Interrupt Service Program {if (Usart_getitstatus (USART1, usart_it_idle)! =
          RESET)//Receive interrupt (the received data must be 0x0d 0x0a end) {usart_receivedata (USART1);//Read Data Note: This sentence must be, otherwise not enough to clear the interrupt flag bit. usart1_rec_cnt =dma_rec_len-dma_getcurrdatacounter (DMA1_CHANNEL5); Figure out the frame data length//*********** frame processing function ************//printf ("thelenght:%d\r\n", usart1_rec_cnt);
          printf ("The data:\r\n");
         Usart1_send (DMA_RECE_BUF,USART1_REC_CNT); printf ("\r\nover!
        \ r \ n ");         Usart_clearitpendingbit (Usart1,usart_it_idle);                  Clear Interrupt Flag mydma_enable (DMA1_CHANNEL5);
 Restore DMA pointer, wait for next receive}}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 4 4 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 1 2 3 4 5 6 7 8 9 10 11 1 2 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 11

Method 3: Implement the idea: directly use Stm32 's rxne and idle interrupt to receive the indeterminate byte data.
Basic knowledge:
When the idle interrupt occurs.
Idle is the interrupt that occurs after the serial port receives a frame of data. What is a frame of data? For example, to a single-chip computer sent 1 bytes, or a hair 8 bytes, these once sent data, called a frame of data, can also be called a packet of data.
How to judge the end of a frame of data is the problem we are discussing today. Because this is used in many projects, you can determine whether a few bytes and the contents of each byte meet the protocol requirement only after receiving a frame of data.
Looking at the definition of idle interrupt in front of you, you will understand that when a frame of data is finished, an idle interrupt is generated.

How to configure a good idle interrupt.
Below we will configure the serial port idle interrupt bar.

This is the serial CR1 Register, wherein, on the BIT4 write 1 Open idle interrupt, to BIT5 write 1 open receive data interrupt. (Note: Different series of STM32, the corresponding register bit may be different)

Rxne the difference between interrupts and idle interrupts.
When 1 bytes are received, a rxne interrupt is generated, and when a frame of data is received, an idle interrupt is generated. For example, to single-chip microcomputer sent 8 bytes, it will produce 8 rxne interrupts, 1 idle interrupts.

This is a status register, when the serial port receives the data, BIT5 will automatically become 1, when the completion of a frame of data, BIT4 will become 1.
It should be noted that in the interrupt function, the corresponding bits need to be cleared 0, otherwise it will affect the next time the reception of data. For example, Rxne receives a data interrupt, as long as the received byte is read out, it will clear the interrupt. Idle interrupt, how is the F0 series of MCU, need to use ICR register to clear, if it is F1 series of MCU, clear method is "read first SR register, read Dr Register". (How do I know.) Written in the manual)

The source program is given in the following example, stm32f103.
Let's look at the main parts of the program first.
Serial port initialization function fragment

Serial Interrupt function

In the serial interrupt function, the most important two statements are the two statements circled in the above figure. The first statement is used to determine if 1 bytes are received, and the second statement is used to determine if 1 frames of data are received. (is not feeling super convenient.) Mom doesn't have to worry about how I can tell if I'm finished with 1 frames of data. )
Main function

This main function is used to verify the correctness of the reception. Rxcounter indicates that this frame of data has a few bytes, after receiving a frame of data, the interrupt function will be placed in the Receivestate 1, and then, through the serial port to send the received data back to the serial port. This verifies the correctness of how many bytes were received and verifies that the received data is correct.

Both program codes have been tested with STM32F103ZET6 and are completely fine.

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.