Detailed explanation of STM32 serial port function library functions and advanced application of DMA serial port (reprinted)

Publisher:脑力激荡Latest update time:2016-06-14 Source: eefocusKeywords:STM32 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere
When transmitting data, you should start from what standards are supported? What is the transmission speed? When does it start? When does it end? What is the content of the transmission? How to prevent communication errors? What to do when the amount of data is large? How to connect the hardware. Of course, for STM32, you must also be familiar with the functions of the library functions.

The differences between RS232 and 485 levels, hardware peripheral chips, baud rate (reflecting the time to transmit one bit), start bit and stop bit, data width, checksum, hardware flow control, and the corresponding interface when connected to the computer. Configuration, use of functions, interrupts, queries and combined with communication protocols are considered to be understood in the use of serial ports.

The above is the basics. Of course, stm has many related multiplexing functions, supports synchronous one-way communication and half-duplex single-line communication, supports local Internet, smart card protocol and infrared data organization related specifications, as well as modem operation, and runs multi-processor communication. At the same time, DMA can be used for high-speed data communication. Pay attention to the time problem of Print function, try to solve it through DMA.

Features: Full-duplex, asynchronous, fractional baud rate generator has the advantage of fast speed, 8 or 9 bits, configurable 1 or 2 stop bits, Lin protocol, and can provide synchronous clock function.

 

Hardware

Generally there are two pins, RX and TX; the synchronous mode requires the SCLK clock pin, and the infrared IRDA requires the irDA_RDI pin as data input and irDA_TDO output.

Parity check is configured by the usart_cr1 pce bit (parity bit is generated when sending and checked when receiving)

LIN local area network mode: by setting the LINEN bit configuration in USART_CR2, a dedicated transceiver is required for use

Synchronous mode: Configure by setting the CLKEN bit in USART_CR2

Smart card mode: Configure by setting the SCEN bit in USART_CR3   

Special research is done on DMA and hardware flow control.

 

What are the interrupt events?

Send data register empty Sending completed Receive data readable Parity error Data overflow CTS flag Idle flag Disconnect flag Noise flag

Unfortunately, there is no receiving buffer, so data loss is easy when using queries

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

The process is clock configuration pin configuration (such as remapping, pin mode) - serial port configuration - interrupt configuration - corresponding interrupt - open serial port

The above are some basic knowledge points. Let's understand the serial port functions from practical applications.

A relatively simple application: initializing the usart

void COM1_Init( void)
{

//First, initialize the structure: the corresponding pins are indispensable, and the usart is also concerned with the interrupt configuration structure, defining space to be graffitied

 GPIO_InitTypeDef GPIO_InitStructure;           
 USART_InitTypeDef USART_InitStructure;
 NVIC_InitTypeDef NVIC_InitStructure; 
 

//The following is to graffiti
 
 GPIORCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA RCC_APB2Periph_AFIO, ENABLE);
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

 

            
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //Select pin position
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //Mode multiplexing push-pull output
 GPIO_InitStructure.GPIO_Speed ​​= GPIO_Speed_50MHz;
 GPIO_Init(GPIOA, &GPIO_InitStructure);
    
 
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //Select pin position
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //Mode is input
 GPIO_Init(GPIOA, &GPIO_InitStructure);
 
 USART_InitStructure.USART_BaudRate = 115200; //Baud rate
 USART_InitStructure.USART_WordLength = USART_WordLength_8b; //8 data bits
 USART_InitStructure.USART_StopBits = USART_StopBits_1; //1 stop bit
 USART_InitStructure.USART_Parity = USART_Parity_No; //No parity check
 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //No data flow control
 USART_InitStructure.USART_Mode = USART_Mode_Rx USART_Mode_Tx; //Transmit and receive mode

 
 USART_Init(USART1, &USART_InitStructure);
 
 //Enable serial port interrupt and set priority
 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = USART1_IRQn_Priority; NVIC_InitStructure.NVIC_IRQChannelSubPriority
 =0; NVIC_InitStructure.NVIC_IRQChannelCmd
 = ENABLE; 
 NVIC_Init(&NVIC_InitStructure); //Throw the structure into the configuration function, that is, write it to the corresponding register

 
    //USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
   
 //All the work is done, don't forget to open the serial port
 USART_Cmd(USART1, ENABLE);
}

 

//USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); Below is the interrupt source

