完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
1.1 实现方法
利用DMA接收接口数据,在一定程度上会节省CPU的消耗。大多数接口接收都是接收一个字节就中断一次,如果数据上需要实时接收大量的数据,这会导致出现中断利用DMA发送数据可以实现自己不会进入中断。实现思路如下:
上代码,这里以STM32G473为例,其他系列需要修改DMA或串口的配置,这种方式在大多数单片上都可以实现,(在华大单片F460上面测试实现了) #include <../COM/MQueue.h> #include <../HAL/MSerial0.h> // #include #include "sys.h" struct MSerial0 gSerial0; #define fa (gSerial0.base) #define me (gSerial0) #define my (gSerial0.pri) #define Serial0_BUFFER_SIZE (1024Ul) // DMA 数据缓存最大长度 uint8_t USART1_R_data[Serial0_BUFFER_SIZE]; uint8_t USART1_T_data[Serial0_BUFFER_SIZE]; struct MSerial0 { struct MSerial base; //继承MSerial struct { uint8_t rxBuf[MSerial_BUFLEN]; uint8_t txBuf[MSerial_BUFLEN]; struct MQueue rq; struct MQueue tq; } pri; }; UART_HandleTypeDef huart1; uint8_t bufrx[64]; //接收缓冲,最大64个字节. //串口1 初始化 void InitUsart1(uint32_t baudRate) { // GPIO端口设置 GPIO_InitTypeDef GPIO_Initure; __HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟 __HAL_RCC_USART1_CLK_ENABLE(); //使能USART1时钟 GPIO_Initure.Pin = GPIO_PIN_9 | GPIO_PIN_10; // PA9,10 GPIO_Initure.Mode = GPIO_MODE_AF_PP; //复用推挽输出 GPIO_Initure.Pull = GPIO_PULLUP; //上拉 GPIO_Initure.Speed = GPIO_SPEED_FAST; //高速 GPIO_Initure.Alternate = GPIO_AF7_USART1; //复用为USART1 HAL_GPIO_Init(GPIOA, &GPIO_Initure); //初始化PA9,10 // USART 初始化设置 huart1.Instance = USART1; huart1.Init.BaudRate = baudRate; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; __HAL_UART_DISABLE_IT(&huart1, UART_IT_TC); if (HAL_UART_Init(&huart1) != HAL_OK) { // Error_Handler(); } } DMA_HandleTypeDef UART1TxDMA_Handler; // DMA句DMA_HandleTypeDef UART1TxDMA_Handler; //DMA句 DMA_HandleTypeDef hdma_usart1_rx; DMA_HandleTypeDef hdma_usart1_tx; // DMA 收发串口数据 初始化 void InitDMAforUsart1() { __HAL_RCC_DMAMUX1_CLK_ENABLE(); __HAL_RCC_DMA1_CLK_ENABLE(); /* USART1 DMA Init */ /* USART1_RX Init */ hdma_usart1_rx.Instance = DMA1_Channel1; hdma_usart1_rx.Init.Request = DMA_REQUEST_USART1_RX; hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart1_rx.Init.Mode = DMA_CIRCULAR; hdma_usart1_rx.Init.Priority = DMA_PRIORITY_MEDIUM; if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK) { // Error_Handler(); } __HAL_LINKDMA(&huart1, hdmarx, hdma_usart1_rx); HAL_UART_Receive_DMA(&huart1, USART1_R_data, Serial0_BUFFER_SIZE); /* USART1_TX Init */ hdma_usart1_tx.Instance = DMA1_Channel2; hdma_usart1_tx.Init.Request = DMA_REQUEST_USART1_TX; hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart1_tx.Init.Mode = DMA_NORMAL; hdma_usart1_tx.Init.Priority = DMA_PRIORITY_MEDIUM; if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK) { // Error_Handler(); } hdma_usart1_tx.Instance->CPAR = (uint32_t)&huart1.Instance->TDR; __HAL_LINKDMA(&huart1, hdmatx, hdma_usart1_tx); } uint32_t Cnum = 0; static void _Init(uint32_t baudRate) { InitUsart1(baudRate); InitDMAforUsart1(); MQueue(&my.rq, MSerial_BUFLEN); MQueue(&my.tq, MSerial_BUFLEN); } static uint32_t _Recv(uint8_t* pData, uint32_t rxMaxLen) { uint32_t max = rxMaxLen; while ((rxMaxLen) && (my.rq.deep > 0)) { rxMaxLen--; *pData++ = my.rxBuf[my.rq.tail]; my.rq.Del(&my.rq); } Cnum += (max - rxMaxLen); return max - rxMaxLen; } static void _Send(uint8_t* dataflow, uint32_t num) { num = (num < MSerial_BUFLEN) ? num : MSerial_BUFLEN; while (num--) { my.txBuf[my.tq.head] = *dataflow++; my.tq.Add(&my.tq); } } static void _Period(void) { static uint8_t step = 1; int len, i; static uint32_t last_add = 0; uint32_t temp_add; temp_add = Serial0_BUFFER_SIZE - hdma_usart1_rx.Instance->CNDTR; if (last_add != temp_add) { if (last_add < temp_add) { len = temp_add - last_add; i = last_add; while (len--) { my.rxBuf[my.rq.head] = USART1_R_data[i++]; my.rq.Add(&my.rq); //队列增加 } last_add = temp_add; } else { len = Serial0_BUFFER_SIZE - last_add; i = last_add; while (len--) { my.rxBuf[my.rq.head] = USART1_R_data[i++]; my.rq.Add(&my.rq); //队列增加 } i = 0; len = temp_add; while (len--) { my.rxBuf[my.rq.head] = USART1_R_data[i++]; my.rq.Add(&my.rq); //队列增加 } last_add = temp_add; } } /**********step2 :处理发送**********/ switch (step) { case 0: if (__HAL_DMA_GET_FLAG(&UART1TxDMA_Handler, DMA_FLAG_TC2)) // DMA 发送完毕 { __HAL_DMA_CLEAR_FLAG(&UART1TxDMA_Handler, DMA_FLAG_TC2); //清除DMA2_Steam7传输完成标志 hdma_usart1_tx.State = HAL_DMA_STATE_READY; hdma_usart1_tx.Lock = HAL_UNLOCKED; step = 1; } hdma_usart1_rx.State = HAL_DMA_STATE_BUSY; break; case 1: len = 0; while ((my.tq.deep > 0)) { USART1_T_data[len++] = my.txBuf[my.tq.tail]; my.tq.Del(&my.tq); //删除一个 } if (len) { HAL_DMA_Start(huart1.hdmatx, (uint32_t)USART1_T_data, (uint32_t)&huart1.Instance->TDR, len); huart1.Instance->CR3 |= USART_CR3_DMAT; //使能串口DMA发送 break step = 0; } else { /* code */ } break; } } /* * 构造函数 * */ struct MSerial* MSerial0_Creat(void) // { memset(&me, 0, sizeof(struct MSerial0)); fa.Init = _Init; fa.Rx = _Recv; fa.Tx = _Send; fa.Period = _Period; return &fa; } #ifndef _BUSART0_H_ #define _BUSART0_H_ #include "MSerial.h" //引用框架 #define MSerial_BUFLEN (1000) struct MSerial * MSerial0_Creat(void); //构造函数要重写 #endif #ifndef _M_SERIAL_H_ #define _M_SERIAL_H_ /************************************ * MSerial 对象模板 ************************************/ struct MSerial { //MD_OBJ parent; //父类 void (* Init)(uint32_t baudRate); uint32_t (* Rx)( uint8_t *pData , uint32_t rxMaxLen); void (* Tx)( uint8_t *pData , uint32_t txLen ); void (* Period)(void); }; #endif 1.2使用方法: 1. 创建对象 初始化 pSerial0 = MSerial0_Creat(); pSerial0->Init(115200) 2. 滴答定时器可以产生系统时间,同时可以将串口的需要定时调用的函数放入,滴答定时器中 void SysTick_Handler(void) { uint8_t reb[500]; int len; static int t = 0; // SysTick_IncTick(); t++; HAL_IncTick(); if (t > 4) { pSerial0->Period(); t = 0; // len = pSerial0->Rx(reb, 250); // pSerial0->Tx(reb, len); } pCpu0->Period1ms(); } 3.发送数据 pSerial0->Tx((uint8_t*)"hello world", strlen("hello world")); 4.接收数据 uint8_t rxByte[128]; pSerial0->Rx(rxByte, 128); |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1627 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1550 浏览 1 评论
984 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
688 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1601 浏览 2 评论
1869浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
652浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
520浏览 3评论
539浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
508浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-25 05:31 , Processed in 0.718560 second(s), Total 79, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号