- 1 前言
- 2 基础
- 3 引脚介绍
- 4 硬件
- 5 代码
- 5.1 main.h
- 5.2 main.c
- 6 结果
- 7 使用函数
- 8 小结
本章介绍下如何使用uart的rx和tx功能,其中tx利用dma更为方便。
2 基础参考文章:STM32单片机串口空闲中断+DMA接收不定长数据
uart一次只能收发一字节数据,所以发送相对简单点,直接用函数USART_SendData(),发送多个数据。
但是rx接收时需要等uart状态rx结束,读取到USART_FLAG_RXDNE状态可以收数据。
不过使用dma更为方便,使用usart目录下的DMA_polling示例。
简单介绍下dma:在内存中开辟一段数组空间,uart收到数据后将存入dma中,指针向后移动,直到填满后产生dma中断。
dma中断中可以配置清空等操作。
整理了一下开发板的uart端口。
其中usart有三个,分别为usart1-3,uart有四个,分别为uart4-7。
usart相对uart多了时钟信号,用于同步。
其中uart4一般作为和电脑的串口通信,用于打印信息。printf函数显示log就通过uart4传输出来。
4 硬件usart3和uart5-7,分别为PC10/11,PB13/14,PB0/1,PC4/5。
uart4根据电路图来看是接到了PA2/3。推测PA2/3和PA13/12有关联,因为PA13/12是microusb数据线。
主要参考两个示例,usart/printf是用于打印log,usart/dma_polling是用于dma接收数据。
printf示例:https://gitee.com/CMIOT-XinShengTech/CMIOT.CM32M4xxR_Library/tree/main/Projects/CM32M433R-START/Examples/USART/Printf
示例源码路径:https://gitee.com/CMIOT-XinShengTech/CMIOT.CM32M4xxR_Library/tree/main/Projects/CM32M433R-START/Examples/USART/DMA_Polling
打印log使用的uart4,用到的io为PD0/1。
uart收发使用的uart5,用到io为PB13/14。
头文件定义uart引脚和dma信息。
#ifndef __MAIN_H__
#define __MAIN_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "nuclei_sdk_soc.h"
#define _USART4_COM_
#ifdef _USART4_COM_
#define USARTx UART4
#define USARTx_GPIO GPIOD
#define USARTx_CLK RCC_APB1_PERIPH_UART4
#define USARTx_GPIO_CLK RCC_APB2_PERIPH_GPIOD
#define USARTx_RxPin GPIO_PIN_1
#define USARTx_TxPin GPIO_PIN_0
#define GPIO_APBxClkCmd RCC_EnableAPB2PeriphClk
#define USART_APBxClkCmd RCC_EnableAPB1PeriphClk
#endif
#define _USART5_USART6_
#ifdef _USART5_USART6_
#define USARTy UART5
#define USARTy_GPIO GPIOB
#define USARTy_CLK RCC_APB1_PERIPH_UART5
#define USARTy_GPIO_CLK RCC_APB2_PERIPH_GPIOB
#define USARTy_TxPin GPIO_PIN_13
#define USARTy_RxPin GPIO_PIN_14
#define USARTy_APBxClkCmd RCC_EnableAPB1PeriphClk
#define USARTy_DMAx DMA1
#define USARTy_DMAx_CLK RCC_AHB_PERIPH_DMA1
#define USARTy_DR_Base (UART5_BASE + 0x04)
#define USARTy_Tx_DMA_Channel DMA1_CH1
#define USARTy_Tx_DMA_FLAG DMA1_FLAG_TC1
#define USARTy_Rx_DMA_Channel DMA1_CH8
#define USARTy_Rx_DMA_FLAG DMA1_FLAG_TC8
#define USARTy_Tx_DMA_IRQn DMA1_Channel1_IRQn
#define USARTy_Tx_DMA_IRQHandler DMA1_Channel1_IRQHandler
#define USARTy_Tx_DMA_INT DMA1_INT_TXC1
#define USARTz UART6
#define USARTz_GPIO GPIOB
#define USARTz_CLK RCC_APB2_PERIPH_UART6
#define USARTz_GPIO_CLK RCC_APB2_PERIPH_GPIOB
#define USARTz_TxPin GPIO_PIN_0
#define USARTz_RxPin GPIO_PIN_1
#define USARTz_APBxClkCmd RCC_EnableAPB2PeriphClk
#define USARTz_DMAx DMA2
#define USARTz_DMAx_CLK RCC_AHB_PERIPH_DMA2
#define USARTz_DR_Base (UART6_BASE + 0x04)
#define USARTz_Tx_DMA_Channel DMA2_CH2
#define USARTz_Tx_DMA_FLAG DMA2_FLAG_TC2
#define USARTz_Rx_DMA_Channel DMA2_CH1
#define USARTz_Rx_DMA_FLAG DMA2_FLAG_TC1
#define USARTz_Rx_DMA_IRQn DMA2_Channel1_IRQn
#define USARTz_Rx_DMA_IRQHandler DMA2_Channel1_IRQHandler
#define USARTz_Rx_DMA_INT DMA2_INT_TXC1
#define USARTz_IRQn UART6_IRQn
#endif
#ifdef __cplusplus
}
#endif
#endif
5.2 main.c
实现uart测试功能。
测试1:dma的tx传输
测试2:uart传输字符串
测试3:dma的rx接收
#include6 结果#include "main.h" typedef enum { FAILED = 0, PASSED = !FAILED } TestStatus; #define TxBufferSize1 (countof(TxBuffer1) - 1) #define TxBufferSize2 (countof(TxBuffer2) - 1) #define countof(a) (sizeof(a) / sizeof(*(a))) USART_InitType USART_InitStructure; uint8_t TxBuffer1[] = "USART DMA Polling: USARTy -> USARTz using DMA"; uint8_t TxBuffer2[] = "USART DMA Polling: USARTz -> USARTy using DMA"; uint8_t RxBuffer1[TxBufferSize2]; uint8_t RxBuffer2[TxBufferSize1]; volatile TestStatus TransferStatus1 = FAILED; volatile TestStatus TransferStatus2 = FAILED; void RCC_Configuration(void); void GPIO_Configuration(void); void DMA_Configuration(void); // youkai add void func_init_uart4(); void print_dma(); bool status_wait_uart = false; #define UART_STATUS_RX true #define UART_STATUS_TX false void print_uart_wait(); void print_uart_wait_end(); void reset_dma_rx(); void reset_dma_tx(); void myUart_rx(uint8_t uart_id,bool rx_tx); void myUart_tx(uint8_t uart_id,uint8_t * data,uint8_t len_send); void myUart_senddata(uint8_t uart_id, uint8_t * data,uint8_t len_send); void myDMA_tx(uint8_t uart_id); void delay(vu32 nCount); int main(void) { func_init_uart4(); printf("start initrn"); printf("-------test1: dma tx---------rn"); RCC_Configuration(); GPIO_Configuration(); DMA_Configuration(); USART_InitStructure.BaudRate = 115200; USART_InitStructure.WordLength = USART_WL_8B; USART_InitStructure.StopBits = USART_STPB_1; USART_InitStructure.Parity = USART_PE_NO; USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE; USART_InitStructure.Mode = USART_MODE_RX | USART_MODE_TX; USART_Init(USARTy, &USART_InitStructure); USART_Init(USARTz, &USART_InitStructure); // strcpy(TxBuffer1,"hihihihihihihihihihihihihihihihihihihihihihih"); // printf("TxBuffer1 = [%s]rn",(char*)TxBuffer1); USART_EnableDMA(USARTy, USART_DMAREQ_RX | USART_DMAREQ_TX, ENABLE); USART_EnableDMA(USARTz, USART_DMAREQ_RX | USART_DMAREQ_TX, ENABLE); DMA_EnableChannel(USARTy_Tx_DMA_Channel, ENABLE); DMA_EnableChannel(USARTy_Rx_DMA_Channel, ENABLE); DMA_EnableChannel(USARTz_Tx_DMA_Channel, ENABLE); DMA_EnableChannel(USARTz_Rx_DMA_Channel, ENABLE); USART_Enable(USARTy, ENABLE); USART_Enable(USARTz, ENABLE); // wait until dma send data ok. while(DMA_GetFlagStatus(DMA1_FLAG_TC1,USARTy_DMAx)==RESET) { } printf("rn-------test2: uart tx---------rn"); delay(1000); printf("dma tx over.rn"); // USART_SendData(USARTy,'n'); // delay(); char temp_rx[]="hihihi"; myUart_tx(5,temp_rx,4); // reset_dma_rx(); printf("rn-------test3: uart rx---------rn"); int count = 0; while (1) { printf("count = %drn",count++); myUart_rx(5,UART_STATUS_RX); } } void RCC_Configuration(void) { RCC_EnableAHBPeriphClk(USARTy_DMAx_CLK, ENABLE); RCC_EnableAHBPeriphClk(USARTz_DMAx_CLK, ENABLE); RCC_EnableAPB2PeriphClk(USARTy_GPIO_CLK | USARTz_GPIO_CLK | RCC_APB2_PERIPH_AFIO, ENABLE); USARTy_APBxClkCmd(USARTy_CLK, ENABLE); USARTz_APBxClkCmd(USARTz_CLK, ENABLE); } void GPIO_Configuration(void) { GPIO_InitType GPIO_InitStructure; GPIO_ConfigPinRemap(GPIO_RMP_USART1,ENABLE); GPIO_InitStructure.Pin = USARTy_RxPin; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(USARTy_GPIO, &GPIO_InitStructure); GPIO_InitStructure.Pin = USARTz_RxPin; GPIO_Init(USARTz_GPIO, &GPIO_InitStructure); GPIO_InitStructure.Pin = USARTy_TxPin; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(USARTy_GPIO, &GPIO_InitStructure); GPIO_InitStructure.Pin = USARTz_TxPin; GPIO_Init(USARTz_GPIO, &GPIO_InitStructure); GPIO_ConfigPinRemap(GPIO_RMP1_UART5, ENABLE); GPIO_ConfigPinRemap(GPIO_RMP3_UART6, ENABLE); } void DMA_Configuration(void) { DMA_InitType DMA_InitStructure; DMA_DeInit(USARTy_Tx_DMA_Channel); DMA_InitStructure.PeriphAddr = USARTy_DR_Base; DMA_InitStructure.MemAddr = (uint32_t)TxBuffer1; DMA_InitStructure.Direction = DMA_DIR_PERIPH_DST; DMA_InitStructure.BufSize = TxBufferSize1; DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_DISABLE; DMA_InitStructure.DMA_MemoryInc = DMA_MEM_INC_ENABLE; DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_BYTE; DMA_InitStructure.MemDataSize = DMA_MEMORY_DATA_SIZE_BYTE; DMA_InitStructure.CircularMode = DMA_MODE_NORMAL; DMA_InitStructure.Priority = DMA_PRIORITY_VERY_HIGH; DMA_InitStructure.Mem2Mem = DMA_M2M_DISABLE; DMA_Init(USARTy_Tx_DMA_Channel, &DMA_InitStructure); DMA_DeInit(USARTy_Rx_DMA_Channel); DMA_InitStructure.PeriphAddr = USARTy_DR_Base; DMA_InitStructure.MemAddr = (uint32_t)RxBuffer1; DMA_InitStructure.Direction = DMA_DIR_PERIPH_SRC; DMA_InitStructure.BufSize = TxBufferSize2; DMA_Init(USARTy_Rx_DMA_Channel, &DMA_InitStructure); DMA_DeInit(USARTz_Tx_DMA_Channel); DMA_InitStructure.PeriphAddr = USARTz_DR_Base; DMA_InitStructure.MemAddr = (uint32_t)TxBuffer2; DMA_InitStructure.Direction = DMA_DIR_PERIPH_DST; DMA_InitStructure.BufSize = TxBufferSize2; DMA_Init(USARTz_Tx_DMA_Channel, &DMA_InitStructure); DMA_DeInit(USARTz_Rx_DMA_Channel); DMA_InitStructure.PeriphAddr = USARTz_DR_Base; DMA_InitStructure.MemAddr = (uint32_t)RxBuffer2; DMA_InitStructure.Direction = DMA_DIR_PERIPH_SRC; DMA_InitStructure.BufSize = TxBufferSize1; DMA_Init(USARTz_Rx_DMA_Channel, &DMA_InitStructure); } void func_init_uart4() { //RCC_Configuration GPIO_APBxClkCmd(USARTx_GPIO_CLK | RCC_APB2_PERIPH_AFIO, ENABLE); USART_APBxClkCmd(USARTx_CLK, ENABLE); //GPIO_Configuration GPIO_InitType GPIO_InitStructure; GPIO_ConfigPinRemap(GPIO_RMP_USART1,ENABLE); GPIO_InitStructure.Pin = USARTx_TxPin; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(USARTx_GPIO, &GPIO_InitStructure); GPIO_InitStructure.Pin = USARTx_RxPin; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(USARTx_GPIO, &GPIO_InitStructure); GPIO_ConfigPinRemap(GPIO_RMP3_UART4, ENABLE); //uart USART_InitStructure.BaudRate = 115200; USART_InitStructure.WordLength = USART_WL_8B; USART_InitStructure.StopBits = USART_STPB_1; USART_InitStructure.Parity = USART_PE_NO; USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE; USART_InitStructure.Mode = USART_MODE_RX | USART_MODE_TX; USART_Init(USARTx, &USART_InitStructure); USART_Enable(USARTx, ENABLE); } void print_dma() { // printf("TxBuffer1 = [%s]rn",(char*)TxBuffer1); // printf("TxBuffer2 = [%s]rn",(char*)TxBuffer2); printf("RxBuffer1 = [%s]rn",(char*)RxBuffer1); // printf("RxBuffer2 = [%s]rn",(char*)RxBuffer2); printf("rn"); } void print_uart_wait() { if(status_wait_uart == true) { status_wait_uart = false; printf("uart transfer waiting......rn"); } } void print_uart_wait_end() { status_wait_uart = true; printf("end uart wait.rn"); } void myDMA_tx(uint8_t uart_id) { // choose dma DMA_Module* dma = USARTy_Tx_DMA_Channel; uint32_t dma_flag = DMA1_FLAG_TC1; switch(uart_id) { case 5: dma = USARTy_Tx_DMA_Channel; dma_flag= DMA1_FLAG_TC1; break; case 6: dma = USARTz_Tx_DMA_Channel; dma_flag = DMA2_FLAG_TC8; break; default: printf("use default uart5rn"); dma = USARTy_Tx_DMA_Channel; dma_flag = DMA1_FLAG_TC1; break; } printf("sendrn"); // tx : send uart data to other dev while (DMA_GetFlagStatus(dma_flag, dma) == RESET) { print_uart_wait(); } print_uart_wait_end(); } void myUart_senddata(uint8_t uart_id,uint8_t* data, uint8_t len_send) { uint8_t * temp_value = data; uint8_t temp_len = len_send; printf("len_send = %d, strvalue = [%s]rn",temp_len,(char * )data); // choose uart USART_Module* uart = USARTy; switch(uart_id) { case 5: uart = USARTy; break; case 6: uart = USARTz; break; default: printf("use default uart5rn"); uart = USARTy; break; } int i=0; while(temp_len > i) { // printf("i = %d, value = %02xrn",i,*temp_value); USART_SendData(uart,*temp_value); // wait until data has send while(USART_GetFlagStatus(uart,USART_FLAG_TXDE)==RESET) { } i++; temp_value++; } return; } void myUart_tx(uint8_t uart_id,uint8_t * data,uint8_t len_send) { int len_str = strlen(data); bool str_data = len_send>=len_str; // if send overside strlen, just send strlen int len = str_data? len_str:len_send; printf("strlen = %d, send len = %d, send>strlen = %srn",len_str,len_send, str_data?"true":"false"); if(str_data == true) { printf("send data len overside str_len.rn"); } else { printf("send data len = %d.rn",len_send); } myUart_senddata(uart_id,data,len); } void myUart_rx(uint8_t uart_id,bool rx_tx) { USART_Module * uart = USARTy; DMA_Module * dma = USARTy_Rx_DMA_Channel; switch(uart_id) { case 5: uart = USARTy; dma = USARTy_Rx_DMA_Channel; break; case 6: uart = USARTz; dma = USARTz_Rx_DMA_Channel; break; default: printf("use default uart5rn"); uart = USARTy; break; } // printf("receivern"); // rx : get uart data from other dev while (USART_GetFlagStatus(uart, USART_FLAG_IDLEF) == RESET) { print_uart_wait(); } print_uart_wait_end(); printf("uart is idlefrn"); int dma_last = DMA_GetCurrDataCounter(USARTy_Rx_DMA_Channel); printf("dma get count =%d rn",dma_last); printf("has recv data len = %drn",TxBufferSize2-dma_last); reset_dma_rx(); } void reset_dma_rx() { print_dma(); memset(RxBuffer1,0x00,sizeof(RxBuffer1)); DMA_EnableChannel(USARTy_Rx_DMA_Channel, DISABLE); DMA_SetCurrDataCounter(USARTy_Rx_DMA_Channel,TxBufferSize1); DMA_EnableChannel(USARTy_Rx_DMA_Channel, ENABLE); // clear idlef flag USART_ReceiveData(USARTy); } void reset_dma_tx() { print_dma(); memset(TxBuffer1,0x00,sizeof(TxBuffer1)); DMA_EnableChannel(USARTy_Rx_DMA_Channel, DISABLE); DMA_SetCurrDataCounter(USARTy_Rx_DMA_Channel,TxBufferSize1); DMA_EnableChannel(USARTy_Rx_DMA_Channel, ENABLE); // clear idlef flag USART_ReceiveData(USARTy); } void delay(vu32 nCount) { vu32 index = 0; for (index = (34000 * nCount); index != 0; index--) { } }
可以看到,串口接收工具
- 收到dma传输的字符串
- 收到通过uart函数传输的字符串
- 向uart5发出不定长度的数据,log中显示出来获取的数据及长度。
USART_SendData:uart传输数据tx
USART_GetFlagStatus:获取uart状态,根据传入的uart和flag,返回set表示该flag已经设置,则跳出while循环
DMA_GetCurrDataCounter:获取dma剩余空间长度,用于计算当前收到了多少数据。
DMA_EnableChannel:开关dma的channel,两个dma,每个有8channel。
DMA_SetCurrDataCounter:设置当前dma的指针。
PS:收到过一次后需要开关dma,然后重新设置当前数据数。
此外,由于判断dma收到数据状态,通过判断usart的idle,空闲中断。
当判定到uart收到空闲中断,则表示uart数据传输完成。不过该状态清空需要使用到receive函数。
USART_ReceiveData:uart接收数据rx。
本章介绍了结合uart及dma实现数据的收发,后续再结合串口屏实现功能。