#define USART_IT_PE ((uint16_t)0x0028)
#define USART_IT_TXE ((uint16_t)0x0727)
#define USART_IT_TC ((uint16_t)0x0626)
#define USART_IT_RXNE ((uint16_t)0x0525)
#define USART_IT_IDLE ((uint16_t)0x 0424)
#define USART_IT_LBD (( uint16_t)0x0846)
#define USART_IT_CTS ((uint16_t)0x096A)
#define USART_IT_ERR ((uint16_t)0x0060)
#define USART_IT_ORE ((uint16_t)0x0360)
#define USART_IT_NE ((uint16_t)0x0260)
#define USART_IT_FE ((uint16_t)0x0160)

 --

The above is the initialization configuration. The following is a minimal application. Let's take the output function as an example.

void PrintUart1(const u8 *Str)
{
 while(*Str)
 {
  USART_SendData(USART1, (unsigned char)*Str++);
  while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
 }
}

Sending characters is to continuously send the next data by querying the status of the string.

Receiving data is achieved through interrupts, and the received data is put into the buffer. The protocol will be discussed in detail later.

 

Want to play with computer serial port data transmission, and use printf() to display it directly in the computer window, isn't it great? Add in the usart.c function

//Do not use semihosting mode
#if 1 //If this section is not included, you need to select USE microLIB in the target option
#pragma import(__use_no_semihosting)
struct __FILE 

 int handle; 
}; 
FILE __stdout; 

_sys_exit(int x) 

 x = x; 
}
#endif

int fputc(int ch, FILE *f)
{
  USART_SendData(USART1, (unsigned char)ch);
  while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
 return ch;
}

The above data sources can be through serial port, USB, wireless, etc. . .

The printf function has a flaw, which is that it takes too much time (in milliseconds). You can't let the CPU wait for a few milliseconds to display the serial port, otherwise even the best CPU will be wasted. What should we do? You can use DMA!! Let other hardware directly transfer these rough tasks. The CPU can do other important work!

Let's talk about serial port reception first, and then talk about DMA. There is a file in the firmware library that is specifically used to store interrupt processing functions.

There is a function
void USART1_IRQHandler(void)
{
 static u8 UartBuf[UART_BUF_LEN]; //Serial port buffer
 if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
 { 
  temp=USART_ReceiveData(USART1);

..............The following are some processing, you can use the state machine mode to play until the serial port buffer data is filled and verified to be correct, no more words

  }
}

The above is a typical interrupt handling function, which is very powerful when combined with the state machine. When it comes to the operating system, you need to learn how to use it further.

 

Through the above study, I believe I have a deeper understanding of basic serial port operations. As mentioned earlier, printf is too slow, so some improvements are needed here.

Considering that the actual execution of serial port output (which is actually completed a few milliseconds later using DMA) is a few milliseconds later than the execution of pruntf (completed immediately), it has no impact on the actual application. Therefore, the CPU can command the DMA module to complete the task of serial port output in the tick interrupt. (In fact, it still has some impact on the system. From a macro perspective, the data output by the serial port is actually very small. Putting a cup of water in a river is almost negligible.)
Then solve how to allocate:
define two global buffers.
One of the buffers is organized in the form of a circular queue, and an element is added to the end of the queue each time fputc is executed.
The other buffer is directly organized in the form of an array as the source address of DMA.
In the tick interrupt, complete the DMA operation in the following order
(1) Determine whether the circular queue is empty. If it is empty, it means that there is no string that needs to be output through the serial port. Jump directly to (6)
(2) Determine whether DMA is working. If DMA is working, it means that any last assigned task has not been completed. Jump directly to (6)
(3) Dequeue N characters from the circular queue to the array cache
(4) Tell DMA the number of bytes N to be transferred this time
(5) Command DMA to start transferring
(6) End the operation
Supplement:
1. How to determine N: If the number of elements in the circular queue is greater than or equal to the length of the array cache (fixed value), assign
the length of the array cache to N. If the number of elements in the circular queue is less than the length of the array cache, assign the number of elements in the circular queue to N.
2. The larger the circular queue is, the more strings can be cached, so the larger the better.
3. The larger the array buffer is, the better it is. This value can be calculated as follows. Assuming the baud rate is 115200 and the tick interrupt
cycle is 2 milliseconds, then theoretically, a maximum of 115200*0.002/10=23 bytes can be transmitted in this 2 milliseconds. Therefore, the size of the array buffer
can be set to a slightly smaller size than 23, such as 20.
The code can run normally. After testing, it only takes 25 microseconds of CPU time to print a string containing 20 characters using the new solution,
while the old solution takes 1.76 milliseconds of CPU time. Therefore, you can safely use printf to debug some functions with high timing requirements.
In addition, the probability of printf being re-entered is greatly reduced due to the execution time period. If you need to completely prevent printf from being re-entered, you can turn off the interrupt before calling printf and turn on the interrupt after printf is executed. The cost is only a possible interrupt delay of tens of microseconds.

