当前位置:首页 > 单片机 > 单片机
[导读] RT-Thread学习笔记八 --------USART DMA方式发送老规矩,首先说一下我的配置STM32F207IGT6 MDK RTT 1.1.0使用UART2作为finsh组件,UART3作为串口输出/* register uart2 */rt_hw_serial_registe

RT-Thread学习笔记八

--------USART DMA方式发送
老规矩,首先说一下我的配置
STM32F207IGT6 MDK RTT 1.1.0

使用UART2作为finsh组件,UART3作为串口输出
/* register uart2 */
rt_hw_serial_register(&uart2_device,"uart2",RT_DEVICE_FLAG_RDWR| RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM,&uart2);
配置成中断接收,数据流发送。

/* register uart3 */
rt_hw_serial_register(&uart3_device,"uart3",RT_DEVICE_FLAG_RDWR| RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_DMA_TX,&uart3);
配置成中断接收,DMA发送

相信大家已经能够正常使用finsh组件了,所以小弟就不献丑了,呵呵!
shaolin前辈写的finsh的使用
连接1

rt-thread下的串口驱动程序分析
连接2
主要写一下UART3 使用DMA发送
#ifdef RT_USING_UART3
struct stm32_serial_int_rx uart3_int_rx;
struct stm32_serial_dma_tx uart3_dma_tx;
struct stm32_serial_device uart3 =
{
USART3,
&uart3_int_rx,
&uart3_dma_tx
};
struct rt_device uart3_device;
#endif

我仍然按照usart.c中rt_hw_usart_init()的顺序进行分析

/************************************ ******************************/
首先时钟配置RCC_Configuration();
#ifdef RT_USING_UART3
/* Enable USART3 and GPIOC clocks */
RCC_AHB1PeriphClockCmd(UART3_APBPeriph_GPIOX, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APBPeriph_UART3, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_APBPeriph_UART3_DMA,ENABLE);
#endif
配置参数时都采用宏定义,如UART3_APBPeriph_GPIOX,RCC_APBPeriph_UART3,之所以不直接采用ST官方的参数,是因为这样不仅方便以后程序的移植,而且不容易出错。

#define UART3_GPIO_RX GPIO_Pin_11
#define UART3_GPIO_TX GPIO_Pin_10
#define UART3_GPIO GPIOC
#define UART3_APBPeriph_GPIOX RCC_AHB1Periph_GPIOC
#define UART3_TX_PinSource GPIO_PinSource10
#define UART3_RX_PinSource GPIO_PinSource11
#define RCC_APBPeriph_UART3 RCC_APB1Periph_USART3
#define RCC_APBPeriph_UART3_DMA RCC_AHB1Periph_DMA1
#define UART3_TX_DMAy_Streamx DMA1_Stream3
#define UART3_TX_DMA_Channel DMA_Channel_4
#define UART3_TX_DMA_IRQHandler DMA1_Stream3_IRQn
#define UART3_TX_DMA_FLAG_TCIF DMA_FLAG_TCIF3
//#define UART3_RX_DMAy_Streamx DMA1_Stream1
//#define UART3_RX_DMA_Channel DMA_Channel_4

/************************************ ******************************/
然后进行管脚配置GPIO_Configuration();
#ifdef RT_USING_UART3
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;

GPIO_InitStruct.GPIO_Pin=UART3_GPIO_TX;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(UART3_GPIO,&GPIO_InitStruct);

GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;
GPIO_InitStruct.GPIO_Pin=UART3_GPIO_RX;
GPIO_Init(UART3_GPIO,&GPIO_InitStruct);

GPIO_PinAFConfig(UART3_GPIO, UART3_TX_PinSource, GPIO_AF_USART3);
GPIO_PinAFConfig(UART3_GPIO, UART3_RX_PinSource, GPIO_AF_USART3);
#endif

