你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

如果可能,别再用中断接收串口数据了

[复制链接]
lusonghua 提问时间:2015-6-10 16:51 /
增加一些注释吧,这个代码能帮上忙就行。

________________________________________________________

实在受不了中断了。
这里使用DMA循环方式接收串口数据,不用中断,空闲时间去查询DMA状态,然后拷贝数据即可。
F407的部分代码如下,F103的类似:

// 宏定义
#define USART3_RXBUF_SIZ   256 /* UART接收缓冲,必须为2^n,增加这个数值可以放宽处理UART接收数据的时间间隔 */
#define USART3_RX_DMA_CHANNEL            DMA_Channel_4 /* UART接收通道 */
#define USART3_RX_DMA_STREAM             DMA1_Stream1 /* UART接收DMA */

// 全局缓冲区
static uint8_t gl_Usart3Rxbuf[USART3_RXBUF_SIZ] = { 0, };

// 初始化串口和DMA..
static void MX_Uart_Init(void)
{
USART_InitTypeDef USART_InitStruct;
DMA_InitTypeDef DMA_InitStruct;

// 初始化USART3的通讯 ----------------------------------------------------------

USART_StructInit(&USART_InitStruct);
USART_InitStruct.USART_BaudRate = 115200;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART3, &USART_InitStruct);

/* 配置UART为DMA循环接收方式,即DMA按照RingBuffer方式写入UART接收缓冲,CPU不参与UART接收 */
DMA_StructInit(&DMA_InitStruct);
DMA_InitStruct.DMA_BufferSize = sizeof(gl_Usart3Rxbuf) ;
DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable ;
DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull ;
DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single ;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
DMA_InitStruct.DMA_PeripheralBaseAddr =(uint32_t) (&(USART3->DR)) ;
DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;
DMA_InitStruct.DMA_Channel = USART3_RX_DMA_CHANNEL;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)gl_Usart3Rxbuf;
DMA_Init(USART3_RX_DMA_STREAM, &DMA_InitStruct);

USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE);
DMA_Cmd(USART3_RX_DMA_STREAM, ENABLE);
USART_Cmd(USART3, ENABLE);
}

// 处理接收的串口数据
void Idle_Proc(void)
{
static uint16_t lastDataCounter = 0; /* 保存已处理的UARt接收数据index */
static char line[256];
static int ncin = 0;

uint16_t currDataCounter;
bool newLine = false;
uint8_t ch;

// 处理USART3接收的数据 ----------------------------------------------------

/* 获取DMA中数据计数,用于计算当前所接收字符的index */
do {
  currDataCounter = DMA_GetCurrDataCounter(USART3_RX_DMA_STREAM);
} while (currDataCounter != DMA_GetCurrDataCounter(USART3_RX_DMA_STREAM));

currDataCounter = sizeof(gl_Usart3Rxbuf) - currDataCounter; /* 计算当前UART接收的index */
while (((currDataCounter - lastDataCounter) & (USART3_RXBUF_SIZ - 1)) != 0) { /* 一直处理到已接收的index */
  ch = gl_Usart3Rxbuf[lastDataCounter++ & (USART3_RXBUF_SIZ - 1)]; /* 拷贝已接收的UART数据,所保存的index增长 */
......
}
}


/* 增加主函数 */
int main(void) {
    for (;;) {
        process1();
        process2();
        process3();
        ...
        process99();

        Idle_Proc();
    }
}

其他的诸如时钟初始化、GPIO初始化等这个就不贴了。

PS:中断是个好东西,但是,...,能不用就不用吧。。。,还有别把程序写成阻塞的。




收藏 1 评论31 发布时间:2015-6-10 16:51

举报

31个回答
QianFan 回答时间:2015-6-10 17:04:04
中断+RingBuffer一起处理。DMA无法做成RingBuffer那样
数码小叶 回答时间:2015-6-10 17:06:44
中断写起来简单,这是最主要的原因
creep 回答时间:2015-6-10 17:33:30
如果接收数据很多的话,频繁的中断的确开销很大。
既然用DMA了,为何不用串口空闲中断+DMA呢,这就不用频繁的查询了,一次能接收不定长的一帧数据。
为什么是EEFOCUS小白 回答时间:2015-6-10 17:33:53
中断接收有什么问题么
dsjsjf 回答时间:2015-6-10 20:12:38
creep 发表于 2015-6-10 17:33
如果接收数据很多的话,频繁的中断的确开销很大。
既然用DMA了,为何不用串口空闲中断+DMA呢,这就不用频繁 ...

这个方法貌似不错,下次试试
moyanming2013 回答时间:2015-6-10 22:38:25
程序一直在查询串口,实在是效率低下把?
你的理由是什么呢?
shadow丶 回答时间:2015-6-10 22:53:49
确实 中断写这方便 使用dma  毕竟没有写串口舒服
creep 回答时间:2015-6-10 23:25:45
dsjsjf 发表于 2015-6-10 20:12
这个方法貌似不错,下次试试

这应该是串口接收数据比较好的方法之一的,中断的方法和这个没法比。
lusonghua 回答时间:2015-6-11 08:51:40
moyanming2013 发表于 2015-6-10 22:38
程序一直在查询串口,实在是效率低下把?
你的理由是什么呢?

没有查询串口,是查询DMA的状态,DMA的设置自行完成了RingBuffer的功能。
串口接收的缓冲长度决定了读取RingBuffer的时间裕度。
1234下一页

所属标签

相似问题

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版