................................................................. ....................................................

Let me talk about my understanding of DMA

stm32 DMA has 8 channels, 07

Since DMA transfers data, of course there is a data width, which needs to be configured. In addition, there must be an address, which address to start the transfer from and which address to transfer to, which needs to be configured. For normal transfers, just transfer directly, and if you want to transfer continuously at high speed, this can also be configured. It is also possible to load directly from ROM to RAM quickly (not vice versa).

The above are some basic tasks that need to be configured

 DMA_DeInit(DMA1_Channel4); 

 The above sentence is to configure the channel for DMA. According to the information provided by ST, the DMA in STM3210Fx contains 7 channels. 

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&((USART_TypeDef *)USART1)->DR);
The above is to set the peripheral address

DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) USART_DMA_BUF;

The above sentence is obviously the address of the variable in Memory that DMA is to be connected to, and the memory address is set above;

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

The above sentence is to set the DMA transmission direction, just as I said before, from memory to peripherals, or from peripherals to memory: just change DMA_DIR_PeripheralSRC to DMA_DIR_PeripheralDST.

DMA_InitStructure.DMA_BufferSize = 0;

The above sentence sets the length of the DMA buffer during transmission. The starting address of the buffer has been defined before: For security and reliability, it is generally necessary to define a storage area for the buffer. There are three types of units for this parameter: Byte, HalfWord, and Word. I set 2 half-words (see the settings below); 1 half-word occupies 16 bits in a 32-bit MCU.

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

The above sentence is to set the peripheral increment mode of DMA. If the channel (CHx) selected by DMA has multiple peripherals connected, you need to use the peripheral increment mode: DMA_PeripheralInc_Enable; in my example, I use DMA_PeripheralInc_Disable

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

The above sentence sets the memory increment mode of DMA. When DMA accesses multiple memory parameters, DMA_MemoryInc_Enable needs to be used. When DMA only accesses one memory parameter, it can be set to: DMA_MemoryInc_Disable.

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

The above sentence is to set the data length of each operation when DMA accesses. There are three types of data length, which have been mentioned before and will not be described here.

DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;

The same as above. No further explanation is given here.

DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

The above sentence sets the DMA transfer mode: continuous loop mode. If you only want to access it once and then not access it (or ask it in reverse according to the instruction operation, that is, access it when you want it to access, and stop it when you don’t want it to access), you can set it to the general mode: DMA_Mode_Normal

DMA_InitStructure.DMA_Priority = DMA_Priority_Low;

The above sentence is to set the DMA priority level: it can be divided into 4 levels: VeryHigh, High, Medium, Low.

DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

The above sentence is to set the variables in the two memories of DMA to access each other.

DMA_Init(DMA_Channel1,&DMA_InitStructure);

The previous ones are settings for the DMA structure members. Now we will initialize the entire DMA module so that the DMA members are consistent with the above parameters.

DMA_Cmd(DMA_Channel1,ENABLE);

 

OK, the above configuration is completed, which is equivalent to setting a pipeline to send the data in the buffer to the serial port through DMA. Of course, to connect DMA to usart1, the DMA function of usart must be turned on in usart1: USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); Then in the program, you only need to monitor the status of data transmission and turn on or off DMA in time, leaving it for the next serial port transmission.

The printf() function is overloaded as follows

int fputc(int ch, FILE *f)
{
  while(En_Usart_Queue(ch)==-1); 
 return ch;
}  

The beginning is to add the data to be printed by the serial port to the circular buffer, which is a relatively fast action. Because the CPU moves data directly very quickly, and the serial port is operated by the CPU, waiting for the response, there is a while (..) which is relatively slow, so there is a delay of several milliseconds. Now, the CPU only moves the data to the buffer through printf. When the buffer is in a certain time, the CPU instructs DMA to start the next operation, and then DMA operates, and the CPU continues to do other things. It only needs to check whether DMA has completed the transmission or whether there is a transmission error when it is idle next time, and change the position of the first position of the circular queue, and change the corresponding status. This can greatly save a lot of time.
You can look at some algorithms for the structure of the circular queue, which is not very difficult.