/************************************ ******************************/
接着中断配置NVIC_Configuration();
#ifdef RT_USING_UART3
/* Enable the USART3 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

/* Enable the DMA1 Stream4 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = UART3_TX_DMA_IRQHandler;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
#endif

这里需要注意说明的是STM32F2系列和STM32F1系列的DMA配置有些不同,F1系列配置时要注意DMAy_Channelx,F2系列用了另外一个名字DMAy_Streamx
DMAy_Channelx,: where y can be 1 or 2 to select the DMA and x can be 1 to 7 for DMA1 and 1 to 5 for DMA2 to select the DMA Channel.

DMAy_Streamx,: where y can be 1 or 2 to select the DMA and x can be 0 to 7 to select the DMA Stream

关于STM32F207的DMA有篇博客写的比较详细,大家可以参考一下。
连接3


/************************************ ******************************/
然后配置DMADMA_Configuration();
DMA_InitTypeDef DMA_InitStructure;

DMA_InitStructure.DMA_Channel = UART3_TX_DMA_Channel;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; /* Specifies whether the Peripheral address register should be incremented or not */
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; /* Specifies whether the memory address register should be incremented or not */
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;

DMA_DeInit(UART3_TX_DMAy_Streamx);
DMA_InitStructure.DMA_PeripheralBaseAddr = USART3_DR_Base;
DMA_InitStructure.DMA_Memory0BaseAddr = (u32)0;
DMA_InitStructure.DMA_BufferSize = 1;
DMA_Init(UART3_TX_DMAy_Streamx,&DMA_InitStructure);
// DMA_Cmd(UART3_TX_DMAy_Streamx, ENABLE);/* move to rt_serial_enable_dma() by RTT */

DMA_ITConfig(UART3_TX_DMAy_Streamx, DMA_IT_TC | DMA_IT_TE, ENABLE);
DMA_ClearFlag(UART3_TX_DMAy_Streamx, UART3_TX_DMA_FLAG_TCIF);

/************************************ ******************************/
最后进行UART的配置
#ifdef RT_USING_UART3
USART_DeInit(USART3);
USART_InitStructure.USART_BaudRate = 19200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowContro=USART_HardwareFlowControl_None;
USART_InitStructure.USART_M = USART_Mode_Rx | USART_Mode_Tx;

USART_Init(USART3, &USART_InitStructure);

uart3_dma_tx.dma_channel= UART3_TX_DMAy_Streamx;

/* register uart3 */
rt_hw_serial_register(&uart3_device, "uart3",
RT_DEVICE_FLAG_RDWR|RT_DEVICE_FLAG_INT_RX|RT_DEVICE_FLAG_DMA_TX,&uart3);

/* Enable USART3 DMA Tx request */
USART_DMACmd(USART3, USART_DMAReq_Tx , ENABLE);

/* enable interrupt */
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);

USART_ClearFlag(USART3,USART_FLAG_TXE);
#endif

uart3_dma_tx.dma_channel= UART3_TX_DMAy_Streamx;这条语句一定要当心,这里不是配置dma_channel,因为在seria.c中rt_serial_enable_dma()进行DMA的使能和失能
例如DMA_Cmd(dma_channel, ENABLE);
但是st的F2系列的库函数中DMA配置的是Stream,而不是channel
DMA_Cmd(DMA_Stream_TypeDef* DMAy_Streamx, FunctionalState NewState)

到这里UART3的初始化就OK了,再进入中断函数stm32f2xx_it.c配置

/*********************DMA中断******************************/
#define UART3_TX_DMAy_Streamx DMA1_Stream3
#define UART3_TX_DMA_IT_TCIF DMA_IT_TCIF3
#define UART3_TX_DMA_IT_TEIF DMA_IT_TCIF3
#define UART3_TX_DMA_FLAG_TCIF DMA_FLAG_TCIF3
#define UART3_TX_DMA_FLAG_TEIF DMA_FLAG_TCIF3
void DMA1_Stream3_IRQHandler(void)
{
#ifdef RT_USING_UART3
extern struct rt_device uart3_device;
extern void rt_hw_serial_dma_tx_isr(struct rt_device *device);

/* enter interrupt */
rt_interrupt_enter();

if(DMA_GetITStatus(UART3_TX_DMAy_Streamx,UART3_TX_DMA_IT_TCIF))
{
/* transmission complete, invoke serial dma tx isr */
rt_hw_serial_dma_tx_isr(&uart3_device);
}
/* clear DMA flag */
DMA_ClearFlag(UART3_TX_DMAy_Streamx,DMA_FLAG_TCIF3 | UART3_TX_DMA_FLAG_TEIF);

/* leave interrupt */
rt_interrupt_leave();
#endif
}

