完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
硬件:stm32f103cbt6
软件:STM32F10x_StdPeriph_Lib_V3.5.0 DMA,直接内存接受访问,类似用它随身释放的CPU的,灵魂,通过USART进行直接接收,接受使用DMA的方式,CPU不需要进行,当完成之后数据可以从内存的读取,从而减少了CPU的压力。 具体的代码实现如下:
头文件 usart_driver.h已经声明了外部函数可能用到的接口; USART3_DR地址的 因为USART3接收到数据会存在DR寄存器中,而DMA控制器则负责将该寄存器中的内容一一搬运到内存的缓冲区中(比如你定义的某个数组中),所以这里需要告诉DMA控制去哪里搬运,因此需要设置USART3_DR的总线地址。 USART3的如图所示; DR基地址的移动地址图所示; 所以最终地址为:0x40004800 + 0x004 #define USART_DR_Base 0x40004804 DMA的通道 有很多外设都可以使用DMA,例如ADC,I2C,SPI等等,所以,不同的外设选择属于自己的DMA通道,看参考手册; 因此USART3_RX会使用DMA1的通道3,这都是自带的已经有了这个管道的好,我们需要遵循规则。 所以在代码中我们做出相应的定义;如下所示; #define USART_Rx_DMA DMA1_Channel3 DMA的中断 DMA支持中断:传输过半,传输完成,传输出错; 因此在使用是相当安全也相当灵活,而这里只是用传输完成中断;如定义了,传输完成中断的标志位,DMA1_FLAG_TC3对应的TCIF; #USART_Rx_DMA_FLAG DMA1_FLAG_TC3 USART接收接收函数 在STM32的HAL中封装了大量的外设,但是自己使用,但是非常方便,但是标准库中没有什么操作,这里我们接收接收就是实现,rx_cbk就是实现,即用户数据完成就可以开始注册了函数; typedef void (*rx_cbk)(void* args); 通过使用usart_set_rx_cbk进行接口函数的注册,pargs为将传递的参数 路径;void usart_set_rx_cbk(uart_mod_t *pmod, rx_cbk pfunc,void *pargs); 头文件源码 #ifndef USART_DRIVER_H #define USART_DRIVER_H #include #include /* Private function prototypes -----------------------------------------------*/ #define USE_MICROLIB_USART 1 #if USE_MICROLIB_USART #ifdef __GNUC__ /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf set to 'Yes') calls __io_putchar() */ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) //#define GETCHAR_PROTOTYPE int fgetc(FILE *f) #endif /* __GNUC__ */ extern PUTCHAR_PROTOTYPE; #else #endif //default 8N1 #define COM_PORT USART3 #define TX_PIN GPIO_Pin_10 #define RX_PIN GPIO_Pin_11 #define BAUDRATE 115200 #define IRQ_UART_PRE 3 #define IRQ_UART_SUB 3 #define USART_Rx_DMA_Channel DMA1_Channel3 #define USART_Rx_DMA_FLAG DMA1_FLAG_TC3 #define USART_DR_Base 0x40004804 #define USART_BUF_SIZE ((uint16_t)16) typedef void (*rx_cbk)(void* args); struct uart_mod { uint8_t rx_buf[USART_BUF_SIZE]; uint8_t rx_dat_len; uint8_t head; uint8_t tail; void (*init)(void); void *pargs; rx_cbk pfunc_rx_cbk; }; typedef struct uart_mod uart_mod_t; extern uart_mod_t user_uart_mod; void usart_init(void); void usart_set_rx_cbk(uart_mod_t *pmod, rx_cbk pfunc,void *pargs); void usart_send_char(char ch); void usart_test_echo(void); uint8_t usart_recv_char(void); int usart_printf(const char *fmt, ...); //extern GETCHAR_PROTOTYPE; #endif DMA的基本配置 串口接收DMA的配置在函数dma_init中; static void dma_init(void) 已经定义了数据缓冲区,如下: uint8_t RxBuffer[USART_BUF_SIZE] = { 0 }; 因此需要在 DMA 中设置 USART_DR 的地址,和数据大小配置的地址,以及接触; 还有就是数据流;
DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_Base; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)RxBuffer; DMA_InitStructure.DMA_BufferSize = USART_BUF_SIZE; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 注意: DMA_DIR_PeripheralSRC,外设作为源地址,数据是从外设地址向内存,即DMA数据从地址USART_DR_Base携带到RxBuffer去。 如果这个地方搞错了,会导致RxBuffer总是没有你想要的数据。 环形队列接收数据 线性缓冲区会因为缓冲器接收数据已满导致无法继续接收的问题;而环形队列进行接收的话,会自动进行覆盖,这样一来,在读取数据的时候,还要处理一个循环循环模式,下面的配置是把DMA配置为循环模式; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; 在结构体_uart_mod中,则用两个变量变量单独的引导队首头和尾队; 具体的在函数中读取数据USART3_IRQHandler中,敏感数据从内存的RxBuffer读取到结构体user_uart_mod的成员rx_buf中; 最终调用回调函数。 |
|
|
|
函数原型 usart_driver.c #include #include #include "stm32f10x_usart.h" #include "usart_driver.h" uint8_t RxBuffer[USART_BUF_SIZE] = { 0 }; uart_mod_t user_uart_mod = { .rx_dat_len = 0, .head = 0, .tail = 0, .pfunc_rx_cbk = NULL, .pargs = NULL }; static USART_InitTypeDef USART_InitStructure; static void rcc_init(void){ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); /* Enable GPIO clock */ RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); RCC_APB1PeriphClockCmd( RCC_APB1Periph_USART3, ENABLE); } static void gpio_init(void){ GPIO_InitTypeDef GPIO_InitStructure; /* Configure USART Tx as alternate function push-pull */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin = TX_PIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); /* Configure USART Rx as input floating */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Pin = RX_PIN; GPIO_Init(GPIOB, &GPIO_InitStructure); } static void dma_init(void){ DMA_InitTypeDef DMA_InitStructure; /* USARTy_Tx_DMA_Channel (triggered by USARTy Tx event) Config */ DMA_DeInit(USART_Rx_DMA_Channel); DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_Base; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)RxBuffer; //DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = USART_BUF_SIZE; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(USART_Rx_DMA_Channel, &DMA_InitStructure); } static void irq_init(void){ NVIC_InitTypeDef NVIC_InitStructure; /* Enable the USART3_IRQn Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = IRQ_UART_PRE; NVIC_InitStructure.NVIC_IRQChannelSubPriority = IRQ_UART_SUB; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } void usart_send_char(char ch){ /* Loop until the end of transmission */ //while (USART_GetFlagStatus(COM_PORT, USART_FLAG_TC) == RESET){} while((COM_PORT->SR & USART_FLAG_TC) != USART_FLAG_TC){ } USART_SendData(COM_PORT, (uint8_t) ch); } uint8_t usart_recv_char(){ /* Wait the byte is entirely received by USARTy */ //while(USART_GetFlagStatus(COM_PORT, USART_FLAG_RXNE) == RESET){} while((COM_PORT->SR & USART_FLAG_RXNE) != USART_FLAG_RXNE){ } /* Store the received byte in the RxBuffer1 */ return (uint8_t)USART_ReceiveData(COM_PORT); } int usart_printf(const char *fmt, ... ) { uint8_t i = 0; uint8_t usart_tx_buf[128] = { 0 }; va_list ap; va_start(ap, fmt ); vsprintf((char*)usart_tx_buf, fmt, ap); va_end(ap); while(usart_tx_buf && i < 128){ usart_send_char(usart_tx_buf); i++; } usart_send_char(' |