The following is the function of CPU operation query during operation.

void DMA_USART_Handler(void){
 u16 num=0;
 s16 read;
 if(DMA_GetCurrDataCounter(DMA1_Channel4)==0){ //Check whether DMA has completed the transmission task
  DMA_Cmd(DMA1_Channel4, DISABLE);
  while((read=De_Usart_Queue())!=-1){
   USART_DMA_BUF[num]=read;
   num++; 
   if(num==USART_DMA_BUF_SIZE)
    break;
  }
  if(num>0){ 
   ((DMA_Channel_TypeDef *)DMA1_Channel4)->CNDTR = num;//Clear the quantity register
   DMA_Cmd(DMA1_Channel4, ENABLE);
  }
 }
}

 

 

 

 

 

1. DMA principle:

DMA (Direct Memory Access) is an important feature of all modern computers. It allows hardware devices of different speeds to communicate without relying on a large interrupt load on the CPU. Otherwise, the CPU needs to move each piece of data from the source to the register, and then write it back to the new location again. During this time, the CPU is unavailable for other work.

DMA transfers move data from one address space to another. While the CPU initiates the transfer, the transfer itself is performed and completed by the DMA controller. A typical example is moving a block of external memory to a faster memory area inside the chip. Operations like this do not delay the processor's work, but can be rescheduled to handle other tasks.

2. STM32 uses DMA

1.DMA settings:

The configurations include DMA transfer channel selection, transfer members and direction, normal mode or circular mode, etc.

void DMA_Configuration(void)
{
    DMA_InitTypeDef DMA_InitStructure;
    //DMA settings:
    //Set DMA source: memory address & serial port data register address
    //Direction: memory-->peripheral
    //Each transfer bit: 8bit
    //Transfer size DMA_BufferSize=SENDBUFF_SIZE
    //Address auto-increment mode: peripheral address does not increase, memory address auto-increment 1
    //DMA mode: one-time transfer, non-cyclic
    //Priority: medium
    DMA_DeInit(DMA1_Channel4); //The DMA transmission channel of serial port 1 is channel 4
    DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff; //Data address accessed by DMA
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //Peripheral as the destination of DMA
    DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE; //Transfer data size
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //Peripheral address does not increase
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //Memory address increases by 1
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    //DMA_Mode_Normal (transmit only once), DMA_Mode_Circular (circular transmission)
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //(DMA transmission priority is medium)
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel4, &DMA_InitStructure);
}
Note:
1. Transmission channel: By looking up the table, the transmission of serial port 1 corresponds to DMA channel 4, so channel 4 is selected here.
2. DMA transmission mode:
(1) DMA_Mode_Normal, normal mode. When a DMA data transfer is completed, the DMA transfer is stopped. For the above example, the transfer is stopped after DMA_PeripheralDataSize_Byte bytes are transferred.
(2) DMA_Mode_Circular
Loop mode, after one transmission is completed, it will continue to transmit without stopping.
 
2. DMA mode setting of peripherals
Set serial port 1 to DMA mode:
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
 
3. Definition and initialization of data to be transmitted
#define SENDBUFF_SIZE 10240
vu8 SendBuff[SENDBUFF_SIZE];
    for(i=0;i     {
        SendBuff[i] = i+'0';
    }
4. Start DMA transfer (enable the corresponding DMA channel)
DMA_Cmd(DMA1_Channel4, ENABLE);
 
5. Completion of DMA transfer
 while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)
 {
       LED_1_REV; //LED changes on and off
       Delay(); //waste time
 }
When the transmission is completed, the above infinite loop will be jumped out.
 
The following is a routine of Jiujiu, which has been tested and can be run!
 

#include "stm32f10x_lib.h"
#include "stdio.h"


#define USART1_DR_Base 0x40013804


#define SENDBUFF_SIZE 10240
vu8 SendBuff[SENDBUFF_SIZE];
vu8 RecvBuff[10];
vu8 recv_ptr;

void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void DMA_Configuration(void);
void USART1_Configuration(void);
int fputc(int ch, FILE *f);
void Delay(void);


