此内容由EEWORLD论坛网友懒猫爱飞原创,如需转载或用于商业用途需征得作者同意并注明出处
关于STM32F03X串口空闲中断+DMA的应用Author:Mark Xu
前言偶然得到一块STM32F030的开发板,业余时间手痒痒,写点小程序练练手,一般调试时,用串口比较多,结合网上的资料,整理了一下串口中断与DMA的结合方式,测试了一下,用来起还不错,发送与接收都是用的是DMA方式,当然如果有其它紧急任务需要用到DMA可以让你其它任务,这里暂时不讨论其它。
概述为了测试方便,暂时没有用到硬件流摈,也没有用到循环队列存储数据,只做了一下简单的测试,STM32F03X某些型号有两个串口,而我这块开发板正好是有两个串口,故两个串口都把它用上了^_^
因为属于简单的应用,说白了就是串口初始化及一些简单的小程序,而又因为是事后结合代码作的总结,故实验结果没有贴上来,如果日后有机会,可以再补齐。关于串口的API主要包括两个源文件Dsk_Usart.c及Dsk_Usart.h
Dsk_Usart.c源文件该源文件中主要包括的是串口的配置及一些简单的API,关于串口的配置主要涉及下面几个:
// 最多可以接收到字节数 #define USART_RXD_BUF_SIZE (64) // 最多可以发送64字节 #define USART_TXD_BUF_SIZE (64) // 最多可以打印64个字符 #define DEBUG_PRINT_BUF_LEN (64) // 串口2缓存大小 #define USART2_RX_BUF_SIZE (32) #define USART2_TX_BUF_SIZE (32) // 发送方式配置 // 查询方式/DMA中断方式 #define UART_SNED_REQ (0) #define UART_SEND_DMA (1) #define USART1_RXD_MODE UART_SEND_DMA #define USART2_RXD_MODE UART_SNED_REQ |
接收缓存与发射缓存根据MCU的RAM而定吧,这个没有什么限制,只要够用就好。发送方式一般用查询方式或用DMA方式,查询方式对于发送少量数据没的应用没有什么影响,如果单次发送的数据量比较大,最好用DMA配合中断的方式,这样不浪费MCU的资源而且不会造成信息阻塞。
该源文件中关于USART的函数有以下几个:
- void Uart1_Gpio_Init(void) - 端口初始化的,注意是否进行了重新映射
- void Uart1_DMA_Init(void) - DMA通道初始化,注意是否进行了重新映射
- void UART1_Api_Init(void) - 串口1初始化函数
- void USART1_IRQHandler(void) –串口1中断函数,函数名要与启动文件中的名称一致
- void Uart1_Data_Process(pRevprocessDat) – 算是接收到的数据
- void Uart1_Send_Bytes(uint8_t*dat,uint16_t len) –通过串口1发送数据
- int Debug_Printf(const char*fmt, ...) – 把串口1发送函数包装成了类似printf的函数,方便调试打印
- void Uart2_Gpio_Init(void) – 与串口11类似
- void Uart2_DMA_Init(void) –DMA初始化,与串口1类似
- void UART2_Api_Init(void) – 串口2初始化化,与串口1类似
- void USART2_IRQHandler(void) –串口2中断,与串口1类似
- void Uart2_Data_Process(pRevprocessDat) – 处理接收数据
- void Uart2_Send_Bytes(uint8_t*dat,uint16_t len) – 串口2发送数据
串口1与串口2的初始化函数及发送接收函数类似,本来可以整理成数组方式,比如把端口,DMA通道等加到相应的数组中,就可以同时初始化,可以节省一些代码空间,代码也可以更整洁一些。由于我开始只做了串口1的测试,没有做串口2的实验,后面想着既然实验就把两个都测试了,于是为了偷懒,直接复制了一份代码,这个不是好习惯,当然这样也代码也更清楚。好吧,不找理由,下次如果项目上用到,直接整合到一块^_^
下面是Dsk_Usart.c的源文件,我用的是3.5版本的库文件,如果您与我的版本不一样,注意修改一下寄存器或修改相关调用的库函数。
- /*********************************************************************************
- * Copyright (C) 2000-2018 Mark Xu WorkStudio,All Rights Reserved.
- *
- * File : Dsk_Uart.c
- *
- * Brief : Uart api Module
- *
- * Author :Mark Xu
- *
- * Remark :None
- ---------------------------------------------------------------------------------
- * Modify Content: NULL
- *
- * Modify Date : xxxx/xx/xx/ xx:xx
- *
- * Modify staff :xx xx
- **********************************************************************************/
- #define DSKUART_IMPLATION
-
-
- /*********************************************************************************
- * Include
- **********************************************************************************/
- #include <stdio.h>
- #include <stdint.h>
- #include <string.h>
- #include <stdarg.h> // 使用可变参数
- #include<stdlib.h> // 动态内存分配
-
- #include"stm32f0xx_Lib.h"
- #include"Dsk_Lib.h"
-
-
- /*********************************************************************************
- * Macros
- **********************************************************************************/
- // 最多可以接收到字节数
- #defineUSART_RXD_BUF_SIZE (64)
- // 最多可以发送64字节
- #defineUSART_TXD_BUF_SIZE (64)
- // 最多可以打印128个字符
- #defineDEBUG_PRINT_BUF_LEN (64)
- // 串口2缓存大小
- #defineUSART2_RX_BUF_SIZE (32)
- #defineUSART2_TX_BUF_SIZE (32)
-
- // 发送方式配置
- // 查询方式/DMA中断方式
- #define UART_SNED_REQ (0)
- #define UART_SEND_DMA (1)
- #define USART1_RXD_MODE UART_SEND_DMA
- #define USART2_RXD_MODE UART_SNED_REQ
-
- /*********************************************************************************
- * Variables
- **********************************************************************************/
- // The receive data buffer
- static uint8_trev_buff[USART_RXD_BUF_SIZE] = {0};
- static uint8_tdatBuff[USART_RXD_BUF_SIZE] = {0};
- static uint8_trevUart2[USART_RXD_BUF_SIZE] = {0};
- static uint8_tdatUart2Buff[USART_RXD_BUF_SIZE] = {0};
- static uint8_t sendBuff[DEBUG_PRINT_BUF_LEN]= {0};
- static uint8_tsend2Buff[USART2_TX_BUF_SIZE] = {0};
-
-
- // TRUE - been receiveddata FALSE - no data received
- static uint8_t revFlag = FALSE;
- static uint8_t revUart2Flag= FALSE;
-
-
- /*********************************************************************************
- * Name : Uart1_Gpio_Init
- *
- * Brief : Initialized the uart1 port.
- *
- * Input : None
- *
- * Output : None
- *
- * Remark :PA9-TX,PA10-RX,banudrate=9600
- ***********************************************************************************/
- void Uart1_Gpio_Init(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- USART_InitTypeDef USART_InitStructure;
- NVIC_InitTypeDef NVIC_InitStructure;
-
- // 开启串口时钟及端口时钟
- RCC_APB2PeriphClockCmd(USART1_RCC, ENABLE);
- RCC_AHBPeriphClockCmd(USART1_PORT_RCC,ENABLE);
- GPIO_PinAFConfig(USART1_MAP_PORT,UART1_TXD_PINSOURCE, UART1_AF_TXD);
- GPIO_PinAFConfig(USART1_MAP_PORT,UART1_RXD_PINSOURCE, UART1_AF_RXD);
-
- // 配置TX端口
- GPIO_InitStructure.GPIO_Pin = (UART1_TXD_PIN | UART1_RXD_PIN);
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
- GPIO_InitStructure.GPIO_OType =GPIO_OType_PP;
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(USART1_MAP_PORT, &GPIO_InitStructure);
-
- // 配置串口模式
- USART_InitStructure.USART_BaudRate = USART1_BAUDRATE;
- USART_InitStructure.USART_WordLength = USART_WordLength_8b;
- USART_InitStructure.USART_StopBits = USART_Parity_No;
- USART_InitStructure.USART_HardwareFlowControl =USART_HardwareFlowControl_None;
- USART_InitStructure.USART_Mode = (USART_Mode_Rx |USART_Mode_Tx);
- USART_Init(USART1,&USART_InitStructure);
-
- // TXE发送中断,TC传输完成中断,RXNE接收中断,PE奇偶错误中断,可以是多个
- USART_ITConfig(USART1,USART_IT_TC,DISABLE);
- // 设置总线空闲产生中断
- USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);
- // 必须先清除IDLE中断,否则会一直进IDLE中断
- USART1->ICR |= 1<<4;
- USART_ITConfig(USART1, USART_IT_RXNE,DISABLE);
-
- // 开启串口DMA接收
- USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
- // 开启串口1
- USART_Cmd(USART1,ENABLE);
-
- // 中断配置
- NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPriority= 2;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
- }
-
- /*********************************************************************************
- * Name : Uart1_DMA_Init
- *
- * Brief : Initialized the uart1 DMA.
- *
- * Input : None
- *
- * Output : None
- *
- * Remark : None
- ***********************************************************************************/
- void Uart1_DMA_Init(void)
- {
- DMA_InitTypeDef DMA_Initstruct;
-
- // 开启DMA时钟
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
- //DMA1通道3配置
- DMA_DeInit(USART1_RXD_MA_CHANNEL);
-
- // DMA配置
- // 外设地址
- DMA_Initstruct.DMA_PeripheralBaseAddr = (uint32_t)(&USART1->RDR);
- // 内存地址
- DMA_Initstruct.DMA_MemoryBaseAddr =(uint32_t)rev_buff;
- // DMA传输方向单向
- DMA_Initstruct.DMA_DIR =DMA_DIR_PeripheralSRC;
- // 设置DMA在传输时缓冲区的长度
- DMA_Initstruct.DMA_BufferSize =USART_RXD_BUF_SIZE;
- // 设置DMA的外设递增模式,一个外设
- DMA_Initstruct.DMA_PeripheralInc =DMA_PeripheralInc_Disable;
- // 设置DMA的内存递增模式
- DMA_Initstruct.DMA_MemoryInc =DMA_MemoryInc_Enable;
- // 外设数据字长
- DMA_Initstruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
- // 内存数据字长
- DMA_Initstruct.DMA_MemoryDataSize =DMA_MemoryDataSize_Byte;
- // 设置DMA的传输模式
- DMA_Initstruct.DMA_Mode =DMA_Mode_Normal;
- // 设置DMA的优先级别
- DMA_Initstruct.DMA_Priority = DMA_Priority_High; //DMA_Priority_VeryHigh;
- // 设置DMA的2个memory中的变量互相访问
- DMA_Initstruct.DMA_M2M =DMA_M2M_Disable;
- DMA_Init(USART1_RXD_MA_CHANNEL,&DMA_Initstruct);
- // USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
- // 开启DMA
- DMA_Cmd(USART1_RXD_MA_CHANNEL,ENABLE);
-
- #if( USART1_RXD_MODE ==UART_SEND_DMA )
- // DMA1通道TXD配置
- DMA_DeInit(USART1_TXD_MA_CHANNEL);
- // 外设地址,串口1
- DMA_Initstruct.DMA_PeripheralBaseAddr =(uint32_t)(&USART1->TDR);
- // 发送内存地址
- DMA_Initstruct.DMA_MemoryBaseAddr = (uint32_t)sendBuff;
- // 外设为传送数据目的地,即发送数据
- DMA_Initstruct.DMA_DIR =DMA_DIR_PeripheralDST;
- // 发送长度为0,即未有快递需要发送
- DMA_Initstruct.DMA_BufferSize = 0;
- // 初始化
- DMA_Init(USART1_TXD_MA_CHANNEL, &DMA_Initstruct);
- // 使能串口发送完成中断
- USART_ITConfig(USART1, USART_IT_TC,ENABLE);
- DMA_Cmd(USART1_TXD_MA_CHANNEL,ENABLE);
- // 使能DMA串口发送和接受请求
- USART_DMACmd(USART1,(USART_DMAReq_Tx|USART_DMAReq_Rx), ENABLE);
- #endif /* USART1_RXD_MODE */
-
- }
-
- /*********************************************************************************
- * Name : UART1_Api_Init
- *
- * Brief : Initialized the uart1
- *
- * Input : None
- *
- * Output : None
- *
- * Remark : None
- ***********************************************************************************/
- void UART1_Api_Init(void)
- {
- Uart1_Gpio_Init();
- Uart1_DMA_Init();
- }
-
- /*********************************************************************************
- * Name : USART1_IRQHandler
- *
- * Brief : USART1 interrupt process handle
- *
- * Input : None
- *
- * Output : None
- *
- * Remark : None
- ***********************************************************************************/
- void USART1_IRQHandler(void)
- {
- uint8_t len = 0;
-
- if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)
- {
- USART1->ICR |= 1<<4; // 清除中断
- DMA_Cmd(USART1_RXD_MA_CHANNEL,DISABLE);
-
- len =USART_RXD_BUF_SIZE - DMA_GetCurrDataCounter(USART1_RXD_MA_CHANNEL);
-
- if(len >USART_RXD_BUF_SIZE)
- len= USART_RXD_BUF_SIZE;
-
- memcpy(datBuff,rev_buff,len);
-
- // 重新设置接收数据个数
- USART1_RXD_MA_CHANNEL->CNDTR =USART_RXD_BUF_SIZE;
- // 开启DMA
- DMA_Cmd(USART1_RXD_MA_CHANNEL,ENABLE);
-
- revFlag = TRUE;
- }
-
- #if( USART1_RXD_MODE ==UART_SEND_DMA )
- // 全部数据发送完成,产生该标记
- if(USART_GetITStatus(USART1,USART_IT_TC)!=RESET)
- {
- // 清除完成标记
- USART_ClearITPendingBit(USART1,USART_IT_TC);
- DMA_Cmd(USART1_TXD_MA_CHANNEL, DISABLE);
- // 清除数据长度
- USART1_TXD_MA_CHANNEL->CNDTR = 0;
- DMA_Cmd(USART1_TXD_MA_CHANNEL, ENABLE);
- }
- #endif /* USART1_RXD_MODE */
- }
-
- /*********************************************************************************
- * Name : Uart1_Data_Process
- *
- * Brief : process the received data
- *
- * Input : processDat - the process function point
- *
- * Output : None
- *
- * Remark : None
- ***********************************************************************************/
- void Uart1_Data_Process(pRevprocessDat)
- {
- if(!revFlag)
- return;
- revFlag = FALSE;
-
- processDat(datBuff);
-
- }
-
-
- /*********************************************************************************
- * Name : Uart1_Send_Bytes
- *
- * Brief : process the received data
- *
- * Input : dat - the data buffer
- *
- * len - the count of data to be send
- *
- * Output : None
- *
- * Remark : None
- ***********************************************************************************/
- voidUart1_Send_Bytes(uint8_t *dat,uint16_t len)
- {
- #if 0//( USART1_RXD_MODE == UART_SNED_REQ )
- while(len--)
- {
- USART_SendData(USART1, *dat++);
- /* Loop until the end of transmission */
- while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
- }
- #else
- // 判断长度是否有效
- if(!len)
- return ;
- while(DMA_GetCurrDataCounter(USART1_TXD_MA_CHANNEL));
-
- // 检查DMA发送通道内是否还有数据
- if(dat)
- memcpy(sendBuff, dat,(len >DEBUG_PRINT_BUF_LEN ? DEBUG_PRINT_BUF_LEN:len));
-
- // DMA发送数据-要先关 设置发送长度 开启DMA
- DMA_Cmd(USART1_TXD_MA_CHANNEL, DISABLE);
- // 设置发送长度
- USART1_TXD_MA_CHANNEL->CNDTR = len;
- // 启动DMA发送
- DMA_Cmd(USART1_TXD_MA_CHANNEL, ENABLE);
- #endif /**/
- }
-
- /*********************************************************************************
- * Name : Debug_Printf
- *
- * Brief : print the debug information
- *
- * Input : *fmt - the print data type
- *
- * Output : None
- *
- * Remark : just like theprintf() function
- ***********************************************************************************/
- int Debug_Printf(const char*fmt, ...)
- {
- uint32_t ulLen = 0;
-
- #ifdef UART_DEBUG_PRINT
-
- va_list ap;
- // 开辟缓冲区
- // char *pBuf = (char*)OS_MALLOC(DEBUG_PRINT_BUF_LEN);
- char *pBuf = (char*)malloc(DEBUG_PRINT_BUF_LEN);
- va_start(ap,fmt);
-
- if(pBuf != NULL)
- {
- // 用虚拟打印函数实现
- ulLen = vsprintf(pBuf,fmt,ap);
-
- va_end(ap);
- // 从串口输出
- Uart1_Send_Bytes((uint8_t *)pBuf,ulLen );
- // 释放存储空间
- //OS_FREE(pBuf);
- free(pBuf);
- }
-
- #endif /* UART_DEBUG_PRINT*/
-
- return ulLen;
- }
-
- /////////////////////////////////////////////////////////////////////////////////////////////////////////
- // USART2 相关API - 主要用于级联信号
- /////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- /*********************************************************************************
- * Name : Uart2_Gpio_Init
- *
- * Brief : Initialized the uart2 port.
- *
- * Input : None
- *
- * Output : None
- *
- * Remark :PA3-TX,PA2-RX,banudrate=9600
- ***********************************************************************************/
- void Uart2_Gpio_Init(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- USART_InitTypeDef USART_InitStructure;
- NVIC_InitTypeDef NVIC_InitStructure;
-
- // 开启串口时钟及端口时钟
- RCC_APB1PeriphClockCmd(USART2_RCC,ENABLE);
- RCC_AHBPeriphClockCmd(USART2_PORT_RCC,ENABLE);
- GPIO_PinAFConfig(USART2_MAP_PORT,UART2_TXD_PINSOURCE, UART2_AF_TXD);
- GPIO_PinAFConfig(USART2_MAP_PORT,UART2_RXD_PINSOURCE, UART2_AF_RXD);
-
- // 配置TX端口
- GPIO_InitStructure.GPIO_Pin = UART2_TXD_PIN | UART2_RXD_PIN;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
- GPIO_InitStructure.GPIO_OType =GPIO_OType_PP;
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(USART2_MAP_PORT, &GPIO_InitStructure);
-
-
- // 配置串口模式
- USART_InitStructure.USART_BaudRate = USART2_BAUDRATE;
- USART_InitStructure.USART_WordLength = USART_WordLength_8b;
- USART_InitStructure.USART_StopBits = USART_Parity_No;
- USART_InitStructure.USART_HardwareFlowControl =USART_HardwareFlowControl_None;
- USART_InitStructure.USART_Mode = USART_Mode_Rx |USART_Mode_Tx;
- USART_Init(USART2,&USART_InitStructure);
-
- //TXE发送中断,TC传输完成中断,RXNE接收中断,PE奇偶错误中断,可以是多个
- USART_ITConfig(USART2,USART_IT_TC,DISABLE);
- // 设置总线空闲产生中断
- USART_ITConfig(USART2,USART_IT_IDLE,ENABLE);
- USART2->ICR |= 1<<4; //必须先清除IDLE中断,否则会一直进IDLE中断
- USART_ITConfig(USART2, USART_IT_RXNE,DISABLE);
-
- // 开启串口DMA接收
- USART_DMACmd(USART2,USART_DMAReq_Rx,ENABLE);
- // 开启串口2
- USART_Cmd(USART2,ENABLE);
-
-
- // 中断配置
- NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPriority= 2;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
- }
-
- /*********************************************************************************
- * Name : Uart2_DMA_Init
- *
- * Brief : Initialized the uart2 DMA.
- *
- * Input : None
- *
- * Output : None
- *
- * Remark : None
- ***********************************************************************************/
- void Uart2_DMA_Init(void)
- {
- DMA_InitTypeDef DMA_Initstruct;
-
- // 开启DMA时钟
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
- //DMA1通道5配置
- DMA_DeInit(USART2_RXD_DMA_CHAN);
-
- // DMA配置
- // 外设地址
- DMA_Initstruct.DMA_PeripheralBaseAddr = (uint32_t)(&USART2->RDR);
- // 内存地址
- DMA_Initstruct.DMA_MemoryBaseAddr =(uint32_t)revUart2;
- // DMA传输方向单向
- DMA_Initstruct.DMA_DIR =DMA_DIR_PeripheralSRC;
- // 设置DMA在传输时缓冲区的长度
- DMA_Initstruct.DMA_BufferSize =USART_RXD_BUF_SIZE;
- // 设置DMA的外设递增模式,一个外设
- DMA_Initstruct.DMA_PeripheralInc =DMA_PeripheralInc_Disable;
- // 设置DMA的内存递增模式
- DMA_Initstruct.DMA_MemoryInc =DMA_MemoryInc_Enable;
- // 外设数据字长
- DMA_Initstruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
- // 内存数据字长
- DMA_Initstruct.DMA_MemoryDataSize =DMA_MemoryDataSize_Byte;
- // 设置DMA的传输模式
- DMA_Initstruct.DMA_Mode =DMA_Mode_Normal;
- // 设置DMA的优先级别
- DMA_Initstruct.DMA_Priority =DMA_Priority_High; // DMA_Priority_VeryHigh;
- // 设置DMA的2个memory中的变量互相访问
- DMA_Initstruct.DMA_M2M =DMA_M2M_Disable;
- DMA_Init(USART2_RXD_DMA_CHAN,&DMA_Initstruct);
-
- // 开启DMA
- DMA_Cmd(USART2_RXD_DMA_CHAN,ENABLE);
-
- #if( USART2_RXD_MODE == UART_SEND_DMA)
- // DMA通道TXD配置
- DMA_DeInit(USART2_TXD_DMA_CHAN);
- // 外设地址,串口1
- DMA_Initstruct.DMA_PeripheralBaseAddr =(uint32_t)(&USART1->TDR);
- // 发送内存地址
- DMA_Initstruct.DMA_MemoryBaseAddr = (uint32_t)send2Buff;
- // 外设为传送数据目的地,即发送数据
- DMA_Initstruct.DMA_DIR =DMA_DIR_PeripheralDST;
- // 发送长度为0,即未有快递需要发送
- DMA_Initstruct.DMA_BufferSize = 0;
- // 初始化
- DMA_Init(USART2_TXD_DMA_CHAN,&DMA_Initstruct);
- // 使能串口发送完成中断
- USART_ITConfig(USART2, USART_IT_TC,ENABLE);
- DMA_Cmd(USART2_TXD_DMA_CHAN,ENABLE);
- // 使能DMA串口发送和接受请求
- USART_DMACmd(USART2,(USART_DMAReq_Tx|USART_DMAReq_Rx), ENABLE);
- #endif /* USART1_RXD_MODE */
- }
-
- /*********************************************************************************
- * Name : UART2_Api_Init
- *
- * Brief : Initialized the uart1
- *
- * Input : None
- *
- * Output : None
- *
- * Remark : None
- ***********************************************************************************/
- void UART2_Api_Init(void)
- {
- Uart2_Gpio_Init();
- Uart2_DMA_Init();
- }
-
- /*********************************************************************************
- * Name : USART2_IRQHandler
- *
- * Brief : USART1 interrupt process handle
- *
- * Input : None
- *
- * Output : None
- *
- * Remark : None
- ***********************************************************************************/
- void USART2_IRQHandler(void)
- {
- uint8_t len = 0;
-
- if(USART_GetITStatus(USART2,USART_IT_IDLE) != RESET)
- {
- USART2->ICR |= 1<<4; // 清除中断
- DMA_Cmd(USART2_RXD_DMA_CHAN,DISABLE);
-
- len =USART_RXD_BUF_SIZE - DMA_GetCurrDataCounter(USART2_RXD_DMA_CHAN);
-
- if(len >USART_RXD_BUF_SIZE)
- len =USART_RXD_BUF_SIZE;
-
- memcpy(datUart2Buff,revUart2,len);
-
- // 重新设置接收数据个数
- USART2_RXD_DMA_CHAN->CNDTR =USART_RXD_BUF_SIZE;
- // 开启DMA
- DMA_Cmd(USART2_RXD_DMA_CHAN,ENABLE);
-
- revUart2Flag = TRUE;
- }
-
- #if( USART2_RXD_MODE ==UART_SEND_DMA )
- // 全部数据发送完成,产生该标记
- if(USART_GetITStatus(USART2,USART_IT_TC)!=RESET)
- {
- // 清除完成标记
- USART_ClearITPendingBit(USART2,USART_IT_TC);
- DMA_Cmd(USART2_TXD_DMA_CHAN,DISABLE);
- // 清除数据长度
- USART2_TXD_DMA_CHAN->CNDTR= 0;
- DMA_Cmd(USART2_TXD_DMA_CHAN, ENABLE);
- }
- #endif /* USART1_RXD_MODE */
- }
-
- /*********************************************************************************
- * Name :Uart2_Data_Process
- *
- * Brief : process the received data
- *
- * Input : processDat - the process function point
- *
- * Output : None
- *
- * Remark : None
- ***********************************************************************************/
- void Uart2_Data_Process(pRevprocessDat)
- {
- if(!revUart2Flag)
- return;
- revUart2Flag = FALSE;
-
- processDat(datUart2Buff);
- }
-
- /*********************************************************************************
- * Name : Uart2_Send_Bytes
- *
- * Brief : process the received data
- *
- * Input : dat - the data buffer
- *
- * len - the count of data to be send
- *
- * Output : None
- *
- * Remark : None
- ***********************************************************************************/
- void Uart2_Send_Bytes(uint8_t*dat,uint16_t len)
- {
- #if (USART2_RXD_MODE ==UART_SNED_REQ)
- while(len--)
- {
- USART_SendData(USART2, *dat++);
- /* Loop until the end of transmission */
- while(USART_GetFlagStatus(USART2,USART_FLAG_TXE) == RESET);
- }
- #else
- // 判断长度是否有效
- if(!len)
- return ;
- while(DMA_GetCurrDataCounter(USART2_TXD_DMA_CHAN));
-
- // 检查DMA发送通道内是否还有数据
- if(dat)
- memcpy(send2Buff,dat,(len > USART2_TX_BUF_SIZE ? USART2_TX_BUF_SIZE:len));
-
- // DMA发送数据-要先关 设置发送长度 开启DMA
- DMA_Cmd(USART2_TXD_DMA_CHAN, DISABLE);
- // 设置发送长度
- USART2_TXD_DMA_CHAN->CNDTR = len;
- // 启动DMA发送
- DMA_Cmd(USART2_TXD_DMA_CHAN, ENABLE);
-
- #endif /* */
- }
本次代码是为了测试用的,所以有些地方写的比较随意,变量命名也不是太规范,这里检讨一下。串口接收到数据处理函数用的是回调函数,方便修改,在使用时,只要调用相关的函数指针即可。关于函数指针的类型,在下面Dsk_Usart.h中有定义。
Dsk_Usart.h源文件笔者习惯一个.c文件跟一个.h文件,方便移植,也方面管理。用到哪个模块直接把两个文件一拷贝,再在相关文件中包含.h文件,就可以直接用,比较方便。有人会说有没有必要,一个.C跟一个.H,这个怎么说呢?看个人习惯吧,编程这玩意只有最适合项目工程的,没有说最好的。一般按功能模块划分,源文件感觉长了,还可以再细分不同的模块,笔者认为,加个头文件,至少不用在.c文件中调用某个函数再用extern声明那个外部函数,至少声明不会乱掉。
关于Dsk_Usart.h中主要是接口的声明,API的声明等,其源代码如下所示:
结语本篇文档主要总结一下如果设置串口的空闲中断+DMA的应用方式,也相当于代码备份吧,具体要怎么测试,测试如果如果,这里不再说细述,如果读者有兴趣,可以自己设置相关的测试^_^
本帖最后由 懒猫爱飞 于 2018-11-29 16:19 编辑