本帖最后由 woai32lala 于 2023-3-19 21:36 编辑
【APM32F107VCT6 MINI开发板测评】之串口空闲帧中断DMA接收
波特率115200 RX PA10 DMA1 通道channel5 /**
* [url=home.php?mod=space&uid=247401]@brief[/url] Definition for COM port1, connected to USART1
*/
#define MINI_COM1 USART1
#define MINI_COM1_CLK RCM_APB2_PERIPH_USART1
#define MINI_COM1_TX_PIN GPIO_PIN_9
#define MINI_COM1_TX_GPIO_PORT GPIOA
#define MINI_COM1_TX_GPIO_CLK RCM_APB2_PERIPH_GPIOA
#define MINI_COM1_RX_PIN GPIO_PIN_10
#define MINI_COM1_RX_GPIO_PORT GPIOA
#define MINI_COM1_RX_GPIO_CLK RCM_APB2_PERIPH_GPIOA
#define MINI_COM1_IRQn USART1_IRQn
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] Definition for COM port2, connected to USART2
*/
#define MINI_COM2 USART2
#define MINI_COM2_CLK RCM_APB1_PERIPH_USART2
#define MINI_COM2_TX_PIN GPIO_PIN_2
#define MINI_COM2_TX_GPIO_PORT GPIOA
#define MINI_COM2_TX_GPIO_CLK RCM_APB2_PERIPH_GPIOA
#define MINI_COM2_RX_PIN GPIO_PIN_3
#define MINI_COM2_RX_GPIO_PORT GPIOA
#define MINI_COM2_RX_GPIO_CLK RCM_APB2_PERIPH_GPIOA
#define MINI_COM2_IRQn USART2_IRQn
我们平时接收固定长度的一般用普通串口中断或者DMA传送完成中断,但串口普通中断是接收到1个字节就会中断一次,这样严重拖慢了CPU的效率。DMA传送完成中断一般是用于固定字节的传输, 但是如果我们发送的数据长度是不固定的怎么办呢?像STM32有串口空闲中断,HC32有串口超时钟中断,那么极海AMP32有什么呢? 我们查阅用户手册发现,极海AMP32有串口空闲帧中断。 那么空闲帧是什么呢?
其实可以说和Stm32的空闲IDLE一样,就是超过1个字节连续高电平,还有断开帧等,如下图所示。
普通的一帧数据有起始位、1个字节数据和停止位。空闲帧没有起始位,是一帧连续高电平。断开是发送一个0x00,其实我有点疑问,那么0x00万一是有效数据视为断开帧咋那么解决,等官方解释一下,我们继续往下说。
像我们下面发送的两帧数据,就可以用空闲帧中断来获取,两帧数据之间有超过一个字节的高电平时间。 要使能空闲帧中断生效,需要我们使能空闲帧中断,也就是这个函数。
串口配置 * [url=home.php?mod=space&uid=247401]@brief[/url] Configures COM port.
*
* @param COM: Specifies the COM port to be configured.
* This parameter can be one of following parameters:
* [url=home.php?mod=space&uid=2817080]@ARG[/url] COM1
* [url=home.php?mod=space&uid=2817080]@ARG[/url] COM2
*
* @retval None
*/
void APM_MINI_COMInit(COM_TypeDef COM, USART_Config_T* configStruct)
{
GPIO_Config_T GPIO_configStruct;
/* Enable GPIO clock */
RCM_EnableAPB2PeriphClock(COM_TX_PORT_CLK[COM] | COM_RX_PORT_CLK[COM]);
if (COM == COM1)
{
RCM_EnableAPB2PeriphClock(COM_USART_CLK[COM]);
}
else
{
RCM_EnableAPB1PeriphClock(COM_USART_CLK[COM]);
}
/* Configure USART Tx as alternate function push-pull */
GPIO_configStruct.mode = GPIO_MODE_AF_PP;
GPIO_configStruct.pin = COM_TX_PIN[COM];
GPIO_configStruct.speed = GPIO_SPEED_50MHz;
GPIO_Config(COM_TX_PORT[COM], &GPIO_configStruct);
/* Configure USART Rx as input floating */
GPIO_configStruct.mode = GPIO_MODE_IN_FLOATING;
GPIO_configStruct.pin = COM_RX_PIN[COM];
GPIO_Config(COM_RX_PORT[COM], &GPIO_configStruct);
/* USART configuration */
USART_Config(COM_USART[COM], configStruct);
/* Enable USART */
USART_Enable(COM_USART[COM]);
}
以上是串口相关函数,下面是DMA部分。
DMA配置 直接存储器访问 (DMA) 用于在外设与存储器之间以及存储器与存储器之间提供高速数据传输。可以在无需任何 CPU 操作的情况下通过 DMA 快速移动数据。这样节省的 CPU 资源可供其它操作使用。说白了DMA就是一个搬运工,将数据从一个地方搬到另一个地方而不需要CPU处理。作为一个搬运工,要他正常工作必须要确定几个重要的参数: 传输模式:数据从哪里搬到哪里。三种可能的传输方向:存储器到外设、外设到存储器或存储器到存储器,我们我次选择的方向是从外设到内存DMA_DIR_PERIPHERAL_SRC。 通道选择:就是数据传输的是走那条道路,这里是DMA1的channel5 仲裁器:多个DMA传输是优先级高的优先传输。 传输字节量:我们这里设置200,最大为65535,根据需求设置。 数据长度:每次传输的数据长度,可以一个字节,两个字节(半字),四个字节(字) 指针递增:如果使能了递增模式,则下一次传输的地址将是前一次传输的地址递增 1(字节)、2(半字)或4(字),我们这里用1个字节。 循环模式:循环模式可用于处理循环缓冲区和连续数据流(例如 ADC 扫描模式)。可以使用 DMA_SxCR寄存器中的 CIRC 位使能,我们用正常模式 其他:关于DMA还有双缓冲区模式、突发传输等等其他设置,一般用不到,具体查询用户手册。 我们这里DMA只需要作为通道,不需要进行中断,DMA中断我们不使能。
中断接收函数 void USART1_Isr(void)
{
if(USART_ReadIntFlag(USART1, USART_INT_IDLE))
{
USART_ClearIntFlag(USART1, USART_INT_IDLE); //清除中断标志
USART_RxData(USART1);
DMA_Disable(DMA1_Channel5);
/* Data number */
data_num = BufSize - DMA_ReadDataNumber(DMA1_Channel5);
DMA_ConfigDataNumber(DMA1_Channel5,BufSize);
DMA_Enable(DMA1_Channel5);
APM_MINI_LEDToggle(LED2);
}
}
测试 接线
XCOM2发送数据
MCU接收到数据
我们可以看到右侧Watch中有35个数据,且数据跟我们发送一致,数量也一致,并用过LED灯反转来表示接收数据次数,因此增加Demo测试成功。
|