int main(void)
{
    u16 i;
#ifdef DEBUG
    debug();
#endif
    recv_ptr = 0;
    
    RCC_Configuration();
    GPIO_Configuration();
    NVIC_Configuration();
    DMA_Configuration();
    USART1_Configuration();
    
    printf("\r\nSystem Start...\r\n");
    printf("Initialling SendBuff... \r\n");
    for(i=0;i     {
        SendBuff[i] = i+'0';
    }
    printf("Initial success!\r\nWaiting for transmission...\r\n");
    //The data to be sent is ready. Press the button to start the transmission
    while(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_3));
    
    printf("Start DMA transmission!\r\n");
    
    //Here are some preparations before starting DMA transmission. Set the USART1 module to work in DMA modeUSART_DMACmd
    (USART1, USART_DMAReq_Tx, ENABLE);
    //Start a DMA transmission!
    DMA_Cmd(DMA1_Channel4, ENABLE);
    
    //Wait for DMA transmission to complete. Now we can do other things, such as turning on the light.
    //In actual applications, other tasks can be performed during data transmissionwhile
    (DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET)
    {
        Delay(); //Waste of time
    }
    //After DMA transmission, the DMA channel is automatically closed without manual closing.
    //The following statements are commented
    //DMA_Cmd(DMA1_Channel4, DISABLE);
    
    printf("\r\nDMA transmission successful!\r\n");
    
   
    while (1)
    {
    }
}

int fputc(int ch, FILE *f)
{
    //USART_SendData(USART1, (u8) ch);
    USART1->DR = (u8) ch;
    
   
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
    {
    }
    return ch;
}

void Delay(void)
{
    u32 i;
    for(i=0;i<0xF0;i++);
    return;
}

void RCC_Configuration(void)
{
    ErrorStatus HSEStartUpStatus;
    //Enable external crystal oscillator
    RCC_HSEConfig(RCC_HSE_ON);
    //Wait for external crystal oscillator to stabilize
    HSEStartUpStatus = RCC_WaitForHSEStartUp();
    //If the external crystal oscillator starts successfully, proceed to the next step
    if(HSEStartUpStatus==SUCCESS)
    {
        //Set HCLK (AHB clock) = SYSCLK
        RCC_HCLKConfig(RCC_SYSCLK_Div1);
        //PCLK1(APB1) = HCLK/2
        RCC_PCLK1Config(RCC_HCLK_Div2);
        //PCLK2(APB2) = HCLK
        RCC_PCLK2Config(RCC_HCLK_Div1);
        //FLASH timing control
        //Recommended value: SYSCLK = 0~24MHz Latency=0
        // SYSCLK = 24~48MHz Latency=1
        // SYSCLK = 48~72MHz Latency=2
        FLASH_SetLatency(FLASH_Latency_2);
        //Enable FLASH prefetch buffer function
        FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
        //PLL setting SYSCLK/1 * 9 = 8*1*9 = 72MHz
        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
        //Start PLL
        RCC_PLLCmd(ENABLE);
        //Wait for PLL to stabilize
        while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
        //System clock SYSCLK comes from PLL output
        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
        //Wait for system clock to stabilize after switching clock
        while(RCC_GetSYSCLKSource()!=0x08);

       
    }
    //The following is to turn on the clock for each module
    //Start GPIO
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA RCC_APB2Periph_GPIOB \
                           RCC_APB2Periph_GPIOC RCC_APB2Periph_GPIOD,\
                           ENABLE);
    //Start AFIO
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    //Start USART1
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    //Start DMA clock
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    
}
 

void GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    //PC port 4567 pin sets GPIO output, push-pull 2M
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 GPIO_Pin_5 GPIO_Pin_6 GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed ​​= GPIO_Speed_2MHz;
    GPIO_Init(GPIOC, & GPIO_InitStructure);
    //KEY2 KEY3 JOYKEY
    //Located at pins 3 4 11-15 of the PD port, enable setting as input
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 GPIO_Pin_4 GPIO_Pin_11 GPIO_Pin_12 \
        GPIO_Pin_13 GPIO_Pin_14 GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOD, &GPIO_InitStructure);
    //USART1_TX
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed ​​= GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    //USART1_RX
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}
 

void NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
#ifdef VECT_TAB_RAM
    // Set the Vector Table base location at 0x20
    NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else 
    // Set the Vector Table base location at 0x08
    NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
    //Set NVIC priority group to Group2: 0-3 preemptive priority, 0-3 responsive priority
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    //Enable serial port receive interrupt    
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}