在中断函数中,大家一定要注意DMA_GetITStatus() 和 DMA_GetFLAGStatus(),不能混淆了,我就吃过亏。一旦弄错了,DMA中断程序不正常,就导致了DMA只能发送一次。

在APPTask.c中创建了一个任务,进行发送。


void usart_tx_thread_entry(void *p)
{
char tx_buf[]="hello pc!rn";
u8 datalen;
while(1)
{
datalen = strlen(tx_buf);
dev_uart3->write(dev_uart3,0,tx_buf,datalen);
rt_thread_delay(RT_TICK_PER_SECOND*2);
}

}
串口输出


因为我刚接触RTT系统,所以会有很多考虑不周全的方面,请大家指出,呵呵!2013.1.6
因为我不能发连接,所以文中提到连接地方到放到了附件pdf中

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

串行通信需要传输的数据通过调制器(Modulator)将数据转换为模拟信号,经过信号调制(Modulation)后在传输线上传输,接收端通过解调器(Demodulator)将信号解码还原成原始数据。

关键字: 串口 串行通信 并行通信

51 单片机内部有一个全双工串行接口。什么叫全双工串口呢?一般来说,只能接受或只能发送的称为单工串行;既可接收又可发送,但不能同时进行的称为半双工;能同时接收和发送的串行口称为全双工串行口。串行通信是指数据一位一位地按顺...

关键字: 单片机 全双工 串口

串口是“串行接口”的简称,即采用串行通信方式的接口。串行通信将数据字节分成一位一位的形式在一条数据线上逐个传送,其特点是通信线路简单,但传输速度较慢。因此串口广泛应用于嵌入式、工业控制等领域中对数据传输速度要求不高的场合...

关键字: 串口 RS232 同步传输

串口作为单片机开发的一个常用的外设,应用范围非常广。大部分时候,串口需要接收处理的数据长度是不定的。那么怎么才能判断一帧数据是否结束呢,今天就以STM32单片机为例,介绍几种接收不定长数据的方法。

关键字: 单片机 串口 STM32

这是FPGA之旅设计的第十例啦,在上一例中,已经成功驱动了OLED屏幕,本例将结合上一例,以及第四例多bytes串口通信做一个有趣的例程。

关键字: FPGA OLED屏 串口

接下来测试烧写功能,本次采用串口和USB烧写方式。使用ISP串口烧写这是51单片机常用的方案,本次测试比较顺利,没有遇到什么问题。但是USB烧写没有测试成功,USB烧写方式不需要任何的驱动和硬件支持,直接将USB线和ST...

关键字: PCB控制板 USB 串口

摘要:多功能电能表在配电系统中应用广泛,其计量的准确度对企业管理和考核至关重要,因此在设计多功能电能表时需要对其进行校准,满足一定应用等级。常规的多功能电能表校准方法是以电能脉冲校准为主,现提出一种基于C#和功率校表法的...

关键字: 多功能电能表 串口 波特率

摘 要:为了能通过串口采集电能参数,完成一种基于串口的三相电能采集设备的研制,设计了电能采集设备的硬件和软件部分。其中硬件采用MCU+专用电能计量芯片的结构,结构简单;软件则用于实现输入、输出、三相电能参数的采集和串行通...

关键字: 电能采集 ATT7022B MSP430 串口

如何确定时基假如要测量的波特率为9600,则每一比特位的时间为:1/9600≈104μs,一般示波器横向上每个大格子里5个小格子,要想看清一比特位一般需要一个小格子就够了,则时基为:104μs*5=520μs,也就是说时...

关键字: 串口

VivadoML最新版2021下载方法:《安装Vivado2021.1ML版,编译时间真的会减少吗?》今天我们通过zedboard串口使用的实例来简单介绍vivado和vitis的使用步骤。1,首先打开软件,新建一个空白...

关键字: 串口 zedboard vi
关闭
关闭