void USART1_Configuration(void)
{
    USART_InitTypeDef USART_InitStructure;
    
    USART_InitStructure.USART_BaudRate = 9600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits =
    USART_StopBits_1; USART_InitStructure.USART_Parity
    = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx USART_Mode_Rx;
    USART_Init(USART1, &USART_InitStructure);
    
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    
    USART_Cmd(USART1, ENABLE);
}

void DMA_Configuration(void)
{
    DMA_InitTypeDef DMA_InitStructure;
    //DMA settings:
    //Set DMA source: memory address & serial port data register address
    //Direction: memory-->peripheral
    //Each transfer bit: 8bit
    //Transfer size DMA_BufferSize=SENDBUFF_SIZE
    //Address auto-increment mode: peripheral address does not increase, memory address auto-increment 1
    //DMA mode: one-time transfer, non-cyclic
    //Priority: medium
    DMA_DeInit(DMA1_Channel4); //The DMA transmission channel of serial port 1 is channel 4
    DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //Peripheral as the destination of DMA
    DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE; //Transfer size
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //Peripheral address does not increase
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //Memory address increases by 1
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //DMA_Mode_Normal (transmit only once), DMA_Mode_Circular (transmit continuously)
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //(DMA transfer priority is medium)
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel4, &DMA_InitStructure);
}

Keywords:STM32 Reference address:Detailed explanation of STM32 serial port function library functions and advanced application of DMA serial port (reprinted)

Previous article:STM32 defect 1: serial port interrupt flag defect
Next article:Detailed explanation of STM32 water temperature control system hardware

Recommended ReadingLatest update time:2024-11-17 01:33

Comparison of stm32 pwm performance and fpga pulse performance
stm32 pwm adopts two methods, one is fixed setting method, for example, setting the counter to 199 clk and the pulse width to 100 clk, the second method adopts DMA configuration pulse width method, for example, I opened an array of size 3000, wrote 100 in it, and adopted circular DMA transmission FPGA is relatively s
[Microcontroller]
STM32 study notes: FSMC details
FSMC (Flexible Static Memory Controller) is a new memory expansion technology used by the STM32 series. It has unique advantages in external memory expansion and can easily expand different types of large-capacity static memories according to system application needs . After using the FSMC controller, the FSMC_A provi
[Microcontroller]
STM32 study notes: FSMC details
STM32 low power experiment summary
STM32 low power experiment summary 1. First of all, let me answer a question. Can STM32 do low power consumption? The answer is yes. This is supported by data. I tested STM32101CB, FLASH: 128K, RAM: 16K and RTC working. The power consumption tested was 16uA, which should be said to be quite good. 2. What should be p
[Microcontroller]
Solution to the problem that the program cannot be burned after STM32 enters low power mode
We often need to set STM32 to enter low power mode at a certain time. Many people cannot burn the program again when entering low power mode for debugging. The solution is: 1. Boot0 must be pulled high, boot1 (PB2) must be pulled low, and then the power must be restarted. The MCU will enter the ISP programming mode. A
[Microcontroller]
Solution to the problem that the program cannot be burned after STM32 enters low power mode
STM32 learning seven
USART serial port learning:        This article is mainly about the connection between the stm32 board and the PC machine. Since I am a beginner, I spent a long time thinking about the experiment before I successfully configured the serial port communication. It was very difficult, so it became a blog.           In
[Microcontroller]
STM32 and Actility ThingPark collaborate to enable efficient wireless firmware updates
In the field of Internet of Things (IoT), the introduction of wireless firmware update (FUOTA) technology has significantly improved the efficiency and flexibility of device management. The combination of STM32 and Actility ThingPark platform provides developers with a powerful tool that enables them to set up and e
[Microcontroller]
The difference between STM32 timer output comparison mode and PWM output mode
I spent several days trying to get a timer to output a square wave. It worked fine at first, but then it stopped working. I was so frustrated...  After a long period of oscilloscope observation and exploration, I found that the functions of the registers in the ordinary comparison output mode and the PWM mode are di
[Microcontroller]
The difference between STM32 timer output comparison mode and PWM output mode
STM32 MCU hardware key foundation essence and precautions
A brief introduction to STM32 1. Background If you are having a hard time choosing a processor for your project: on the one hand, you are complaining about the limited instructions and performance of 16-bit microcontrollers, and on the other hand, you are complaining about the high cost and high power
[Microcontroller]
STM32 MCU hardware key foundation essence and precautions
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号